简介:
之前写过一篇俄罗斯方块在ubuntu上用ANSI控制码运行的文章,因为没有可移植性,并且没有考虑信号处理函数的可重入性,当方块下落速度较快时,可能导致程序崩溃,在此基础上用frmaebuffer和多线程并发来对以前程序进行重构。
代码:
game.h
#ifndef GAME_H__
#define GAME_H__
#define ROW 19
#define LINE 14
#define DIA 4
#define BASE 7
#define SPINSTA 4
//方块函数,base为基本类型,spinsta为旋转状态
struct Blocks
{
int space[DIA][DIA];
}blocks[BASE][SPINSTA];
//操作方式
enum move_way
{
CHANGE = 0,
MOVE_LEFT,
MOVE_RIGHT,
MOVE_DOWN,
PAUSE
};
void Game_start(); //游戏开始函数
void Init_data(); //初始化数据
void Interface(); //游戏界面
int Init_blocks(); //方块初始化
void Next_blocks(); //下一个方块的打印
int Read_record(); //读取历史记录
void Grade_print(int); //分数打印
void Select_colour(int *); //选择颜色
void Ols_load(); //棋盘读入数据
void trave_(); //根据棋盘数值打印相对应的颜色
int Set_time(); //设置下落速度
void Game_pause(); //游戏暂停
int Run(); //游戏运行
int Judge_over(); //判断游戏结束
int Judge_move(int); //判断方块是否能移动
int Judge_chage(); //判断方块能否旋转
void Judge_dis(); //判断能否消行
void Exec_command(int); //执行命令
void Dis_last(int); //销毁上一位置方块
void Exec_dis(int); //执行消行
#endif
game.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include "framebuffer.h"
#include <pthread.h>
#include "game.h"
#define BUFFSIZE 1024
//历史最高记录读取文件名
#define FILENAME "/home/ll/log"
int Els[ROW][LINE] = {0}; //棋盘数组
int row_ = 0; //方块在棋盘中的行
int line_ = 0; //方块在棋盘中的列
int colour_[ROW][LINE] = {0}; //每个方块对应的颜色
int colour = 0; //当前方块的颜色
int colour_next = 0; //下一个方块的颜色
int base = 0; //当前方块类型
int base_next = 0; //下一个方块类型
int spinsta = 0; //方块的4种变化
int grade = 0; //成绩
int level = 1; //等级
int stop_ = 1; //当前方块能否继续下落
int over = 0; //判断当前游戏是否结束
int FLAG = -1; //触摸区域对应的操作
pthread_t id = 0; //线程id
/* 根据触摸区域获取相应的操作 */
static int Get_Handle(int x, int y)
{
if (x >= 525 && x <= 645 \
&& y >= 348 && y <= 460)
{
return CHANGE;
}
else if (x >= 623 && x <= 713 \
&& y >= 215 && y <= 348)
{
return MOVE_LEFT;
}
else if (x >= 623 && x <= 713 \
&& y >= 5 && y <= 115)
{
return MOVE_RIGHT;
}
else if (x >= 630 && x <= 790 \
&& y >= 137 && y <= 200)
{
return MOVE_DOWN;
}
else if (x >= 385 && x <= 511 \
&& y >= 1 && y <= 127)
{
return PAUSE;
}
return -1;
}
/* 不断获取触摸坐标 */
static void *Touch(void *args)
{
struct point p;
while (stop_)
{
p = clickTouch();
FLAG = Get_Handle(p.x, p.y);
}
pthread_exit((void *)0);
}
void Game_start() //游戏开始主函数
{
initEquipment();
struct point p;
Init_blocks();
pthread_create(&id, NULL, Touch, NULL);
while (1)
{
lcdDisplayPictures("/home/ll/ols/12.bmp", 0, 0);
p = clickTouch();
stop_ = 1;
if (p.x >= 181 && p.x <= 608 \
&& p.y >= 234 && p.y <= 305)
{
Init_data();
Interface();
srand((unsigned)time(NULL));
base = rand() % 7;
colour = rand() % 5;
while(Run());
over = 1;
}
else if (p.x >= 280 && p.x <= 510 \
&& p.y >= 358 && p.y <= 438)
{
setBackground(0xffffff);
break;
}
}
closeEquipment();
}
/* 初始化数据 */
void Init_data()
{
int i, j;
for (i = 0; i < ROW; i++)
{
for (j = 0; j < LINE; j++)
{
Els[i][j] = 0;
colour_[i][j] = 0;
}
}
row_ = 0;
line_ = 0;
colour = 0;
colour_next = 0;
grade = 0;
level = 1;
over = 0;
}
/* 界面打印 */
void Interface()
{
int x, y, k;
int i, j;
setBackground(0xffffff);
for (x = 17; x < 511; x++)
{
for (i = 465; i < 471; i++)
{
lcdDrawPoint(x, i, 0xff0000);
}
for (y = 137; y < 143; y++)
{
lcdDrawPoint(x, y, 0xff0000);
}
}
for (y = 143; y < 465; y++)
{
for (x = 17; x < 23; x++)
{
lcdDrawPoint(x, y, 0xff0000);
}
for (j = 505; j < 511; j++)
{
lcdDrawPoint(j, y, 0xff0000);
}
}
for (y = 145; y < 465; y += 32)
{
for (x = 25; x < 505; x += 32)
{
lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
}
}
lcdDisplayPictures("/home/ll/ols/10.bmp", 385, 1);
lcdDisplayPictures("/home/ll/ols/11.bmp", 515, 0);
lcdDisplayPictures("/home/ll/ols/14.bmp", 185, 1);
lcdDisplayPictures("/home/ll/ols/15.bmp", 281, 1);
//初始化棋盘边界
for (i = 0,k = ROW-2; i < 2 && k < ROW; i++,k++)
{
for (j = 0; j < LINE; j++)
{
Els[i][j] = 2;
Els[k][j] = 2;
}
}
for (i = 2; i < ROW-2; i++)
{
for (j = 0,k = LINE-2; j < 2 && k < LINE; j++,k++)
{
Els[i][j] = 2;
Els[i][k] = 2;
}
}
Grade_print(grade);
}
int Init_blocks() //初始化方块,共28种
{
int i, j;
int temp[DIA][DIA] = {0};
int base_, spinsta_;
for (i = 0; i < 2; i++)
{
//田
blocks[0][0].space[1][i+1] = 1;
blocks[0][0].space[2][i+1] = 1;
//Z
blocks[1][0].space[1][i] = 1;
blocks[1][0].space[2][i+1] = 1;
//反Z
blocks[2][0].space[1][i+1] = 1;
blocks[2][0].space[2][i] = 1;
}
for (i = 1;i < 4; i++)
{
//7
blocks[3][0].space[1][0] = 1;
blocks[3][0].space[i][1] = 1;
//反7
blocks[4][0].space[1][2] = 1;
blocks[4][0].space[i][1] = 1;
}
for (i = 0; i < 4; i++)
{
//|
blocks[5][0].space[i][1] = 1;
}
for (i = 0; i < 3; i++)
{
//土
blocks[6][0].space[1][1] = 1;
blocks[6][0].space[2][i] = 1;
}
//根据7种基本形态衍生的其他方块
for (base_ = 0; base_ < 7; base_++)
{
for (spinsta_ = 0; spinsta_ < 3; spinsta_++)
{
for (i = 0; i < DIA; i++)
{
for (j = 0;j < DIA; j++)
{
temp[i][j] = blocks[base_][spinsta_].space[i][j];
}
}
for (i = 0; i < DIA; i++)
{
for (j = 0; j < DIA; j++)
{
blocks[base_][spinsta_+1].space[i][j] = temp[4-1-j][i];
}
}
}
}
return 0;
}
void Next_blocks() //下一个方块的打印
{
int i, j;
int x, y;
for (j = 0, y = (129-32); y >= 1; j++, y -= 32)
{
for (i = 0, x = 25; x < 126; i++, x += 32)
{
if (blocks[base_next][0].space[i][j] == 1)
{
Select_colour(&colour_next);
lcdDrawRectangle(x, y, 30, 30, colour_next);
continue;
}
lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
}
}
}
int Read_record() //从文件中读取最高记录
{
FILE *fps = NULL;
FILE *fpd = NULL;
char buff[BUFFSIZE] = {0};
int n = 0;
fps = fopen(FILENAME,"r+");
if (fps == NULL)
{
perror("fopen()");
exit(1);
}
fgets(buff,BUFFSIZE,fps);
n = atoi(buff);
if (grade > n)
{
fpd = fopen(FILENAME,"w+");
if (fpd == NULL)
{
perror("fopen()");
exit(1);
}
fprintf(fpd,"%d",grade);
fclose(fpd);
}
fclose(fps);
return n;
}
/* 根据分数打印相应图片 */
static void get_score(int number, int temp)
{
int i, x, y;
int buf[4] = {0};
char Name[126] = {0};
int k = 0;
if (number < 10000)
{
do
{
buf[k++] = number % 10;
number /= 10;
} while (number);
}
if (grade > 0 && grade % 100 == 0) //每一100分等级加一
{
level++;
}
if (temp == 1)
{
for (i = 0, x = 217, y = 1; i < 4; i++, y += 32)
{
sprintf(Name,"%s%d.bmp","/home/ll/ols/",buf[i]);
lcdDisplayPictures(Name, x, y);
}
}
else if (temp == 0)
{
for (i = 0, x = 313, y = 1; i < 4; i++, y += 32)
{
sprintf(Name,"%s%d.bmp","/home/ll/ols/",buf[i]);
lcdDisplayPictures(Name, x, y);
}
}
}
void Grade_print(int grade) //打印成绩
{
get_score(grade, 0);
get_score(Read_record(), 1);
}
void Select_colour(int *select) //颜色选择函数
{
switch (*select)
{
case 0:
{
*select = 0xff0000;
break;
}
case 1:
{
*select = 0xff00;
break;
}
case 2:
{
*select = 0xff;
break;
}
case 3:
{
*select = 0xa020f0;
break;
}
case 4:
{
*select = 0xff34b3;
break;
}
}
}
void Ols_load() //方块赋值给棋盘
{
int i, j;
for (i = 0; i < DIA; i++)
{
for (j = 0;j < DIA; j++)
{
if (Els[i+row_][line_+j] != 2) //防止覆盖已经下落完成的方块
Els[i+row_][line_+j] = blocks[base][spinsta].space[i][j];
}
}
trave_();
}
void trave_() //根据棋盘数值打印相对应的颜色
{
int i, j;
int x, y;
int colour_cur = 0;
for (j = 2, y = (465-32); y >= 145; j++, y -= 32)
{
for (i = 2, x = 25; x < 505; i++, x += 32)
{
if (Els[i][j] == 1) //表示正在下落的方块
{
Select_colour(&colour);
lcdDrawRectangle(x, y, 30, 30, colour);
}
else if(Els[i][j] == 2) //已经下落完成的方块
{
Select_colour(&colour_[i][j]);
lcdDrawRectangle(x, y, 30, 30, colour_[i][j]);
}
else
lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
}
}
}
static void alrmAction(int s, siginfo_t *infop, void *unused) //信号控制函数,内为下落函数
{
if (over || (stop_ == 0) || (infop->si_code != SI_KERNEL))
return ;
if (Judge_move(MOVE_DOWN) == 1)
Exec_command(MOVE_DOWN);
else
{
stop_ = 0;
}
}
int Set_time() //根据等级设置下落速度并用信号控制并发
{
struct sigaction sa;
sa.sa_sigaction = alrmAction;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGALRM, &sa, NULL);
if (level == 1)
{
struct itimerval new = {{0,800000},{0,800000}};
setitimer(ITIMER_REAL,&new,NULL);
}
else if (level == 2)
{
struct itimerval new = {{0,600000},{0,600000}};
setitimer(ITIMER_REAL,&new,NULL);
}
else if (level >= 3)
{
struct itimerval new = {{0,500000},{0,500000}};
setitimer(ITIMER_REAL,&new,NULL);
}
FLAG = -1;
while(stop_)
{
if (FLAG < 0)
continue;
switch(FLAG)
{
//退出
case PAUSE:
Game_pause();
break;
case CHANGE: //变形
if (Judge_chage() == 1)
Exec_command(CHANGE);
break;
case MOVE_LEFT: //左移
if (Judge_move(MOVE_LEFT) == 1)
Exec_command(MOVE_LEFT);
break;
case MOVE_RIGHT://右移
if (Judge_move(MOVE_RIGHT) == 1)
Exec_command(MOVE_RIGHT);
break;
case MOVE_DOWN: //加速下落
if (Judge_move(MOVE_DOWN) == 1)
{
Exec_command(MOVE_DOWN);
}
else
{
Judge_dis();
return 1;
}
default :
break;
}
FLAG = -1;
}
Judge_dis();
return 1;
}
void Game_pause() //游戏暂停
{
struct itimerval pause_ = {0}, old;
setitimer(ITIMER_REAL,&pause_,&old);
lcdDisplayPictures("/home/ll/ols/13.bmp", 385, 1);
FLAG = -1;
while(1)
{
if (FLAG == PAUSE)
break;
}
Interface();
Next_blocks();
setitimer(ITIMER_REAL,&old,NULL);
}
int Run() //运行函数
{
//初始化方块下落位置
int ret = 0;
spinsta = 0;
row_ = 2;
line_ = 6;
stop_ = 1;
//给下一个方块确定类型和颜色
srand((unsigned)time(NULL));
base_next = rand() % 7;
colour_next = rand() % 5;
Next_blocks();
//判断游戏是否结束
if (Judge_over() == 0)
{
return 0;
}
Ols_load();
//根据等级匹配下落速度
ret = Set_time();
base = base_next;
colour = colour_next;
return ret;
}
//游戏结束判断
int Judge_over()
{
int i, j;
//最上一格存在方块
for (j = 2; j < LINE-2; j++)
{
if (Els[2][j] == 2)
{
return 0;
}
}
//下一个方块不能进入棋盘
for (i = 0; i < DIA; i++)
{
for (j = 0; j < DIA; j++)
{
if (blocks[base][spinsta].space[i][j] == 1)
{
if (Els[row_+i][line_+j] == 2)
{
return 0;
}
}
}
}
return 1;
}
//判断方块能否移动
int Judge_move(int move)
{
int i, j;
int f_row,f_line;
switch(move)
{
case 1: //left
f_row = 0;
f_line = -1;
break;
case 2: //right
f_row = 0;
f_line = 1;
break;
case 3: //down
f_row = 1;
f_line = 0;
break;
}
for (i = 0; i < DIA; i++)
{
for (j = 0; j < DIA; j++)
{
if (Els[row_+i][line_+j] == 1)
{
if (Els[row_+i+f_row][line_+j+f_line] == 2)
{
return 0;
}
}
}
}
return 1;
}
//判断方块是否能旋转
int Judge_chage()
{
int i, j;
int count = 0;
if (spinsta+1 > 3)
spinsta = -1;
for (i = 0; i < DIA; i++)
{
for (j = 0; j < DIA; j++)
{
if (blocks[base][spinsta+1].space[i][j] == 1)
{
if (Els[row_+i][line_+j] != 2)
{
count++;
if (count == 4)
{
return 1;
}
}
}
}
}
return 0;
}
void Judge_dis()
{
int i, j;
int count = 0;
int temp = 0;
int flag = 0;
int n = 0;
int score = 0;
//下落完成的方块记录颜色并赋值为2
for (i = 2; i < ROW-2; i++)
{
for (j = 2; j < LINE-2; j++)
{
if (Els[i][j] == 1)
{
Els[i][j] = 2;
colour_[i][j] = colour;
}
}
}
//判断是否能消行
for (i = ROW-3; i >= 2; i--)
{
count = 0;
flag = 0;
for (j = 2; j < LINE-2; j++)
{
if (Els[i][j] == 2)
{
count++;
}
}
if (count == 10)
{
temp = i;
Exec_dis(temp);
n++;
grade += 10;
i = temp+1; //i从原来位置重新判断
flag = 1;
}
if (flag)
score += n*10;
}
if (n >= 2)
grade += score;
Grade_print(grade);
trave_();
}
//执行命令
void Exec_command(int command)
{
switch(command)
{
case 0: //旋转
spinsta++;
Dis_last(command);
break;
case 1: //左移
line_--;
Dis_last(command);
break;
case 2: //右移
line_++;
Dis_last(command);
break;
case 3: //下落
row_++;
Dis_last(command);
}
}
//执行消行
void Exec_dis(int row)
{
int i, j;
for (j = 2;j < LINE-2; j++)
{
Els[row][j] = 0;
}
for (i = row; i > 2; i--)
{
for (j = 2; j < LINE-2; j++)
{
Els[i][j] = 0;
Els[i][j] = Els[i-1][j];
}
}
}
void Dis_last(int flag) //消除上个状态
{
int i, j;
int last_row, last_line;
//变形
if (flag == 0)
{
last_row = 0;
last_line = 0;
}
//左移
else if(flag == 1)
{
last_row = 0;
last_line = 1;
}
//右移
else if(flag == 2)
{
last_row = 0;
last_line = -1;
}
//下移
else
{
last_row = -1;
last_line = 0;
}
for (i = 0; i < DIA; i++)
{
for (j = 0; j < DIA; j++)
{
if (Els[i+row_+last_row][line_+j+last_line] != 2)
Els[i+row_+last_row][line_+j+last_line] = 0;
}
}
Ols_load();
}
Makefile
TARGET := main
CC := arm-linux-gnueabi-gcc
INCLUDE := -I/usr/local/include
LDFLAGS := -L/usr/local/lib
LIBS := -lframebuffer -lpthread
SRC := $(wildcard *.c)
DEPEND := $(patsubst %.c, %.o, $(SRC))
$(TARGET) : $(DEPEND)
$(CC) $^ -o $@ $(LIBS)
%.o : %.c
$(CC) -c $< $(INCLUDE) $(LDFLAGS) -o $@
.PHONY:clean
clean:
$(RM) $(TARGET) $(DEPEND) -r
.PHONY:install
install:
mv $(TARGET) /mnt/hgfs/share/code