This is a sample implementation of the tetris game in console. The tetris game was implemented both in C++ and C#. C++ version uses a predefined base class that provides access to character console buffer, keyboard control and main generic game cycle. C# version uses the same C++ base class, but this time compiled into managed DLL assembly.
Download C++ console tetris game source code
Download C# console tetris game source code
const float tetris::SPEED = 0.5; // default seconds per each down move
const float tetris::HIGH_SPEED = 0.05;
tetris::tetris() : BaseApp(24, 30)
{
srand (time(NULL));
pausing = true;
figure=NULL;
figureNext=NULL;
moveTimer = 0;
DrawScene(); // draw scene
DrawWalls();
SpawnNewFigure();
}
void tetris::SpawnNewFigure()
{
Figure::POINT pt;
currentSpeed = SPEED;
moveDownCounter = 0;
// take next figure as current one
if (figure) {
delete figure;
figure=NULL;
}
if (figureNext)
figure = figureNext;
// initialize current figure for the first time
// place current figure at initial position on top
pt.x = (X_SIZE-6)/2;
pt.y = 2;
if (!figure) figure = new Figure(pt,this);
else figure->PlaceTo(pt);
figure->Draw();
// prepare next figure for future cycle
// create and show next figure on the right
pt.x = X_SIZE-5;
figureNext = new Figure(pt,this);
figureNext->Draw();
pausing = false;
}
void tetris::KeyPressed(int btnCode)
{
try {
if (btnCode == 224) btnCode = getch();
switch(btnCode)
{
case 119: case 72: currentSpeed=SPEED; break; // w, up arrow
case 115: case 80: currentSpeed=HIGH_SPEED; break; // s, down arrow
case 97: case 75: figure->MoveLeft(); break; // a, left arrow
case 100: case 77: figure->MoveRight(); break; // d, right arrow
case 32: figure->Rotate(); break; // space
case 'p': pausing=!pausing; break; // pause
}
} catch(...) {
pausing = true;
SpawnNewFigure();
}
}
void tetris::UpdateF(float deltaTime)
{
try {
if (figure && !pausing)
{
moveTimer += deltaTime;
if (moveTimer>=currentSpeed)
{
moveTimer = 0;
bool ok = figure->MoveDown();
if (ok)
{
moveDownCounter++;
ok = figure->CanMoveDown();
}
if (!ok)
{
pausing = true;
if (moveDownCounter==0) // if we could not make even 1 move down - GAME OVER: restart a game
{
DrawScene(); // draw scene
DrawWalls();
}
SpawnNewFigure(); // if reached a floor, respawn a new figure from top
}
}
}
} catch(...) {
pausing = true;
SpawnNewFigure();
}
}
void tetris::DrawWalls()
{
for (int x = 0; x < X_SIZE; x++)
{
SetChar(x, 0, W);
SetChar(x, Y_SIZE-1, W);
}
for (int y = 0; y < Y_SIZE; y++)
{
SetChar(0, y, W);
SetChar(X_SIZE-1, y, W);
}
for (int x = X_SIZE-7; x < X_SIZE; x++)
{
SetChar(x, 5, W);
}
for (int y = 0; y < 5; y++)
{
SetChar(X_SIZE-7, y, W);
}
}
void tetris::DrawScene()
{
for (int x = 0; x < X_SIZE; x++)
{
for (int y = 0; y < Y_SIZE; y++)
{
SetChar(x,y, E);
}
}
}
C# source code sample
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using FigureLayout = System.Collections.Generic.List; namespace tetrisCSharp { class Tetris : BaseApp { public const char W = '#'; // wall character public const char F = '*'; // figure character public const char E = '.'; // empty character float moveTimer; bool pausing; int moveDownCounter; const float SPEED = 0.5f; // default speed: seconds per move const float HIGH_SPEED = 0.05f; // high speed float currentSpeed = SPEED; // current speed Figure figure; Figure figureNext; void DrawWalls() { Enumerable.Range(0, X_SIZE).ForEach(x => { SetChar(x, 0, W); SetChar(x, Y_SIZE - 1, W); }); // horizontal walls Enumerable.Range(0, Y_SIZE).ForEach(y => { SetChar(0, y, W); SetChar(X_SIZE - 1, y, W); }); // vertical walls // box, showing next figure Enumerable.Range(X_SIZE - 7, 7).ForEach(x => SetChar(x, 5, W)); Enumerable.Range(0, 5).ForEach(y => SetChar(X_SIZE - 7, y, W)); } void DrawScene() { // place empty char in all cells Enumerable.Range(0, X_SIZE).CrossJoinAndExecute(Enumerable.Range(0, Y_SIZE), (x, y) => SetChar(x, y, E)); } void SpawnNewFigure() { POINT pt; currentSpeed = SPEED; moveDownCounter = 0; // take next figure as current one if (figure != null) { figure = null; } if (figureNext != null) figure = figureNext; // initialize current figure for the first time // place current figure at initial position on top pt.x = (X_SIZE - 6) / 2; pt.y = 2; if (figure == null) figure = new Figure(pt, this); else figure.PlaceTo(pt); figure.Draw(); // prepare next figure for future cycle // create and show next figure on the right pt.x = X_SIZE - 5; figureNext = new Figure(pt, this); figureNext.Draw(); pausing = false; } internal Tetris() : base(24, 30) { pausing = true; moveTimer = 0; DrawScene(); // draw scene DrawWalls(); SpawnNewFigure(); } public override void KeyPressed(int btnCode) { try { switch (btnCode) { case 119: case 72: currentSpeed = SPEED; break; // w, up arrow case 115: case 80: currentSpeed = HIGH_SPEED; break; // s, down arrow case 97: case 75: figure.MoveLeft(); break; // a, left arrow case 100: case 77: figure.MoveRight(); break; // d, right arrow case 32: figure.Rotate(); break; // space case 'p': pausing = !pausing; break; // pause } } catch { pausing = true; SpawnNewFigure(); } } public override void UpdateF(float deltaTime) { try { if (figure!=null && !pausing) { moveTimer += deltaTime; if (moveTimer >= currentSpeed) { moveTimer = 0; bool ok = figure.MoveDown(); if (ok) { moveDownCounter++; ok = figure.CanMoveDown(); } if (!ok) { pausing = true; if (moveDownCounter == 0) // if we could not make even 1 move down - GAME OVER: restart a game { DrawScene(); // draw scene DrawWalls(); } SpawnNewFigure(); // if reached a floor, respawn a new figure from top } } } } catch { pausing = true; SpawnNewFigure(); } } } }
Комментариев нет :
Отправить комментарий