воскресенье, 3 ноября 2013 г.

Console Tetris game


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


C++ code sample
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();
            }
        }
    }
}


Комментариев нет :

Отправить комментарий