文章目录
一、小游戏简介
1、起源
2048小游戏最早于2014年3月20日发行。原版的2048最早于GitHub上发行,后被移植到了各个平台。是基于《1024》开发的新型数字游戏
2、玩法
这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。
二、编程思路
三、各个功能的实现
1、图片的制作
每个正方形数字图片的大小都为60 * 60像素
最后游戏窗体的大小为240 * 300像素、
2、创建2048.h头文件
由于是使用分文件编写的方式(主要是所有函数都写在一个文件里面实在是不方便看),所以需要创建一个头文件来声明我们需要使用到的库、变量和自定义函数,代码如下:
#ifndef SMALLGAME
#define SMALLGAME
#include <cstdio>
#include <conio.h>
#include <cstdlib>
#include <graphics.h> //用到的第一个非C++自带库--->Easyz的图片库
#include <ctime>
//由于分文件编写的
//所以注意我们定义的变量都要使用extern类型
extern IMAGE img[15];//存放的是我们的15张图片
extern int map[4][4];//4*4的地图
extern int Imagine_number[12];
void Loadimage();//加载所有的图片
void DrawMap();//根据二维数组中的数据来贴上相应的图片
void KeyDown();//模拟按键
int RandNum();//在地图中随机产生数据
int MoveRight();//向右走
int MoveLeft();//向左走
int MoveUp();//向上走
int MoveDown();//向下走
void GAMEOVER();//游戏结束
void PLAYERWIN();//游戏获胜
int ScanMap2();//扫描判断是否获胜
bool ScanMap();//扫描判断是否游戏结束
#endif
3、加载图片资源
Easyx开发的图片库可以进行图片的操作,在使用图片之前,需要加载要使用的图片,一共需要加载15张图,所以直接编写一个加载图片的函数利用循环加载即可,代码如下:
#include "2048.h"
#define _CRT_SECURE_NO_WARNINGS //去除内扩增的影响
void Loadimage(){
//加载所有的图片
for (int i = 0; i < 12; i++) {
char FileName[200]={
};
sprintf(FileName,"%d.jpg",Imagine_number[i]);
loadimage(img + i,FileName);
}
loadimage(img + 12, "111.jpg");
loadimage(img + 13, "12345.jpg");
loadimage(img + 14, "444.jpg");
}
注意:sprintf具有不安全性,如果将一个长度大于原定字符数组大小的字符串存放进字符数组,就会发生越界的现象。可以使用snprintf替换sprintf
4、绘制地图
遍历二维数组中的数据,根据二维数组中每个元素的数据来判断应该在某个位置贴上对应的图片,注意需要根据图片的尺寸来计算每个点的x,y坐标。
代码如下:
#include "2048.h"
void DrawMap(){
//画地图
setbkcolor(RGB(244,215,215)); //设置窗体背景颜色
cleardevice();//更新一遍窗体
settextcolor(WHITE);//设置文本颜色
settextstyle(30,0,"圆体");//字体大小
outtextxy(50,10,"2048小游戏");//文字内容
int x,y,k;
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
x=60*j;//列
y=60*i+60;//行
//printf("%d %d\n",x,y);
for(k = 0;k < 12;k++){
//遍历12张图片
if(Imagine_number[k] == map[i][j])
//判断应该贴哪一张图片
break;//退出循环
}
putimage(x,y,img+k);//在(x,y)的位置贴上第k张图
}
}
}
5、在二维数组中产生随机数
C++中产生随机数需要使用到随机数函数srand();(包含于cstdlib库中)
用法:srand((unsigned int)随机数种子(NULL))
若随机数种子保持不变,那么所生成的随机数也不会改变(感觉没说清楚,只能自行理解了)。故此我们一般使用电脑的系统时间作为随机数种子,也就是:
srand((unsigned int)time(NULL));
由于这里使用到了系统时间,所以需要包含C++的系统库---->ctime
在2048小游戏中,每次产生的随机数为2或4。
那么如何产生这种随机数?可以这么做👇
temp=(rand()%3) * 2;
注意:rand() % n得到的就是[0,n)的数据
那么不可避免地会生成0这么一个随机数,但我们只需要在生成后判断一次即可,如果是0,那么我们就在其他的区域内继续生成一个随机数。
代码如下:
#include "2048.h"
int RandNum(){
//在地图中随机产生数字
srand((unsigned int)time(NULL));
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
if(map[i][j] == 0){
map[i][j] = (rand()%3)*2;
if(map[i][j] == 0) continue; //如果产生的随机数为0 那么就在其他的区域内继续产生随机数
return 0;
}
}
}
return 0;
}
6、按键操作
Ⅰ、数的合并操作
在上下左右的移动过程中,如果移动路径上有可以合并的数,按照规则我们需要进行合并操作;
Ⅱ、数的移动
在移动的过程中,如果某个方块在移动路径上没有数字方块,那么我们就需要对该方块进行移动操作;
不同方向上的合并和移动操作的代码是有些许不同的,但是其思想都是一样的
下面就以按下右键向右移动为例:
#include "2048.h"
int MoveRight(){
bool flag = false;
for(int i = 0;i < 4;i++){
//判断是否可以合并
for(int j = 3;j >= 0;j--){
int k = j - 1;//取当前元素的前一个元素
int NowKey = map[i][j];//取当前的元素
if(NowKey != 0){
// 等于0的时候再去判断是没有意义的
while(k >= 0){
//列指针移动
int NextKey = map[i][k];//取当前元素的下一个元素
if(NextKey != 0){
//如果下一个块已经有数据
if(NextKey == NowKey){
//如果下一块和当前块的数据是相同的
flag = true;
map[i][j]*=2;//那么就进行合并
map[i][k] = 0;
}
break; //按照规则,每次只能合并两个方块
}
k--;
}
}
}
}
for(int i = 0;i<4;i++){
for(int j = 3;j>=0;j--){
int nowkey = map[i][j];
if(map[i][j] == 0){
int k = j - 1;
while(k >= 0){