2048小游戏的实现

头文件

#ifndef __COMMON_H
#define __COMMON_H

#include  
#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

#include 
#include 

#define MATRIX_X0     0   //整个棋盘的左上角顶点的x轴坐标
#define MATRIX_Y0     0   //整个棋盘的左上角顶点的y轴坐标

#define BOARDSIZE  4  // 整个棋盘的大小BORADSIZE * BOARDSIZE

#define MOVE_LEFT  1
#define MOVE_RIGHT 2
#define MOVE_UP    3
#define MOVE_DOWN  4

extern int g_lcd_width;
extern int g_lcd_height;
extern int g_lcd_bpp;

//游戏结束标志
bool game_over = false;

int *plcd = NULL;//指向framebuffer(屏幕显存第一个点的内存)

//将所有的图片名保存到一个数组中
const char * bmpfiles[] =	
{
	"res/2.bmp", 
	"res/4.bmp",
	"res/8.bmp",
	"res/16.bmp",
	"res/32.bmp",
	"res/64.bmp",
	"res/128.bmp",
	"res/256.bmp",
	"res/512.bmp",
	"res/1024.bmp",
	"res/2048.bmp",
	"res/4096.bmp",
	"res/8192.bmp",
	"res/16384.bmp",
	"res/32768.bmp",
	"res/65536.bmp",
};

#endif

文件名bmp.h

#ifndef __BMP_H
#define __BMP_H

struct header
{
	int16_t type;
	int32_t size;
	int16_t reserved1;
	int16_t reserved2;
	int32_t offbytes;
}__attribute__((packed));

struct info
{
	int32_t size;
	int32_t width;
	int32_t height;
	int16_t planes;

	int16_t bit_count;
	int32_t compression;
	int32_t size_img;
	int32_t xpel;
	int32_t ypel;
	int32_t clrused;
	int32_t partant;
}__attribute__((packed));

#endif

2048.c

#include "common.h"
#include "bmp.h"

int g_lcd_width  = 0;
int g_lcd_height = 0;
int g_lcd_bpp    = 0;

/*
get_bmpfiles_index:根据你要显示的数字(2,4,8,16,...)
	返回你对应的文件名的下标
返回值:
	返回 x对应的文件名在数组bmpfiles的下标
*/
int get_bmpfiles_index(int x)
{
	int exp;
	for(exp=0; x!=0; x >>= 1, exp++);

	return exp-2;
}


//棋盘矩阵
int matrix[BOARDSIZE][BOARDSIZE] =
{
	0,0,0,0,
	0,0,0,0,
	0,0,0,0,
	0,0,0,0	
};


/*
	get_zero_num:求棋盘矩阵里面有多少个0
	返回值:
		返回棋盘矩阵中0的个数
*/
int get_zero_num(void)
{
	int z = 0;//棋盘矩阵中元素为0的个数
	int i, j;

	//BOARDSIZE = 4,整个棋盘大小为BOARDSIZE*BOARDSIZE
	for (i = 0; i < BOARDSIZE; i++)
	{
		for (j = 0; j < BOARDSIZE; j++)
		{
			if (matrix[i][j] == 0)
			{
				z++;
			}
		}
	}

	return z;
}


/*
	set_matrix:给棋盘矩阵第z个0的位置,填充一个
		值s
*/
void set_matrix(int z,  int s)
{
	int i, j;
	int k = 0 ;//0的个数

	for (i = 0; i < BOARDSIZE ;i++)
	{
		for (j = 0; j < BOARDSIZE; j++)
		{
			if (matrix[i][j] == 0)
			{
				k++;
				if (k == z)
				{
					matrix[i][j] = s;
					return ;
				}
			}
			
		}
	}

}


/*
	lcd_draw_point:在屏幕坐为(x, y)这个点,填充color
	这个颜色值。
	@x: x轴坐标
	@y: y轴坐标
	@color: 要填充的辨色值

	返回值:
		无返回值。

*/
void lcd_draw_point(int x, int y, int color)
{
	int *p = plcd;

	if (x >= 0 && x < g_lcd_width && y>=0 && y < g_lcd_height)
	{
		*(p + g_lcd_width *y + x) = color;
	}
}


/*
	lcd_draw_dect: 在屏幕上画一个矩形,并且用
		color这种颜色填充该矩形。

	@x0:该矩形的左上角的那个点x轴坐标
	@y0:该矩形的左上角的那个点y轴坐标
	@w:该矩形的宽
	@h:该矩形的高
	@color:该矩形要填充的色值

	返回值:
		无返回值。
		
*/
void lcd_draw_dect(int x0, int y0, int w, int h, int color)
{
	if (x0 < 0 || y0 < 0 || w < 0 || h <0)
		return;

	if ((x0 + w > g_lcd_width) || (y0+h) > g_lcd_height)
	{
		return;
	}

	int x, y;

	for (y = y0; y < y0 + h; y++)
	{
		for (x = x0; x < x0 + w; x++)
		{
			lcd_draw_point(x, y, color);
		}
	}

}

