编译环境 : arm-linux-gcc
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <pthread.h>
#include <signal.h>
int *plcd = NULL;
// statu 表示选择的是 理科版,文科版,经典版
int statu = 0;
// flag 用来标识"返回"键是否被点击
int flag = 0;
pthread_t pid;
// 初始化矩形数字
int matrix[4][4] =
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 2,
0, 4, 0, 2,
};
// 随机矩阵
int s[] =
{
2,4,2,2,2
};
//临时数组,用来保存matrix 的值
int ck[4][4] =
{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
//枚举类型 表示手指滑动方向
enum finger_move
{
MOVE_LEFT = 1,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN,
};
// 音乐文件名
char *bgm_name[] =
{
"1.mp3",
"2.mp3",
"NULL",
};
// 文科版文件名
char *bmp_name_3[]={
NULL,
"one.bmp",
"two.bmp",
"three.bmp",
"four.bmp",
"five.bmp",
"six.bmp",
"seven.bmp",
"egiht.bmp",
NULL,
};
// 经典版文件名
char *bmp_name_1[] =
{
NULL,
"digit_2.bmp",
"digit_4.bmp",
"digit_8.bmp",
"digit_16.bmp",
"digit_32.bmp",
"digit_64.bmp",
"digit_128.bmp",
"digit_256.bmp",
"digit_512.bmp",
"digit_1024.bmp",
"digit_2048.bmp",
"digit_4096.bmp",
NULL,
};
//理科版文件名
char *bmp_name_2[]=
{
NULL,
"2.bmp",
"4.bmp",
"8.bmp",
"16.bmp",
"32.bmp",
"64.bmp",
"128.bmp",
"256.bmp",
"512.bmp",
"1024.bmp",
"2048.bmp",
"4096.bmp",
NULL,
};
/*
功能:@得到相应数字的文件名
*/
char *get_file_name_by_digit(int num)
{
int index = 0;
switch (num)
{
case 2:
index = 1;
break;
case 4:
index = 2;
break;
case 8:
index = 3;
break;
case 16:
index = 4;
break;
case 32:
index = 5;
break;
case 64:
index = 6;
break;
case 128:
index = 7;
break;
case 256:
index = 8;
break;
case 512:
index = 9;
break;
case 1024:
index = 10;
break;
case 2048:
index = 11;
break;
case 4096:
index = 12;
break;
case 8192:
index = 13;
break;
case 16384:
index = 14;
break;
case 32768:
index = 15;
break;
case 65536:
index = 16;
break;
default:
index = 0;
break;
}
// printf("%d \n",statu);
if(statu== 1)
{
return bmp_name_1[index];
}
else if(statu == 2)
{
return bmp_name_3[index];
}
else if (statu == 3)
{
return bmp_name_2[index];
}
}
void lcd_draw_point(int x, int y, int color)
{
*(plcd + y*800 + x) = color;
}
/*
功能:画出一大矩阵
@(x0,y0) 为起点坐标
@(w,h) 为宽和高
*/
void lcd_draw_rect(int x0, int y0, int w, int h, int color)
{
int x, y;
for (y = y0; y < y0 + h; y++)
{
for (x = x0; x < x0 + w; x++)
lcd_draw_point(x, y, color);
}
}
/*
功能:画出一个bmp图片的内容
@(x0,y0) 为起点坐标
@(w,h) 为宽和高
*/
void lcd_draw_bmp(const char *file_name, int x0, int y0,int w,int h)
{
int fd;
fd = open(file_name, O_RDONLY);
if (fd < 0)
{
perror("open file error: ");
return ;
}
//跳过 前边54个字节,这54个字节是用来存储bmp图片的相关信息的
lseek(fd, 54, SEEK_SET);
//从第55个字节开始,读取bmp图片的像素数组
char buf[800*480*3];
read(fd, buf, 800*480*3);//因为这个bmp图片是24位色
close(fd);
int color, x, y, i = 0;
unsigned char r, g, b;
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
b = buf[i++];
g = buf[i++];
r = buf[i++];
color = (r << 16) | (g << 8) | b;
lcd_draw_point(x + x0, h-1-y+y0, color);
}
}
}
/*
@功能:从顶点坐标为(x0, y0)的位置开始 画一个num*num的矩阵,每一个矩形的大小为pice_size*pice_size,
*/
void lcd_draw_matrix(int x0, int y0, int num, int pice_size, int blank,int color)
{
int i, j;
int x, y;
for (j = 0; j < num; j++)
{
y = y0 + (pice_size + blank)*j;
//画一行,这一行有4个矩形
for (i = 0; i < num; i++)
{
x = x0 + (pice_size + blank)*i;
if (matrix[j][i] == 0)
lcd_draw_rect(x, y, pice_size, pice_size, color);
else
lcd_draw_bmp(get_file_name_by_digit(matrix[j][i]), x, y,100,100);
}
}
}
/*
功能:@判断手指的移动方向 以及 是否按下返回键
*/
int get_finger_move_direction()
{
int fd, ret;
int x1=-1, y1= -1;
int x2, y2;
struct input_event ev;
fd = open("/dev/event0", O_RDWR);
if (fd < 0)
{
perror("open event0 error: ");
return ;
}
int count = 0;
while (1)
{
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(ev))
{
continue;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_X))
{
if (x1 == -1)
x1 = ev.value;
else
x2 = ev.value;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_Y))
{
if (y1 == -1)
y1 = ev.value;
else
y2 = ev.value;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_PRESSURE) && (ev.value == 0)) //手指弹起 手指离开了触摸屏
{
if(x1 > 550 && x1 < 750 && y1> 50 && y1< 150) //返回键
{
flag = 1;
printf("%d %d\n",x2,y2);
return -1;
}
int delta_x = abs(x2 - x1);
int delta_y = abs(y2 - y1);
if (delta_x > 2*delta_y)
{
if (x2 > x1)
{
printf("right\n");
close(fd);
return MOVE_RIGHT; //向右
}
else if (x2 < x1)
{
printf("left\n");
close(fd);
return MOVE_LEFT; //向左
}
}
else if (delta_x < 2*delta_y)
{
if (y2 < y1)
{
printf("down\n");
close(fd);
return MOVE_UP; //向上
}
else if (y2 > y1)
{
printf("up\n");
close(fd);
return MOVE_DOWN; //向下
}
}
else //该手势不能识别 再来一次
{
x1 = -1;
y1 = -1;
}
}
}
}
/*
功能:@判断初始界面中被点击的选项
*/
int get_finger_touch_area()
{
int fd, ret;
int x2, y2;
struct input_event ev;
fd = open("/dev/event0", O_RDWR);
if (fd < 0)
{
perror("open event0 error: ");
return ;
}
int count = 0;
while (1)
{
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(ev))
{
continue;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_X))
{
x2 = ev.value;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_Y))
{
y2 = ev.value;
}
if ((ev.type == EV_ABS) && (ev.code == ABS_PRESSURE) && (ev.value == 0)) //手指弹起 手指离开了触摸屏
{
if( statu==0 && x2>600 && x2<800 && y2>27 && y2<=177) // 经典版
{
close(fd);
return 1;
}
else if(statu == 0 && x2>600 && x2<800 && y2>178 && y2<=327) //理科版
{
close(fd);
return 2;
}
else if(statu == 0 && x2>600 && x2<800 && y2>328 && y2<=479) //文科版
{
close(fd);
return 3;
}
}
}
}
void handle_left()
{
int i,j,k,z;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
if(matrix[i][j] == 0) continue;
for(z = j+1;z < 4;z++)
{
if(matrix[i][j] == matrix[i][z])
{
matrix[i][j] = matrix[i][j]*2;
matrix[i][z] = 0;
break;
}
if(matrix[i][z] != 0)
{
break;
}
}
}
}
for(i = 0;i < 4;i++)
{
k = 0;
for(j = 0;j < 4;j++)
{
if(matrix[i][j]!= 0)
{
matrix[i][k] = matrix[i][j];
if(j != k) matrix[i][j] = 0;
k++;
}
}
}
}
void hand_right()
{
int i,j,k,z;
for(i = 0;i < 4;i++)
{
for(j = 3;j >= 0;j--)
{
if(matrix[i][j] == 0) continue;
for(z= j-1;z >= 0;z--)
{
if(matrix[i][j] == matrix[i][z])
{
matrix[i][j] = matrix[i][j]*2;
matrix[i][z] = 0;
break;
}
if(matrix[i][z] != 0)
{
break;
}
}
}
}
for(i = 0;i < 4;i++)
{
k = 3;
for(j = 3;j >= 0;j--)
{
if(matrix[i][j] != 0)
{
matrix[i][k] = matrix[i][j];
if(j != k) matrix[i][j] = 0;
k--;
}
}
}
}
void hand_up()
{
int i,j,k,z;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
if(matrix[j][i] == 0) continue;
for(z = j+1;z < 4;z++)
{
if(matrix[j][i] == matrix[z][i])
{
matrix[j][i] = matrix[j][i]*2;
matrix[z][i] = 0;
break;
}
if(matrix[z][i] != 0)
{
break;
}
}
}
}
for(i = 0;i < 4;i++)
{
k = 0;
for(j = 0;j < 4;j++)
{
if(matrix[j][i] != 0)
{
matrix[k][i] = matrix[j][i];
if(j != k) matrix[j][i] = 0;
k++;
}
}
}
}
void hand_down()
{
int i,j,k,z;
for(i = 0;i < 4;i++)
{
for(j = 3;j >= 0;j--)
{
if(matrix[j][i] == 0) continue;
for(z = j-1;z >= 0;z--)
{
if(matrix[j][i] == matrix[z][i])
{
matrix[j][i] = matrix[j][i]*2;
matrix[z][i] = 0;
break;
}
if(matrix[z][i] != 0)
{
break;
}
}
}
}
for(i = 0;i < 4;i++)
{
k = 3;
for(j = 3;j >= 0;j--)
{
if(matrix[j][i]!= 0)
{
matrix[k][i] = matrix[j][i];
if(j != k) matrix[j][i] = 0;
k--;
}
}
}
}
/*
曾加随机数
*/
void add_number()
{
int t,k,x,y,sum=0;
t = rand()%4;
k = rand()%5;
x,y,sum=0;
for(x = t;;)
{
for(y = 0;y < 4;y++)
{
sum++;
if(matrix[x][y] == 0)
{
matrix[x][y] = s[k];
sum = 16;
break;
}
}
x++;
x %= 4;
if(sum > 15) break;
}
lcd_draw_matrix(50, 10, 4, 100, 20, 0x00EDEDED);
}
int game_over_judge()
{
int i,j;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
if(matrix[i][j] == 0)
{
return -1;
}
if(j-1 > 0 && matrix[i][j] == matrix[i][j-1])
{
return -1;
}
if(j+1 < 4 && matrix[i][j] == matrix[i][j+1])
{
return -1;
}
if(i-1 > 0 && matrix[i][j] == matrix[i-1][j])
{
return -1;
}
if(i+1 < 4 && matrix[i][j] == matrix[i+1][j])
{
return -1;
}
}
}
return 1;
}
/*
功能:@初始化statu,并画出整个界面;
*/
void start()
{
int i,j;
statu = 0;
while(1)
{
lcd_draw_bmp("jm.bmp",0,0,400,479);
lcd_draw_bmp("lk.bmp",400,0,400,150);
lcd_draw_bmp("wk.bmp",400,151,400,150);
lcd_draw_bmp("jd.bmp",400,302,400,150);
statu = get_finger_touch_area();
if(statu == 1||statu == 2 || statu == 3)
{
lcd_draw_rect(0, 0 , 800, 480, 0x0086B7DF);
lcd_draw_matrix(50, 10, 4, 100, 20, 0x00EDEDED);
//printf("start() at the end\n");
break;
}
}
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
matrix[i][j] = 0;
}
matrix[3][1] = 4;
matrix[3][3] = matrix[2][3] =2;
lcd_draw_bmp("back.bmp", 550, 350 , 200, 100);
}
/*
功能:@找出最大分数,并画出。
*/
void max_grand()
{
int k = 0,i,j;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
if(matrix[i][j] > k )
k = matrix[i][j];
}
}
lcd_draw_bmp(get_file_name_by_digit(k), 550, 200, 100, 100);
for(i = 0;i < 1e6;i++);
}
/*
功能:@在需要的时候返回大初始界面
*/
void back_to_start()
{
if(flag)
{
lcd_draw_rect(0, 0 , 800, 480, 0x0086B7DF);
start();
}
}
void copy_matrix()
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
ck[i][j] = matrix[i][j];
}
}
}
int check_change()
{
int i,j;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
if(matrix[i][j] != ck[i][j])
return 1;
}
}
return 0;
}
void game_play()
{
int move = 0,t,check;
while (1)
{
move = get_finger_move_direction();
if(move == -1) back_to_start();
lcd_draw_matrix(50, 10, 4, 100, 20, 0x00EDEDED);
copy_matrix();
switch (move)
{
case MOVE_LEFT:
handle_left();
break;
case MOVE_RIGHT:
hand_right();
break;
case MOVE_DOWN:
hand_up();
break;
case MOVE_UP:
hand_down();
break;
default:
break;
}
max_grand();
t = game_over_judge();
//游戏结束清屏,返回主界面
if(t > 0)
{
lcd_draw_rect(0, 0 , 800, 480, 0x0086B7DF);
start();
break;
}
lcd_draw_matrix(50, 10, 4, 100, 20, 0x00EDEDED);
//int check;
if(check_change())
{
//printf("%d\n",check);
add_number();
}
}
}
// 音乐线程
void *music_play(void *arg)
{
int i = 0;
char name[10];
char cmd[64];
while (1)
{
i = 0;
while (strcmp(bgm_name[i], "NULL") != 0)
{
//初始化一个字符串
memset(name, 0, sizeof(name));
//字符串的拷贝
strcpy(name, bgm_name[i]);
memset(cmd, 0, sizeof(cmd));
sprintf(cmd, "madplay %s", name);
system(cmd);
i++;
}
}
}
void bgm_play()
{
pthread_create(&pid, NULL, music_play,NULL);
}
void sig_handler(int num)
{
printf("sig_handler...\n");
pthread_cancel(pid);
exit(0);
}
int main(int argc, char *argv[])
{
srand(time(NULL));
int fd; //framebuffer
fd = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
perror("open file error: ");
return 0;
}
plcd = mmap(NULL, 800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if (plcd == MAP_FAILED)
{
perror("mmap error :");
return 0;
}
//初始清屏
lcd_draw_rect(0, 0 , 800, 480, 0x0086B7DF);
//播放音乐
bgm_play();
signal(SIGINT, sig_handler);
//初始界面
start();
srand(time(NULL));
while(1)
{
game_play();
}
phread_join(pid);
munmap(plcd, 800*480*4);
//关闭设备
close(fd);
return 0;
}
额,第一次写这么长的代码,过程中收获了不少,但也感觉到自己犯了很多错误,是时候做一波总结了!
(1) 写在思考前。不急着下手,额,现在经验告诉我在编写前没有认真思考,往往都是错的(对本学渣而言,大神请靠边),往往花大量的功夫的重调代码。
(2) 缺少必要的注释。 个人觉得注释影响代码的美观,所以在编程过程中,很少注。特别是函数参数都没注释,调用的时候,总得再看看,关键还容易出错。额,不好的地方,需改。
(3) 变量命名还是不太规范。对于某个函数的局部时,因为采用随便命名,可能到后期过程中从新看代码的时候就不太好看,这个时候花了可能要花不少功夫重新看代码。
(4) 代码的美观性。考虑必要的逻辑空行,和空格。