2048-优化篇四稿-激活最高分数输出【补充文件操作】
(更新中……) 参考博客:https://blog.csdn.net/qq_39151563/article/details/104283217 目前写完的:
补充之前遗漏的(历史)最高分数输出,重点是文件操作
一、基本文件操作模板
看了很多关于C++文件操作的博客,感觉C++没有C好用,所以还是用C的文件操作格式,C++中可以用C的代码
#include <iostream>
using namespace std;
const char FILE_NAME[10] = "test.txt";
int main()
{
//利用 fprintf 函数向文件中写入格式化数据
FILE* fp = fopen(FILE_NAME,"w");//"w"表示 write,写
fprintf(fp,"这是一个测试,输入:%d",30);
fclose(fp);
//利用 fscanf 函数从文件中读取格式化数据(相当于匹配)
int a = 0;
fp = fopen(FILE_NAME,"r"); //"r"表示 read,读
fscanf(fp,"这是一个测试,输入:%d",&a);
cout << a << endl;
return 0;
}
二、激活最高分数输出
重点在于记录下历史最高分,所以涉及到文件操作
2.1-上篇类封装后的代码总览
图中画红线的部分就是要改的部分: 1.游戏开始时通过LoadRecord() 函数读取历史最高分数给m_TopSocre 2.每一次合并数字后判断当前分数是否大于历史最高分数(在Move() 函数中),如果大于,通过GameSave() 函数保存最高分数 3.绘制图像时读取m_TopSocre
2.2-GameSave() 和 LoadRecord() 函数
具体细节请参考后面的全部代码
const char RECORD_FILE_NAME[15] = "RECORD.txt";//存档文件名 (ConstDate.h中)
void Game2048::GameSave()//游戏保存
{
FILE* fp = fopen(RECORD_FILE_NAME,"w");
if(fp==NULL)
{
this->RestartDate();
fclose(fp);
return;
}
fprintf(fp,"TopSocre:%d",this->m_TopScore);
fclose(fp);
}
void Game2048::LoadRecord()//读档
{
FILE* fp = fopen(RECORD_FILE_NAME,"r");
if(fp==NULL)
{
this->RestartDate();
fclose(fp);
return;
}
fscanf(fp,"TopSocre:%d",&this->m_TopScore);
fclose(fp);
}
三、删除不必要的代码
- 删除与
// void PrintGrid();//打印函数,void ShowInfo();//显示信息 两个函数有关的代码 - 项目->项目设置->Win32图形界面程序(这样就没有控制台了)
四、全部代码和运行结果
录的时候还没删除相关代码和改设置
#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 = 80+LOGO_Y; //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 AIImg;//AI按键图
PIMAGE ScoreBgImg;//分数背景图
/*-----------------------------------------------------------*/
#endif //CONST_DATE_H
#include <iostream>
#include "graphics.h"
#include <cmath>
//#include <fstream>
#include "ConstDate.h"
using namespace std;
int Grid[4][4] = {0}; //【全局变量】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();//初始化
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();//读档
void AI();//AI自动到2048
};
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.LoadImgs(); //加载图片
MainObj.LoadRecord();
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)
{
//图形更新
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) MainObj.Addnum(1);
MainObj.Draw();
MainObj.m_Dir = -1;//将 Dir 置为无效
}
//鼠标检测
bool RestartClickflag = 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))
{
RestartClickflag = true;
}
}
if(RestartClickflag)
{
MainObj.RestartDate();
MainObj.Draw();
}
if(MainObj.isGameOver())
{
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;
}
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]);
if(this->m_TopScore<this->m_Score)
{
this->m_TopScore = this->m_Score;
this->GameSave();
}
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];
//cout << "Move Test" << endl;
// moved = true;
}
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);//当前分数
xyprintf(TOP_SCORE_X,TOP_SCORE_Y,"%4d",this->m_TopScore);//历史最高分数
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;
}
void Game2048::GameSave()//游戏保存
{
FILE* fp = fopen(RECORD_FILE_NAME,"w");
if(fp==NULL)
{
this->RestartDate();
fclose(fp);
return;
}
fprintf(fp,"TopSocre:%d",this->m_TopScore);
fclose(fp);
}
void Game2048::LoadRecord()//读档
{
FILE* fp = fopen(RECORD_FILE_NAME,"r");
if(fp==NULL)
{
this->RestartDate();
fclose(fp);
return;
}
fscanf(fp,"TopSocre:%d",&this->m_TopScore);
fclose(fp);
}
优化篇到这里就结束了!!! 感谢您看到这里。 这已经是一个相对完整的小项目了。 接下来是进阶篇: 1. 滑块效果 2. AI 自动到2048
|