zoukankan      html  css  js  c++  java
  • 游戏开发(二)——控制台 俄罗斯方块

    俄罗斯方块游戏设计中主要须要注意的几点:

    1:依旧是坐标的定义:定义为左上角为(0,0),向右为x正方向,向下为y正方向


    2:游戏画面是分两个区域的。左边是游戏区域,就是俄罗斯方块下落的区域。右边一个小的显示下一个方块是什么的区域。

    可是,方块出现并開始下落时,并非一个方块直接出如今画面顶部,而是从最上面一行開始,一行一行的逐行落下来。

    比方一个竖长条,并非一出现就直接占了4行,而是一格一格的出现,一格一格的落下来的,这里也用了一个取巧的做法,

    就是在游戏画面顶部,多定义4行,仅仅是这4行不显示,一个新的方块出来,是放在不显示的那4行上,然后一行一行的下移,

    使得游戏画面看起来像是方块一格一格的出现的效果


    3:俄罗斯方块有7种,每种有4个方向,这里定义成一个常量数组,固定填好每一个格子的相对坐标。

    /*
            □■■□    □■■□    □■■□    □■■□
            □■■□    □■■□    □■■□    □■■□
            □□□□    □□□□    □□□□    □□□□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □■□□    □■■□    □■□□    □■■□
            □■■□    ■■□□    □■■□    ■■□□
            □□■□    □□□□    □□■□    □□□□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □□■□    ■■□□    □□■□    ■■□□
            □■■□    □■■□    □■■□    □■■□
            □■□□    □□□□    □■□□    □□□□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □■□□    □□□□    ■■□□    □□■□
            □■□□    ■■■□    □■□□    ■■■□
            □■■□    ■□□□    □■□□    □□□□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □■□□    ■□□□    □■■□    □□□□
            □■□□    ■■■□    □■□□    ■■■□
            ■■□□    □□□□    □■□□    □□■□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □■□□    □■□□    □□□□    □■□□
            ■■■□    □■■□    ■■■□    ■■□□
            □□□□    □■□□    □■□□    □■□□
            □□□□    □□□□    □□□□    □□□□
    */
    /*
            □■□□    □□□□    □■□□    □□□□
            □■□□    ■■■■    □■□□    ■■■■
            □■□□    □□□□    □■□□    □□□□
            □■□□    □□□□    □■□□    □□□□
    */

    4:俄罗斯方块类的设计:

    属性:

    m_TypeIndex,表示当前方块是7种俄罗斯方块中的哪一种

    m_TurnIndex,表示当前方块是4种朝向中的哪一种

    m_Row_y,m_Column_x,表示以4*4范围为准的左上角当前坐标,转向时也做为对齐的基准点

    m_Tetris,表示方块4个小格的当前位置,是相对坐标加上m_Row_y,m_Column_x算出来的坐标

    动作:

    Init,初始化这个方块

    MoveTo,将当前方块移动到某个坐标

    Turn,方块转向

    Down,方块下移

    Left,方块左移

    Right,方块右移

    GetTetris,获取当前4个小格,主要是用来获取方块的每一个小格坐标


    5:地图场景的设计,和之前的贪吃蛇的场景类似

    地图是个二维数组,在控制台下,每一个元素能够用一个字符表示:'  '表示空地,'□'表示落究竟不能再动的方块格子,'■';表示正在下落的方块格子,以及右边显示的下一个方块格子,'◆'表示边框

    这个二维数组用到了之前的数组模板

    这里採用两个二维数组m_map1,和m_map2作为双缓冲,能够比对游戏前后的变化,每次游戏画面的更新,仅仅重绘改变的部分,这样能够防止全屏重绘导致的闪屏。

    地图上还包含三个成员,当前下落的方块m_CurrTetris,下一个方块m_NextTetris,以及用来測试方块下落的下一个位置能否够到达的測试方块m_TestTetris

    地图场景提供的功能主要有:

    RandNextTetris,随机生成下一个方块

    RandCurrTetris,将下一个方块方块赋值给当前方块

    IsShow,推断一个方块是否已经移出顶部不显示的那4行,未移出的方块不能做转向,左右移动的操作

    IsDeath,推断场景中是否有随意一列方块累积到顶了,触顶则游戏结束

    CanMove,推断方块能否够移动或转向,主要用到了上面的m_TestTetris

    CanRemove,推断是否有一行方格全满,一行全满的则能够消除

    Remove,消除满的方格行

    ProcessLogic,处理用户按下上、下、左、右时,方块的移动和转向,以及能否移动的推断,能否消除行的推断,落底之后的新方块的生成


    6:控制台的程序,怎样将字符绘制到指定的位置上去,和上一篇贪吃蛇类似

    用到了FillConsoleOutputCharacter,以及检測按键的_kbhit,和_getch

    详细函数功能就不介绍了,能够google


    7:定时下落的控制,计时器


    8:游戏主循环逻辑,与上一篇贪吃蛇一致,能够直接套用

        //初始化  
        while(true)  
        {  
            if (玩家有键盘操作)  
            {  
                if (ESC键)  
                {  
                    //跳出循环  
                }  
                else if (方向键)  
                {  
                    if (游戏正在进行中没有结束)  
                    {  
                        //方块按玩家操作的方向移动  
                    }  
                }  
                else //其它按键  
                {  
                    //不处理  
                }  
            }  
          
            //假定300毫秒处理一次游戏逻辑  
            //就是无论人是否控制的情况下,每300毫秒方块固定移动一步  
            if (300毫秒间隔时间到)  
            {  
                if (游戏正在进行中没有结束)  
                {  
                    //方块按默认方向移动  
                }  
            }  
              
            if (游戏结束)  
            {  
                //显示游戏结束  
            }  
          
            sleep  
        }  

    游戏截图:


    以下先给出代码


    Tetris.h:

    #ifndef _Tetris_
    #define _Tetris_
    
    typedef struct TetrisGrid
    {
    	int row_y;
    	int column_x;
    
    	TetrisGrid& operator= (const TetrisGrid& temp);
    }Grid;
    
    const int TETRIS_UP = 1;
    const int TETRIS_DOWN = 2;
    const int TETRIS_LEFT = 3;
    const int TETRIS_RIGHT = 4;
    
    const int MAX_GRID = 4;//每一个俄罗斯方块4个小格
    typedef struct Tetris
    {
    	TetrisGrid grids[MAX_GRID];
    
    	Tetris& operator= (const Tetris& temp);
    
    	void MoveTo(int row_y, int column_x);
    
    	void Left();
    
    	void Right();
    
    	void Down();
    }Tetris;
    
    const int MAX_TETRIS_FORWARD = 4;//俄罗斯方块4种朝向
    const int MAX_TETRIS_COUNT = 7;//7种俄罗斯方块
    const Tetris g_tetris[MAX_TETRIS_COUNT][MAX_TETRIS_FORWARD] = 
    {
    	{
    		/*
    		□■■□	□■■□	□■■□	□■■□
    		□■■□	□■■□	□■■□	□■■□
    		□□□□	□□□□	□□□□	□□□□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,1},{0,2},{1,1},{1,2}}},
    		{{{0,1},{0,2},{1,1},{1,2}}},
    		{{{0,1},{0,2},{1,1},{1,2}}},
    		{{{0,1},{0,2},{1,1},{1,2}}},
    	},
    	{
    		/*
    		□■□□	□■■□	□■□□	□■■□
    		□■■□	■■□□	□■■□	■■□□
    		□□■□	□□□□	□□■□	□□□□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,1},{1,1},{1,2},{2,2}}},
    		{{{0,1},{0,2},{1,0},{1,1}}},
    		{{{0,1},{1,1},{1,2},{2,2}}},
    		{{{0,1},{0,2},{1,0},{1,1}}},
    	},
    	{
    		/*
    		□□■□	■■□□	□□■□	■■□□
    		□■■□	□■■□	□■■□	□■■□
    		□■□□	□□□□	□■□□	□□□□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,2},{1,1},{1,2},{2,1}}},
    		{{{0,0},{0,1},{1,1},{1,2}}},
    		{{{0,2},{1,1},{1,2},{2,1}}},
    		{{{0,0},{0,1},{1,1},{1,2}}},
    	},
    	{
    		/*
    		□■□□	□□□□	■■□□	□□■□
    		□■□□	■■■□	□■□□	■■■□
    		□■■□	■□□□	□■□□	□□□□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,1},{1,1},{2,1},{2,2}}},
    		{{{1,0},{1,1},{1,2},{2,0}}},
    		{{{0,0},{0,1},{1,1},{2,1}}},
    		{{{0,2},{1,0},{1,1},{1,2}}},
    	},
    	{
    		/*
    		□■□□	■□□□	□■■□	□□□□
    		□■□□	■■■□	□■□□	■■■□
    		■■□□	□□□□	□■□□	□□■□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,1},{1,1},{2,0},{2,1}}},
    		{{{0,0},{1,0},{1,1},{1,2}}},
    		{{{0,1},{0,2},{1,1},{2,1}}},
    		{{{1,0},{1,1},{1,2},{2,2}}},
    	},
    	{
    		/*
    		□■□□	□■□□	□□□□	□■□□
    		■■■□	□■■□	■■■□	■■□□
    		□□□□	□■□□	□■□□	□■□□
    		□□□□	□□□□	□□□□	□□□□
    		*/
    		{{{0,1},{1,0},{1,1},{1,2}}},
    		{{{0,1},{1,1},{1,2},{2,1}}},
    		{{{1,0},{1,1},{1,2},{2,1}}},
    		{{{0,1},{1,0},{1,1},{2,1}}},
    	},
    	{
    		/*
    		□■□□	□□□□	□■□□	□□□□
    		□■□□	■■■■	□■□□	■■■■
    		□■□□	□□□□	□■□□	□□□□
    		□■□□	□□□□	□■□□	□□□□
    		*/
    		{{{0,1},{1,1},{2,1},{3,1}}},
    		{{{1,0},{1,1},{1,2},{1,3}}},
    		{{{0,1},{1,1},{2,1},{3,1}}},
    		{{{1,0},{1,1},{1,2},{1,3}}},
    	}
    };
    
    class MyTetris
    {
    public:
    	void Init(int row_y, int column_x, int typeIndex, int turnIndex);
    
    	void MoveTo(int row_y, int column_x);
    
    	void Turn();
    	
    	void Down();
    	
    	void Left();
    	
    	void Right();
    
    	MyTetris& operator= (const MyTetris& temp);
    
    	Tetris& GetTetris();
    
    private:
    	int m_TypeIndex;//7种俄罗斯方块中的哪一种
    	int m_TurnIndex;//4种朝向中的哪一种
    
    	int m_Row_y;//以4*4范围为准的左上角当前坐标,转向时也做为对齐的基准点
    	int m_Column_x;
    
    	Tetris m_Tetris;//当前位置
    };
    
    #endif


    Tetris.cpp:

    #include "Tetris.h"
    
    TetrisGrid& TetrisGrid::operator= (const TetrisGrid& temp)
    {
    	row_y = temp.row_y;
    	column_x = temp.column_x;
    	return *this;
    }
    
    Tetris& Tetris::operator= (const Tetris& temp)
    {
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		grids[i] = temp.grids[i];
    	}
    	return *this;
    }
    
    void Tetris::MoveTo(int row_y, int column_x)
    {
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		grids[i].row_y = grids[i].row_y + row_y;
    		grids[i].column_x = grids[i].column_x + column_x;
    	}
    }
    
    void Tetris::Left()
    {
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		grids[i].column_x--;
    	}
    }
    
    void Tetris::Right()
    {
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		grids[i].column_x++;
    	}
    }
    
    void Tetris::Down()
    {
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		grids[i].row_y++;
    	}
    }
    
    void MyTetris::Init(int row_y, int column_x, int typeIndex, int turnIndex)
    {
    	if (typeIndex < MAX_TETRIS_COUNT && turnIndex < MAX_TETRIS_FORWARD)
    	{
    		m_TypeIndex = typeIndex;
    		m_TurnIndex = turnIndex;
    	}
    	else
    	{
    		m_TypeIndex = 0;
    		m_TurnIndex = 0;
    	}
    	m_Tetris = g_tetris[m_TypeIndex][m_TurnIndex];
    
    	m_Row_y = row_y;
    	m_Column_x = column_x;
    	m_Tetris.MoveTo(m_Row_y, m_Column_x);
    }
    
    void MyTetris::MoveTo(int row_y, int column_x)
    {
    	m_Tetris = g_tetris[m_TypeIndex][m_TurnIndex];
    
    	m_Row_y = row_y;
    	m_Column_x = column_x;
    	m_Tetris.MoveTo(m_Row_y, m_Column_x);
    }
    
    void MyTetris::Turn()
    {
    	m_TurnIndex++;
    	if (MAX_TETRIS_FORWARD == m_TurnIndex)
    	{
    		m_TurnIndex = 0;
    	}
    	m_Tetris = g_tetris[m_TypeIndex][m_TurnIndex];
    
    	m_Tetris.MoveTo(m_Row_y, m_Column_x);
    }
    
    void MyTetris::Down()
    {
    	m_Row_y++;
    	m_Tetris.Down();
    }
    
    void MyTetris::Left()
    {
    	m_Column_x--;
    	m_Tetris.Left();
    }
    
    void MyTetris::Right()
    {
    	m_Column_x++;
    	m_Tetris.Right();
    }
    
    MyTetris& MyTetris::operator= (const MyTetris& temp)
    {
    	m_TypeIndex = temp.m_TypeIndex;
    	m_TurnIndex = temp.m_TurnIndex;
    	m_Tetris = g_tetris[m_TypeIndex][m_TurnIndex];
    
    	m_Row_y = temp.m_Row_y;
    	m_Column_x = temp.m_Column_x;
    	m_Tetris.MoveTo(m_Row_y, m_Column_x);
    
    	return *this;
    }
    
    Tetris& MyTetris::GetTetris()
    {
    	return m_Tetris;
    }


    TetrisScene.h:

    #ifndef _Tetris_Scene_
    #define _Tetris_Scene_
    
    #include "TArray.h"
    
    #include "Tetris.h"
    
    //用于显示当前方块的区域在Map中的初始位置,行数,列数
    const int TETRIS_CURR_INIT_ROW_Y = 1;
    const int TETRIS_CURR_INIT_COLUMN_X = 7;
    const int TETRIS_CURR_MAX_ROW = 4;
    const int TETRIS_CURR_MAX_COLUMN = 4;
    
    //游戏区域在Map中的位置,行数,列数
    const int TETRIS_GAME_ROW_Y = 5;
    const int TETRIS_GAME_COLUMN_X = 1;
    const int TETRIS_GAME_MAX_ROW = 20;
    const int TETRIS_GAME_MAX_COLUMN = 16;
    
    //用于显示下一个方块的区域在Map中的位置,行数,列数
    const int TETRIS_NEXT_ROW_Y = 6;
    //1列是左边框,1列是游戏区域和下一个方块的区域的间隔
    const int TETRIS_NEXT_COLUMN_X = 1 + TETRIS_GAME_MAX_COLUMN + 1;
    const int TETRIS_NEXT_MAX_ROW = 4;
    const int TETRIS_NEXT_MAX_COLUMN = 4;
    
    //整个Map的行数,列数
    //多2行是上下边框
    //多3列是左右边框,以及游戏区域和下一个方块的区域的间隔
    const int TETRIS_SCENE_MAX_ROW = 1 + TETRIS_CURR_MAX_ROW + TETRIS_GAME_MAX_ROW + 1;
    const int TETRIS_SCENE_MAX_COLUMN = 1 + TETRIS_GAME_MAX_COLUMN + 1 + TETRIS_NEXT_MAX_COLUMN + 1;
    
    //空白场景格
    const WCHAR WS_TETRIS_SCENE_GRID = L' ';
    //已经落下不能再动的方块
    const WCHAR WS_TETRIS_OLD = L'□';
    //新生成正在往下移动的方块,以及下一个方块
    const WCHAR WS_TETRIS_NEW = L'■';
    //场景边框格
    const WCHAR WS_TETRIS_SCENE_FRAME = L'◆';
    
    
    class TetrisScene 
    {
    public:
    	TetrisScene();
    
    	void InitMap();
    
    	void RandNextTetris();
    
    	void RandCurrTetris();
    
    	bool CanMove(int forward);
    
    	bool IsShow(MyTetris& mytetris);
    
    	bool IsDeath();
    
    	bool CanRemove(int row);
    
    	void Remove();
    	void Remove(int row);
    
    	TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW>& GetMap1();
    	TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW>& GetMap2();
    
    	bool ProcessLogic();
    	bool ProcessLogic(int forward);
    
    	void SetSceneGrid(MyTetris& mytetris);
    	void SetTetrisOld(MyTetris& mytetris);
    	void SetTetrisNew(MyTetris& mytetris);
    
    
    private:
    	TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW> m_map1;
    	TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW> m_map2;//双缓冲,用于对照改变了的位置,防止闪屏
    	
    	MyTetris m_CurrTetris;
    	MyTetris m_TestTetris;//CurrTetris的下一步位置,用于推断下一个位置能否移动
    	MyTetris m_NextTetris;
    };
    
    #endif


    TetrisScene.cpp:

    #include "TetrisScene.h"
    
    #include <time.h>
    
    TetrisScene::TetrisScene()
    {
    	srand((unsigned)time(NULL));
    
    	InitMap();
    	RandNextTetris();
    	RandCurrTetris();
    	RandNextTetris();
    }
    
    void TetrisScene::InitMap()
    {
    	for (int y = 0; y < TETRIS_SCENE_MAX_ROW; y++)
    	{
    		for (int x = 0; x< TETRIS_SCENE_MAX_COLUMN; x++)
    		{
    			m_map1[y][x] = WS_TETRIS_SCENE_FRAME;
    		}
    	}
    
    	for (int y = TETRIS_CURR_INIT_ROW_Y; y < TETRIS_CURR_INIT_ROW_Y + TETRIS_CURR_MAX_ROW; y++)
    	{
    		for (int x = TETRIS_CURR_INIT_COLUMN_X; x< TETRIS_CURR_INIT_COLUMN_X + TETRIS_CURR_MAX_COLUMN; x++)
    		{
    			m_map1[y][x] = WS_TETRIS_SCENE_GRID;
    		}
    	}
    
    	for (int y = TETRIS_GAME_ROW_Y; y < TETRIS_GAME_ROW_Y + TETRIS_GAME_MAX_ROW; y++)
    	{
    		for (int x = TETRIS_GAME_COLUMN_X; x< TETRIS_GAME_COLUMN_X + TETRIS_GAME_MAX_COLUMN; x++)
    		{
    			m_map1[y][x] = WS_TETRIS_SCENE_GRID;
    		}
    	}
    
    	for (int y = TETRIS_NEXT_ROW_Y; y < TETRIS_NEXT_ROW_Y + TETRIS_NEXT_MAX_ROW; y++)
    	{
    		for (int x = TETRIS_NEXT_COLUMN_X; x< TETRIS_NEXT_COLUMN_X + TETRIS_NEXT_MAX_COLUMN; x++)
    		{
    			m_map1[y][x] = WS_TETRIS_SCENE_GRID;
    		}
    	}
    }
    
    void TetrisScene::RandNextTetris()
    {
    	int typeIndex = rand() % MAX_TETRIS_COUNT;
    	int turnIndex = rand() % MAX_TETRIS_FORWARD;
    	m_NextTetris.Init(TETRIS_NEXT_ROW_Y, TETRIS_NEXT_COLUMN_X, typeIndex, turnIndex);
    
    	SetTetrisNew(m_NextTetris);
    }
    
    void TetrisScene::RandCurrTetris()
    {
    	m_CurrTetris = m_NextTetris;
    	SetSceneGrid(m_NextTetris);
    
    	m_CurrTetris.MoveTo(TETRIS_CURR_INIT_ROW_Y, TETRIS_CURR_INIT_COLUMN_X);
    	SetTetrisNew(m_CurrTetris);
    }
    
    bool TetrisScene::CanMove(int forward)
    {
    	m_TestTetris = m_CurrTetris;
    	switch (forward)
    	{
    	case TETRIS_UP:
    		m_TestTetris.Turn();
    		break;
    	case TETRIS_DOWN:
    		m_TestTetris.Down();
    		break;
    	case TETRIS_LEFT:
    		m_TestTetris.Left();
    		break;
    	case TETRIS_RIGHT:
    		m_TestTetris.Right();
    		break;
    	default:
    		m_TestTetris.Down();
    		break;
    	}
    
    	Tetris& tetris = m_TestTetris.GetTetris();
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		if (m_map1[tetris.grids[i].row_y][tetris.grids[i].column_x] == WS_TETRIS_SCENE_FRAME)
    		{
    			return false;
    		}
    		if (m_map1[tetris.grids[i].row_y][tetris.grids[i].column_x] == WS_TETRIS_OLD)
    		{
    			return false;
    		}
    	}
    	return true;
    }
    
    bool TetrisScene::IsShow(MyTetris& mytetris)
    {
    	Tetris& tetris = mytetris.GetTetris();
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		if (tetris.grids[i].row_y < TETRIS_GAME_ROW_Y)
    		{
    			return false;
    		}
    	}
    
    	return true;
    }
    
    bool TetrisScene::IsDeath()
    {
    	for (int i = TETRIS_GAME_COLUMN_X; i < TETRIS_GAME_COLUMN_X + TETRIS_GAME_MAX_COLUMN; i++)
    	{
    		if (m_map1[TETRIS_GAME_ROW_Y][i] == WS_TETRIS_OLD)
    		{
    			return true;
    		}
    	}
    	
    	return false;
    }
    
    bool TetrisScene::CanRemove(int row)
    {
    	for (int i = TETRIS_GAME_COLUMN_X; i < TETRIS_GAME_COLUMN_X + TETRIS_GAME_MAX_COLUMN; i++)
    	{
    		if (m_map1[row][i] != WS_TETRIS_OLD)
    		{
    			return false;
    		}
    	}
    	return true;
    }
    
    void TetrisScene::Remove()
    {
        //TETRIS_SCENE_MAX_ROW - 1 是最后一行的下标
        //再-1,是去掉最后一行的边框
        for (int i = TETRIS_SCENE_MAX_ROW - 1 - 1; i > TETRIS_GAME_ROW_Y;)
        {
            if (CanRemove(i))
            {
                Remove(i);
            }
            else
            {
                i--;
            }
        }
    }
    
    void TetrisScene::Remove(int row)
    {
    	for (int i = row; i > TETRIS_GAME_ROW_Y; i--)
    	{
    		for (int j = TETRIS_GAME_COLUMN_X; j < TETRIS_GAME_COLUMN_X + TETRIS_GAME_MAX_COLUMN; j++)
    		{
    			m_map1[i][j] = m_map1[i - 1][j];
    		}
    	}
    	for (int j = TETRIS_GAME_COLUMN_X; j < TETRIS_GAME_COLUMN_X + TETRIS_GAME_MAX_COLUMN; j++)
    	{
    		m_map1[TETRIS_GAME_ROW_Y][j] = WS_TETRIS_SCENE_GRID;
    	}
    }
    
    TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW>& TetrisScene::GetMap1()
    {
    	return m_map1;
    }
    
    TArray1<TArray1<WCHAR, TETRIS_SCENE_MAX_COLUMN>, TETRIS_SCENE_MAX_ROW>& TetrisScene::GetMap2()
    {
    	return m_map2;
    }
    
    bool TetrisScene::ProcessLogic()
    {
    	return ProcessLogic(TETRIS_DOWN);
    };
    
    bool TetrisScene::ProcessLogic(int forward)
    {
    	if (IsShow(m_CurrTetris))
    	{
    		switch (forward)
    		{
    		case TETRIS_UP:
    			{
    				if (CanMove(TETRIS_UP))
    				{
    					SetSceneGrid(m_CurrTetris);
    					m_CurrTetris.Turn();
    					SetTetrisNew(m_CurrTetris);
    				}
    			}
    			break;
    		case TETRIS_DOWN:
    			{
    				if (CanMove(TETRIS_DOWN))
    				{
    					SetSceneGrid(m_CurrTetris);
    					m_CurrTetris.Down();
    					SetTetrisNew(m_CurrTetris);
    				}
    				else
    				{
    					SetTetrisOld(m_CurrTetris);
    
    					if (!IsDeath())
    					{
    						Remove();
    
    						RandCurrTetris();
    						RandNextTetris();
    					}
    					else
    					{
    						return false;
    					}
    				}
    			}
    			break;
    		case TETRIS_LEFT:
    			{
    				if (CanMove(TETRIS_LEFT))
    				{
    					SetSceneGrid(m_CurrTetris);
    					m_CurrTetris.Left();
    					SetTetrisNew(m_CurrTetris);
    				}
    			}
    			break;
    		case TETRIS_RIGHT:
    			{
    				if (CanMove(TETRIS_RIGHT))
    				{
    					SetSceneGrid(m_CurrTetris);
    					m_CurrTetris.Right();
    					SetTetrisNew(m_CurrTetris);
    				}
    			}
    			break;
    		}
    	}
    	else
    	{
    		if (CanMove(TETRIS_DOWN))
    		{
    			SetSceneGrid(m_CurrTetris);
    			m_CurrTetris.Down();
    			SetTetrisNew(m_CurrTetris);
    		}
    		else
    		{
    			SetTetrisOld(m_CurrTetris);
    
    			if (!IsDeath())
    			{
    				Remove();
    				
    				RandCurrTetris();
    				RandNextTetris();
    			}
    			else
    			{
    				return false;
    			}
    		}
    	}
    
    	return true;
    }
    
    void TetrisScene::SetSceneGrid(MyTetris& mytetris)
    {
    	Tetris& tetris = mytetris.GetTetris();
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		m_map1[tetris.grids[i].row_y][tetris.grids[i].column_x] = WS_TETRIS_SCENE_GRID;
    	}
    }
    void TetrisScene::SetTetrisOld(MyTetris& mytetris)
    {
    	Tetris& tetris = mytetris.GetTetris();
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		m_map1[tetris.grids[i].row_y][tetris.grids[i].column_x] = WS_TETRIS_OLD;
    	}
    }
    void TetrisScene::SetTetrisNew(MyTetris& mytetris)
    {
    	Tetris& tetris = mytetris.GetTetris();
    	for (int i = 0; i < MAX_GRID; i++)
    	{
    		m_map1[tetris.grids[i].row_y][tetris.grids[i].column_x] = WS_TETRIS_NEW;
    	}
    }


    main.cpp:(事实上主函数和之前的贪吃蛇游戏全然一致,仅仅是改了几个坐标、和方向的常量)

    #include <stdio.h>
    #include <windows.h>
    #include <conio.h>
    
    #include "TArray.h"
    #include "TRandPool.h"
    
    #include "Tetris.h"
    #include "TetrisScene.h"
    
    #include "CPerformance.h"
    
    const unsigned char KEY_FORWARD = 224;
    const unsigned char KEY_UP = 72;
    const unsigned char KEY_DOWN = 80;
    const unsigned char KEY_LEFT = 75;
    const unsigned char KEY_RIGHT = 77;
    const unsigned char KEY_ESC = 27;
    
    TetrisScene g_TetrisScene;
    
    const int SCENE_ROW_Y = -5;
    const int SCENE_COLUMN_X = 20;
    const int SCENE_MAX_ROW = TETRIS_SCENE_MAX_ROW;
    const int SCENE_MAX_COLUMN = TETRIS_SCENE_MAX_COLUMN;
    
    const int LOGIC_UP = TETRIS_UP;
    const int LOGIC_DOWN = TETRIS_DOWN;
    const int LOGIC_LEFT = TETRIS_LEFT;
    const int LOGIC_RIGHT = TETRIS_RIGHT;
    
    void DrawMap(HANDLE hOut)
    {
    	COORD pos = {0, 0};
    	for (int y = 0; y < SCENE_MAX_ROW; y++)
    	{
    		for (int x = 0; x< SCENE_MAX_COLUMN; x++)
    		{
    			if (g_TetrisScene.GetMap1()[y][x] != g_TetrisScene.GetMap2()[y][x])
    			{
    				pos.X = x * 2 + SCENE_COLUMN_X;
    				pos.Y= y + SCENE_ROW_Y;
    				FillConsoleOutputCharacter(hOut, g_TetrisScene.GetMap1()[y][x], 2, pos, NULL);
    
    				g_TetrisScene.GetMap2()[y][x] = g_TetrisScene.GetMap1()[y][x];
    			}
    		}
    	}
    }
    
    int main()
    {
    	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    
    	CONSOLE_SCREEN_BUFFER_INFO bInfo;
    	GetConsoleScreenBufferInfo(hOut, &bInfo );
    
    	DrawMap(hOut);
    
    	CPerformance perf;//计时器
    	perf.Start();
    	float times = 0.0f;
    
    	bool bRes = true;//游戏是否结束的标志,true为进行中,false为结束
    
    	while (true)
    	{
    		if(_kbhit())
    		{
    			int ch = _getch();
    			if (KEY_ESC == ch)
    			{
    				break;
    			}
    			else if (KEY_FORWARD == ch)
    			{
    				if (bRes)
    				{
    					ch = _getch();
    					switch (ch)
    					{
    					case KEY_UP:
    						bRes = g_TetrisScene.ProcessLogic(LOGIC_UP);
    						break;
    					case KEY_DOWN:
    						bRes = g_TetrisScene.ProcessLogic(LOGIC_DOWN);
    						break;
    					case KEY_LEFT:
    						bRes = g_TetrisScene.ProcessLogic(LOGIC_LEFT);
    						break;
    					case KEY_RIGHT:
    						bRes = g_TetrisScene.ProcessLogic(LOGIC_RIGHT);
    						break;
    					}
    					DrawMap(hOut);
    				}
    			}
    		}
    
    		times = perf.End();
    		if (times > 300)
    		{
    			perf.Start();
    
    			if (bRes)
    			{
    				bRes = g_TetrisScene.ProcessLogic();
    				DrawMap(hOut);
    			}
    		}
    
    		if (!bRes)
    		{
    			WCHAR info[100] = {0};
    			wcscpy_s(info, 100, L"game over, press ESC key to exit.");
    			for (size_t i = 0; i < wcslen(info); i++)
    			{
    				COORD pos = {i, SCENE_MAX_ROW + SCENE_ROW_Y + 2};
    				FillConsoleOutputCharacter(hOut, info[i], 1, pos, NULL);
    			}
    		}
    		
    		Sleep(1);
    	}
    
    	CloseHandle(hOut);
    
    	return 0;
    }


  • 相关阅读:
    json返回数据拼接HTML
    jquery文本框验证字符长度和只能输入数字
    DataTable转换为Json格式
    将集合类转换成DataTable
    class创建单击事件
    ajax局部刷新分页
    查找根字符串
    游标的使用——mysql
    .NET 各种框架
    xml与datatable类型互换
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4008040.html
Copyright © 2011-2022 走看看