first commit
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+2
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||||
Generated
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MaterialThemeProjectNewConfig">
|
||||||
|
<option name="metadata">
|
||||||
|
<MTProjectMetadataState>
|
||||||
|
<option name="migrated" value="true" />
|
||||||
|
<option name="pristineConfig" value="false" />
|
||||||
|
<option name="userId" value="51fce684:19c942ae0f3:-7ffd" />
|
||||||
|
</MTProjectMetadataState>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakePythonSetting">
|
||||||
|
<option name="pythonIntegrationState" value="YES" />
|
||||||
|
</component>
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Lab9_UNIX.iml" filepath="$PROJECT_DIR$/.idea/Lab9_UNIX.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
cmake_minimum_required(VERSION 4.0)
|
||||||
|
project(Lab9_UNIX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
find_package(Curses REQUIRED)
|
||||||
|
|
||||||
|
include_directories(${CURSES_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_executable(Lab9_UNIX main.cpp
|
||||||
|
core/Vector2.cpp
|
||||||
|
core/Vector2.h
|
||||||
|
core/PaintDevice.cpp
|
||||||
|
core/PaintDevice.h
|
||||||
|
core/Size.cpp
|
||||||
|
core/Size.h
|
||||||
|
core/Square.cpp
|
||||||
|
core/Square.h
|
||||||
|
core/Engine.cpp
|
||||||
|
core/Engine.h
|
||||||
|
core/ExampleGame.cpp
|
||||||
|
core/ExampleGame.h
|
||||||
|
core/Point.h
|
||||||
|
core/Figure.cpp
|
||||||
|
core/Figure.h
|
||||||
|
core/IBlock.cpp
|
||||||
|
core/IBlock.h
|
||||||
|
core/GameField.cpp
|
||||||
|
core/GameField.h
|
||||||
|
core/Tetris.cpp
|
||||||
|
core/Tetris.h)
|
||||||
|
|
||||||
|
target_link_libraries(Lab9_UNIX ${CURSES_LIBRARIES})
|
||||||
|
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
#include "Engine.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
Engine::ErrorCode Engine::run()
|
||||||
|
{
|
||||||
|
ErrorCode errorCode =
|
||||||
|
ErrorCode::success;
|
||||||
|
|
||||||
|
auto lastUpdate =
|
||||||
|
std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
auto lag =
|
||||||
|
std::chrono::milliseconds(0);
|
||||||
|
|
||||||
|
const auto timeQuantum =
|
||||||
|
std::chrono::milliseconds(15);
|
||||||
|
|
||||||
|
while (!end())
|
||||||
|
{
|
||||||
|
// INPUT
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
updateInput();
|
||||||
|
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
// UPDATE
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
auto now =
|
||||||
|
std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
lag +=
|
||||||
|
std::chrono::duration_cast
|
||||||
|
<
|
||||||
|
std::chrono::milliseconds
|
||||||
|
>
|
||||||
|
(
|
||||||
|
now - lastUpdate
|
||||||
|
);
|
||||||
|
|
||||||
|
lastUpdate = now;
|
||||||
|
|
||||||
|
while (lag >= timeQuantum)
|
||||||
|
{
|
||||||
|
lag -= timeQuantum;
|
||||||
|
|
||||||
|
update(
|
||||||
|
static_cast<int>(
|
||||||
|
timeQuantum.count()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
// RENDER
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
if (!m_PaintDevice.ready())
|
||||||
|
{
|
||||||
|
errorCode =
|
||||||
|
ErrorCode::paint_device_not_ready;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_PaintDevice.clear();
|
||||||
|
|
||||||
|
render(m_PaintDevice);
|
||||||
|
|
||||||
|
m_PaintDevice.render();
|
||||||
|
|
||||||
|
//=================================
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(
|
||||||
|
std::chrono::milliseconds(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::updateInput()
|
||||||
|
{
|
||||||
|
int key = getch();
|
||||||
|
|
||||||
|
while (key != ERR)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
m_TrackedKeys.find(key)
|
||||||
|
!=
|
||||||
|
m_TrackedKeys.end()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
on_button_press(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
key = getch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::track_key(int key)
|
||||||
|
{
|
||||||
|
m_TrackedKeys.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::untrack_key(int key)
|
||||||
|
{
|
||||||
|
auto it =
|
||||||
|
m_TrackedKeys.find(key);
|
||||||
|
|
||||||
|
if (it != m_TrackedKeys.end())
|
||||||
|
{
|
||||||
|
m_TrackedKeys.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "PaintDevice.h"
|
||||||
|
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class ErrorCode
|
||||||
|
{
|
||||||
|
success = 0,
|
||||||
|
paint_device_not_ready
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Engine() = default;
|
||||||
|
|
||||||
|
ErrorCode run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void track_key(int key);
|
||||||
|
|
||||||
|
void untrack_key(int key);
|
||||||
|
|
||||||
|
PaintDevice& paint_device()
|
||||||
|
{
|
||||||
|
return m_PaintDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool end() const = 0;
|
||||||
|
|
||||||
|
virtual void on_button_press(
|
||||||
|
int button
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
virtual void update(
|
||||||
|
int dt
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
virtual void render(
|
||||||
|
PaintDevice& paintDevice
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateInput();
|
||||||
|
|
||||||
|
PaintDevice m_PaintDevice;
|
||||||
|
|
||||||
|
std::set<int> m_TrackedKeys;
|
||||||
|
};
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
#include "ExampleGame.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
void Bullet::render(PaintDevice& paintDevice)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
m_Position,
|
||||||
|
'|'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bullet::update(const int dt)
|
||||||
|
{
|
||||||
|
m_Lag += dt;
|
||||||
|
|
||||||
|
const int quant = 50;
|
||||||
|
|
||||||
|
if (m_Lag <= quant)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Lag -= quant;
|
||||||
|
|
||||||
|
m_Position.y()--;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gun::Gun()
|
||||||
|
{
|
||||||
|
m_Body =
|
||||||
|
{
|
||||||
|
Vector2(5, 0),
|
||||||
|
Vector2(5, 1),
|
||||||
|
|
||||||
|
Vector2(4, 2),
|
||||||
|
Vector2(4, 3),
|
||||||
|
Vector2(4, 4),
|
||||||
|
|
||||||
|
Vector2(6, 2),
|
||||||
|
Vector2(6, 3),
|
||||||
|
Vector2(6, 4),
|
||||||
|
|
||||||
|
Vector2(3, 5),
|
||||||
|
Vector2(7, 5),
|
||||||
|
|
||||||
|
Vector2(2, 6),
|
||||||
|
Vector2(5, 6),
|
||||||
|
Vector2(8, 6),
|
||||||
|
|
||||||
|
Vector2(1, 7),
|
||||||
|
Vector2(5, 7),
|
||||||
|
Vector2(9, 7),
|
||||||
|
|
||||||
|
Vector2(0, 8),
|
||||||
|
Vector2(1, 8),
|
||||||
|
Vector2(2, 8),
|
||||||
|
|
||||||
|
Vector2(8, 8),
|
||||||
|
Vector2(9, 8),
|
||||||
|
Vector2(10, 8),
|
||||||
|
|
||||||
|
Vector2(3, 9),
|
||||||
|
Vector2(7, 9),
|
||||||
|
|
||||||
|
Vector2(3, 10),
|
||||||
|
Vector2(7, 10),
|
||||||
|
|
||||||
|
Vector2(4, 11),
|
||||||
|
Vector2(6, 11),
|
||||||
|
|
||||||
|
Vector2(4, 12),
|
||||||
|
Vector2(5, 12),
|
||||||
|
Vector2(6, 12)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Bullet> Gun::fire()
|
||||||
|
{
|
||||||
|
std::vector<Bullet> bullets;
|
||||||
|
|
||||||
|
if (m_CooldownCenter == 0)
|
||||||
|
{
|
||||||
|
bullets.push_back(Bullet());
|
||||||
|
|
||||||
|
bullets.back().m_Position =
|
||||||
|
Vector2(
|
||||||
|
m_Position.x() + 4,
|
||||||
|
m_Position.y() + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
bullets.push_back(Bullet());
|
||||||
|
|
||||||
|
bullets.back().m_Position =
|
||||||
|
Vector2(
|
||||||
|
m_Position.x() + 6,
|
||||||
|
m_Position.y() + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
m_CooldownCenter = 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_CooldownSide == 0)
|
||||||
|
{
|
||||||
|
bullets.push_back(Bullet());
|
||||||
|
|
||||||
|
bullets.back().m_Position =
|
||||||
|
Vector2(
|
||||||
|
m_Position.x(),
|
||||||
|
m_Position.y() + 7
|
||||||
|
);
|
||||||
|
|
||||||
|
bullets.push_back(Bullet());
|
||||||
|
|
||||||
|
bullets.back().m_Position =
|
||||||
|
Vector2(
|
||||||
|
m_Position.x() + 10,
|
||||||
|
m_Position.y() + 7
|
||||||
|
);
|
||||||
|
|
||||||
|
m_CooldownSide = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bullets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gun::update(const int dt)
|
||||||
|
{
|
||||||
|
m_CooldownCenter -= dt;
|
||||||
|
m_CooldownSide -= dt;
|
||||||
|
|
||||||
|
if (m_CooldownCenter < 0)
|
||||||
|
{
|
||||||
|
m_CooldownCenter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_CooldownSide < 0)
|
||||||
|
{
|
||||||
|
m_CooldownSide = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gun::render(PaintDevice& paintDevice)
|
||||||
|
{
|
||||||
|
for (const Vector2& point : m_Body)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
m_Position.x() + point.x(),
|
||||||
|
m_Position.y() + point.y()
|
||||||
|
),
|
||||||
|
'#'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::render(PaintDevice& paintDevice)
|
||||||
|
{
|
||||||
|
for (const Vector2& point : m_Enemys)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
point,
|
||||||
|
'V'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::update(const int dt)
|
||||||
|
{
|
||||||
|
m_Lag += dt;
|
||||||
|
|
||||||
|
const int quant = 800;
|
||||||
|
|
||||||
|
if (m_Lag <= quant)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Lag -= quant;
|
||||||
|
|
||||||
|
for (Vector2& point : m_Enemys)
|
||||||
|
{
|
||||||
|
point.y()++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 20; ++i)
|
||||||
|
{
|
||||||
|
if (rand() % 2)
|
||||||
|
{
|
||||||
|
m_Enemys.push_back(
|
||||||
|
Vector2(i, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Enemy::hit(Vector2 point)
|
||||||
|
{
|
||||||
|
for (const Vector2& enemy : m_Enemys)
|
||||||
|
{
|
||||||
|
if (enemy == point)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::remove(Vector2 point)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_Enemys.size(); ++i)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
point.x() == m_Enemys[i].x()
|
||||||
|
&&
|
||||||
|
point.y() == m_Enemys[i].y()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (int j = i; j < m_Enemys.size() - 1; ++j)
|
||||||
|
{
|
||||||
|
m_Enemys[j] = m_Enemys[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Enemys.pop_back();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExampleGame::ExampleGame()
|
||||||
|
{
|
||||||
|
paint_device().resize(
|
||||||
|
Size(
|
||||||
|
m_Width,
|
||||||
|
m_Height
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
track_key(KEY_LEFT);
|
||||||
|
track_key(KEY_RIGHT);
|
||||||
|
|
||||||
|
m_Gun.m_Position =
|
||||||
|
Vector2(
|
||||||
|
m_Width / 2 - 2,
|
||||||
|
m_Height - 14
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExampleGame::on_button_press(const int button)
|
||||||
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case KEY_LEFT:
|
||||||
|
{
|
||||||
|
m_Gun.m_Position.x()--;
|
||||||
|
|
||||||
|
if (m_Gun.m_Position.x() < 0)
|
||||||
|
{
|
||||||
|
m_Gun.m_Position.x() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEY_RIGHT:
|
||||||
|
{
|
||||||
|
m_Gun.m_Position.x()++;
|
||||||
|
|
||||||
|
if (m_Gun.m_Position.x() > m_Width - 11)
|
||||||
|
{
|
||||||
|
m_Gun.m_Position.x() = m_Width - 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExampleGame::update(const int dt)
|
||||||
|
{
|
||||||
|
m_Enemy.update(dt);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_Bullets.size(); i++)
|
||||||
|
{
|
||||||
|
m_Bullets[i].update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_Bullets.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_Bullets[i].m_Position.y() < 0)
|
||||||
|
{
|
||||||
|
for (int j = i; j < m_Bullets.size() - 1; j++)
|
||||||
|
{
|
||||||
|
m_Bullets[j] = m_Bullets[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Bullets.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_Bullets.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_Enemy.hit(m_Bullets[i].m_Position))
|
||||||
|
{
|
||||||
|
m_Enemy.remove(
|
||||||
|
m_Bullets[i].m_Position
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int j = i; j < m_Bullets.size() - 1; ++j)
|
||||||
|
{
|
||||||
|
m_Bullets[j] = m_Bullets[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Bullets.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Gun.update(dt);
|
||||||
|
|
||||||
|
std::vector<Bullet> newBullets =
|
||||||
|
m_Gun.fire();
|
||||||
|
|
||||||
|
m_Bullets.insert(
|
||||||
|
m_Bullets.end(),
|
||||||
|
newBullets.begin(),
|
||||||
|
newBullets.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExampleGame::render(PaintDevice& paintDevice)
|
||||||
|
{
|
||||||
|
for (Bullet& bullet : m_Bullets)
|
||||||
|
{
|
||||||
|
bullet.render(paintDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Enemy.render(paintDevice);
|
||||||
|
|
||||||
|
m_Gun.render(paintDevice);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Bullet {
|
||||||
|
public:
|
||||||
|
void render(PaintDevice& paintDevice);
|
||||||
|
void update(const int dt);
|
||||||
|
|
||||||
|
Vector2 m_Position;
|
||||||
|
int m_Lag = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Gun {
|
||||||
|
public:
|
||||||
|
Gun();
|
||||||
|
std::vector<Bullet> fire();
|
||||||
|
void render(PaintDevice& paintDevice);
|
||||||
|
void update(const int dt);
|
||||||
|
|
||||||
|
Vector2 m_Position;
|
||||||
|
std::vector<Vector2> m_Body;
|
||||||
|
|
||||||
|
int m_CooldownCenter = 0;
|
||||||
|
int m_CooldownSide = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Enemy {
|
||||||
|
public:
|
||||||
|
void render(PaintDevice& paintDevice);
|
||||||
|
void update(const int dt);
|
||||||
|
int m_Lag = 0;
|
||||||
|
bool hit(Vector2 point);
|
||||||
|
void remove(Vector2 point);
|
||||||
|
Vector2 first() const { return m_Enemys.front(); }
|
||||||
|
bool empty() const { return m_Enemys.empty(); }
|
||||||
|
private:
|
||||||
|
std::vector<Vector2> m_Enemys;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExampleGame : public Engine {
|
||||||
|
public:
|
||||||
|
ExampleGame();
|
||||||
|
private:
|
||||||
|
virtual bool end() const { return !m_Enemy.empty() && m_Enemy.first().y() >= m_Height; }
|
||||||
|
virtual void on_button_press(const int button);
|
||||||
|
virtual void update(const int dt);
|
||||||
|
virtual void render(PaintDevice& paintDevice);
|
||||||
|
|
||||||
|
const size_t m_Width = 20;
|
||||||
|
const size_t m_Height = 40;
|
||||||
|
Gun m_Gun;
|
||||||
|
std::vector<Bullet> m_Bullets;
|
||||||
|
Enemy m_Enemy;
|
||||||
|
};
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#include "Figure.h"
|
||||||
|
|
||||||
|
Figure::Figure(Point position)
|
||||||
|
:
|
||||||
|
m_Position(position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::update(double dt)
|
||||||
|
{
|
||||||
|
m_TimeFromLastUpdate += dt;
|
||||||
|
|
||||||
|
if (m_TimeFromLastUpdate >= m_TimeForUpdate)
|
||||||
|
{
|
||||||
|
m_TimeFromLastUpdate = 0;
|
||||||
|
|
||||||
|
++m_Position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::render(PaintDevice& paintDevice)
|
||||||
|
{
|
||||||
|
for (const Point& point : m_Body[m_CurrentRotate])
|
||||||
|
{
|
||||||
|
Vector2 v(
|
||||||
|
point.x + m_Position.x,
|
||||||
|
point.y + m_Position.y
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
v,
|
||||||
|
0x25D8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::move_left()
|
||||||
|
{
|
||||||
|
--m_Position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::move_right()
|
||||||
|
{
|
||||||
|
++m_Position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::boost()
|
||||||
|
{
|
||||||
|
m_TimeForUpdate = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::rotate()
|
||||||
|
{
|
||||||
|
++m_CurrentRotate;
|
||||||
|
|
||||||
|
if (m_CurrentRotate >= m_Body.size())
|
||||||
|
{
|
||||||
|
m_CurrentRotate = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::backup()
|
||||||
|
{
|
||||||
|
m_PositionBackup = m_Position;
|
||||||
|
|
||||||
|
m_CurrentRotateBackup = m_CurrentRotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::restore()
|
||||||
|
{
|
||||||
|
m_Position = m_PositionBackup;
|
||||||
|
|
||||||
|
m_CurrentRotate = m_CurrentRotateBackup;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Figure::get_position() const
|
||||||
|
{
|
||||||
|
return m_Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Figure::set_position(Point position)
|
||||||
|
{
|
||||||
|
m_Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Point>& Figure::get_body() const
|
||||||
|
{
|
||||||
|
return m_Body[m_CurrentRotate];
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Point.h"
|
||||||
|
#include "PaintDevice.h"
|
||||||
|
|
||||||
|
class Figure
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Point m_Position;
|
||||||
|
|
||||||
|
Point m_PositionBackup;
|
||||||
|
|
||||||
|
double m_TimeFromLastUpdate = 0;
|
||||||
|
double m_TimeForUpdate = 500;
|
||||||
|
|
||||||
|
std::vector<std::vector<Point>> m_Body;
|
||||||
|
|
||||||
|
size_t m_CurrentRotate = 0;
|
||||||
|
size_t m_CurrentRotateBackup = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Figure(Point position);
|
||||||
|
|
||||||
|
virtual ~Figure() = default;
|
||||||
|
|
||||||
|
void update(double dt);
|
||||||
|
|
||||||
|
void render(PaintDevice& paintDevice);
|
||||||
|
|
||||||
|
void move_left();
|
||||||
|
|
||||||
|
void move_right();
|
||||||
|
|
||||||
|
void boost();
|
||||||
|
|
||||||
|
void rotate();
|
||||||
|
|
||||||
|
void backup();
|
||||||
|
|
||||||
|
void restore();
|
||||||
|
|
||||||
|
Point get_position() const;
|
||||||
|
|
||||||
|
void set_position(Point position);
|
||||||
|
|
||||||
|
const std::vector<Point>& get_body() const;
|
||||||
|
};
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
#include "GameField.h"
|
||||||
|
|
||||||
|
void GameField::resize(
|
||||||
|
size_t width,
|
||||||
|
size_t height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
|
||||||
|
m_Field =
|
||||||
|
std::vector<
|
||||||
|
std::vector<wchar_t>
|
||||||
|
>(
|
||||||
|
m_Height - 2,
|
||||||
|
std::vector<wchar_t>(
|
||||||
|
m_Width - 2,
|
||||||
|
0x0387
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void GameField::render(
|
||||||
|
PaintDevice& paintDevice
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (int x = 1; x < m_Width - 1; x++)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(x,0),
|
||||||
|
'-'
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
x,
|
||||||
|
m_Height - 1
|
||||||
|
),
|
||||||
|
'-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 1; y < m_Height - 1; y++)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(0,y),
|
||||||
|
'|'
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
m_Width - 1,
|
||||||
|
y
|
||||||
|
),
|
||||||
|
'|'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(0,0),
|
||||||
|
'+'
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
m_Width - 1,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
'+'
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
0,
|
||||||
|
m_Height - 1
|
||||||
|
),
|
||||||
|
'+'
|
||||||
|
);
|
||||||
|
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
m_Width - 1,
|
||||||
|
m_Height - 1
|
||||||
|
),
|
||||||
|
'+'
|
||||||
|
);
|
||||||
|
for (size_t y = 0; y < m_Field.size(); y++)
|
||||||
|
{
|
||||||
|
for (size_t x = 0;
|
||||||
|
x < m_Field[y].size();
|
||||||
|
x++)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(
|
||||||
|
x + 1,
|
||||||
|
y + 1
|
||||||
|
),
|
||||||
|
m_Field[y][x]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameField::has_collision(
|
||||||
|
const Figure& figure)
|
||||||
|
{
|
||||||
|
Point position =
|
||||||
|
figure.get_position();
|
||||||
|
|
||||||
|
for (const Point& point :
|
||||||
|
figure.get_body())
|
||||||
|
{
|
||||||
|
int x =
|
||||||
|
point.x + position.x;
|
||||||
|
|
||||||
|
int y =
|
||||||
|
point.y + position.y;
|
||||||
|
|
||||||
|
if (x < 1 ||
|
||||||
|
x > m_Width - 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (y < 1 ||
|
||||||
|
y > m_Height - 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (
|
||||||
|
m_Field[y - 1][x - 1]
|
||||||
|
!= 0x0387
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameField::merge(const Figure& figure)
|
||||||
|
{
|
||||||
|
Point position = figure.get_position();
|
||||||
|
|
||||||
|
for (const Point& point : figure.get_body())
|
||||||
|
{
|
||||||
|
int x = point.x + position.x;
|
||||||
|
int y = point.y + position.y;
|
||||||
|
|
||||||
|
if (x < 1 || x > m_Width - 2 ||
|
||||||
|
y < 1 || y > m_Height - 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_Field[y - 1][x - 1] = L'#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GameField::clear_lines()
|
||||||
|
{
|
||||||
|
int cleared = 0;
|
||||||
|
|
||||||
|
for (int y = (int)m_Field.size() - 1; y >= 0; y--)
|
||||||
|
{
|
||||||
|
bool full = true;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < m_Field[y].size(); x++)
|
||||||
|
{
|
||||||
|
if (m_Field[y][x] == L' ')
|
||||||
|
{
|
||||||
|
full = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
cleared++;
|
||||||
|
|
||||||
|
for (int j = y; j > 0; j--)
|
||||||
|
{
|
||||||
|
m_Field[j] = m_Field[j - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Field[0] = std::vector<wchar_t>(
|
||||||
|
m_Width - 2,
|
||||||
|
L' '
|
||||||
|
);
|
||||||
|
|
||||||
|
y++; // 🔥 ВАЖНО: перескан строки после сдвига
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleared;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Figure.h"
|
||||||
|
|
||||||
|
class GameField
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
size_t m_Width = 0;
|
||||||
|
size_t m_Height = 0;
|
||||||
|
|
||||||
|
std::vector<std::vector<wchar_t>> m_Field;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void resize(
|
||||||
|
size_t width,
|
||||||
|
size_t height
|
||||||
|
);
|
||||||
|
|
||||||
|
void render(
|
||||||
|
PaintDevice& paintDevice
|
||||||
|
);
|
||||||
|
|
||||||
|
bool has_collision(
|
||||||
|
const Figure& figure
|
||||||
|
);
|
||||||
|
|
||||||
|
void merge(
|
||||||
|
const Figure& figure
|
||||||
|
);
|
||||||
|
int clear_lines();
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#include "IBlock.h"
|
||||||
|
|
||||||
|
IBlock::IBlock(Point position)
|
||||||
|
:
|
||||||
|
Figure(position)
|
||||||
|
{
|
||||||
|
m_Body =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Point(1,0),
|
||||||
|
Point(1,1),
|
||||||
|
Point(1,2),
|
||||||
|
Point(1,3)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Point(0,2),
|
||||||
|
Point(1,2),
|
||||||
|
Point(2,2),
|
||||||
|
Point(3,2)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Point(2,0),
|
||||||
|
Point(2,1),
|
||||||
|
Point(2,2),
|
||||||
|
Point(2,3)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Point(0,1),
|
||||||
|
Point(1,1),
|
||||||
|
Point(2,1),
|
||||||
|
Point(3,1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Figure.h"
|
||||||
|
|
||||||
|
class IBlock : public Figure
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IBlock(Point position);
|
||||||
|
};
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include "PaintDevice.h"
|
||||||
|
|
||||||
|
PaintDevice::PaintDevice()
|
||||||
|
: m_Size(40, 40)
|
||||||
|
{
|
||||||
|
initscr();
|
||||||
|
|
||||||
|
noecho();
|
||||||
|
|
||||||
|
curs_set(0);
|
||||||
|
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
|
||||||
|
nodelay(stdscr, TRUE);
|
||||||
|
|
||||||
|
resize(m_Size);
|
||||||
|
|
||||||
|
m_Ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaintDevice::~PaintDevice()
|
||||||
|
{
|
||||||
|
endwin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PaintDevice::ready() const
|
||||||
|
{
|
||||||
|
return m_Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintDevice::resize(const Size& size)
|
||||||
|
{
|
||||||
|
m_Size = size;
|
||||||
|
|
||||||
|
m_Buffer =
|
||||||
|
std::vector<std::vector<wchar_t>>
|
||||||
|
(
|
||||||
|
m_Size.height(),
|
||||||
|
std::vector<wchar_t>(
|
||||||
|
m_Size.width(),
|
||||||
|
L' '
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintDevice::clear()
|
||||||
|
{
|
||||||
|
for (int y = 0; y < m_Size.height(); y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < m_Size.width(); x++)
|
||||||
|
{
|
||||||
|
m_Buffer[y][x] = L' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintDevice::set_char(
|
||||||
|
const Vector2& position,
|
||||||
|
wchar_t c
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
position.x() >= 0 &&
|
||||||
|
position.x() < m_Size.width() &&
|
||||||
|
position.y() >= 0 &&
|
||||||
|
position.y() < m_Size.height()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Buffer[position.y()][position.x()] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t PaintDevice::get_char(
|
||||||
|
const Vector2& position
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
position.x() >= 0 &&
|
||||||
|
position.x() < m_Size.width() &&
|
||||||
|
position.y() >= 0 &&
|
||||||
|
position.y() < m_Size.height()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return m_Buffer[position.y()][position.x()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintDevice::render()
|
||||||
|
{
|
||||||
|
::clear();
|
||||||
|
|
||||||
|
for (int y = 0; y < m_Size.height(); y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < m_Size.width(); x++)
|
||||||
|
{
|
||||||
|
mvaddch(
|
||||||
|
y,
|
||||||
|
x,
|
||||||
|
m_Buffer[y][x]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#include "Size.h"
|
||||||
|
#include "Vector2.h"
|
||||||
|
|
||||||
|
class PaintDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PaintDevice();
|
||||||
|
~PaintDevice();
|
||||||
|
|
||||||
|
bool ready() const;
|
||||||
|
|
||||||
|
void resize(const Size& size);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void set_char(
|
||||||
|
const Vector2& position,
|
||||||
|
wchar_t c
|
||||||
|
);
|
||||||
|
|
||||||
|
wchar_t get_char(
|
||||||
|
const Vector2& position
|
||||||
|
);
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::vector<wchar_t>> m_Buffer;
|
||||||
|
|
||||||
|
Size m_Size;
|
||||||
|
|
||||||
|
bool m_Ready = false;
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
Point(
|
||||||
|
int x = 0,
|
||||||
|
int y = 0
|
||||||
|
)
|
||||||
|
:
|
||||||
|
x(x),
|
||||||
|
y(y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "Size.h"
|
||||||
|
|
||||||
|
Size::Size(
|
||||||
|
PointType width,
|
||||||
|
PointType height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size::PointType Size::width() const
|
||||||
|
{
|
||||||
|
return m_Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size::PointType Size::height() const
|
||||||
|
{
|
||||||
|
return m_Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size::PointType& Size::width()
|
||||||
|
{
|
||||||
|
return m_Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size::PointType& Size::height()
|
||||||
|
{
|
||||||
|
return m_Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size::PointType Size::area() const
|
||||||
|
{
|
||||||
|
return m_Width * m_Height;
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Size
|
||||||
|
{
|
||||||
|
using PointType = long long;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Size(
|
||||||
|
PointType width = 0,
|
||||||
|
PointType height = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
PointType width() const;
|
||||||
|
PointType height() const;
|
||||||
|
|
||||||
|
PointType& width();
|
||||||
|
PointType& height();
|
||||||
|
|
||||||
|
PointType area() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PointType m_Width;
|
||||||
|
PointType m_Height;
|
||||||
|
};
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "Square.h"
|
||||||
|
|
||||||
|
Square::Square(
|
||||||
|
const Vector2& position,
|
||||||
|
const Size& size
|
||||||
|
)
|
||||||
|
: m_Position(position),
|
||||||
|
m_Size(size)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Square::hit(
|
||||||
|
const Vector2& point
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
point.x() >= top_left().x() &&
|
||||||
|
point.x() <= bottom_right().x() &&
|
||||||
|
point.y() >= top_left().y() &&
|
||||||
|
point.y() <= bottom_right().y();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Square::top_left() const
|
||||||
|
{
|
||||||
|
return m_Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Square::bottom_right() const
|
||||||
|
{
|
||||||
|
return Vector2(
|
||||||
|
m_Position.x() + m_Size.width() - 1,
|
||||||
|
m_Position.y() + m_Size.height() - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Square::collide(
|
||||||
|
const Square& other
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
bool xProjectionCollide =
|
||||||
|
top_left().x() <= other.bottom_right().x() &&
|
||||||
|
bottom_right().x() >= other.top_left().x();
|
||||||
|
|
||||||
|
bool yProjectionCollide =
|
||||||
|
top_left().y() <= other.bottom_right().y() &&
|
||||||
|
bottom_right().y() >= other.top_left().y();
|
||||||
|
|
||||||
|
return
|
||||||
|
xProjectionCollide &&
|
||||||
|
yProjectionCollide;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vector2.h"
|
||||||
|
#include "Size.h"
|
||||||
|
|
||||||
|
class Square
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Square(
|
||||||
|
const Vector2& position,
|
||||||
|
const Size& size
|
||||||
|
);
|
||||||
|
|
||||||
|
bool hit(
|
||||||
|
const Vector2& point
|
||||||
|
) const;
|
||||||
|
|
||||||
|
bool collide(
|
||||||
|
const Square& other
|
||||||
|
) const;
|
||||||
|
|
||||||
|
Vector2 top_left() const;
|
||||||
|
|
||||||
|
Vector2 bottom_right() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector2 m_Position;
|
||||||
|
|
||||||
|
Size m_Size;
|
||||||
|
};
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#include "Tetris.h"
|
||||||
|
|
||||||
|
Tetris::Tetris()
|
||||||
|
{
|
||||||
|
paint_device().resize(
|
||||||
|
Size(
|
||||||
|
m_Width + 6,
|
||||||
|
m_Height
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
m_GameField.resize(
|
||||||
|
m_Width,
|
||||||
|
m_Height
|
||||||
|
);
|
||||||
|
|
||||||
|
m_Figure =
|
||||||
|
new IBlock(
|
||||||
|
Point(5,1)
|
||||||
|
);
|
||||||
|
|
||||||
|
track_key(KEY_LEFT);
|
||||||
|
track_key(KEY_RIGHT);
|
||||||
|
track_key(KEY_DOWN);
|
||||||
|
track_key(' ');
|
||||||
|
}
|
||||||
|
Tetris::~Tetris()
|
||||||
|
{
|
||||||
|
delete m_Figure;
|
||||||
|
}
|
||||||
|
bool Tetris::end() const
|
||||||
|
{
|
||||||
|
return m_End;
|
||||||
|
}
|
||||||
|
void Tetris::render(
|
||||||
|
PaintDevice& paintDevice
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_GameField.render(
|
||||||
|
paintDevice
|
||||||
|
);
|
||||||
|
|
||||||
|
if (m_Figure)
|
||||||
|
{
|
||||||
|
m_Figure->render(
|
||||||
|
paintDevice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 scorePos(m_Width + 1, 2);
|
||||||
|
|
||||||
|
std::wstring text = L"SCORE: " + std::to_wstring(m_Score);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < text.size(); i++)
|
||||||
|
{
|
||||||
|
paintDevice.set_char(
|
||||||
|
Vector2(scorePos.x() + i, scorePos.y()),
|
||||||
|
text[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Tetris::update(int dt)
|
||||||
|
{
|
||||||
|
m_Figure->backup();
|
||||||
|
|
||||||
|
m_Figure->update(dt);
|
||||||
|
|
||||||
|
if (m_GameField.has_collision(*m_Figure))
|
||||||
|
{
|
||||||
|
m_Figure->restore();
|
||||||
|
|
||||||
|
m_GameField.merge(*m_Figure);
|
||||||
|
|
||||||
|
int lines = m_GameField.clear_lines();
|
||||||
|
|
||||||
|
if (lines > 0)
|
||||||
|
{
|
||||||
|
m_Score += lines * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_Figure;
|
||||||
|
|
||||||
|
m_Figure =
|
||||||
|
new IBlock(Point(5,1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Tetris::on_button_press(
|
||||||
|
int button
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Figure->backup();
|
||||||
|
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case KEY_LEFT:
|
||||||
|
m_Figure->move_left();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_RIGHT:
|
||||||
|
m_Figure->move_right();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_DOWN:
|
||||||
|
m_Figure->boost();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
m_Figure->rotate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
m_GameField.has_collision(
|
||||||
|
*m_Figure
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Figure->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
#include "GameField.h"
|
||||||
|
#include "IBlock.h"
|
||||||
|
|
||||||
|
class Tetris : public Engine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
GameField m_GameField;
|
||||||
|
|
||||||
|
Figure* m_Figure = nullptr;
|
||||||
|
|
||||||
|
bool m_End = false;
|
||||||
|
|
||||||
|
const size_t m_Width = 14;
|
||||||
|
const size_t m_Height = 26;
|
||||||
|
|
||||||
|
int m_Score = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Tetris();
|
||||||
|
|
||||||
|
~Tetris() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool end() const override;
|
||||||
|
|
||||||
|
void on_button_press(int button) override;
|
||||||
|
|
||||||
|
void update(int dt) override;
|
||||||
|
|
||||||
|
void render(PaintDevice& paintDevice) override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#include "Vector2.h"
|
||||||
|
|
||||||
|
Vector2::Vector2()
|
||||||
|
: m_X(0),
|
||||||
|
m_Y(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2::Vector2(
|
||||||
|
PointType x,
|
||||||
|
PointType y
|
||||||
|
)
|
||||||
|
: m_X(x),
|
||||||
|
m_Y(y)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2::PointType Vector2::x() const
|
||||||
|
{
|
||||||
|
return m_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2::PointType Vector2::y() const
|
||||||
|
{
|
||||||
|
return m_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2::PointType& Vector2::x()
|
||||||
|
{
|
||||||
|
return m_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2::PointType& Vector2::y()
|
||||||
|
{
|
||||||
|
return m_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Vector2::operator*(
|
||||||
|
const PointType& rhs
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return Vector2(
|
||||||
|
m_X * rhs,
|
||||||
|
m_Y * rhs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2& Vector2::operator+=(
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_X += rhs.m_X;
|
||||||
|
m_Y += rhs.m_Y;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2& Vector2::operator-=(
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_X -= rhs.m_X;
|
||||||
|
m_Y -= rhs.m_Y;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(
|
||||||
|
const Vector2& lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
lhs.m_X == rhs.m_X &&
|
||||||
|
lhs.m_Y == rhs.m_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(
|
||||||
|
const Vector2& lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 operator+(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
lhs += rhs;
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 operator-(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
lhs -= rhs;
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(
|
||||||
|
std::ostream& os,
|
||||||
|
const Vector2& obj
|
||||||
|
)
|
||||||
|
{
|
||||||
|
os
|
||||||
|
<< "{"
|
||||||
|
<< obj.x()
|
||||||
|
<< ", "
|
||||||
|
<< obj.y()
|
||||||
|
<< "}";
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
class Vector2
|
||||||
|
{
|
||||||
|
using PointType = long long;
|
||||||
|
|
||||||
|
friend bool operator==(
|
||||||
|
const Vector2& lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
friend Vector2 operator+(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
friend Vector2 operator-(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector2();
|
||||||
|
|
||||||
|
Vector2(
|
||||||
|
PointType x,
|
||||||
|
PointType y
|
||||||
|
);
|
||||||
|
|
||||||
|
PointType x() const;
|
||||||
|
PointType y() const;
|
||||||
|
|
||||||
|
PointType& x();
|
||||||
|
PointType& y();
|
||||||
|
|
||||||
|
Vector2 operator*(
|
||||||
|
const PointType& rhs
|
||||||
|
) const;
|
||||||
|
|
||||||
|
Vector2& operator+=(
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
Vector2& operator-=(
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PointType m_X;
|
||||||
|
PointType m_Y;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(
|
||||||
|
const Vector2& lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
bool operator!=(
|
||||||
|
const Vector2& lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
Vector2 operator+(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
Vector2 operator-(
|
||||||
|
Vector2 lhs,
|
||||||
|
const Vector2& rhs
|
||||||
|
);
|
||||||
|
|
||||||
|
std::ostream& operator<<(
|
||||||
|
std::ostream& os,
|
||||||
|
const Vector2& obj
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user