听了老师的思路,自己实现了一个. 没有参考任何工程, 分层不是很明显.
本来应该分成4个层 : UI + 逻辑 + 算法 + 基础函数集. 中间调试花了很长时间,将自己玩的不轻.
现在大概分为 : UI + 逻辑 + 键盘处理. 没有做优化, 该做其他事情了.
/// @file exam_1_1\doc\readme.txt
/// @brief 游戏设计文档
工程名称 Russia blocks (俄罗斯方块 控制台版)
子目录定义
./ui 界面绘制
./logic 业务逻辑
./alg 算法
./doc 文档
./lib 第三方库
中文的显示
画墙 2维数组
初始化墙 墙在数组内用1表示
墙在UI上用输入法输入符号"■"表示
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 0000000000 00000000000 1
1 1111111111 11111111111 1
砖头用2维数组表示, 1表示砖头, 0表示砖头图案中的空白
砖头在UI上用输入法输入符号"□"表示
横着的砖头
1111
0000
0000
0000
砖头属性: 位置, 类型
类型: 大类型,小类型
大类型: 横转, 竖砖 etc.
小类型: 旋转后的类型(一样是横转,旋转的角度不同,显示的图案不同)
随机方法
srand
rand() % n; ///< 0 ~ (n - 1)
砖头的显示
将砖头画到UI上(将砖头数据画到UI中), 砖头用2表示
接受控制
_kbhit() 是否有键按下
getchar()
键处理
上下左右 + 旋转(单方向)
建立当前砖头
消除砖头(固定砖头, 清掉当前砖头数据)
固定砖头(将当前砖头数据和UI溶为一体)
消行
产生新砖头
优化: 只更新需要显示的数据
记时: clock_t ts = clock() 单位(ms)
分数的显示
游戏循环的流程
自动下落
判断游戏结束
胜利的判断(得分超过多少)
失败的判断(无法显示新砖头)
/// @file \lesson\2015_1030\exam_1_1\main.c
/// @brief Russia blocks
#include "gameControl.h"
int main(int argc, char** argv)
{
startGame();
return 0;
}
/// @file \2015_1030\exam_1_1\ui\const_define_ui.h
/// @brief UI常量的定义
#ifndef __CONST_DEFINE_UI_H__
#define __CONST_DEFINE_UI_H__
/// 墙的size
#define WALL_ROW 20
#define WALL_COL 16
extern unsigned char g_cGameUI[WALL_ROW][WALL_COL];
/// 砖头的size
#define BRICK_ROW 4
#define BRICK_COL 4
/// 砖头起始位置
#define BRICK_FIRST_POSITION_ROW 0
#define BRICK_FIRST_POSITION_COL ((int)(WALL_COL / 2) - BRICK_COL)
#define BRICK_BIG_TYPE_CNT 5 ///< (横砖, 竖砖, 三角形, L型, Z型)
#define BRICK_SMALL_TYPE_CNT 4 ///< (旋转: 0度, 90度,180度, 270度)
#define BRICK_ROW_ALL (BRICK_BIG_TYPE_CNT * BRICK_SMALL_TYPE_CNT * BRICK_ROW)
/// 墙的厚度
#define WALL_WIDTH 2 ///< 左右的墙厚度
#define WALL_HEIGHT 2 ///< 下面的墙厚度
#define DATA_EMPTY 0
#define DATA_WALL 1
#define DATA_BRICK 2
/// 图形符号
/// 为了使UI居中,在左面打印一行空格
#define GRAPH_OFFSET_LINE " "
/// 使用说明
#define GRAPH_USAGE_LINE1 "左箭头 => 向左, 右箭头 => 向右, 上箭头 => 向上"
#define GRAPH_USAGE_LINE2 "下箭头 => 向下, W键 => 旋转, Q键 => 退出"
#define GRAPH_EMPTY " "
#define GRAPH_WALL "■"
#define GRAPH_BRICK "□"
#endif
/// @file \2015_1030\exam_1_1\ui\ui.h
/// @brief UI显示
#ifndef __UI_H__
#define __UI_H__
void updateUI();
void clearScreen();
void DrawUI();
#endif // #ifndef __UI_H__
/// @file \exam_1_1\ui\ui.c
/// @brief
#include "common.h"
unsigned char g_cGameUI[WALL_ROW][WALL_COL] = {0}; ///< 游戏显示区
unsigned char g_cBrickData[BRICK_ROW][BRICK_COL] = {0}; ///< 当前单块砖头数据
/// 从指定的行列取的砖头数据大小的墙数据, 用于是否能将砖块挪动到这个位置
unsigned char g_cUiWallDataByPos[BRICK_ROW][BRICK_COL] = {0};
/// 砖头图案库
unsigned char g_cBrickDataLib[BRICK_ROW_ALL][BRICK_COL] =
{
/// 逆时针旋转
/// ========================================
/// 横砖头 大类型0
/// ========================================
/// 横砖头 - 0度
1, 1, 1, 1,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
/// 横砖头 - 90度
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
/// 横砖头 - 180度
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
/// 横砖头 - 270度
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
/// ========================================
/// 竖砖头 大类型1
/// ========================================
/// 竖砖头 - 0度
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
/// 竖砖头 - 90度
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
/// 竖砖头 - 180度
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
/// 竖砖头 - 270度
1, 1, 1, 1,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
/// ========================================
/// 三角型砖头 大类型2
/// ========================================
/// 三角型砖头 - 0度
1, 0, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0,
/// 三角型砖头 - 90度
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
1, 1, 1, 0,
/// 三角型砖头 - 180度
0, 0, 0, 0,
0, 0, 0, 1,
0, 0, 1, 1,
0, 0, 0, 1,
/// 三角型砖头 - 270度
0, 1, 1, 1,
0, 0, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0,
/// ========================================
/// L型砖头 大类型3
/// ========================================
/// L型砖头 - 0度
1, 1, 1, 1,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
/// L型砖头 - 90度
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 0, 0,
/// L型砖头 - 180度
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 1,
1, 1, 1, 1,
/// L型砖头 - 270度
0, 0, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
/// ========================================
/// Z型砖头 大类型4
/// ========================================
/// L型砖头 - 0度
0, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 0,
0, 0, 0, 0,
/// Z型砖头 - 90度
1, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 1, 0,
/// Z型砖头 - 180度
0, 0, 0, 0,
0, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 0,
/// Z型砖头 - 270度
0, 1, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 1,
};
void updateUI()
{
if (IsDataDrity())
{
mergeBrickDataToUi();
clearScreen();
DrawUI();
SetDataDirty(FALSE);
}
}
void DrawUI()
{
int i = 0;
int j = 0;
for (i = 0; i < WALL_ROW; i++)
{
printf("%s", GRAPH_OFFSET_LINE);
for (j = 0; j < WALL_COL; j++)
{
switch(g_cGameUI[i][j])
{
case DATA_WALL:
printf("%s", GRAPH_WALL);
break;
case DATA_BRICK:
printf("%s", GRAPH_BRICK);
break;
default:
printf("%s", GRAPH_EMPTY);
break;
}
}
printf("\n");
}
printf("%s", GRAPH_OFFSET_LINE);
printf("%s\n", GRAPH_USAGE_LINE1);
printf("%s", GRAPH_OFFSET_LINE);
printf("%s\n", GRAPH_USAGE_LINE2);
}
void clearScreen()
{
system("cls");
}
/// @file \2015_1030\exam_1_1\gameControl.h
/// @brief 游戏控制逻辑
#ifndef __GAMECONTROL_H__
#define __GAMECONTROL_H__
#include "common.h"
#include "logic/keyBoardControl.h"
typedef enum eBrickType
{
eBrickType_unknown = -1,
eBrickType_Horizontal_bar, ///< 横块
eBrickType_Vertical_bar, ///< 竖块
eBrickType_Triangle, ///< 三角型
eBrickType_L, ///< L型
eBrickType_Z, ///< Z型
}ENUM_EBRICKTYPE;
typedef enum eBrickRotateAngle
{
eBrickRotateAngle_unknown = -1,
eBrickRotateAngle_0, ///< 0度
eBrickRotateAngle_90, ///< 90度
eBrickRotateAngle_180, ///< 180度
eBrickRotateAngle_270, ///< 270度
}ENUM_EBRICKROTATEANGLE;
void startGame();
void InitGameData();
void SetDataDirty(BOOL bDirty);
BOOL IsDataDrity();
void SetHaveBrickOnUI(BOOL bHave);
BOOL IsHaveBrickOnUI();
int GetBrickFirstPositionRow();
int GetBrickFirstPositionCol();
void SetBrickData(
int iBrickPosRow,
int iBrickPosCol,
ENUM_EBRICKTYPE BrickType,
ENUM_EBRICKROTATEANGLE BrickRotateAngle);
BOOL GetBrickData(
int* piBrickPosRow,
int* piBrickPosCol,
ENUM_EBRICKTYPE* pBrickType,
ENUM_EBRICKROTATEANGLE* pBrickRotateAngle);
void GenBrickData(BOOL bGenData);
void fillBrickData();
BOOL IsEmptyBrickData();
void mergeBrickDataToUi();
void clearBrickDataOnUiData(int iUiPosRow, int iUiPosCol);
void mergeBrickDataOnUiData();
ENUM_EBRICKTYPE GenRand_BrickType();
ENUM_EBRICKROTATEANGLE GenRand_BrickAngle();
/// 是否给定坐标在固定墙内(固定墙:程序初始化时,画出的墙)
BOOL IsFixWall(int iCoordinatesX, int iCoordinatesY);
/// 判断该点在UI上是否为墙数据
BOOL IsWallData(int iRow, int iCol, BOOL* pbIsWallData);
ENUM_EKBINPUT procKbInput(enum eKbInput KbInput);
void procKbInput_Left();
void procKbInput_Right();
void procKbInput_Up();
void procKbInput_Down();
void procKbInput_Rotate();
void Brick2Wall(); ///< 砖块数据转墙数据
void KillRows(); ///< 消行
void KillRow(int iRow); ///< 消指定行
BOOL GetWallDataOnUi(unsigned char cData[BRICK_ROW][BRICK_COL], int iRowBegin, int iColBegin);
BOOL IsSrcDataCanPutOnDst(
unsigned char cDataSrc[BRICK_ROW][BRICK_COL],
unsigned char cDataDst[BRICK_ROW][BRICK_COL]);
#endif // #ifndef __GAMECONTROL_H__
/// @file \2015_1030\exam_1_1\gameControl.cpp
/// @brief
#include "common.h"
#include "gameControl.h"
#include "ui/ui.h"
#include "logic/keyBoardControl.h"
BOOL g_bDrity = FALSE;
BOOL g_bHaveBrickOnUI = FALSE;
/// 如果屏幕上还没有砖头, 砖头的数据如下
int g_iUiBrickPosRow = -1;
int g_iUiBrickPosCol = -1;
ENUM_EBRICKTYPE g_BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE g_BrickRotateAngle = eBrickRotateAngle_0;
extern unsigned char g_cBrickData[BRICK_ROW][BRICK_COL];
extern unsigned char g_cBrickDataLib[BRICK_ROW_ALL][BRICK_COL];
void startGame()
{
InitGameData();
do
{
if (!IsHaveBrickOnUI())
{
GenBrickData(TRUE);
}
updateUI();
if (_kbhit() > 0)
{
if (eKbInput_quit == procKbInput(GetKbInput()))
{
break;
}
}
} while (1);
}
int GetBrickFirstPositionRow()
{
return BRICK_FIRST_POSITION_ROW;
}
int GetBrickFirstPositionCol()
{
return BRICK_FIRST_POSITION_COL;
}
void SetHaveBrickOnUI(BOOL bHave)
{
if (!bHave)
{
_ASSERT(1);
}
g_bHaveBrickOnUI = bHave;
}
BOOL IsHaveBrickOnUI()
{
return g_bHaveBrickOnUI;
}
void SetBrickData(
int iBrickPosRow,
int iBrickPosCol,
ENUM_EBRICKTYPE BrickType,
ENUM_EBRICKROTATEANGLE BrickRotateAngle)
{
g_iUiBrickPosRow = iBrickPosRow;
g_iUiBrickPosCol = iBrickPosCol;
g_BrickType = BrickType;
g_BrickRotateAngle = BrickRotateAngle;
}
BOOL GetBrickData(
int* piBrickPosRow,
int* piBrickPosCol,
ENUM_EBRICKTYPE* pBrickType,
ENUM_EBRICKROTATEANGLE* pBrickRotateAngle)
{
BOOL bRc = FALSE;
do
{
if ((NULL == piBrickPosRow)
|| (NULL == piBrickPosCol)
|| (NULL == pBrickType)
|| (NULL == pBrickRotateAngle))
{
_ASSERT(0);
break;
}
*piBrickPosRow = g_iUiBrickPosRow;
*piBrickPosCol = g_iUiBrickPosCol;
*pBrickType = g_BrickType;
*pBrickRotateAngle = g_BrickRotateAngle;
bRc = TRUE;
} while (0);
return bRc;
}
ENUM_EBRICKTYPE GenRand_BrickType()
{
BOOL bRc = FALSE;
int iCnt = (eBrickType_Z - eBrickType_Horizontal_bar) + 1;
int iIndex = rand() % iCnt;
bRc = ((iIndex > eBrickType_unknown) && (iIndex <= eBrickType_Z));
if (!bRc)
{
_ASSERT(0);
}
return (ENUM_EBRICKTYPE)iIndex;
}
ENUM_EBRICKROTATEANGLE GenRand_BrickAngle()
{
BOOL bRc = FALSE;
int iCnt = (eBrickRotateAngle_270 - eBrickRotateAngle_0) + 1;
int iIndex = rand() % iCnt;
bRc = ((iIndex > eBrickRotateAngle_unknown) && (iIndex <= eBrickRotateAngle_270));
if (!bRc)
{
_ASSERT(0);
}
return (ENUM_EBRICKTYPE)iIndex;
}
void GenBrickData(BOOL bGenData)
{
if (bGenData)
{
SetBrickData(
GetBrickFirstPositionRow(),
GetBrickFirstPositionCol(),
GenRand_BrickType(),
GenRand_BrickAngle());
}
fillBrickData();
SetHaveBrickOnUI(TRUE);
SetDataDirty(TRUE);
}
void fillBrickData()
{
int iIndex = 0;
int i = 0;
int j = 0;
int iBrickPosRow = 0;
int iBrickPosCol = 0;
ENUM_EBRICKTYPE BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE BrickRotateAngle = eBrickRotateAngle_unknown;
GetBrickData(&iBrickPosRow, &iBrickPosCol, &BrickType, &BrickRotateAngle);
// fill g_cBrickData from g_cBrickDataLib
/// 砖块数据在砖块图形库中的数组位置索引,
iIndex = (BrickType - eBrickType_Horizontal_bar) * BRICK_SMALL_TYPE_CNT + (BrickRotateAngle - eBrickRotateAngle_0);
_ASSERT(iIndex < BRICK_ROW_ALL);
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
g_cBrickData[i][j] = g_cBrickDataLib[iIndex * BRICK_ROW + i][j];
}
}
if (IsEmptyBrickData())
{
_ASSERT(0);
}
}
BOOL IsEmptyBrickData()
{
BOOL bEmpty = TRUE; ///< 假设为空
int i = 0;
int j = 0;
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
if (0 != g_cBrickData[i][j])
{
/// not empty
bEmpty = FALSE;
goto LABEL_ISEMPTYBRICKDATA_END;
}
}
}
LABEL_ISEMPTYBRICKDATA_END:
return bEmpty;
}
void mergeBrickDataToUi()
{
/// 有砖头数据, 就将砖头数据写到UI数组
/// 砖头数据没有的标记,在消行时处理
if (IsHaveBrickOnUI() && IsDataDrity())
{
/// 在UI数据中清掉"当前显示的砖头数据"
clearBrickDataOnUiData(g_iUiBrickPosRow, g_iUiBrickPosCol);
/// 将"砖头数据"合并到UI数据
mergeBrickDataOnUiData();
}
}
BOOL IsFixWall(int iCoordinatesX, int iCoordinatesY)
{
if ((iCoordinatesY >= 0)
&& (iCoordinatesY < WALL_WIDTH))
{
return TRUE;
}
else if ((iCoordinatesY >= (WALL_COL - WALL_WIDTH))
&& (iCoordinatesY < WALL_COL))
{
return TRUE;
}
else if ((iCoordinatesX >= (WALL_ROW - WALL_HEIGHT))
&& (iCoordinatesX < WALL_ROW))
{
return TRUE;
}
return FALSE;
}
BOOL IsWallData(int iRow, int iCol, BOOL* pbIsWallData)
{
BOOL bRc = FALSE;
do
{
_ASSERT(NULL != pbIsWallData);
*pbIsWallData = TRUE;
if (((iCol < 0 ) || (iCol > (WALL_COL - 1)))
|| ((iRow < 0 ) || (iRow > (WALL_ROW - 1))))
{
break;
}
*pbIsWallData = (DATA_WALL == g_cGameUI[iRow][iCol]);
bRc = TRUE;
} while (0);
return bRc;
}
void clearBrickDataOnUiData(int iUiPosRow, int iUiPosCol)
{
int i = 0;
int j = 0;
BOOL bIsWallData = FALSE;
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_ROW; j++)
{
if (IsWallData(iUiPosRow + i, iUiPosCol + j, &bIsWallData) && !bIsWallData)
{
g_cGameUI[iUiPosRow + i][iUiPosCol + j] = DATA_EMPTY;
}
}
}
}
void mergeBrickDataOnUiData()
{
int i = 0;
int j = 0;
BOOL bIsWallData = FALSE;
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
if (IsWallData(g_iUiBrickPosRow + i, g_iUiBrickPosCol + j, &bIsWallData) && !bIsWallData)
{
g_cGameUI[g_iUiBrickPosRow + i][g_iUiBrickPosCol + j] = (1 == g_cBrickData[i][j]) ? DATA_BRICK : DATA_EMPTY;
}
}
}
}
void SetDataDirty(BOOL bDirty)
{
g_bDrity = bDirty;
}
BOOL IsDataDrity()
{
return g_bDrity;
}
void InitGameData()
{
int i = 0;
int j = 0;
srand(time(NULL));
setlocale(LC_ALL, ".936"); ///< 设置中文代码页, 用来显示中文字符
SetDataDirty(TRUE);
SetHaveBrickOnUI(FALSE);
for (i = 0; i < WALL_ROW; i++)
{
for (j = 0; j < WALL_COL; j++)
{
if (IsFixWall(i, j))
{
g_cGameUI[i][j] = DATA_WALL;
}
else
{
g_cGameUI[i][j] = DATA_EMPTY;
}
}
}
}
ENUM_EKBINPUT procKbInput(enum eKbInput KbInput)
{
switch (KbInput)
{
case eKbInput_up:
procKbInput_Up();
break;
case eKbInput_down:
procKbInput_Down();
break;
case eKbInput_left:
procKbInput_Left();
break;
case eKbInput_right:
procKbInput_Right();
break;
case eKbInput_rotate:
procKbInput_Rotate();
break;
}
return KbInput;
}
void procKbInput_Left()
{
int iBrickPosRow = 0;
int iBrickPosCol = 0;
ENUM_EBRICKTYPE BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE BrickRotateAngle = eBrickRotateAngle_unknown;
unsigned char cUiWallDataByPos[BRICK_ROW][BRICK_COL] = {0};
GetBrickData(&iBrickPosRow, &iBrickPosCol, &BrickType, &BrickRotateAngle);
do
{
GetWallDataOnUi(cUiWallDataByPos, iBrickPosRow, iBrickPosCol - 1);
clearBrickDataOnUiData(iBrickPosRow, iBrickPosCol);
if (IsSrcDataCanPutOnDst(g_cBrickData, cUiWallDataByPos))
{
SetBrickData(iBrickPosRow, --iBrickPosCol, BrickType, BrickRotateAngle);
}
SetDataDirty(TRUE);
} while (0);
}
void procKbInput_Right()
{
int iBrickPosRow = 0;
int iBrickPosCol = 0;
ENUM_EBRICKTYPE BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE BrickRotateAngle = eBrickRotateAngle_unknown;
unsigned char cUiWallDataByPos[BRICK_ROW][BRICK_COL] = {0};
GetBrickData(&iBrickPosRow, &iBrickPosCol, &BrickType, &BrickRotateAngle);
do
{
GetWallDataOnUi(cUiWallDataByPos, iBrickPosRow, iBrickPosCol + 1);
clearBrickDataOnUiData(iBrickPosRow, iBrickPosCol);
if (IsSrcDataCanPutOnDst(g_cBrickData, cUiWallDataByPos))
{
SetBrickData(iBrickPosRow, ++iBrickPosCol, BrickType, BrickRotateAngle);
}
SetDataDirty(TRUE);
} while (0);
}
void procKbInput_Up()
{
int iBrickPosRow = 0;
int iBrickPosCol = 0;
ENUM_EBRICKTYPE BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE BrickRotateAngle = eBrickRotateAngle_unknown;
unsigned char cUiWallDataByPos[BRICK_ROW][BRICK_COL] = {0};
GetBrickData(&iBrickPosRow, &iBrickPosCol, &BrickType, &BrickRotateAngle);
do
{
if (iBrickPosRow <= 0)
break;
GetWallDataOnUi(cUiWallDataByPos, iBrickPosRow - 1, iBrickPosCol);
clearBrickDataOnUiData(iBrickPosRow, iBrickPosCol);
if (IsSrcDataCanPutOnDst(g_cBrickData, cUiWallDataByPos))
{
SetBrickData(--iBrickPosRow, iBrickPosCol, BrickType, BrickRotateAngle);
}
SetDataDirty(TRUE);
} while (0);
}
void procKbInput_Down()
{
int iBrickPosRow = 0;
int iBrickPosCol = 0;
ENUM_EBRICKTYPE BrickType = eBrickType_unknown;
ENUM_EBRICKROTATEANGLE BrickRotateAngle = eBrickRotateAngle_unknown;
unsigned char cUiWallDataByPos[BRICK_ROW][BRICK_COL] = {0};
GetBrickData(&iBrickPosRow, &iBrickPosCol, &BrickType, &BrickRotateAngle);
GetWallDataOnUi(cUiWallDataByPos, iBrickPosRow + 1, iBrickPosCol);
clearBrickDataOnUiData(iBrickPosRow, iBrickPosCol);
if (IsSrcDataCanPutOnDst(g_cBrickData, cUiWallDataByPos))
{
SetBrickData(++iBrickPosRow, iBrickPosCol, BrickType, BrickRotateAngle);
}
else
{
mergeBrickDataOnUiData();
Brick2Wall();
SetHaveBrickOnUI(FALSE);
KillRows();
}
SetDataDirty(TRUE);
}
void Brick2Wall()
{
int i = 0;
int j = 0;
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
if (DATA_BRICK == g_cGameUI[g_iUiBrickPosRow + i][g_iUiBrickPosCol + j])
{
g_cGameUI[g_iUiBrickPosRow + i][g_iUiBrickPosCol + j] = DATA_WALL;
}
}
}
}
void KillRows()
{
BOOL bAllColWasNoZero = TRUE;
int i = 0;
int j = 0;
do
{
for (i = (WALL_ROW - WALL_HEIGHT - 1); i >= 0; i--)
{
bAllColWasNoZero = TRUE;
for (j = WALL_WIDTH; j < (WALL_COL - WALL_WIDTH); j++)
{
if (DATA_EMPTY == g_cGameUI[i][j])
{
bAllColWasNoZero = FALSE;
break;
}
}
if (bAllColWasNoZero)
{
/// 消掉一行后,游戏区都下降了一行
KillRow(i++);
}
}
} while (0);
}
void KillRow(int iRow)
{
int i = 0;
int j = 0;
for (i = iRow; i >= 0; i--)
{
for (j = WALL_WIDTH; j < (WALL_COL - WALL_WIDTH); j++)
{
g_cGameUI[i][j] = g_cGameUI[i - 1][j];
}
}
for (j = WALL_WIDTH; j < (WALL_COL - WALL_WIDTH); j++)
{
g_cGameUI[0][j] = 0;
}
}
void procKbInput_Rotate()
{
switch (g_BrickRotateAngle)
{
case eBrickRotateAngle_0:
g_BrickRotateAngle = eBrickRotateAngle_90;
break;
case eBrickRotateAngle_90:
g_BrickRotateAngle = eBrickRotateAngle_180;
break;
case eBrickRotateAngle_180:
g_BrickRotateAngle = eBrickRotateAngle_270;
break;
case eBrickRotateAngle_270:
g_BrickRotateAngle = eBrickRotateAngle_0;
break;
default:
_ASSERT(0);
break;
}
GenBrickData(FALSE);
}
BOOL GetWallDataOnUi(unsigned char cData[BRICK_ROW][BRICK_COL], int iRowBegin, int iColBegin)
{
BOOL bRc = FALSE;
BOOL bError = FALSE;
BOOL bIsWall = FALSE;
int i = 0;
int j = 0;
do
{
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
if (((iRowBegin + i) >= 0)
&& ((iRowBegin + i) < WALL_ROW)
&& ((iColBegin + j) >= 0)
&& ((iColBegin + j) < WALL_COL))
{
bIsWall = (DATA_WALL == g_cGameUI[iRowBegin + i][iColBegin + j]);
cData[i][j] = bIsWall ? DATA_WALL : DATA_EMPTY;
}
else
{
cData[i][j] = DATA_EMPTY;
}
}
}
bRc = TRUE;
} while (0);
return bRc;
}
BOOL IsSrcDataCanPutOnDst(
unsigned char cDataSrc[BRICK_ROW][BRICK_COL],
unsigned char cDataDst[BRICK_ROW][BRICK_COL])
{
BOOL bRc = FALSE;
BOOL bCanPut = TRUE;
int i = 0;
int j = 0;
do
{
for (i = 0; i < BRICK_ROW; i++)
{
for (j = 0; j < BRICK_COL; j++)
{
if ((cDataSrc[i][j] != 0)
&& (cDataDst[i][j] != 0))
{
bCanPut = FALSE;
goto LABLE_ISSRCDATACANPUTONDST_END;
}
}
}
bRc = TRUE;
} while (0);
LABLE_ISSRCDATACANPUTONDST_END:
return bRc;
}
/// @file \exam_1_1\logic\keyBoardControl.h
/// @brief 键盘控制
#ifndef __KEYBOARDCONTROL_H__
#define __KEYBOARDCONTROL_H__
typedef enum eKbInput
{
eKbInput_unknown = -1,
eKbInput_left,
eKbInput_right,
eKbInput_up,
eKbInput_down,
eKbInput_rotate,
eKbInput_quit,
}ENUM_EKBINPUT;
/// 键盘接收到的值
#define KB_VAL_ARROW_UP 72 ///< 上
#define KB_VAL_ARROW_DOWN 80 ///< 下
#define KB_VAL_ARROW_LEFT 75 ///< 左
#define KB_VAL_ARROW_RIGHT 77 ///< 右
#define KB_VAL_CHAR_ROTATE 119 ///< 旋转 W键
#define KB_VAL_CHAR_QUIT 113 ///< 退出 Q键
ENUM_EKBINPUT GetKbInput();
#endif
/// @file \exam_1_1\logic\keyBoardControl.c
/// @brief
#include "keyBoardControl.h"
#include "common.h"
ENUM_EKBINPUT GetKbInput()
{
int iRc = 0;
ENUM_EKBINPUT KbInput = eKbInput_unknown;
iRc = _getch();
switch (iRc)
{
case KB_VAL_ARROW_UP:
KbInput = eKbInput_up;
break;
case KB_VAL_ARROW_DOWN:
KbInput = eKbInput_down;
break;
case KB_VAL_ARROW_LEFT:
KbInput = eKbInput_left;
break;
case KB_VAL_ARROW_RIGHT:
KbInput = eKbInput_right;
break;
case KB_VAL_CHAR_ROTATE:
KbInput = eKbInput_rotate;
break;
case KB_VAL_CHAR_QUIT:
KbInput = eKbInput_quit;
break;
default:
break;
}
return KbInput;
};
/// @file \2015_1030\exam_1_1\common.h
/// @brief 公用头文件
#ifndef __COMMON_H__
#define __COMMON_H__
#include
#include
#include
#include
#include
#include
#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
#include "./ui/const_define_ui.h"
#include "./ui/ui.h"
#include "./logic/gameControl.h"
#include "./logic/keyBoardControl.h"
#endif // #ifndef __COMMON_H__