Return to Snippet

Revision: 48037
at June 22, 2011 19:36 by offs


Updated Code
#include "gl.h"
#include <time.h>
#include "Draw.h"
#include "Text.h"


#include "Game.h"

const unsigned char ESC   = 27;
const unsigned char SPACE = 32;

const unsigned MIN_SPEED  = 1;
const unsigned MAX_SPEED  = 9;

const unsigned BASE_SCORE = 100;
const unsigned NEXT_LEVEL_LINES_LIMIT = 10;

Game::Game() 
: _lines(0)
, _score(0)
, _speed(MIN_SPEED)
, _lose(false)
, _paused(false)
, _nextFigIndex(rand() % VARIOUS_BLOCKS)
, _nextRotIndex(rand() % ROTATIONS)
{
    srand(time(NULL));
    
    _well  = WellPtr(new Well(this));
    _block = BlockPtr(new Block(_well));
    
    _StartNextBlock();
}

#pragma warning (disable : 4100) //to suppress unused warning int x, int y needed by GLUT API
void Game::KeyPressed(int specialKey, unsigned char key, int x, int y)
{
    switch (specialKey)
    {
        case GLUT_KEY_UP    :    
        case GLUT_KEY_DOWN  :    
        case GLUT_KEY_LEFT  :    
        case GLUT_KEY_RIGHT : _InGameKey(specialKey, 0);  break;
    }

    switch (key)
    { 
        case SPACE          : _InGameKey(0, key);         break;
        case '+'            : _SpeedUp();                 break;
        case '-'            : _SpeedDown();               break;
        case 'p'            :           
        case 'P'            : _Pause();                   break;
        case 'r'            :   
        case 'R'            : _Restart();                 break;
        case ESC            : _Stop();                    break;
    }
}
#pragma warning (default : 4100)

void Game::_InGameKey(int specialKey, unsigned char key)
{
    if (!_paused && !_lose)
    {
        switch (specialKey)
        {
            case GLUT_KEY_UP    :    _block->Rotate();    break;
            case GLUT_KEY_DOWN  :    _block->MoveDown();  break;
            case GLUT_KEY_LEFT  :    _block->MoveLeft();  break;
            case GLUT_KEY_RIGHT :    _block->MoveRight(); break;
        }

        switch (key)
        {
            case SPACE          :    _block->FallDown();
                                     Update();            break;
        }
    }
}

void Game::Draw()
{
    unsigned x0 = 50, y0 = 50, x0new = 0, y0new = 0;

    glClear(GL_COLOR_BUFFER_BIT);
    _DrawWell(x0, y0, x0new, y0new);
    _DrawStatus(x0new, y0);

    glutSwapBuffers();
}

void Game::_DrawStatus(unsigned x0, unsigned y0)
{
    DrawText(x0, y0 + 20, GLUT_BITMAP_HELVETICA_12, FormatText("Lines: %i", _lines).c_str());
    DrawText(x0, y0 + 40, GLUT_BITMAP_HELVETICA_12, FormatText("Score: %i", _score).c_str());
    DrawText(x0, y0 + 60, GLUT_BITMAP_HELVETICA_12, FormatText("Speed: %i", _speed).c_str());

    DrawText(x0, y0 + 420, GLUT_BITMAP_HELVETICA_18, " Next");
    _DrawNext(x0, y0 + 460);

    if (_lose)
    {
        DrawText(x0, y0 + 240, GLUT_BITMAP_HELVETICA_18, "    Game over."     );
        DrawText(x0, y0 + 220, GLUT_BITMAP_HELVETICA_18, "Press R to restart.");
    }
    else if (_paused)
    {
        DrawText(x0, y0 + 240, GLUT_BITMAP_HELVETICA_18, "   Game paused."     );
        DrawText(x0, y0 + 220, GLUT_BITMAP_HELVETICA_18, "Press P to continue.");
    }
}

void Game::_DrawNext(unsigned x0, unsigned y0)
{
    for (unsigned cell = 0; cell != FIGURE_COMPLEXITY; ++cell)
    {
        unsigned x = x0 + _blocks[_nextFigIndex][_nextRotIndex][2*cell]*_well->CellSize();
        unsigned y = y0 + _blocks[_nextFigIndex][_nextRotIndex][2*cell + 1]*_well->CellSize();

        DrawRect(x, y, x + _well->CellSize(), y + _well->CellSize(), Color[_nextColor - 1]);
    }
}

