2048-优化篇三稿-类封装
- 代码有点乱,把代码整理封装一下,全部代码在最后。
一、定义全局变量和新建ConstDate.h
新建一个项目
Grid 放在类成员变量中不好操作,索性就定义为全局变量
新建了一个
ConstDate.h
文件存放固定的变量–在main.cpp
中要包含该头文件
int Grid[4][4] = {{1,2,3,4},}; //【全局变量】4*4矩阵
二、定义类
类名为
Game2048
,成员变量为公共属性,因为发现后面操作要改他们的值,定义函数改太麻烦了
class Game2048{
//private:
public:
int m_Dir; //方向:0-左,1-上,2-右,3-下
int m_EmptyBlock; //空格数
int m_Score; //记录分数
int m_MaxValue; //记录合成的最大值
int m_TopScore; //记录最高分数
public:
Game2048();//初始化
void PrintGrid();//打印函数
void ShowInfo();//显示信息
int CalculateEmpty();//计算空格函数
int GetMaxValue();//计算合成的最大值
void Move(int dir);//移动函数
void Addnum(int n);//添加新数
void LoadImgs();//加载图片
void ReleaseImgs();//释放图片
void Draw();//绘制图像
bool isGameOver();//判断游戏结束
void RestartDate();//重新开始
bool isClicInRectangle(int xClick,int yClick,int Rectangle_X,int Rectangle_Y,
int Rectangle_WIDTH,int Rectangle_HEIGHT);//检测是否点击在矩形区域内
void GameSave();//游戏保存--未写
void LoadRecord();//读档--未写
};
三、具体函数代码实现(copy)
就是把之前的代码整合一下,把名称统一,不必要的注释删了,全部代码在后面
四、全部代码
mian.cpp
也有近400行,不过至少看着舒服点
ConstDate.h
:
#ifndef CONST_DATE_H
#define CONST_DATE_H
const char RECORD_FILE_NAME[15] = "RECORD.txt";//存档文件名
const int DEVIDE = 15; //间隔
const int GRID_WIDTH = 106; //格子宽
const int WIDTH = 500+2*DEVIDE; //总界面宽
const int HEIGHT = 660+3*DEVIDE; //总界面高
const int BOARD_X = 0+DEVIDE; //棋盘起始点x
const int BOARD_Y = 160+2*DEVIDE; //棋盘起始点y
const int LOGO_X = 25+DEVIDE; //2048logo起始点x
const int LOGO_Y = 20+DEVIDE; //2048logo起始点y
const int RESTART_X = 0+DEVIDE; //restart起始点x
const int RESTART_Y = 90+DEVIDE; //restart起始点y
const int RESTART_WIDTH = 220; //restart 宽度
const int RESTART_HEIGHT = 50; //restart 高度
const int SCOREGB_X = 230+DEVIDE; //分数背景图起始点x
const int SCOREGB_Y = 0+DEVIDE; //分数背景图起始点y
const color_t TEXT_COLOR = EGERGB(241, 231, 214); //字体颜色
const color_t BG_COLOR = EGERGB(250,248, 239);//背景颜色淡黄色
const int MAXVALUE_X = SCOREGB_X+160; //最大值起始点x
const int MAXVALUE_Y = SCOREGB_Y+112; //最大值起始点y
const int SCORE_X = MAXVALUE_X; //本次分数起始点x
const int SCORE_Y = MAXVALUE_Y-45; //本次分数起始点y
const int TOP_SCORE_X = SCORE_X; //最高分数起始点x
const int TOP_SCORE_Y = SCORE_Y-45; //最高分数起始点y
/*-----------------------------------------------------------*/
//移动函数中使用
static int x0[4] = {0, 0, 3, 0};
static int y0[4] = {0, 0, 0, 3};
static int firstOffset[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}};
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
//图片存储
PIMAGE BlockImgs[18];//0-背景图,1-17数字图
PIMAGE GameOverImg;//游戏结束图
PIMAGE GameLogoImg;//游戏 Logo 图
PIMAGE RestartImg;//重新开始图
PIMAGE ScoreBgImg;//分数背景图
/*-----------------------------------------------------------*/
#endif //CONST_DATE_H
main.cpp
:
#include <iostream>
#include "graphics.h"
#include <cmath>
#include <fstream>
#include "ConstDate.h"
using namespace std;
int Grid[4][4] = {{1,2,3,4},}; //【全局变量】4*4矩阵
class Game2048{
//private:
public:
int m_Dir; // 方向:0-左,1-上,2-右,3-下
int m_EmptyBlock; //空格数
int m_Score; //记录分数
int m_MaxValue; //记录合成的最大值
int m_TopScore; //记录最高分数
public:
Game2048();//初始化
void PrintGrid();//打印函数
void ShowInfo();//显示信息
int CalculateEmpty();//计算空格函数
int GetMaxValue();//计算合成的最大值
void Move(int dir);//移动函数
void Addnum(int n);//添加新数
void LoadImgs();//加载图片
void ReleaseImgs();//释放图片
void Draw();//绘制图像
bool isGameOver();//判断游戏结束
void RestartDate();//重新开始
bool isClicInRectangle(int xClick,int yClick,int Rectangle_X,int Rectangle_Y,
int Rectangle_WIDTH,int Rectangle_HEIGHT);//检测是否点击在矩形区域内
void GameSave();//游戏保存--未写
void LoadRecord();//读档--未写
};
int main()
{
/*初始化-------------------------------------------------------------------------------*/
initgraph(WIDTH, HEIGHT);
setcaption("2048Game"); //设置游戏标题
setbkcolor(BG_COLOR);
setfont(25,0,"黑体");
setbkmode(TRANSPARENT); //文字输出为透明
Game2048 MainObj;
MainObj.Addnum(2); //在随机2个位置添加新数
MainObj.m_MaxValue = MainObj.GetMaxValue(); //更新最大值
MainObj.ShowInfo(); //控制台显示信息
MainObj.LoadImgs(); //加载图片
MainObj.Draw(); //画出初始界面
/*-------------------------------------------------------------------------------初始化*/
/*开始游戏-------------------------------------------------------------------------------*/
for ( ; is_run(); delay_fps(60) )
{
//按键检测
while(kbmsg())
{
key_msg keyMsg = getkey();
if(keyMsg.msg == key_msg_down)
{
switch(keyMsg.key)
{
case 'A':case key_left : MainObj.m_Dir = 0; break;//左
case 'W':case key_up : MainObj.m_Dir = 1; break;//上
case 'D':case key_right : MainObj.m_Dir = 2; break;//右
case 'S':case key_down : MainObj.m_Dir = 3; break;//下
}
}
}
if(MainObj.m_Dir!=-1)
{
system("cls");
switch(MainObj.m_Dir)
{
case 0: cout << "按下了 A/左 键" << endl; break;//左
case 1: cout << "按下了 W/上 键" << endl; break;//上
case 2: cout << "按下了 D/右 键" << endl; break;//右
case 3: cout << "按下了 S/下 键" << endl; break;//下
}
//图形更新
bool flag = false; //移动标志位
int tempGrid[4][4]; //暂存数组
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
tempGrid[i][j] = Grid[i][j];
MainObj.Move(MainObj.m_Dir);
//比较
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(Grid[i][j]!=tempGrid[i][j])
{
flag = true;
break;
}
if(flag)
{
cout << "有效移动" << endl;
MainObj.Addnum(1);
}
else cout << "无效移动" << endl;
MainObj.ShowInfo();
cout << "最大值:" << pow(2,MainObj.GetMaxValue())<< endl;
cout << "gameover: " << (MainObj.isGameOver()?"是":"否") << endl;
MainObj.Draw();
MainObj.m_Dir = -1;//将 Dir 置为无效,否则控制台会一直刷新
}
//鼠标检测
bool Clickflag= false;
while (mousemsg())
{
mouse_msg msg = getmouse();
if (msg.is_left() && msg.is_down()&&
MainObj.isClicInRectangle(msg.x,msg.y,RESTART_X,RESTART_Y,RESTART_WIDTH,RESTART_HEIGHT))
{
Clickflag = true;
}
}
if(Clickflag)
{
MainObj.RestartDate();
MainObj.Draw();
}
if(MainObj.isGameOver())
{
cout << "Game Over!" << endl;
//putimage(150,150,GameOver);
putimage_withalpha(NULL,GameOverImg,120,200);
break;
}
}
MainObj.ReleaseImgs();
getch();
closegraph();
return 0;
}
/*------------------------------------------------------------------------------开始游戏-*/
Game2048::Game2048()//初始化
{
this->m_Dir = -1;
this->m_EmptyBlock = 16;
this->m_MaxValue = 0;
this->m_Score = 0;
this->m_TopScore = 0;
}
void Game2048::PrintGrid()//打印数组
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
cout << Grid[i][j] << " ";
cout << endl;
}
cout << endl;
}
void Game2048::ShowInfo()//显示信息
{
cout << "方向:" << this->m_Dir << " (0-左,1-上,2-右,3-下 ,-1-无效)" << endl;
cout<< "空格数:" << this->CalculateEmpty() << endl;
this->PrintGrid();
}
int Game2048::CalculateEmpty()//计算空格函数
{
int cnt = 0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(Grid[i][j]==0) cnt++;
return cnt;
}
int Game2048::GetMaxValue()//计算合成的最大值
{
int temp=0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
if(Grid[i][j]>temp) temp = Grid[i][j];
}
return temp;
}
void Game2048::Move(int dir)//移动函数
{
if(dir==-1) return;
int tx, ty;
int t1x, t1y;
int t2x, t2y;
for(int i=0; i<4; i++)
{
tx = x0[dir] + i*secondOffset[dir][0];
ty = y0[dir] + i*secondOffset[dir][1];
t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir][0];
t2y = ty + firstOffset[dir][1];
for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1])
{
if(Grid[t2y][t2x]!=0)
{
if(Grid[t1y][t1x]==0)
{
Grid[t1y][t1x] = Grid[t2y][t2x];
Grid[t2y][t2x] = 0;
}
else if(Grid[t1y][t1x]==Grid[t2y][t2x])
{
Grid[t1y][t1x]++;//合并
this->m_MaxValue = this->GetMaxValue();//更新最大值
this->m_Score += (int)pow(2,Grid[t1y][t1x]);
Grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
// moved = true;
}
else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y)
{
Grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = Grid[t2y][t2x];
Grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
}
else
{
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
}
}
}
}
//return moved;
}
void Game2048::Addnum(int n)//添加新数
{
while(n--)//添加n个
{
this->m_EmptyBlock = this->CalculateEmpty();
if(this->m_EmptyBlock<=0) return;
int cnt = random(this->m_EmptyBlock)+1;//随机得到一个空格数以内的数
int *p = &Grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++
for(int i=0; i<4&&cnt; i++)
for(int j=0; j<4&&cnt; j++)
{
if(Grid[i][j]==0 && cnt)//如果有空格并且cnt有效
{
cnt--;//找到一个划一个
}
p++;//p 指向下一个再进行判断
}
//循环结束时 p 指向我们之前随机指定的空格
*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
//*p = (random(10)==0)+1;//这样写也可以
this->m_EmptyBlock--;
}
}
void Game2048::LoadImgs()//加载图片
{
char imgAdress[40];
for(int i=1,num=2; i<18; i++,num*=2)
{
sprintf(imgAdress,"..\\image\\block_%d.png",num);
BlockImgs[i] = newimage();;
getimage(BlockImgs[i], imgAdress);
//cout << imgAdress << endl;
}
BlockImgs[0] = newimage();
GameOverImg = newimage();
GameLogoImg = newimage();
RestartImg = newimage();
ScoreBgImg = newimage();
getimage(BlockImgs[0], "..\\image\\background.png");
getimage(GameOverImg, "..\\image\\gameOver.png");
getimage(GameLogoImg, "..\\image\\gamelogo.png");
getimage(RestartImg, "..\\image\\restart.png");
getimage(ScoreBgImg, "..\\image\\scorebg.png");
}
void Game2048::ReleaseImgs()//释放图片
{
for(int i=0; i<18; i++)
{
delimage(BlockImgs[i]);
}
delimage(GameOverImg);
delimage(GameLogoImg);
delimage(RestartImg);
delimage(ScoreBgImg);
}
void Game2048::Draw()//绘制图像
{
cleardevice();
putimage_withalpha(NULL, BlockImgs[0], BOARD_X, BOARD_Y);//格子背景图
putimage_withalpha(NULL, GameLogoImg, LOGO_X, LOGO_Y);//Logo图
putimage_withalpha(NULL, RestartImg, RESTART_X, RESTART_Y);//重新开始图
putimage_withalpha(NULL, ScoreBgImg, SCOREGB_X, SCOREGB_Y);//计分背景图
//MaxValue = GetMaxValue();//更新最大值
setcolor(TEXT_COLOR);
xyprintf(MAXVALUE_X, MAXVALUE_Y,"%4d",(int)pow(2,this->m_MaxValue));
xyprintf(SCORE_X, SCORE_Y, "%4d",this->m_Score);
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int x = (j+1)*DEVIDE + j*GRID_WIDTH + BOARD_X ;
int y = (i+1)*DEVIDE + i*GRID_WIDTH + BOARD_Y ;
//cout << "(x,y) = " << "(" << x << ","<< y << ")" << endl;
if(Grid[i][j]!=0)
{
putimage_withalpha(NULL,BlockImgs[Grid[i][j]],x,y);
}
}
}
}
bool Game2048::isGameOver()//判断游戏结束
{
this->m_EmptyBlock = this->CalculateEmpty();
if(this->m_EmptyBlock>0) return false;
for(int i=0;i<4;i++)
{
int t1=0,t2=1;
while(t2<=3)
{
if(Grid[i][t1]==Grid[i][t2] || Grid[t1][i]==Grid[t2][i])// 横 ||纵
{
return false;
}
else
{
t1++;
t2++;
}
}
}
return true;
}
void Game2048::RestartDate()//重新开始
{
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
Grid[i][j] = 0;
Addnum(2);
this->m_MaxValue = this->GetMaxValue();
this->m_Dir = -1;
this->m_EmptyBlock = 14;
this->m_Score = 0;
// this->m_TopScore = 0;
}
bool Game2048::isClicInRectangle(int xClick,int yClick,int Rectangle_X,int Rectangle_Y,int Rectangle_WIDTH,int Rectangle_HEIGHT)//检测是否点击在矩形区域内
{
if(xClick>Rectangle_X&&xClick<Rectangle_X+Rectangle_WIDTH &&
yClick>Rectangle_Y&&yClick<Rectangle_Y+Rectangle_HEIGHT)
return true;
return false;
}
注意一点:
最高分数的获取和文件操作有关,也就是要存档;本次分数和最大合成均是指本次游戏的