该项目只是一个原始版本,图片已经删除,我已经上传完整的项目资源zip,如有需要请自行下载!!!
https://download.csdn.net/download/weixin_46836491/86694132?spm=1001.2014.3001.5503
完成图:
点击左上角
随机清除4个不为0的数
点击左下角重置游戏
代码如下:
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>//字符串函数的头文件
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <time.h>
/*宏定义*/
#define LCD_PATH "/dev/fb0" //语法高亮
#define TOUCH_PATH "/dev/input/event0"
#define DWON 0 //上
#define UP 1 //下
#define LEFT 2 //左
#define RIGHT 3 //右
#define EXIT 4 //退出游戏
#define RE_START 5//重新开始游戏
#define Remove 6//消除
//...可以实现其他的按键功能
/*全局变量*/
int* plcd = NULL;//指向帧缓冲的映射区域的首地址 初始化的时候指向为空
int fb_fd = -1;
int x = -1,y = -1;
int matrix[4][4]={
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0
};
int OLD_matrix[4][4];
/*函数声明*/
void Init_Lcd(void);
void UNinit_Lcd(void);
void LCD_Draw_Point(int x,int y,int color);
int Bmp_display(char *bmp_file,int x0,int y0);
void get_xy(int *x,int *y);
void Init_Game_view(void);
int Get_Zero_num(void);//获取二维数字有多少个0元素
int Rand_Fill_Num(void);//随机位置填充随机数字
int Usr_Control_touch(void);
int IS_Win(void);
int IS_Failed(void);
void Save_old_matrix(void);
int Judge_matrix(void);
void Display_matrix(void);
void matrix_right(void);
void matrix_left(void);
void matrix_down(void);
void matrix_up(void);
void GAME_INIT(void);
void Game_Remove(void);
int Rand_Fill_Num2(void);
int Get_One_num(void);
int main()
{
srand(time(NULL));
//1.打开屏幕
Init_Lcd();
//2.显示开机图片
Bmp_display("Begin.bmp",0, 0);
Bmp_display("play.bmp",240,380);
//3.判断用户是否按下了开始按键
while(1)
{
get_xy(&x, &y);
if(x>=0 && x<=800 && y>=300 && y<=480)
{
//Bmp_display("7.bmp",0, s0);
break;
}
}
x = -1,y=-1;
InitGame:
//4.进入游戏界面
Init_Game_view();
//5.开始游戏
while(1)
{
int direction = Usr_Control_touch();
//保存以前的数组
Save_old_matrix();
if(direction == RIGHT)
{
//棋盘向右移动
matrix_right();
}
else if(direction == LEFT)
{
matrix_left();
}
else if(direction == UP)
{
matrix_up();
}
else if(direction==DWON)
{
matrix_down();
}
else if(direction==RE_START)
{
GAME_INIT();
goto InitGame;
}else if(direction==Remove)
{
Game_Remove();
}
x = -1,y = -1;//坐标重置
//在随机的位置填充随机数字之前我们需要判断是否需要填充
if(Judge_matrix())
{
Rand_Fill_Num();
}
Display_matrix();
//判断
if(IS_Win()==1)
{
Bmp_display("shengli.bmp",0,0);
//询问用户是否重新开始游戏
while(1)
{
get_xy(&x, &y);
if(x>=280 && x<=450 && y>=350 && y<=600)
{
break;
}
}
x = -1,y=-1;
GAME_INIT();
goto InitGame;
break;
}
else if(IS_Failed()==1)
{
Bmp_display("shibai.bmp",0, 0);
//嘲讽用户一波 询问是否重新开始游戏
while(1)
{
get_xy(&x, &y);
if(x>=280 && x<=450 && y>=350 && y<=600)
{
break;
}
}
x = -1,y=-1;
GAME_INIT();
goto InitGame;
break;
}
}
//Bmp_display("2.bmp", 0, 0);
UNinit_Lcd();
}
//重新开始
void GAME_INIT()
{
UNinit_Lcd();
srand(time(NULL));
Init_Lcd();
int b[4][4] = {0};
int x = -1,y = -1;
memcpy(matrix, b, sizeof(matrix));
}
//随机清除4个
void Game_Remove()
{
UNinit_Lcd();
srand(time(NULL));
Init_Lcd();
Rand_Fill_Num2();
Rand_Fill_Num2();
Rand_Fill_Num2();
Rand_Fill_Num2();
}
//初始化屏幕 打开屏幕 然后映射
void Init_Lcd(void)
{
//1.打开屏幕
//1.打开文件
int fd = open(LCD_PATH,O_RDWR);//文件描述符 代表 一个已经打开文件
if(-1 == fd) // fd == -1 <==> fd = -1 -1 = fd =>编译错误
{
perror("open LCD fail");//打印错误
return ;
}
fb_fd = fd;
//2.映射
plcd = mmap(NULL,480*800*4,PROT_READ|PROT_WRITE,MAP_SHARED,
fd,0);
if(MAP_FAILED == plcd)
{
perror("mmap fail");
return ;
}
}
//关闭屏幕
void UNinit_Lcd(void)
{
munmap(plcd,480*800*4);
plcd = NULL;
close(fb_fd);
}
//把屏幕上任意的x y的像素点显示成color颜色
void LCD_Draw_Point(int x,int y,int color)
{
if(x>=0&&x<800&&y>=0&&y<480)//防止传入的参数异常
*(plcd+x+y*800) = color;
}
/*
解析显示一张bmp图片的
bmp_file:图片文件的路径名 比如:1.bmp /home/2.bmp
x0,y0 在屏幕上显示的起始坐标
*/
int Bmp_display(char *bmp_file,int x0,int y0)
{
//1.打开bmp图片
int fd = open(bmp_file,O_RDONLY);
if(-1==fd)
{
printf("open %s fail\n",bmp_file);
perror("--->");
return -1;
}
//2.判断到底是不是一张bmp图片
unsigned char buf[4];
read(fd,buf,2);
if(buf[0]!= 0x42 || buf[1]!= 0x4d)//若果不是B M
{
printf("NOT BMP\n");
goto ERROR_END;
}
//3.获取bmp图片的属性 宽 高 色深
int width,height;
short depth;
lseek(fd,0x12,SEEK_SET);
read(fd,buf,4);
width=(buf[3]<<24)|
(buf[2]<<16)|
(buf[1]<<8)|
(buf[0]);
lseek(fd,0x16,SEEK_SET);
read(fd,buf,4);
height=(buf[3]<<24)|
(buf[2]<<16)|
(buf[1]<<8)|
(buf[0]);
lseek(fd,0x1c,SEEK_SET);
read(fd,buf,2);
depth=(buf[1]<<8)|
(buf[0]);
//只支持色深为24和32的
if(!(depth == 24 || depth == 32))
{
printf("NOT Support!\n");
goto ERROR_END;
}
printf("%s:%d*%d depth=%d\n",bmp_file,width,height,depth);
//4.获取像素数组
int line_valid_bytes = abs(width)*depth/8;//一行有效字节数
int line_bytes;//一行总字节数=有效字节数+赖子数
int laizi = 0;
if(line_valid_bytes%4)//判断是否有赖子 不能被4整除
{
laizi = 4-line_valid_bytes%4;//差多少就补多少个赖子 要满足4的倍数
}
line_bytes = line_valid_bytes + laizi;
int total_bytes = line_bytes*abs(height);//整个像素数组的大小
//是不是需要一个地方来存放读出来的这个像素数组呢??
//unsigned char piexl[total_bytes];
//也可以向系统申请一块动态内存
unsigned char *piexl = (unsigned char *)malloc(total_bytes);
lseek(fd,54,SEEK_SET);
read(fd,piexl,total_bytes);
//5.在屏幕上一一显示这些像素点
//读像素点字节--->ARGB--->在屏幕上进行显示
unsigned char a,r,g,b;
int color;
int i = 0;
int x,y;
for(y=0;y<abs(height);y++)
{
for(x=0;x<abs(width);x++)
{
//a r g b 0xargb 小端模式 b g r a
b = piexl[i++];
g = piexl[i++];
r = piexl[i++];
if(depth == 32)
{
a = piexl[i++];
}
else
{
a = 0;//不透明
}
color=(a<<24)|(r<<16)|(g<<8)|(b);
//printf("%x\n",color);
//在屏幕对应的位置显示
LCD_Draw_Point(width>0?x0+x:x0+abs(width)-x-1,
height>0?y0+abs(height)-y-1:y0+y,
color);
}
//每一行的末尾 有可能填充几个赖子
i += laizi;
}
free(piexl);
close(fd);
ERROR_END:
close(fd);
return -2;
}
/*获取用户的输入:x轴的值 y轴的值*/
void get_xy(int *x,int *y)
{
//1.打开触摸屏
int fd = open(TOUCH_PATH,O_RDONLY);
if(-1 == fd)
{
perror("open touch fail");
return ;
}
//2.获取用户输入
//获取屏幕信息
struct input_absinfo absI;
ioctl(fd,EVIOCGABS(ABS_X),&absI); //获取屏幕的x轴信息 最小~最大坐标
printf("x:%d ~ %d\n",absI.minimum,absI.maximum);
ioctl(fd,EVIOCGABS(ABS_Y),&absI);//y轴信息
printf("y:%d ~ %d\n",absI.minimum,absI.maximum);
ioctl(fd,EVIOCGABS(ABS_PRESSURE),&absI);//屏幕的压力的最小~最大
printf("pres:%d ~ %d\n",absI.minimum,absI.maximum);
struct input_event ev;
int flag_x = 0,flag_y = 0;
while(1)
{
int res = read(fd,&ev,sizeof(ev));//sizeof 求变量所占的字节数(空间) 读一个结构体大小
//假设我读出来的字节数跟ev所占的空间不一样 那么就是读取失败
if(res!=sizeof(ev))
{
continue;
}
if(ev.type == EV_ABS && ev.code == ABS_X)//获取X轴坐标
{
*x = ev.value*(1.0*800/1024);
flag_x = 1;
if(flag_y)
break;
}
if(ev.type == EV_ABS && ev.code == ABS_Y)//获取Y轴坐标
{
*y = ev.value*(1.0*480/600);
flag_y = 1;
if(flag_x)
break;
}
}
//3.关闭触摸屏
close(fd);
}
/*根据二维数组的内容更新游戏棋盘*/
void Display_matrix(void)
{
char bmp_name[64]={0};//保存游戏区域格子需要显示的图片的名字
int i,j;
for(i=0;i<4;i++)//遍历二维数组的每一个元素
{
for(j=0;j<4;j++)
{
if(matrix[i][j])//假设不为0 则显示对应的图片 为0则显示一张空白图片
{
memset(bmp_name,0,64);//将数组清空
sprintf(bmp_name,"9090/digit_%d.bmp",matrix[i][j]);//相当于把color_x80_4.bmp-->bmp_name
Bmp_display(bmp_name,100+j*(80+10),65+i*(80+10));
}
else
{
//显示一张空白图片
Bmp_display("play1.bmp",100+j*(80+10),65+i*(80+10));
}
}
}
}
/*显示游戏界面*/
void Init_Game_view(void)
{
//0.显示游戏界面的背景
Bmp_display("7.bmp",0, 0);
//1.显示四个按键
Bmp_display("xx.bmp",450,170);
Bmp_display("xx.bmp",660,170);
Bmp_display("xx.bmp",550,58);
Bmp_display("xx.bmp",550,295);
Bmp_display("shuaxin1.bmp",0,430);
Bmp_display("futou1.bmp",0,0);
//3.更新棋盘
//在棋盘的随机两个位置填充随机数字
Rand_Fill_Num();
Rand_Fill_Num();//随机位置填充随机数字
Display_matrix();
}
int Get_Zero_num(void)//获取二维数字有多少个0元素
{
int i,j,count=0;
for(i=0;i<4;i++)//遍历二维数组的每一个元素
{
for(j=0;j<4;j++)
{
if(matrix[i][j]==0)
{
count++;
}
}
}
return count;
}
//获取不为0的数
int Get_One_num(void)//获取二维数字有多少个0元素
{
int i,j,count=0;
for(i=0;i<4;i++)//遍历二维数组的每一个元素
{
for(j=0;j<4;j++)
{
if(matrix[i][j]!=0)
{
count++;
}
}
}
return count;
}
int Rand_Fill_Num(void)//随机位置填充随机数字
{
//随机位置
int pos_k = rand()%Get_Zero_num()+1;//1~K
int i,j,count=0;
int num[] = {2,2,2,2,4,4,8};//模拟概率
//遍历到填充位置
for(i=0;i<4;i++)//遍历二维数组的每一个为0元素
{
for(j=0;j<4;j++)
{
if(matrix[i][j]==0)
{
count++;
if(count == pos_k)
{
//填充
int n = rand()%7;//0~6
matrix[i][j]=num[n];
/*
以上代码可以简化为matrix[i][j]=num[rand()%7];
*/
}
}
}
}
}
int Rand_Fill_Num2(void)//随机位置填充随机数字
{
//随机位置
int pos_k = rand()%Get_One_num()+1;//1~K
int i,j,count=0;
int num[] = {0,0,0,0,0,0,0};//模拟概率
//遍历到填充位置
for(i=0;i<4;i++)//遍历二维数组的每一个不为0元素
{
for(j=0;j<4;j++)
{
if(matrix[i][j]!=0)
{
count++;
if(count == pos_k)
{
//填充
int n = rand()%7;//0~6
matrix[i][j]=num[n];
/*
以上代码可以简化为matrix[i][j]=num[rand()%7];
*/
}
}
}
}
}
int Usr_Control_touch(void)
{
while(1)
{
get_xy(&x,&y);//这个函数返回之后 就是获取了x y
if(x>440&&y>160&&x<550&&y<300){
//左按钮
printf("x:%d y:%d\n",x,y);
Bmp_display("bjn.bmp",450,170);
usleep(50000);
Bmp_display("xx.bmp",450,170);
return LEFT;
}else if(x>550&&y>300&&x<660&&y<430){
printf("x:%d y:%d\n",x,y);
Bmp_display("bjn.bmp",550,295);
usleep(50000);
Bmp_display("xx.bmp",550,295);
//下按钮
return DWON;
}else if(x>660&&y>188&&x<792&&y<298){
printf("x:%d y:%d\n",x,y);
Bmp_display("bjn.bmp",660,170);
usleep(50000);
Bmp_display("xx.bmp",660,170);
//右按钮
return RIGHT;
}else if(x>550&&y>58&&x<662&&y<188){
printf("x:%d y:%d\n",x,y);
Bmp_display("bjn.bmp",550,58);
usleep(50000);
Bmp_display("xx.bmp",550,58);
//上按钮
return UP;
}else if(x>0&&y>410&&x<100&&y<480){
printf("x:%d y:%d\n",x,y);
Bmp_display("shuaxin1.bmp",0,430);
usleep(50000);
Bmp_display("shuaxin2.bmp",0,430);
//上按钮
return RE_START;
}else if(x>0&&y>0&&x<100&&y<100){
printf("x:%d y:%d\n",x,y);
Bmp_display("futou1.bmp",0,0);
usleep(50000);
Bmp_display("futou2.bmp",0,0);
return Remove;
printf("x:%d y:%d\n",x,y);
}
}
}
void matrix_left(void)
{
//改变棋盘的 改变的二维数组
int i, j;//i为矩阵行下标,j为矩阵列下标
int value, save_zero;
for(i = 0; i < 4; i++)
{
value = 0;
save_zero= 0;
for(j = 0; j < 4 ; j++)
{
if (matrix[i][j] == 0)
continue;
if (value == 0)
value = matrix[i][j];
else
{
if (value == matrix[i][j])
{
matrix[i][save_zero++] = value * 2;
value = 0;
} else {
matrix[i][save_zero++] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if (value != 0)
matrix[i][save_zero] = value;
}
}
void matrix_right(void)
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for (i = 0; i < 4; i++)
{
value = 0;
save_zero = 4 -1;
for (j = 4 - 1; j >= 0 ; j--)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[i][save_zero--] = 2 * value;
value = 0;
}
else
{
matrix[i][save_zero--] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[i][save_zero] = value;
}
}
}
void matrix_up(void)
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for(j = 0; j < 4; j++)
{
value = 0;
save_zero= 0;
for(i = 0; i < 4 ; i++)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[save_zero++][j] =2 * value;
value = 0;
}
else
{
matrix[save_zero++][j] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[save_zero][j] = value;
}
}
}
void matrix_down(void)
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for(j = 0; j < 4; j++)
{
value = 0;
save_zero = 4 - 1;
for(i = 4 - 1; i >= 0 ; i--)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[save_zero--][j] = 2 * value;
value = 0;
}
else
{
matrix[save_zero--][j] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[save_zero][j] = value;
}
}
}
/*成功返回1 没有失败返回0*/
int IS_Win(void)
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(matrix[i][j] == 32)
{
return 1;
}
}
}
return 0;
}
/*失败返回1 没有失败返回0*/
int IS_Failed(void)
{
int i, j;
if(Get_Zero_num() != 0)
{
return 0;
}
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4 ; j++)
{
if (j != 4 -1)
{
if (matrix[i][j] == matrix[i][j+1])
{
return 0;
}
}
if (i != 4 - 1)
{
if (matrix[i][j] == matrix[i+1][j])
{
return 0;
}
}
}
}
return 1;
//棋盘满了
}
/*保存原来的数组*/
void Save_old_matrix(void)
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
OLD_matrix[i][j] = matrix[i][j];
}
}
}
/*相同返回0 不相同返回1*/
int Judge_matrix(void)
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(OLD_matrix[i][j] != matrix[i][j])
{
return 1;
}
}
}
return 0;
}