Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Project exclude paths
|
||||
/cmake-build-debug/
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -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
|
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/tetris.iml" filepath="$PROJECT_DIR$/.idea/tetris.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
2
.idea/tetris.iml
generated
Normal file
2
.idea/tetris.iml
generated
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(tetris)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(X11 REQUIRED)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
|
||||
link_directories(${X11_LIBRARIES})
|
||||
|
||||
|
||||
add_executable(${PROJECT_NAME} src/olcPixelGameEngine.hpp src/main.cpp )
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC "src")
|
||||
target_link_libraries(${PROJECT_NAME} X11 GL png stdc++fs pthread)
|
326
src/main.cpp
Normal file
326
src/main.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
#define OLC_PGE_APPLICATION
|
||||
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "olcPixelGameEngine.hpp"
|
||||
|
||||
olc::Pixel tetcolors[10] = {
|
||||
olc::RED,
|
||||
olc::MAGENTA,
|
||||
olc::YELLOW,
|
||||
olc::GREEN,
|
||||
olc::CYAN,
|
||||
olc::BLUE,
|
||||
olc::DARK_YELLOW,
|
||||
olc::DARK_RED,
|
||||
olc::GREY,
|
||||
olc::WHITE,
|
||||
};
|
||||
|
||||
// Cyan Tetramino
|
||||
std::wstring tetramino[7];
|
||||
|
||||
void define_tetraminos()
|
||||
{
|
||||
tetramino[0].append(L" X ");
|
||||
tetramino[0].append(L" X ");
|
||||
tetramino[0].append(L" X ");
|
||||
tetramino[0].append(L" X ");
|
||||
|
||||
tetramino[1].append(L" X ");
|
||||
tetramino[1].append(L" XX ");
|
||||
tetramino[1].append(L" X ");
|
||||
tetramino[1].append(L" ");
|
||||
|
||||
tetramino[2].append(L" X ");
|
||||
tetramino[2].append(L" XX ");
|
||||
tetramino[2].append(L" X ");
|
||||
tetramino[2].append(L" ");
|
||||
|
||||
tetramino[3].append(L" ");
|
||||
tetramino[3].append(L" XX ");
|
||||
tetramino[3].append(L" XX ");
|
||||
tetramino[3].append(L" ");
|
||||
|
||||
tetramino[4].append(L" X ");
|
||||
tetramino[4].append(L" XX ");
|
||||
tetramino[4].append(L" X ");
|
||||
tetramino[4].append(L" ");
|
||||
|
||||
tetramino[5].append(L" ");
|
||||
tetramino[5].append(L" XX ");
|
||||
tetramino[5].append(L" X ");
|
||||
tetramino[5].append(L" X ");
|
||||
|
||||
tetramino[6].append(L" ");
|
||||
tetramino[6].append(L" XX ");
|
||||
tetramino[6].append(L" X ");
|
||||
tetramino[6].append(L" X ");
|
||||
}
|
||||
|
||||
int rotate(int px, int py, int r)
|
||||
{
|
||||
switch(r%4)
|
||||
{
|
||||
case 0: return py * 4 + px; // 0 degrees
|
||||
case 1: return 12 + py - (px*4); // 90 degrees
|
||||
case 2: return 15 - (py * 4) - px; // 180 degrees
|
||||
case 3: return 3 - py + (px * 4); // 270 degrees
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fieldWidth = 12;
|
||||
int fieldHeight = 18;
|
||||
|
||||
|
||||
unsigned char *pField = nullptr;
|
||||
void setup_playing_field()
|
||||
{
|
||||
pField = new unsigned char[fieldWidth*fieldHeight];
|
||||
for (int x = 0; x < fieldWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < fieldHeight; y++)
|
||||
{
|
||||
pField[y*fieldWidth + x] = (x == 0 || x == fieldWidth - 1 || y == fieldHeight - 1) ? 9 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool does_piece_fit(int nTetromino, int rotation, int posX, int posY)
|
||||
{
|
||||
for (int px = 0; px < 4; px++) {
|
||||
for (int py = 0; py < 4; py++) {
|
||||
int pi = rotate(px, py, rotation);
|
||||
|
||||
int fi = (posY + py) * fieldWidth + (posX + px);
|
||||
|
||||
if (posX + px >= 0 && posX + px < fieldWidth) {
|
||||
if (posY + py >= 0 && posY + py < fieldHeight) {
|
||||
if (tetramino[nTetromino][pi] == L'X' && pField[fi] != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Tetris : public olc::PixelGameEngine
|
||||
{
|
||||
|
||||
public:
|
||||
int score = 0;
|
||||
|
||||
float gameTime = 0;
|
||||
|
||||
int currentPiece = 0;
|
||||
int currentRotation = 0;
|
||||
int currentX = fieldWidth / 2;
|
||||
int currentY = 0;
|
||||
|
||||
float gamespeed = 1; // Increment to speed up gameticks
|
||||
|
||||
|
||||
std::vector<int> vLines;
|
||||
|
||||
Tetris()
|
||||
{
|
||||
sAppName = "Tetris in C++ by Josh";
|
||||
score = 0;
|
||||
// Clear board
|
||||
}
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawBoard()
|
||||
{
|
||||
for (int x = 0; x < fieldWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < fieldHeight; y++)
|
||||
{
|
||||
auto cell = pField[y*fieldWidth + x];
|
||||
if (cell > 0)
|
||||
{
|
||||
this->FillRect(x*4, y*4, 4, 4, tetcolors[cell]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCurrentPiece()
|
||||
{
|
||||
for (int px = 0; px < 4; px++)
|
||||
for (int py = 0; py < 4; py++)
|
||||
if (tetramino[currentPiece][rotate(px, py, currentRotation)]==L'X')
|
||||
this->FillRect(
|
||||
(currentX+px)*4,
|
||||
(currentY+py)*4,
|
||||
4, 4,
|
||||
tetcolors[currentPiece+1]);
|
||||
}
|
||||
|
||||
void DrawInfo()
|
||||
{
|
||||
DrawString(0, 80, "Scr:"+ std::to_string(score));
|
||||
}
|
||||
|
||||
void Input()
|
||||
{
|
||||
// left
|
||||
if (this->GetKey(olc::Key::A).bPressed &&
|
||||
does_piece_fit(currentPiece, currentRotation, currentX-1, currentY))
|
||||
currentX--;
|
||||
|
||||
// right
|
||||
if (this->GetKey(olc::Key::D).bPressed &&
|
||||
does_piece_fit(currentPiece, currentRotation, currentX+1, currentY))
|
||||
currentX++;
|
||||
|
||||
// Down
|
||||
if (this->GetKey(olc::Key::S).bPressed &&
|
||||
does_piece_fit(currentPiece, currentRotation, currentX, currentY+1))
|
||||
currentY++;
|
||||
|
||||
// Rotate
|
||||
if (this->GetKey(olc::Key::Z).bPressed &&
|
||||
does_piece_fit(currentPiece, currentRotation+1, currentX, currentY))
|
||||
currentRotation++;
|
||||
}
|
||||
|
||||
void Render()
|
||||
{
|
||||
DrawBoard();
|
||||
DrawCurrentPiece();
|
||||
DrawInfo();
|
||||
}
|
||||
|
||||
// Checks for instances of "Tetris" (a full line) on the board
|
||||
void CheckForTetris()
|
||||
{
|
||||
// Check for horiz lines
|
||||
for (int py = 0; py < 4; py++)
|
||||
if (currentY + py < fieldHeight - 1)
|
||||
{
|
||||
bool bLine = true;
|
||||
for (int px = 1; px < fieldWidth-1; px++)
|
||||
{
|
||||
bLine &= (pField[(currentY+py)*fieldWidth+px]) != 0;
|
||||
}
|
||||
|
||||
if (bLine)
|
||||
{
|
||||
for (int px = 1; px < fieldWidth-1; px++)
|
||||
{
|
||||
pField[(currentY+py) * fieldWidth + px] = 8;
|
||||
|
||||
}
|
||||
|
||||
vLines.push_back(currentY+py);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClearLines()
|
||||
{
|
||||
int prescore = 0;
|
||||
for (auto &v: vLines)
|
||||
{
|
||||
prescore++;
|
||||
for (int px = 1; px < fieldWidth-1; px++)
|
||||
{
|
||||
for (int py = v; py > 0; py--)
|
||||
{
|
||||
pField[py*fieldWidth+px] = pField[(py-1)*fieldWidth+px];
|
||||
|
||||
}
|
||||
pField[px] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
score += 50*prescore;
|
||||
vLines.clear();
|
||||
|
||||
}
|
||||
|
||||
void NextPiece()
|
||||
{
|
||||
// Choose Next Piece
|
||||
currentX = fieldWidth/2;
|
||||
currentY = 0;
|
||||
currentRotation = 0;
|
||||
currentPiece = rand() % 7;
|
||||
}
|
||||
void DropCurrentPiece() {
|
||||
// lock current piece into the field
|
||||
for (int px = 0; px < 4; px++)
|
||||
{
|
||||
for (int py = 0; py < 4; py++)
|
||||
{
|
||||
if (tetramino[currentPiece][rotate(px, py, currentRotation)]==L'X')
|
||||
pField[(currentY+py)*fieldWidth + (currentX+px)] = currentPiece+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
void GameTick()
|
||||
{
|
||||
// Can the piece move?
|
||||
if (does_piece_fit(currentPiece, currentRotation, currentX, currentY+1)) {
|
||||
currentY++;
|
||||
} else {
|
||||
DropCurrentPiece();
|
||||
CheckForTetris();
|
||||
NextPiece();
|
||||
|
||||
if (!vLines.empty())
|
||||
{
|
||||
DrawBoard(); // ASS HACK
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(400ms);
|
||||
ClearLines();
|
||||
}
|
||||
}
|
||||
|
||||
// if piece does not fit
|
||||
bool gameOver = does_piece_fit(currentPiece, currentRotation, currentX, currentY);
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float delta) override
|
||||
{
|
||||
|
||||
Clear(olc::BLACK);
|
||||
|
||||
gameTime += delta;
|
||||
|
||||
if (gameTime > 1/gamespeed)
|
||||
{
|
||||
gameTime = 0;
|
||||
GameTick();
|
||||
}
|
||||
Input();
|
||||
Render();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "Spin it up!" << std::endl;
|
||||
define_tetraminos();
|
||||
setup_playing_field();
|
||||
|
||||
Tetris game;
|
||||
if (game.Construct(92, 128, 4, 4))
|
||||
game.Start();
|
||||
return 0;
|
||||
}
|
6691
src/olcPixelGameEngine.hpp
Normal file
6691
src/olcPixelGameEngine.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user