/*
	draw_bmp:把一张bmp图片显示在屏幕上特定的位置
	@bmpfile:要显示的bmp图片的文件名
	@x0: 在屏幕上显示的左上角顶点的x轴坐标
	@y0: 在屏幕上显示的左上角顶点的y轴坐标
	返回值:
		无返回值.
*/
void draw_bmp(const char *bmpfile, int x0, int y0)
{
	int fd;
	int x, y;

	fd = open(bmpfile, O_RDONLY);
	if (fd == -1)
	{
		perror("open bmpfile error:");
		return ;
	}
		
	struct header head;
	struct info   info;
	read(fd, &head, sizeof(head));
	read(fd, &info, sizeof(info));

	char *bmpdata = calloc(1, head.size-head.offbytes);
	read(fd, bmpdata, info.width * info.height * info.bit_count/8);

	close(fd);

	int i = 0;
	for (y = 0; y < info.height; y++)
	{
		unsigned char r,g ,b;
		int color;

		for (x = 0; x < info.width; x++)
		{
			b = bmpdata[i++];
			g = bmpdata[i++];
			r = bmpdata[i++];
			color = (r << 16) | (g << 8) | b;

			lcd_draw_point(x0+ x, y0 + (info.height -1 - y) ,color);
		}
	}
	free(bmpdata);
}



/*
	draw_matrix:把棋盘矩阵在屏幕上显示出来
*/
void draw_matrix(void)
{
	int i, j;
	for (i = 0; i < BOARDSIZE; i++)
	{
		for (j = 0; j < BOARDSIZE;j++)
		{
			int x0, y0;
			x0 = 185;//棋盘矩阵左上角那个点的x轴坐标
			y0 = 25;//棋盘矩阵左上角那个点的y轴坐标
			if (matrix[i][j] == 0)
			{
				lcd_draw_dect(x0+j*110,  y0+i*110,
					      100 , 100, 
					      0xb4eeb4);//如果此处元素的值为0,那么
								//就显示
			}
			else
			{
				int f_index = get_bmpfiles_index(matrix[i][j]);
				draw_bmp(bmpfiles[f_index],
						x0+j*110,  y0+i*110);
			}
		}
	}
}

/*
	init_matrix:初始化棋盘矩阵
			在任意x个位置,填充x个数字(2,4,8)
*/

void init_matrix(void)
{
	//规则x >= 1,x <= 3
	int x = (random() % 3) + 1;

	int i;

	/*
		step1:随机产生x个数字,并填充到棋盘矩阵中去
	*/

	for(i = 0; i < x; i++)
	{
		int pos = (random() % get_zero_num()) + 1;

		int s[] = {2, 4, 8, 2};
		int s_i = (random() % 3);

		set_matrix(pos, s[s_i]);
	}

	/*
		step 2: 绘制棋盘矩阵
	*/
	draw_matrix();

}

/*
	rand1_matrix:移动之后随机产生一个数字填充到
	任意一个0的位置上
*/
void rand_matrix()
{
	int pos = (random() % get_zero_num()) + 1;

	int s[] = {2, 4, 8, 2};
	int s_i = (random() % 4);

	set_matrix(pos, s[s_i]);
	draw_matrix();

}

/*
	get_finger_direction:获取手指在触摸屏上面的滑动方向
	返回值:
		MOVE_LEFT:手指向左移动
		MOVE_RIGHT:手指向右移动
		MOVE_UP:手指向上移动
		MOVE_DOWN:手指向下移动
*/
int get_finger_direction()
{
	int ret;
	int fd = open("/dev/input/event0", O_RDONLY);
	if (fd == -1)
	{
		perror("open event failed:");
		return -1;
	}

	struct input_event ev;

	int  x1 = -1; //在滑动过程中第一个点的x轴坐标
	int x2; //在滑动过程中最后一个点的x轴坐标
	int y1 = -1;//在滑动过程中第一个点的y轴坐标
	int y2;//在滑动过程中最后一个点的y轴坐标

	while (1)
	{
		ret = read(fd, &ev, sizeof(ev));
		if(ret != sizeof(ev))
		{
			continue;
		}
		
		if (ev.type == EV_ABS && ev.code == ABS_X)//是x轴坐标
		{
			if (x1 == -1)//x1重来没有赋过值,那么肯定是第一个点
			{
				x1 = ev.value;
			}
			x2 = ev.value;
		}
		if (ev.type == EV_ABS && ev.code == ABS_Y)//是y轴坐标
		{
			if ( y1 == -1)//y1重来没有赋过值,那么肯定是第一个点
			{
				y1 = ev.value;
			}
			y2 = ev.value;
		}


		if (ev.type == EV_KEY && ev.code == BTN_TOUCH //手指弹起,再计算滑动方向
			&& ev.value == 0)//触摸屏压力值为0, press up
		{
			int x_cz;//x轴的位移
			int y_cz;//y轴的位移
			int abs_x;
			int abs_y;
			x_cz = x2 - x1;
			y_cz = y2 - y1;
			abs_x = abs(x_cz);
			abs_y = abs(y_cz);
			
			if((x_cz > 30) && (abs_x > 2 * abs_y))
			{
				close(fd);
				return MOVE_RIGHT;
			}
			else if((x_cz < -30) && (abs_x > 2 * abs_y))
			{
				close(fd);
				return MOVE_LEFT;
			}
			else if((y_cz > 30) && (abs_y > 2 * abs_x))
			{
				close(fd);
				return MOVE_UP;
			}
			else if((y_cz < -30) && (abs_y > 2 * abs_x))
			{
				close(fd);
				return MOVE_DOWN;
			}	
			else	
			{
				x1 = y1 = -1;
				continue;
			}
		}
	}


	close(fd);

}

