Thread: Tetris implementation question

  1. #1
    Registered User
    Join Date
    Oct 2006
    Location
    Mainz, Germany
    Posts
    2

    Question Tetris implementation question

    Hi,

    My background: I am a 18-year-old student from Germany and have some programming experience in different languages, however I have so far not used C++ very much.

    My aim: I want to write a simple Tetris game using C++ and the SDL library. I have already used the SDL library to some extent in a previous C++ program of mine that I didn't finish.

    My question: I am a bit lost when it comes to implementing the game logic so I hope you can help me. This is only about the game logic, not about the engine and so on. I thought I'd use a two-dimensional array (vector) of ints to store the tetris field whereas the values in the array represent the colors of the tetris stones. E.g., a value of zero means, there is no stone at this position, 1 is for red, 2 to for blue and so forth.
    But then I need an extra struct or class or something to store the current element that is moving down until it hits an existing stone. And I would need two simultaneous loops running concurrently, one for moving the current element down step by step and another one for tracking the keyboard input.
    If anyone has an idea how to implement this reasonably please don't hesitate to post it.

    Thanks a lot, David.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Pretty much all games can be reduced to
    Code:
    bool alive = true;
    do {
      if ( inputAvailable() ) {
        // user did something, update the game state
        // say rotate a block
        input = readInput();
        updateGame(input);
      } else {
        // they did nothing, move block down a step
        updateGame(timer);
      }
      redrawScreen();
      alive = checkGameOver();
    } while ( alive );
    All you basically need to do is make sure you have non-blocking sources of input.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In the case of SDL, I believe the interesting function here is SDL_PeekEvent.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well you are right about the array. So in order to make a 'piece' fit into the array paradigm you need a function that can take a piece 'definition' so to speak which would inform the game about which array elements to 'turn on' to show the piece. If you do it right, by using offsets you should be able to get away with simply setting the start row and column of the piece in question and have a piece type. The piece type then would index into a piece defintion array that tells how to draw that piece. If you do it this way, moving the piece left/right and down/up becomes a snap because you simply increment/decrement start row and column since everything being drawn on screen from memory is relative to the starting offset of the piece.

    After you get the drawing routine down eliminating rows is a simple matter of eliminating the bottom row in memory and then doing a reverse bubble sort to move the other rows down.

    The best place to track row deletions is when you draw. If the total number of same colored squares equals the total number of columns on the board, you have a deletion row. Add this row to a vector or array. At the end of the drawing function you then iterate the array or vector and call DeleteRow(DeletionArray[iIndex]) for each row in the deletion array. Then reverse bubble sort the array and return. Since you will be re-drawing the board on the next game iteration, you don't need to draw twice. The new information will be reflected to the player when the screen is refreshed.

    For special effects when deleting rows you would have to implement something a bit different but it would not be too difficult.


    Code:
    enum BLOCK_ROT
    {
      DEG0,
      DEG90,
      DEG180,
      DEG270
    };
    
    struct BlockDef
    {
      int iRowOffset;
      int iColOffset;
    }
    
    class CGamePiece
    {
      BlockDef *m_pPieceDef;
    
      int m_iNumBlocks;
      BLOCK_ROT m_iRotationType;
      ...
    };
    
    class CTetrisPiece
    {
      CGamePiece *m_pPieces;
      int m_iTotalPieces;
      int m_iMaxPieces;
      DWORD m_dwRow;
      DWORD m_dwCol;
      DWORD m_dwOffset;
      BLOCK_ROT m_iCurRotation;
      
      ...
      ...
    
      public:
        void Create(int iMaxPieces.....) {m_pPieces=new CGamePiece[iMaxPieces]; m_iMaxPieces=iMaxPieces; .....   }
    
        bool AddPiece(CGamePiece *pPiece)
        {
           if (m_iTotalPieces<m_iMaxPieces)
           {
               //Add piece here
               m_iTotalPieces++;
               return false;
           } else return true;
       }
    
       bool AddPiece(BlockDef *pBlocks,int iNumBlocks);
       ....
    };
    
    class CArray2D
    {
      protected:
        DWORD *m_pArray;
        DWORD m_dwWidth;
        DWORD m_dwHeight;
        DWORD m_dwMaxOffset;
    
      public:
        CArray2D():m_pArray(NULL),m_dwWidth(0),m_dwHeight(0),m_dwMaxOffset(0) { }
    
        bool Create(DWORD dwWidth,DWORD dwHeight)
        {
           m_dwWidth=dwWidth;
           m_dwHeight=dwHeight;
           m_dwMaxOffset=m_dwWidth*m_dwHeight;
           
           m_pArray=new DWORD[m_dwMaxOffset];
           if (!m_pArray) 
           {
              return false;
           } else return true;
        }
    
        DWORD GetValue(bool &bFailed);
        DWORD GetValue(DWORD dwRow,DWORD dwCol,bool &bFailed);
        bool SetValue(DWORD dwOffset);
        bool SetValue(DWORD dwRow,DWORD dwCol);
    };
    
    class CTetrisBoard
    {
      protected:
        CArray *m_pBoard;
        
        void SortRows();           
    
      public:
    
        ....
        void Update(float fFrameDelta);
        void Render();
        bool DeleteRow(DWORD dwRow);
        
    };
    That's a good start. I left a lot out and you might also want to employ the STL more to ease your pain. There are array wrappers already available to you so writing your own isn't completely necessary.
    Last edited by VirtualAce; 10-22-2006 at 06:31 AM.

  5. #5
    Registered User
    Join Date
    Oct 2006
    Location
    Mainz, Germany
    Posts
    2
    Thanks a lot for your replies, they seem to be very useful. But unfortunalety today school started here and we have to do a lot of exams so I have to see when I manage to try it out.

    ts.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. another do while question
    By kbpsu in forum C++ Programming
    Replies: 3
    Last Post: 03-23-2009, 12:14 PM
  2. rand() implementation
    By habert79 in forum C Programming
    Replies: 4
    Last Post: 02-07-2009, 01:18 PM
  3. implementation file
    By bejiz in forum C++ Programming
    Replies: 5
    Last Post: 11-28-2005, 01:59 AM
  4. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 09:47 PM
  5. opengl DC question
    By SAMSAM in forum Game Programming
    Replies: 6
    Last Post: 02-26-2003, 09:22 PM