【C++】2048游戏系列—优化模块第三稿【类封装】

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;	
}

游戏界面预览
注意一点:
最高分数的获取和文件操作有关,也就是要存档;本次分数和最大合成均是指本次游戏的

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值