void Game::_DrawWell( unsigned x0, unsigned y0, unsigned& x0new, unsigned& y0new )
{
    unsigned rectX1 = x0, rectX2 = rectX1 + _well->CellSize();
    unsigned rectY1 = y0, rectY2 = rectY1 + _well->CellSize();

    DrawGrid(x0, y0, _well->Width(), _well->RedLine(), _well->CellSize());
    DrawBorder(x0, y0, _well->Width() * _well->CellSize(), _well->Height() * _well->CellSize());


    for (unsigned width = 0; width != _well->Width(); ++width)
    {
        rectY1 = y0;
        rectY2 = rectY1 + _well->CellSize();
        
        for (unsigned height = 0; height != _well->Height(); ++height)
        {
            DrawRect(rectX1, rectY1, rectX2, rectY2, Color[(_well->Cell(width, height) & COLOR_MASK) - 1]);
            
            rectY1  = rectY2;
            rectY2 += _well->CellSize();
        }

        rectX1  = rectX2;
        rectX2 += _well->CellSize();
    }

    x0new = rectX2;
    y0new = rectY2;
}  

void Game::ReportLinesRemoval(unsigned lines)
{
    _lines += lines;
    _score += lines * BASE_SCORE;

    while (lines--) 
        _score += lines * (BASE_SCORE >> lines);
}

void Game::_StartNextBlock()
{
    _block->Update(_nextFigIndex, _nextRotIndex); 
    
    _nextFigIndex = rand() % VARIOUS_BLOCKS;
    _nextRotIndex = rand() % ROTATIONS;
    _nextColor    = _nextFigIndex + 1;
    
    _block->PutOnTop();
}

void Game::Update()
{
    if (!_paused && !_block->MoveDown())
    {
        _block->CheckLines();
        if (!_lose)
        {    
            if (_lines >= NEXT_LEVEL_LINES_LIMIT)
            {
                _SpeedUp();
                _lines = 0;
            }

            _StartNextBlock();
        }
    }
}

void Game::_Restart()
{
    _lose   = false;
    _paused = false;
    _lines  = 0;
    _score  = 0;

    _well->Clear();
    _StartNextBlock();
}

void Game::_Pause()
{
    _paused = !_paused;
}

void Game::_Stop()
{
    exit(0);    
}

void Game::ReportLoseState()
{
    _lose = true;
}

unsigned Game::UpdateInterval()
{
    return (MAX_SPEED - _speed + 1)*100;
}

void Game::_SpeedUp()
{
    if (_speed < MAX_SPEED) ++_speed; 
}

void Game::_SpeedDown()
{
    if (_speed > MIN_SPEED) --_speed; 
}

Revision: 48036
at June 22, 2011 09:22 by offs


Initial Code
#include "gl.h"
#include <time.h>
#include "Draw.h"
#include "Text.h"
#include "Game.h"

const unsigned char ESC   = 27;
const unsigned char SPACE = 32;

const unsigned MIN_SPEED  = 1;
const unsigned MAX_SPEED  = 9;

const unsigned BASE_SCORE = 100;
const unsigned NEXT_LEVEL_LINES_LIMIT = 10;

Game::Game() 
: _lines(0)
, _score(0)
, _speed(MIN_SPEED)
, _lose(false)
, _paused(false)
, _nextFigIndex(rand() % VARIOUS_BLOCKS)
, _nextRotIndex(rand() % ROTATIONS)
{
    srand(time(NULL));
    
    _well  = WellPtr(new Well(this));
    _block = std::tr1::shared_ptr<Block>(new Block(_well));
    
    _StartNextBlock();
}

#pragma warning (disable : 4100) //to suppress unused warning int x, int y needed by GLUT API
void Game::KeyPressed(int specialKey, unsigned char key, int x, int y)
{
    switch (specialKey)
    {
        case GLUT_KEY_UP    :    
        case GLUT_KEY_DOWN  :    
        case GLUT_KEY_LEFT  :    
        case GLUT_KEY_RIGHT : _InGameKey(specialKey, 0);  break;
    }

    switch (key)
    { 
        case SPACE          : _InGameKey(0, key);         break;
        case '+'            : _SpeedUp();                 break;
        case '-'            : _SpeedDown();               break;
        case 'p'            :           
        case 'P'            : _Pause();                   break;
        case 'r'            :   
        case 'R'            : _Restart();                 break;
        case ESC            : _Stop();                    break;
    }
}
#pragma warning (default : 4100)

void Game::_InGameKey(int specialKey, unsigned char key)
{
    if (!_paused && !_lose)
    {
        switch (specialKey)
        {
            case GLUT_KEY_UP    :    _block->Rotate();    break;
            case GLUT_KEY_DOWN  :    _block->MoveDown();  break;
            case GLUT_KEY_LEFT  :    _block->MoveLeft();  break;
            case GLUT_KEY_RIGHT :    _block->MoveRight(); break;
        }

        switch (key)
        {
            case SPACE          :    _block->FallDown();
                                     Update();            break;
        }
    }
}

