event.h
屏幕点击事件.h文件:获取屏幕的xy坐标,获取手指滑动的方向,获取点击事件。
#ifndef __EVENT_H_
#define __EVENT_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#define BIN_TOUCH 0x14a
#define up 1
#define down 2
#define left 3
#define right 4
void get_event_xy(int *x,int *y);
int get_event_dirention();
void photo();
int get_event_button();
#endif
event.c
屏幕点击事件.c文件:实现屏幕的xy坐标,获取手指滑动的方向,获取点击事件函数。
#include "event.h"
#include "lcd.h"
void get_event_xy(int *x,int *y)//获取像素的坐标
{
int fd_ev = open("/dev/input/event0",O_RDONLY);//打开屏幕()
if(fd_ev ==-1)
{
perror("open error");
exit(1);
}
printf("open duccess\n");
struct input_event ev;
while(1)
{
int ret =read(fd_ev,&ev,sizeof(ev));
if(ret ==-1)
{
perror("read ev error");
exit(1);
}
if(ev.type == EV_ABS && ev.code ==ABS_X)
{
*x = ev.value;
}
if(ev.type == EV_ABS && ev.code ==ABS_Y)
{
*y = ev.value;
}
if(ev.type == EV_KEY &&ev.code ==BIN_TOUCH && ev.value == 0)
{
break;
}
}
close(fd_ev);
}
int get_event_dirention()
{//按键方向的判断
int fd_ev = open("/dev/input/event0",O_RDONLY);
if(fd_ev ==-1)
{
perror("open error");
exit(1);
}
printf("open duccess\n");
struct input_event ev;
int x0 =-1,y0=-1;
int x1=-1,y1 =-1;
while(1)
{
int ret =read(fd_ev,&ev,sizeof(ev));
if(ret ==-1)
{
perror("read ev error");
exit(1);
}
if(ev.type == EV_ABS && ev.code ==ABS_X)
{
if(x0==-1)
{
x0=ev.value;
}else{
x1=ev.value;
}
}
if(ev.type == EV_ABS && ev.code ==ABS_Y)
{
if(y0==-1)
{
y0=ev.value;
}else{
y1=ev.value;
}
}
if(ev.type == EV_KEY &&ev.code ==BIN_TOUCH && ev.value == 0)
{
int x_d =x1-x0;
int y_d=y1-y0;
printf("x0=%d,y0=%d,x1=%d,y1=%d\n",x0,x1,y0,y1);
printf("x_d=%d,y_d=%d\n",x_d,y_d);
if(abs(x_d)>abs(y_d))
{
if(x_d>100)
{
close(fd_ev);
return right;
}else if(x_d<-100)
{
close(fd_ev);
return left;
}
}else{
if(y_d>100)
{
close(fd_ev);
return down;
}else if(y_d<-100)
{
close(fd_ev);
return up;
}
}
}
}
close(fd_ev);
}
int get_event_button()
{//对按键的监听
int x2 = -1, y2 = -1;
get_event_xy(&x2, &y2);
// 转换成像素点的坐标
int x0 = x2 /1.28;
int y0 = y2 /1.25;
int w=150 ,h=80;
//符合区间就返回那个值
if((x0 > 480 && x0 < 480 + w) && (y0 > 250 && y0 < h + 250)) // 重启
{
return 1;
}
else if ((x0 > 480 && x0 < 480 + w) && (y0 > 340 && y0 < h + 340)) // 退出
{
return 2;
}
else
{
return -1;
}
}
lcd.h
系统IO操作LCD,内存映射操作显示屏。
#ifndef __LCD_H_
#define __LCD_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
//BMP图片信息结构体
typedef struct bmp_info
{
int size; //图片的大小
int width; //图片的宽度
int height; //图片的高度
short depth; //图片的色深
char* data; //保存像素数组首地址
}BMP;
//系统IO操作显示屏
void open_lcd();
void close_lcd();
void write_lcd(unsigned int color);
void rgbrun();
//内存映射操作显示屏
void lcd_init();
void lcd_uninit();
void lcd_draw_point(int i, int j, unsigned int color);
void lcd_draw_background(unsigned int color);
void lcd_draw_word(int x0,int y0,int w, int h,unsigned int color,char *lcd_draw_word);
void lcd_draw_bmp(int x, int y, char* bmpname);
BMP get_bmp_info(char *bmpname);
#endif
lcd.c
系统IO完成:打开LCD函数,关闭LCD函数,写入像素点颜色函数,刷屏函数。
#include "lcd.h"
int fd_lcd = -1; //显示屏的文件描述符
int* plcd = NULL; //内存映射区域的首地址
struct fb_var_screeninfo fbinfo; //屏幕属性信息结构体
/********************系统IO操作显示屏************************/
/**
* @brief 打开LCD显示屏
*
*/
void open_lcd()
{
fd_lcd = open("/dev/fb0", O_WRONLY);
if(fd_lcd == -1)
{
perror("open error");
exit(1);
}
printf("open /dev/fb0 success\n");
}
/**
* @brief 关闭显示屏
*
*/
void close_lcd()
{
close(fd_lcd);
}
/**
* @brief 往屏幕文件中写入数据
*
* @param color 需要显示的颜色
*/
void write_lcd(unsigned int color)
{
int array[480][800] = {0}; //二维数组 对应显示屏上的像素点
for(int i = 0; i < 480; i++) //行
{
for(int j = 0; j < 800; j++) //列
{
array[i][j] = color;
}
}
//把颜色数据写入到显示屏文件中
write(fd_lcd, array, 800*480*4);
}
/**
* @brief 实现显示屏的刷屏
*
*/
void change_lcd()
{
unsigned int color[3] = {0xFF0000, 0x00FF00, 0x0000FF};
int i = 0;
while(1)
{
write_lcd(color[i]);
sleep(3); //延时3秒
i++;
if(i > 2)
i = 0;
//把光标偏移到文件开头
lseek(fd_lcd, 0, SEEK_SET);
}
}
屏幕的初始化:打开屏幕,内存映射。
/*********************内存映射操作显示屏********************/
/**
* @brief 屏幕初始化:打开显示屏,内存映射
*
*/
void lcd_init()
{
//可读可写方式打开显示屏
fd_lcd = open("/dev/fb0", O_RDWR);
if(fd_lcd == -1)
{
perror("open error");
exit(1);
}
printf("open /dev/fb0 success\n");
//使用ioctl获取屏幕的属性信息
int ret = ioctl(fd_lcd, FBIOGET_VSCREENINFO, &fbinfo);
if(ret == 0)
{
printf("LCD: %d, %d, %d\n", fbinfo.xres, fbinfo.yres, fbinfo.bits_per_pixel);
}
//进行内存映射
plcd = mmap(
NULL, //映射区域的地址由系统自行分配
//800*480*4, //映射区域的大小
fbinfo.xres * fbinfo.yres * fbinfo.bits_per_pixel / 8, //映射区域的大小
PROT_READ | PROT_WRITE, //可读可写
MAP_SHARED, //共享映射,操作立马响应
fd_lcd, //文件描述符
0 //文件映射偏移量,为0,表示从文件开头进行映射
);
if(plcd == MAP_FAILED)
{
perror("mmap error");
exit(1);
}
printf("mmap success\n");
}
关闭屏幕,解除映射。
/**
* @brief 接触显示屏初始化: 解除映射,关闭显示屏
*
*/
void lcd_uninit()
{
//解除内存映射
munmap(plcd, 800*480*4);
//关闭显示屏
close(fd_lcd);
}
/**
* @brief 画背景色(让整个屏幕显示某种颜色)
*
* @param color 颜色
*/
void lcd_draw_background(unsigned int color)
{
for(int i = 0; i < 480; i++) //行
{
for(int j = 0; j < 800; j++) //列
{
lcd_draw_point(i, j, color);
}
}
}
/**
* @brief 显示一个字符
*
* @param x0
* @param y0 第y行的第x个像素点为字符的最左上角的坐标
* @param w 宽
* @param h 高
* @param color 颜色
* @param word 需要显示的字符的字模数据
*/
void lcd_draw_word(int x0, int y0, int w, int h, unsigned int color, char* word)
{
int x, y; //表示需要进行显示的像素点的下标 第y行的第x个像素点
for(int i = 0; i < w*h/8; i++) //对点阵数组进行遍历
{
for(int j = 0; j < 8; j++) //对点阵矩阵中的元素一个一个bit进行分析
{
//word[i]对应有8bit, 一个一个bit来分析,从左往右,高字节到子字节
if(word[i] & (1<<(7-j)))
{
y = i/(w/8); //第几行 w/8一行有多少字节
x = i % (w/8) * 8 + j;
//i%(w/8) 当前元素在这一行前面有多少个字节的元素
//i%(w/8)*8 当前元素在这一行前面有多少个像素点
lcd_draw_point(y+y0, x+x0, color);
}
}
}
}
/**
* @brief Get the bmp info object
*
* @param bmpname 需要进行属性信息获取的bmp图片路径
* @return BMP 返回获取到的属性信息
*/
BMP get_bmp_info(char* bmpname)
{
//打开图片
int fd_bmp = open(bmpname, O_RDONLY);
if(fd_bmp == -1)
{
perror("open bmp error");
exit(1);
}
//判断该文件是否为bmp文件
char bm[2] = {0};
read(fd_bmp, bm, 2);
if(!(bm[0] == 'B' && bm[1] == 'M'))
{
printf("%s is not BMP file\n", bmpname);
exit(1);
}
//获取BMP图片数据
BMP bmpinfo;
//文件大小
lseek(fd_bmp, 0x02, SEEK_SET);
read(fd_bmp, &bmpinfo.size, 4);
//宽度和高度
lseek(fd_bmp, 0x12, SEEK_SET);
read(fd_bmp, &bmpinfo.width, 4);
read(fd_bmp, &bmpinfo.height, 4);
//色深
lseek(fd_bmp, 0x1C, SEEK_SET);
read(fd_bmp, &bmpinfo.depth, 2);
//像素数组
char* p = malloc(bmpinfo.size - 54); //图片的总大小-文件头大小
lseek(fd_bmp, 0x36, SEEK_SET); //偏移到像素数组的位置
read(fd_bmp, p, bmpinfo.size-54);
bmpinfo.data = p;
//关闭文件
close(fd_bmp);
return bmpinfo;
}
/**
* @brief 显示一张bmp图片
*
* @param x
* @param y 第y行的第x个像素点为图片最左上角的坐标
* @param bmpname 图片的路径
*/
void lcd_draw_bmp(int x, int y, char* bmpname)
{
//获取bmp图片信息
BMP bmp = get_bmp_info(bmpname);
printf("bmpname = %s, size = %d, width = %d, height = %d, depth = %d\n",
bmpname, bmp.size, bmp.width, bmp.height, bmp.depth);
//一行的有效字节数
int line_bytes = bmp.width * bmp.depth / 8;
//一行的填充字节数
int pad_bytes = (line_bytes % 4 == 0) ? 0 : (4 - line_bytes%4);
//解析像素数组中的数据
unsigned int color = 0; //像素点的颜色
unsigned char a, r, g, b; //颜色分量
//开始进行解析
char* p = bmp.data;
for(int h = 0; h < abs(bmp.height); h++)
{
for(int w = 0; w < abs(bmp.width); w++)
{
//获取颜色分量
b = *(p++);
g = *(p++);
r = *(p++);
//只考虑24位和32位图片
a = (bmp.depth == 24) ? 0 : *(p++);
//颜色分量合成颜色数据
color = a<<24 | r<<16 | g<<8 | b;
//描点
// width > 0 : 每一行的像素点从左往右存放
// width < 0 : 每一行的像素点从右往左存放
// height > 0 : 每一行像素点从下往上存放
// height < 0 : 每一行像素点从上往下存放
int m = x + w;//横坐标 一行中的第几个像素点
int n = y+bmp.height-1 - h; //纵坐标 第几行
lcd_draw_point(n, m, color);
}
//跳过填充字节数
p += pad_bytes;
}
free(bmp.data); //把申请的空间释放
}
2048.h
#ifndef __2048_H_
#define __2048_H_
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
char *pic_bmp(int n);
void menu();//主页面
int Rander();//随机数
void InitNode();//初始化节点
int UP();//上下左右
int RIGHT();
int LEFT();
int DOWN();
void move();//移动方向判断
int over();//判断结束条件
void start();//开始函数
void Init_menu();//初始化页面
void *Botton(void *arg);//线程按键
#endif
2048.c
#include "2048.h"
#include "event.h"
#include "lcd.h"
int map[4][4] = {0};//存放数组
int score = 0;//分数
char input;//判断屏幕上下左右接收的数据
int gameover = 1;//判断游戏是否继续
int flag = 1;//判断数组是否移动
//==初始化函数用在重新开始和结束按钮=====
void Init_menu()
{
lcd_draw_background(0xFFFFFF);
int i = 0;
int j = 0;
score = 0;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
map[i][j] = 0;
}
}
InitNode();
menu();
}
//=====上下左右移动的函数=====
int UP()
{ // 向上
int now, next; // 定义当前和下一个元素的变量
int i, j, k;
for (j = 0; j < 4; j++) // 外层循环遍历列(竖直方向)
{
for (i = 0; i < 4; i++) // 内层循环遍历行(从上到下)
{
now = map[i][j]; // 获取当前位置的元素值
if (now != 0) // 如果当前元素不为0(即非空)
{
k = i + 1;
while (k < 4) // 从当前行的下一行开始向下查找
{
next = map[k][j]; // 获取下一个位置的元素值
if (next != 0) // 如果下一个位置不为0(即非空)
{
if (now == next) // 如果当前元素与下一个元素相等
{
flag = 1; // 设置标志位为1,表示发生了合并操作
score += map[k][j]; // 更新分数,加上合并后的值
map[i][j] = 2 * map[k][j]; // 当前位置更新为两者之和
map[k][j] = 0; // 下一个位置清零(合并后该位置为空)
}
k = 4; // 跳出循环
}
k++; // 继续向下查找
}
}
}
}
for (j = 0; j < 4; j++) // 第二个for语句是把当前控制方向的非零元素移动当前方向的前面
{
for (i = 0; i < 4; i++)
{
now = map[i][j];
if (now == 0) // 如果当前位置为空(值为0)
{
k = 1 + i;
while (k < 4) // 从当前位置的下一行开始向下查找
{
next = map[k][j]; // 获取下一个位置的元素值
if (next != 0) // 如果下一个位置不为空
{
flag = 1; // 设置标志位为1,表示发生了移动操作
map[i][j] = next; // 当前位置更新为下一个位置的值
map[k][j] = 0; // 下一个位置清零
k = 4; // 跳出循环
}
k++; // 继续向下查找
}
}
}
}
// 返回注释代码
return flag;
}
向上移动代码中注释很清楚,其他方向同理,暂不例出了。
//======创建线程对重新开始按钮和游戏结束按钮=======
void *Botton(void *arg)
{
int button = -1;
while (1)
{
button = get_event_button();
if (button == 1)
{
Init_menu();
}
else if (button == 2)
{
lcd_draw_bmp(0, 0, "game_over.bmp");
lcd_draw_bmp(0, 0, "game_over.bmp");
lcd_draw_bmp(0, 0, "game_over.bmp");
exit(1);
}
}
}
main.c
#include "lcd.h"
#include "event.h"
#include "2048.h"
#include <pthread.h>
int main()
{
lcd_init();
lcd_draw_background(0xFFFFFF);
pthread_t pid;
int ret=pthread_create(&pid,NULL,Botton,NULL);
start();
lcd_uninit();
return 0;
}
演示图片如下: 初始状态
向下移动
标签:ev,int,bmp,2048,lcd,小游戏,fd,include,ARM From: https://blog.csdn.net/qq_63147384/article/details/142372107完整项目:
链接:https://pan.baidu.com/s/1vO1ZAuLbndoxoN5Kt02ALg?pwd=ucyl
提取码:ucyl