TetrisData.h 里面定义了 TBaseTetris 类,主要对俄罗斯方块的一些算法进行了封装。
MapXsize 和 MapYsize 是俄罗斯方块的操作部分的面积(格数),修改这两个参数值,会得到不同大小的俄罗斯方块
TTetrisUnit 是每个单元的 4x4 矩阵数组,数组每个元素储存的是 Blocks.bmp 的方块的索引值
TTetrisUnits 是每个单元的 4 个旋转方向的矩阵,每个方向的状态不是在程序里面做的矩阵旋转,而是事先填好的,x,y,r储存的是位置和角度(r=0,1,2,3表示旋转0,90,180,270度),un[0],un[1],un[2],un[3]是旋转0,90,180,270的状态时对应的方块形状。
TTetrisBuffer 是俄罗斯方块操作区域每个小方格对应的 Blocks.bmp 位图的索引号 (0 表示空白)
TMoveDir 定义了动作类型,左、右、下、顺时针、逆时针
属性 Busy 处理忙,由于某些操作要显示动画,在这个过程中不允许键盘操作
属性 Started 是否已经开始玩游戏
属性 GameOver 是否游戏结束
属性 Score 为分数
属性 Lines 为消去的行数
属性 DisplayBuffer 为显示缓存,即俄罗斯方块操作区域每个方格里面对应的位图索引号
属性 IncomingUnits 为下一个要出现的下落的单元的形状和角度
NewGame 函数是开始新游戏
Move 函数是进行一次动作,动作由 TMoveDir 里面的数据表示
TBaseTetris(); //构造函数
~TBaseTetris(); //析构函数
NumUnits 下落的单元的种类数
BaseUnits[NumUnits] 每种下落的单元的形状(用在位图里面的索引号表示)
Ux0, Uy0; 下落的开始位置,每个下落单元都是从这个坐标开始下落的
CurrUnit, IncmUnit; 当前正在下落的单元,下一个(未来)要下落的单元
DispBuffer 显示缓存, 包括所有要显示的内容
BlockBuffer 运算用的缓存, 不包括正在下落的单元
int CheckUnit(int x, int y, int r); 检查当前下落单元的状态,
返回0:还可以继续下落,返回1:不能继续下落了,返回2或3:在无效的状态(有重叠现象了)
int TryToRemove(void); 消除完整的行,
返回值为是否已经处理完,如果返回值为零,操作完成,如果不为零,需要继续进行消除处理
void GenNewUnit(void); 生成新的下落单元
void DispTetris(void); 根据处理的数据(BlockBuffer) 和正在下落的单元(CurrUnit) 生成显示单元的内容
void AddScore(int iRmv); //加分, 参数为本次操作消去的行数
--------------------next---------------------
int TBaseTetris::CheckUnit(int x, int y, int r) //检查当前下落的方块单元的状态
这个函数涉及的变量:
BlockBuffer 是已经摆好的方块, 这些方块是每次摆放方块不能消去的, 有空白格的那些剩在屏幕上的小方格的缓存,
这个数组 不包含 正在下落的方块单元的内容。里面每个元素对应一个小方格, 如果是 0 代表空白, 不等于 0 就是位图索引号。
CurrUnit 是正在下落的方块单元的位置、角度、和形状。
通过 CurrUnit 和 BlockBuffer 两个数组的比较分析,
1.如果正在下落的方块单元当中任何一个 有位图索引(≠0)的小方块, 在 BlockBuffer 的对应位置的下面一个小方格都有空位置,
就说明这个正在下落的单元可以继续下落, 函数返回值为 0
2.如果正在下落的方块单元当中, 只要有一个有位图索引(≠0)的小方块, 在 BlockBuffer 的对应位置的下面一个小方格没有空位置,
就说明正在下落的单元不能继续下落, 已经到底了, 函数返回值为 1
3.如果正在下落的方块单元当中, 只要有一个有位图索引(≠0)的小方块, 超出屏幕范围(MapXsize,MapYsize),
或者在 BlockBuffer 的对应位置已经有位图索引(≠0)的小方块, 发生了重叠现象, 就认为处于非法状态, 返回值为2或3 (D1=1)。
--------------------next---------------------
// ... 前面的内容省略...
// ... 下面只介绍手动添加的内容 ...
public:
static const NumScores = 5; //按分数取前 5 名加入英雄榜
#pragma pack(push,1) //对齐方式:按字节
typedef struct
{
int Score; //分数
char Name[32]; //名字
} TScoreItem; //取得名次的 player 的信息结构
typedef union
{
TScoreItem Scores[NumScores]; //英雄榜
char Buffer[512]; //如果英雄榜不足 512 字节,填充到 512 字节
} TTetrisParams; //配置信息, 这个信息要储存到一个文件里面
#pragma pack(pop)
private: // User declarations
__property bool Paused = { read = _bPaused, write = SetPause }; //暂停
bool _bPaused; //是否处于暂停状态
TBaseTetris Tetris; //俄罗斯方块类
TTetrisParams TetrisParams; //配置信息,里面包含俄罗斯方块的英雄榜
Graphics::TBitmap *TtBmp, *PsBmp, *OvBmp; //方块、暂停信息、游戏结束的位图
void __fastcall SetPause(bool); //设置暂停状态
void __fastcall CheckGameStatus(void); //检查游戏状态,如果游戏结束,处理并显示英雄榜
void __fastcall RefreshDisplay(void); //刷新显示
void LoadParams(void); //从文件里面读取配置信息
void SaveParams(void); //把配置信息储存到文件里
void GetPlayerName(char *lpName); //通过一个对话框询问 player 的名字
void ShowHighScores(void); //显示英雄榜
public: // User declarations
__fastcall TFormTetris(TComponent* Owner); //Form 的构造函数
__fastcall ~TFormTetris(); //Form 的析构函数
//.... 后面的内容省略...
--------------------next---------------------
void __fastcall TFormTetris::PaintBox1Paint(TObject *Sender) //这个是 PaintBox1 的绘图事件
在这个绘图事件里面,要画出俄罗斯方块操作区域 (ScrollBox1) 里面的所有内容,包括已经下落的方块和正在下落方块
如果在暂停状态,还要显示暂停信息;如果在游戏结束的状态,要显示游戏结束的信息。
事件的 Sender 参数的意义为:产生这个事件的控件,在这个事件里面,Sender 就是 PaintBox1
函数一开始通过 FillRect 函数(用当前刷子填充矩形)来清除 PaintBox1 所有的内容
然后接下来的循环是显示出 TBaseTetris 类的显示缓存里面的内容,就是俄罗斯方块的内容
然后显示暂停或游戏结束的信息,如果有的话。
程序里面涉及到了一个绘图的 API 函数 ::BitBlt, 把位图的 某个部分 画到一个画布的 某个部分
BitBlt(画布的句柄, 画布的位置x,y坐标, 画图区域的宽度,高度, 位图画布的句柄, 位图需要画到画布上的部分的起始坐标x,y, 绘图方式);
这个函数按 1:1 的比例(原始大小)画在画布上, SRCCOPY 为直接复制的画图方式
void __fastcall TFormTetris::PaintBox2Paint(TObject *Sender) //这个是 PaintBox2 的绘图事件
在这个事件里画出下一个要出现的方块单元,给 Player 提示, 预先准备的作用
这个函数比较简单,只是一个循环画出 TBaseTetris 类的 IncomingUnits 正在下落单元的每个小方块
--------------------next---------------------
void __fastcall TFormTetris::Timer1Timer(TObject *Sender) //定时器事件
这个事件里面判断,如果正在操作中,没有暂停,没有结束,就要让下落的单元下落,并且检查下落之后的状态
void __fastcall TFormTetris::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) //窗口的按键事件
这个事件非常重要,这个事件的内容也比较简单。
处理用户的所有操作。在这个事件里面判断用户按键,对相应按键做方块的移动处理,并且检查移动之后的状态。
void __fastcall TFormTetris::RefreshDisplay(void) //刷新显示
PaintBox1->Invalidate(); 这句话是刷新 PaintBox1 的显示,即:产生 OnPaint 事件
void __fastcall TFormTetris::CheckGameStatus(void) //检查游戏状态
如果游戏结束,要处理英雄榜,如果分数进入名次,加入英雄榜,然后显示出英雄榜。
void TFormTetris::GetPlayerName(char *lpName) //利用 FormEnterName 对话框窗口,让用户输入名字,这是加入英雄榜的名字
--------------------next---------------------
阅读(1344) | 评论(0) | 转发(0) |