/*
	fin_left:手指左划后棋子移动及合并的方式
*/
void fin_left()
{
	int i, j;//i为矩阵行下标,j为矩阵列下标
	int value, save_zero;
	for(i = 0; i < BOARDSIZE; i++)
	{
		value = 0;
		save_zero= 0;
		for(j = 0; j < BOARDSIZE ; 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 fin_right()
{
	int i, j;//i为矩阵行下标,j为矩阵列下标
	int value;
	int save_zero;
	for (i = 0; i < BOARDSIZE; i++)
	{
		value = 0;
		save_zero = BOARDSIZE -1;
		for (j = BOARDSIZE - 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;
		}
	
	}
}
/*
	fin_up:手指上划后棋子移动及合并的方式
*/
void fin_up()
{

	int i, j;//i为矩阵行下标,j为矩阵列下标
	int value;
	int save_zero;

	for(j = 0; j < BOARDSIZE; j++)
	{
		value = 0;
		save_zero= 0;
		for(i = 0; i < BOARDSIZE ; 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;
		}

	}

}
	
	//draw_matrix();
/*
	fin_down:手指上划后棋子移动及合并的方式
*/
void fin_down()
{
	int i, j;//i为矩阵行下标,j为矩阵列下标
	int value;
	int save_zero;
	
	for(j = 0; j < BOARDSIZE; j++)
	{
		value = 0;
		save_zero = BOARDSIZE - 1;
		for(i = BOARDSIZE - 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;
		}
		
	}
}

/*
	判断是否还能移动
*/
bool is_game_over(void)
{
	int i, j;
	if(get_zero_num() != 0)
	{
		return false;
	}

	for(i = 0; i < BOARDSIZE; i++)
	{
		for(j = 0; j < BOARDSIZE ; j++)
		{
			if (j != BOARDSIZE -1)
			{
				if (matrix[i][j] == matrix[i][j+1])
				{
					return false;
				}
			}

			if (i != BOARDSIZE - 1)
			{
				if (matrix[i][j] == matrix[i+1][j])
				{
					return false;
				}
			}
		}
	}
	
	return true;
}


/*
	change_matrix:根据手指滑动(direction),
		变换棋盘矩阵
*/
int change_matrix()
{
	int direction = get_finger_direction();
	if (direction == MOVE_LEFT)
	{
		fin_left();
	}
	else if (direction == MOVE_RIGHT)
	{
		fin_right();
	}
	else if (direction == MOVE_UP)
	{
		fin_down();
	}
	else
	{
		fin_up();
	}
}

		
int main(void)
{
	int lcd = open("/dev/fb0", O_RDWR);
	if (lcd == -1)
	{
		perror("open fb0 failed:");
		exit(0);
	}

	struct fb_var_screeninfo vinfo;
	ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);

	g_lcd_width  = vinfo.xres;
	g_lcd_height = vinfo.yres;
	g_lcd_bpp    = vinfo.bits_per_pixel;

	int screen_size = g_lcd_width * g_lcd_height * g_lcd_bpp/8;
	
	plcd = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, lcd, 0);
	lcd_draw_dect(0, 0, g_lcd_width, g_lcd_height, 0xffffff);//清屏
	
	srandom(time(NULL)); //设置随机数种子
	init_matrix();
	
	while (!game_over) //游戏没结束
	{
		//用来保存原来的矩阵值
		int matrix_v1[BOARDSIZE][BOARDSIZE];
		int i, j, flag = 0;
		for(i = 0; i < BOARDSIZE; ++i)
		{
			for (j = 0; j < BOARDSIZE; ++j)
			{
				matrix_v1[i][j] = matrix[i][j];
			}
		}
		/*
			step 1: 变换矩阵
		*/
		change_matrix();

		for (i = 0; i < BOARDSIZE; ++i)
		{
			for (j = 0; j < BOARDSIZE; ++j)
			{
				if (matrix_v1[i][j] != matrix[i][j])
				{
					flag = 1;
					i = j = BOARDSIZE;
				}
			}
		}
		if (flag)
		{
			rand_matrix();
			draw_matrix();
		} 
		else 
		{
			draw_matrix();
		}
		game_over = is_game_over();
	}

	lcd_draw_dect(0, 0, g_lcd_width, g_lcd_height, 0xffffff);//清屏
	draw_bmp("res/game_over.bmp", 250, 165);
	
	munmap(plcd, screen_size);
	close(lcd);
}

你可能感兴趣的:(2048小游戏的实现)