Tool.h
class Tool
{
protected:
int_data[4][4]; //4*4的方块组数量
int_type; //俄罗斯方块的类型变量
private:
void Make_1();
void Make_2();
void Make_3();
void Make_4();
void Make_5();
public:
Tool(int type);//构造函数,本类没有使用动态分布,无需析构,类对象可直接复制、赋值
const int GetTpe() const; //获取Tool的类型
const int & ElementAt (int i,int j) const; //获取小方块的赋值
Tool Roll(); //对小方块进行形态变换
};
Tool.cpp
#include "Tool.h"
Tool::Tool(void)
{
_type=type;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
_data[i][j]=0;
switch (_type){
case 1:Make_1();break;
case 2:Make_2();break;
case 3:Make_3();break;
case 4:Make_4();break;
case 5:Make_5();break;
}
}
void Tool::Make_1()
{
_data[1][0]=_data[1][1]=_data[1][2]=_data[1][3]=1;
}
void Tool::Make_2()
{
_data[1][1]=_data[1][2]=_data[2][1]=_data[2][2]=2;
}
void Tool::Make_3()
{
_data[1][1]=_data[1][2]=_data[2][1]=_data[3][1]=3;
}
void Tool::Make_4()
{
_data[1][0]=_data[1][1]=_data[2][1]=_data[3][1]=4;
}
void Tool::Make_5()
{
_data[1][0]=_data[1][1]=_data[2][1]=_data[2][2]=5;
}
const int & Tool::ElementAt(int i,int j)const{//获取小方块的元素数值
return_data[i][j];
}
const int Toll::GetType()const{
return_type;
}
//返回顺时针旋转90度后的俄罗斯方块
Tool Tool::Roll(){
Tool toolRotated (*this);//复制一个俄罗斯方块
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
toolRotated._data[i][j]=_data[3-j][i];
return toolRotated;
}
Game.h
#pragma once
#include "Tool.h"
enum GAME_STATE {
PAUSE,//暂停
GO, //工作
STOP //停止
};
class Game
{
friend class CMyBoxDlg;
private:
GAME_STATE _state; //游戏状态
int *_bigNet; //游戏主界面表示数组
int *_bigNetAux; //游戏主界面表示辅助数组
int _netWidth, _netHeight; //主游戏界面的宽度、高度
Tool _tool; //当前游戏主界面正在下落的方块
Tool _nextTool; //下一个即将出现出现的下落方块
int _iLocX, _iLocY; //方块坐标,俄罗斯方块左上角位置
public:
Game(int height, int width);
~Game();
void Start(); //开始游戏
void Input(UINT nChar); //键盘输入接收处理函数
bool Go(); //运行一步
void PauseOrContinue(); //暂停/继续键的控制函数
private:
void NextTool(); //生成下一个方块
bool CanMoveDown(); //方块是否可以向下移动
//计算参数中的一维数组中不为0的元素数
int CountNoneZero(int * matrix, int Height, int Width);
//将俄罗斯方块标记加入到指定主界面数组中
void AddToolToAux(int *net, int iOffsetX, int iOffsetY,
const Tool &_tool);
void MoveDown(); //方块向下移动一格
bool CanMoveLeft(); //方块是否可以向左移动
bool CanMoveRight(); //方块是否可以向右移动
void MoveLeft(); //方块向左移动一格
void MoveRight(); //方块向右移动一格
bool CanRoll(); //方块是否可以变换形态
void Roll(); //变换方块形态
void RemoveLines(); //移除行操作
bool CanRemoveLine(int index);//是否可以移除一行
void RemoveLine(int index); //移除一行
bool IsDead(); //游戏是否结束
};
Game.cpp
#include "stdafx.h"
#include "Game.h"
//Game类的构造函数
Game::Game(int height, int width) : _tool(0), _nextTool(0)
{
_netWidth = width; //20
_netHeight = height; //9
_bigNet = _bigNetAux = NULL;
_state = STOP;
// 分配游戏界面表示数组
_bigNet = new int[_netHeight*_netWidth];
// 分配游戏界面表示辅助数组
_bigNetAux = new int[_netHeight*_netWidth];
// 初始化游戏界面表示数组为0
for (int i = 0; i < _netHeight; i++)
for (int j = 0; j < _netWidth; j++)
_bigNet[i*_netWidth + j] = 0;
// 随机数播种,产生俄罗斯方块形状随机数使用
srand((unsigned int)time(0));
}
//析构函数
Game::~Game(void)
{
delete[] _bigNet;
delete[] _bigNetAux;
}
//生成下一个方块,更换新的积木
void Game::NextTool()
{
//设置4*4方块所在的左上角坐标
_IlocY=0;
_iLocX = (_netWidth - 4) / 2;
_tool = _nextTool;
//更新下一个俄罗斯方块
_nextTool = Tool(rand() % 5 + 1);
}
//开始游戏
void Game::Start()
{
//初始化游戏主界面内的下落方块
_tool=Tool(0);
//初始化下一个方块
_nextTool=Tool(0);
// 初始化游戏状态为运行状态
_state = GO;
// 初始化游戏界面表示数组为0
for (int i = 0; i < _netHeight; i++)
for (int j = 0; j < _netWidth; j++)
_bigNet[i*_netWidth + j] = 0;
// 连续调用两次方块的产生
NextTool();
NextTool();
}
//暂停/继续键的控制函数
void Game::HaltOrContinue()
{
if (_state == HALT)
_state = GO;
else if (_state == GO)
_state = HALT;
}
//键盘输入接收处理函数
void Game::Input(UINT nChar)
{
switch (nChar) {
case VK_UP: if (CanRoll()) Roll(); break;
case VK_DOWN: if (CanMoveDown()) MoveDown(); break;
case VK_LEFT: if (CanMoveLeft()) MoveLeft(); break;
case VK_RIGHT: if (CanMoveRight()) MoveRight(); break;
}
}
//方块是否可以向下移动
bool Game::CanMoveDown()
{
int cnt1 = 4, cnt2 = 0;
cnt1 += CountNoneZero(_bigNet, _netHeight, _netWidth);
// 假设发生变换
AddToolToAux(_bigNetAux, _iLocX, _iLocY + 1, _tool);
// 统计变换后方块数
cnt2 = CountNoneZero(_bigNetAux, _netHeight, _netWidth);
return cnt2 == cnt1;
}
//将俄罗斯方块标记加入到指定主界面数组中
void Game::AddToolToAux(int *net, int iOffsetX, int iOffsetY , const Tool &_tool)
{
//必要时先复制主界面数组至指定数组
if (net != _bigNet)
for (int i = 0; i < _netHeight; i++)
for (int j = 0; j < _netWidth; j++)
net[i*_netWidth+j]=_bigNet[i*_netWidth+j];
int iType = _tool.GetType();
if (iType != 0) {
//合并俄罗斯方块数据
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if (i + iOffsetY >= 0 &&
i + iOffsetY < _netHeight &&
j + iOffsetX >= 0 &&
j + iOffsetX < _netWidth &&
_tool.ElementAt(i, j) != 0)
net[(i+iOffsetY)*_netWidth+j+iOffsetX]=iType;
}
}
}
//计算数组中不为0的元素数
int Game::CountNoneZero(int *matrix, int Height, int Width)
{
int cnt = 0;
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++) {
if (matrix[i*Width + j] != 0)
++cnt;
}
return cnt;
}
//方块向下移动一格
void Game::MoveDown()
{
++_iLocY;
}
//方块是否可以向左移动
bool Game::CanMoveLeft()
{
int cnt1 = 4, cnt2 = 0;
cnt1 += CountNoneZero(_bigNet, _netHeight, _netWidth);
// 假设发生变换
AddToolToAux(_bigNetAux, _iLocX - 1, _iLocY, _tool);
// 统计变换后方块数
cnt2 = CountNoneZero(_bigNetAux, _netHeight, _netWidth);
return cnt2 == cnt1;
}
//方块是否可以向右移动
bool Game::CanMoveRight()
{
int cnt1 = 4, cnt2 = 0;
cnt1 += CountNoneZero(_bigNet, _netHeight, _netWidth);
// 假设发生变换
AddToolToAux(_bigNetAux, _iLocX + 1, _iLocY, _tool);
// 统计变换后方块数
cnt2 = CountNoneZero(_bigNetAux, _netHeight, _netWidth);
return cnt2 == cnt1;
}
//方块向左移动一格
void Game::MoveLeft()
{
--_iLocX;
}
//方块向右移动一格
void Game::MoveRight()
{
++_iLocX;
}
//方块是否可以变换形态
bool Game::CanRoll()
{
int cnt1 = 4, cnt2 = 0;
cnt1 += CountNoneZero(_bigNet, _netHeight, _netWidth);
// 假设发生变换
Tool toolRotated = _tool.Roll();
AddToolToAux(_bigNetAux, _iLocX, _iLocY, toolRotated);
// 统计变换后方块数
cnt2 = CountNoneZero(_bigNetAux, _netHeight, _netWidth);
return cnt2 == cnt1;
}
//变换方块形态
void Game::Roll()
{
//用旋转后俄罗斯方块代替
_tool = _tool.Roll();
}
//运行一步
bool Game::Go()
{
if (CanMoveDown()) { //判断是否可以向下移动一格
MoveDown(); //向下移动一格
return true;
}
else {
//将方块加到游戏主界面数组中
AddToolToAux(_bigNet, _iLocX, _iLocY, _tool);
RemoveLines(); //移除满行
NextTool(); //向界面中加入下一个方块
if (IsDead()) {
_state = STOP; //设置游戏状态为停止
return false;
}
return true;
}
}
//移除行操作
void Game::RemoveLines()
{
for (int i = _netHeight - 1; i >= 0; i--)
while (CanRemoveLine(i))
RemoveLine(i); //可消除本行时,消除本行
}
//是否可以移除一行
bool Game::CanRemoveLine(int index)
{
int count = 0;
for (int i = 0; i < _netWidth; i++)
if (_bigNet[index*_netWidth + i] != 0)
count++;
//小方块数量等于主界面宽度时本行可消除
return count == _netWidth;
}
//移除一行
void Game::RemoveLine(int index)
{
for (int i = index; i > 0; i--) //前面所有行下移一行
for (int j = 0; j < _netWidth; j++)
_bigNet[i*_netWidth+j]=_bigNet[(i-1)*_netWidth+j];
for (int j = 0; j < _netWidth; j++)
_bigNet[j] = 0; //第1行清0
}
//游戏是否结束
bool Game::IsDead()
{
int cnt1 = 4, cnt2 = 0;
cnt1 += CountNoneZero(_bigNet, _netHeight, _netWidth);
// 假设发生变换
AddToolToAux(_bigNetAux, _iLocX, _iLocY, _tool);
// 统计加入俄罗斯方块后小方块数
cnt2 = CountNoneZero(_bigNetAux, _netHeight, _netWidth);
//不等就是有重叠的情况发生,代表Dead
return cnt2 != cnt1;
}
//获取游戏状态值
GAME_STATE Game::GetState(){
return state;
}
在MyBoxDlg头文件中加入
private;
Game game;
void DrawNet();
void DrawBigNet();
void DrawSmallNet();
void OnKeyDown(UINT nChar);
以及
#include"Game.h"
MyBoxDlg.cpp文件的实现
构造长宽高
修改其中MyBoxDlg的构造函数为
CMyBoxDlg::CMyBoxDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMyBoxDlg::IDD, pParent),_game(20,9)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
开始按钮
点击MyBoxDlg,右键选择其中的类向导,选择