(updating...)
Reference blog: https://blog.csdn.net/qq_39151563/article/details/104283217
Currently completed:
- [C + +] 2048 game series - Overview
- [C + +] 2048 game series - first draft of function module [matrix operation]
- [C + +] 2048 game series - second draft of function module [keyboard input]
- [C + +] 2048 game series - third draft of function module [add new number]
- [C + +] 2048 game series - fourth draft of function module [end detection]
- [C + +] 2048 game series - first draft of optimization module [load picture]
- [C + +] 2048 game series - second draft of optimization module [scoring module]
- [C + +] 2048 game series - third draft of optimization module [class encapsulation]
Supplement the previously omitted (historical) highest score output, focusing on file operation
1, Basic file operation template
After reading a lot of blogs about C + + file operation, I feel that C + + is not easy to use, so I still use the C file operation format. C code can be used in C + +
#include <iostream> using namespace std; const char FILE_NAME[10] = "test.txt"; int main() { //Using fprintf function to write formatted data to file FILE* fp = fopen(FILE_NAME,"w");//"w" means write fprintf(fp,"This is a test, enter:%d",30); fclose(fp); //Use the fscanf function to read the formatted data from the file (equivalent to matching) int a = 0; fp = fopen(FILE_NAME,"r"); //"r" means read, read fscanf(fp,"This is a test, enter:%d",&a); cout << a << endl; return 0; }
2, Activate highest score output
The focus is to record the highest score in history, so it involves file operation
2.1 - Code overview after class encapsulation
The red line in the figure is the part to be changed:
1. At the beginning of the game, read the highest score in history to m through the LoadRecord() function_ TopSocre
2. After merging numbers each time, judge whether the current score is greater than the highest score in history (in the Move() function). If greater than, save the highest score through the GameSave() function
3. Read m when drawing the image_ TopSocre
2.2-GameSave() and LoadRecord() functions
Please refer to the following codes for details
const char RECORD_FILE_NAME[15] = "RECORD.txt";//Archive file name (in ConstDate.h) void Game2048::GameSave()//Game save { 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 reading { FILE* fp = fopen(RECORD_FILE_NAME,"r"); if(fp==NULL) { this->RestartDate(); fclose(fp); return; } fscanf(fp,"TopSocre:%d",&this->m_TopScore); fclose(fp); }
3, Delete unnecessary code
- Delete / / void PrintGrid()// Print function, void ShowInfo()// Displays information about the two functions
- Project - > project settings - > Win32 graphical interface program (so there is no console)
4, All code and running results
The relevant codes and settings have not been deleted when recording
#ifndef CONST_DATE_H #define CONST_DATE_H const char RECORD_FILE_NAME[15] = "RECORD.txt";//Archive Filename const int DEVIDE = 15; //interval const int GRID_WIDTH = 106; //Lattice width const int WIDTH = 500+2*DEVIDE; //Total interface width const int HEIGHT = 660+3*DEVIDE; //Total interface height const int BOARD_X = 0+DEVIDE; //Chessboard start point x const int BOARD_Y = 160+2*DEVIDE; //Chessboard starting point y const int LOGO_X = 25+DEVIDE; //2048logo starting point x const int LOGO_Y = 20+DEVIDE; //2048logo starting point y const int RESTART_X = 0+DEVIDE; //restart start point x const int RESTART_Y = 80+LOGO_Y; //restart start point y const int RESTART_WIDTH = 220; //restart width const int RESTART_HEIGHT = 50; //restart height const int SCOREGB_X = 230+DEVIDE; //Score background starting point x const int SCOREGB_Y = 0+DEVIDE; //Starting point y of fractional background image const color_t TEXT_COLOR = EGERGB(241, 231, 214); //Font color const color_t BG_COLOR = EGERGB(250,248, 239);//Background color light yellow const int MAXVALUE_X = SCOREGB_X+160; //Maximum starting point x const int MAXVALUE_Y = SCOREGB_Y+112; //Maximum starting point y const int SCORE_X = MAXVALUE_X; //Starting point of this score x const int SCORE_Y = MAXVALUE_Y-45; //Starting point of this score y const int TOP_SCORE_X = SCORE_X; //Highest score starting point x const int TOP_SCORE_Y = SCORE_Y-45; //Highest score starting point y /*-----------------------------------------------------------*/ //Use in move function 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}}; /*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/ //Picture storage PIMAGE BlockImgs[18];//0-background, 1-17 digital PIMAGE GameOverImg;//Game end chart PIMAGE GameLogoImg;//Game Logo PIMAGE RestartImg;//Restart diagram PIMAGE AIImg;//AI key diagram PIMAGE ScoreBgImg;//Score background /*-----------------------------------------------------------*/ #endif //CONST_DATE_H
#include <iostream> #include "graphics.h" #include <cmath> //#include <fstream> #include "ConstDate.h" using namespace std; int Grid[4][4] = {0}; //[global variable] 4 * 4 matrix class Game2048{ //private: public: int m_Dir; // Direction: 0-left, 1-up, 2-right, 3-down int m_EmptyBlock; //Number of spaces int m_Score; //Record score int m_MaxValue; //Record the maximum value of the composite int m_TopScore; //Record the highest score public: Game2048();//initialization int CalculateEmpty();//Calculate space function int GetMaxValue();//Calculate the maximum value of the composite void Move(int dir);//Moving function void Addnum(int n);//Add new number void LoadImgs();//Load picture void ReleaseImgs();//Release picture void Draw();//Draw image bool isGameOver();//Judge the end of the game void RestartDate();//restart bool isClicInRectangle(int xClick,int yClick,int Rectangle_X,int Rectangle_Y, int Rectangle_WIDTH,int Rectangle_HEIGHT);//Check whether the click is in the rectangular area void GameSave();//Game save void LoadRecord();//File reading void AI();//AI automatically to 2048 }; int main() { /*Initialization-------------------------------------------------------------------------------*/ initgraph(WIDTH, HEIGHT); setcaption("2048Game"); //Set game title setbkcolor(BG_COLOR); setfont(25,0,"Blackbody"); setbkmode(TRANSPARENT); //Text output is transparent Game2048 MainObj; MainObj.Addnum(2); //Add a new number at 2 random locations MainObj.m_MaxValue = MainObj.GetMaxValue(); //Update maximum MainObj.LoadImgs(); //Load picture MainObj.LoadRecord(); MainObj.Draw(); //Draw the initial interface /*-------------------------------------------------------------------------------initialization*/ /*Start the game-------------------------------------------------------------------------------*/ for ( ; is_run(); delay_fps(60) ) { //Key detection 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;//Left case 'W':case key_up : MainObj.m_Dir = 1; break;//upper case 'D':case key_right : MainObj.m_Dir = 2; break;//right case 'S':case key_down : MainObj.m_Dir = 3; break;//lower } } } if(MainObj.m_Dir!=-1) { //Graphic update bool flag = false; //Move flag bit int tempGrid[4][4]; //Temporary array 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); //compare 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;//Set Dir to invalid } //Mouse detection 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; } } /*------------------------------------------------------------------------------Start the game-*/ MainObj.ReleaseImgs(); getch(); closegraph(); return 0; } Game2048::Game2048()//initialization { this->m_Dir = -1; this->m_EmptyBlock = 16; this->m_MaxValue = 0; this->m_Score = 0; this->m_TopScore = 0; } int Game2048::CalculateEmpty()//Calculate space function { 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()//Calculate the maximum value of the composite { 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)//Moving function { 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]++;//merge 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)//Add new number { while(n--)//Add n { this->m_EmptyBlock = this->CalculateEmpty(); if(this->m_EmptyBlock<=0) return; int cnt = random(this->m_EmptyBlock)+1;//Randomly get a number within the number of spaces int *p = &Grid[0][0]-1;//Record the first address of the matrix, because the following p will be returned when it is found++ for(int i=0; i<4&&cnt; i++) for(int j=0; j<4&&cnt; j++) { if(Grid[i][j]==0 && cnt)//If there are spaces and cnt is valid { cnt--;//Find one, scratch one } p++;//p points to the next one for judgment } //At the end of the loop, p points to the space we randomly specified before *p = (random(10)==0)?2:1;// The probability of 0.1 is 2 and the probability of 0.9 is 1 //*p = (random(10)==0)+1;// It's OK to write like this this->m_EmptyBlock--; } } void Game2048::LoadImgs()//Load picture { 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()//Release picture { for(int i=0; i<18; i++) { delimage(BlockImgs[i]); } delimage(GameOverImg); delimage(GameLogoImg); delimage(RestartImg); delimage(ScoreBgImg); } void Game2048::Draw()//Draw image { cleardevice(); putimage_withalpha(NULL, BlockImgs[0], BOARD_X, BOARD_Y);//Grid background putimage_withalpha(NULL, GameLogoImg, LOGO_X, LOGO_Y);//Logo diagram putimage_withalpha(NULL, RestartImg, RESTART_X, RESTART_Y);//Restart diagram putimage_withalpha(NULL, ScoreBgImg, SCOREGB_X, SCOREGB_Y);//Scoring background //MaxValue = GetMaxValue();// Update maximum setcolor(TEXT_COLOR); xyprintf(MAXVALUE_X, MAXVALUE_Y, "%4d",(int)pow(2,this->m_MaxValue));//Maximum number of currently synthesized xyprintf(SCORE_X, SCORE_Y, "%4d",this->m_Score);//Current score xyprintf(TOP_SCORE_X,TOP_SCORE_Y,"%4d",this->m_TopScore);//Highest score in history 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()//Judge the end of the game { 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])// Horizontal and vertical { return false; } else { t1++; t2++; } } } return true; } void Game2048::RestartDate()//restart { 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)//Check whether the click is in the rectangular area { if(xClick>Rectangle_X&&xClick<Rectangle_X+Rectangle_WIDTH && yClick>Rectangle_Y&&yClick<Rectangle_Y+Rectangle_HEIGHT) return true; return false; } void Game2048::GameSave()//Game save { 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 reading { FILE* fp = fopen(RECORD_FILE_NAME,"r"); if(fp==NULL) { this->RestartDate(); fclose(fp); return; } fscanf(fp,"TopSocre:%d",&this->m_TopScore); fclose(fp); }
Optimization is over here!!!
Thank you for seeing here.
This is already a relatively complete small project.
Next is advanced:
1. Slider effect
2. AI automatically to 2048