void Game::Draw()
{
    unsigned x0 = 50, y0 = 50, x0new = 0, y0new = 0;

    glClear(GL_COLOR_BUFFER_BIT);
    _DrawCan(x0, y0, x0new, y0new);
    _DrawStatus(x0new, y0);

    glutSwapBuffers();
}

void Game::_DrawStatus(unsigned x0, unsigned y0)
{
    DrawText(x0, y0 + 20, GLUT_BITMAP_HELVETICA_12, FormatText("Lines: %i", _lines).c_str());
    DrawText(x0, y0 + 40, GLUT_BITMAP_HELVETICA_12, FormatText("Score: %i", _score).c_str());
    DrawText(x0, y0 + 60, GLUT_BITMAP_HELVETICA_12, FormatText("Speed: %i", _speed).c_str());

    DrawText(x0, y0 + 420, GLUT_BITMAP_HELVETICA_18, " Next");
    _DrawNext(x0, y0 + 460);

    if (_lose)
    {
        DrawText(x0, y0 + 240, GLUT_BITMAP_HELVETICA_18, "    Game over."     );
        DrawText(x0, y0 + 220, GLUT_BITMAP_HELVETICA_18, "Press R to restart.");
    }
    else if (_paused)
    {
        DrawText(x0, y0 + 240, GLUT_BITMAP_HELVETICA_18, "   Game paused."     );
        DrawText(x0, y0 + 220, GLUT_BITMAP_HELVETICA_18, "Press P to continue.");
    }
}

void Game::_DrawNext(unsigned x0, unsigned y0)
{
    for (unsigned cell = 0; cell != FIGURE_COMPLEXITY; ++cell)
    {
        unsigned x = x0 + _blocks[_nextFigIndex][_nextRotIndex][2*cell]*_well->CellSize();
        unsigned y = y0 + _blocks[_nextFigIndex][_nextRotIndex][2*cell + 1]*_well->CellSize();

        DrawRect(x, y, x + _well->CellSize(), y + _well->CellSize(), Color[_nextColor - 1]);
    }
}

void Game::_DrawCan(unsigned x0, unsigned y0, unsigned& x0new, unsigned& y0new)
{
    unsigned rectX1 = x0, rectX2 = rectX1 + _well->CellSize();
    unsigned rectY1 = y0, rectY2 = rectY1 + _well->CellSize();

    DrawGrid(x0, y0, _well->Width(), _well->RedLine(), _well->CellSize());
    DrawBorder(x0, y0, _well->Width() * _well->CellSize(), _well->Height() * _well->CellSize());


    for (unsigned width = 0; width != _well->Width(); ++width)
    {
        rectY1 = y0;
        rectY2 = rectY1 + _well->CellSize();
        
        for (unsigned height = 0; height != _well->Height(); ++height)
        {
            DrawRect(rectX1, rectY1, rectX2, rectY2, Color[(_well->Cell(width, height) & COLOR_MASK) - 1]);
            
            rectY1  = rectY2;
            rectY2 += _well->CellSize();
        }

        rectX1  = rectX2;
        rectX2 += _well->CellSize();
    }

    x0new = rectX2;
    y0new = rectY2;
}  

void Game::ReportLinesRemoval(unsigned lines)
{
    _lines += lines;
    _score += lines * BASE_SCORE;

    while (lines--) 
        _score += lines * (BASE_SCORE >> lines);
}

void Game::_StartNextBlock()
{
    _block->Update(_nextFigIndex, _nextRotIndex); 
    
    _nextFigIndex = rand() % VARIOUS_BLOCKS;
    _nextRotIndex = rand() % ROTATIONS;
    _nextColor    = _nextFigIndex + 1;
    
    _block->PutOnTop();
}

void Game::Update()
{
    if (!_paused && !_block->MoveDown())
    {
        _block->CheckLines();
        if (!_lose)
        {    
            if (_lines >= NEXT_LEVEL_LINES_LIMIT)
            {
                _SpeedUp();
                _lines = 0;
            }

            _StartNextBlock();
        }
    }
}

void Game::_Restart()
{
    _lose   = false;
    _paused = false;
    _lines  = 0;
    _score  = 0;

    _well->Clear();
    _StartNextBlock();
}

void Game::_Pause()
{
    _paused = !_paused;
}

void Game::_Stop()
{
    exit(0);    
}

void Game::ReportLoseState()
{
    _lose = true;
}

unsigned Game::UpdateInterval()
{
    return (MAX_SPEED - _speed + 1)*100;
}

void Game::_SpeedUp()
{
    if (_speed < MAX_SPEED) ++_speed; 
}

void Game::_SpeedDown()
{
    if (_speed > MIN_SPEED) --_speed; 
}

Initial URL


Initial Description
Кусок самописного тетриса. C++/openGL.

Initial Title
Tetris main logic

Initial Tags


Initial Language
C++