闲着没事,写的俄罗斯方块。
运行于ucosii+x86pc。显示界面为字符表示
/*
*description: 基于ucosii+x86pc的俄罗斯方块
*create data: 2015.7.12
*author: jalen_king
*/
#include "includes.h"
#ifndef NULL
#define NULL 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define LEFT 1
#define RIGHT 2
#define DOWN 3
#define CHANGE 4
#define DEFAULT_INIT_POSITION_X 5
#define DEFAULT_INIT_POSITION_Y 20
#define BLOCK_COUNT 7 /*block的种类*/
const char block_form[BLOCK_COUNT] = {2, 1, 4, 4, 4, 2, 2}; /*每种block的可变换样式个数*/
/*
**** 竖block的形状坐标
*/
const char block0[2][4][2] = {
{{-1,0},{0,0},{1,0}, {2,0}},
{{0,1},{0,0},{0,-1}, {0,-2}}
};
/*
** 方块
**
*/
const char block1[1][4][2] = {
{{-1,0},{0,0},{-1,-1}, {0,-1}}
};
/*
*
***
*/
const char block2[4][4][2] = {
{{1,1},{-1,0},{0,0}, {1,0}},
{{0,1},{1,1},{0,0},{0,-1}},
{{-1,0},{0,0},{1,0},{-1,-1}},
{{0,1},{0,0},{-1,-1},{0,-1}}
};
/*
***
*
*/
const char block3[4][4][2] = {
{{-1,0},{0,0},{1,0},{-1,-1}},
{{-1,1},{0,1},{0,0},{0,-1}},
{{1,1},{-1,0},{0,0},{1,0}},
{{0,1},{0,0},{0,-1},{1,-1}}
};
/*
***
*
*/
const char block4[4][4][2] = {
{{-1,0},{0,0},{1,0}, {0,-1}},
{{0,1},{-1,0},{0,0},{0,-1}},
{{0,1},{-1,0},{0,0},{1,0}},
{{0,1},{0,0},{1,0},{0,-1}}
};
/*
**
**
*/
const char block5[2][4][2] = {
{{-1,0},{0,0},{0,-1}, {1,-1}},
{{0,1},{-1,0},{0,0}, {-1,-1}}
};
/*
**
**
*/
const char block6[2][4][2] = {
{{0,0},{1,0},{-1,-1}, {0,-1}},
{{-1,1},{-1,0},{0,0}, {0,-1}}
};
typedef struct {
char type; //block的形状
char form; //当前变换形状的状态
char position_x; //当前所处的x坐标
char position_y; //当前所处的y坐标
char (*body_offset)[4][2]; //block自身包含各点的相对坐标
}block_t;
#define MAX_SPEED 1000
#define GAME_MAP_X 10 //游戏宽
#define GAME_MAP_Y 20 //游戏高
char game_map[GAME_MAP_X][GAME_MAP_Y + 4] = {0}; //游戏主界面
//block_t block;
int grade = 0; //成绩
int speed = MAX_SPEED; //速率初始1s
/*获取方块为type型的form状态的偏移*/
void * get_body_offset(char type, char form)
{
switch(type) {
case 0: return (void *)&block0[form];//break;
case 1: return (void *)&block1[form];//break;
case 2: return (void *)&block2[form];//break;
case 3: return (void *)&block3[form];//break;
case 4: return (void *)&block4[form];//break;
case 5: return (void *)&block5[form];//break;
case 6: return (void *)&block6[form];//break;
default : return -1;
}
//return 0;
}
void display_next(block_t *block) /*显示方块*/
{
int i;
int x,y;
for(x = 15; x <= 18; x++) {
for(y = 13; y <= 16; y++) {
PC_DispChar(x, GAME_MAP_Y - y, ' ', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
}
}
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + 16;
y = (*block->body_offset)[i][1]+ 15;
PC_DispChar(x, GAME_MAP_Y - y, '*', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
}
}
void display_block(block_t *block, char enable) /*显示方块*/
{
int i;
int x,y;
char (*offset)[4][2];
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + block->position_x;
y = (*block->body_offset)[i][1]+ block->position_y;
if(enable == TRUE) {
PC_DispChar(x, GAME_MAP_Y - y, '*', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
} else {
PC_DispChar(x, GAME_MAP_Y - y, ' ', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
}
}
}
int create_new_block(block_t *block) /*生成新块*/
{
char buf[64];
char type,form;
if(block == NULL) {
return FALSE;
}
type = random(BLOCK_COUNT);
form = random(block_form[type]);
block->type = type;
block->form = form;
block->position_x = DEFAULT_INIT_POSITION_X;
block->position_y = DEFAULT_INIT_POSITION_Y;
block->body_offset = get_body_offset(type, form);
return TRUE;
}
/*描述:block移动
*返回值:0 可以,-1 不可以
*/
int block_move(block_t *block, char direct)
{
if(block == NULL) {
return FALSE;
}
display_block(block, FALSE); // 去除旧的显示
switch(direct) {
case LEFT: block->position_x--; break;
case RIGHT: block->position_x++; break;
case DOWN: block->position_y--; break;
default : return FALSE;
}
display_block(block, TRUE); //显示新的
return TRUE;
}
/*描述:判断当前block是否可以继续下降
*返回值:0 可以,-1 不可以
*/
int block_move_down(block_t *block)
{
int i;
int x = 0,y = 0;
if(block == NULL) {
return FALSE;
}
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + block->position_x;
y = (*block->body_offset)[i][1] + block->position_y;
y--; //(x,y-1)
if(y >= GAME_MAP_Y) {
//continue;
}
if(y < 0 || game_map[x][y] != NULL) { //判断(x,y-1)的位置有没有方块
return FALSE; //如果有方块,则不能下移
}
}
return block_move(block, DOWN);
}
/*描述:判断当前block是否可以继续下降
*返回值:0 可以,-1 不可以
*/
int block_move_left(block_t *block)
{
int i;
int x,y;
if(block == NULL) {
return FALSE;
}
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + block->position_x;
y = (*block->body_offset)[i][1] + block->position_y;
x--; //(x-1,y)
if(y >= GAME_MAP_Y) {
continue;
}
if(x < 0 || game_map[x][y] != NULL) { //判断(x-1,y)的位置有没有方块
return FALSE; //如果有方块,则不能移
}
}
return block_move(block, LEFT);
}
/*描述:判断当前block是否可以继续下降
*返回值:0 可以,-1 不可以
*/
int block_move_right(block_t *block)
{
int i;
int x,y;
if(block == NULL) {
return FALSE;
}
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + block->position_x;
y = (*block->body_offset)[i][1] + block->position_y;
x++; //(x+1,y)
if(x >= GAME_MAP_X || game_map[x][y] != NULL) { //判断(x+1,y)的位置有没有方块
return FALSE; //如果有方块,则不能移
}
}
return block_move(block, RIGHT);
}
/*描述:判断当前block是否可以旋转
*返回值:0 可以,-1 不可以
*/
int block_spin(block_t *block)
{
char buf[24];
int i;
int x,y;
int tmp_x, tmp_y;
int form;
char (*body_offset)[4][2];
if(block == NULL) {
return FALSE;
}
form = (block->form + 1) % block_form[block->type];
if(form == block->form) { //如果变换后还是它自身则直接返回。
return TRUE;
}
tmp_x = block->position_x;
tmp_y = block->position_y;
body_offset = get_body_offset(block->type, form); //取得变换后的坐标偏移
for(i = 0; i < 4; i++) {
x = (*body_offset)[i][0] + tmp_x;
y = (*body_offset)[i][1] + tmp_y;
if(x < 0) {
tmp_x = tmp_x - x;
}
if(x >= GAME_MAP_X) {
tmp_x = tmp_x - (x - GAME_MAP_X + 1);
}
if(y < 0) {
tmp_y = tmp_y - y;
}
}
for(i = 0; i < 4; i++) {
x = (*body_offset)[i][0] + tmp_x;
y = (*body_offset)[i][1] + tmp_y;
if(game_map[x][y] != NULL) { //判断(x,y)的位置有没有方块
return FALSE; //如果有方块,则不能变
}
}
display_block(block, FALSE);
block->position_x = tmp_x;
block->position_y = tmp_y;
block->form = form;
block->body_offset = body_offset;//get_body_offset(block->type, form);
display_block(block, TRUE);
return TRUE;
}
/*描述:获取用户按键
*返回值:a==change, s== left,d==down, f==right,esc==quit, -1
*/
char get_ch()
{
INT16S key = 0;
if (kbhit()) { /* See if a key has been pressed */
key = (INT16S)getch(); /* Get key pressed */
switch(key) {
case 97: return CHANGE;//break; \\space
case 115: return LEFT;//break;
case 102: return RIGHT;//break;
case 100: return DOWN;//break;
case 27: PC_DOSReturn();//break;
default: return -1;//break;
}
}
return -1;
}
/*描述:sleep,s为毫秒
*返回值:
*/
void my_sleep(int s)
{
if(s >= 1000) {
OSTimeDlyHMSM(0, 0, s/1000, 0);
} else {
OSTimeDlyHMSM(0, 0, 0, s);
}
}
/*描述:显示(刷新)游戏界面
*返回值:
*/
void display_game_map()
{
int x,y;
for(x = 0; x < GAME_MAP_X; x++) {
for(y = 0; y < GAME_MAP_Y; y++) {
if(game_map[x][y] == 1) {
PC_DispChar(x, GAME_MAP_Y - y, '*', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
} else {
PC_DispChar(x, GAME_MAP_Y - y, ' ', DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
}
}
}
}
/*描述:显示(刷新)成绩
*返回值:
*/
void display_grade()
{
char buf[24];
sprintf(buf, "grade: %-3d",grade);
PC_DispStr( 15, 16, buf, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
}
/*描述:消除行
*返回值:
*/
void clear_line(int line)
{
int x,y;
for(y = line; y < GAME_MAP_Y; y++) {
for(x = 0; x < GAME_MAP_X; x++) {
game_map[x][y] = game_map[x][y+1];
}
}
}
/*描述:刷新游戏下降速率
*返回值:
*/
void change_speed()
{
int level = 0;
level = grade / 200;
speed = MAX_SPEED - 100 * level;
}
/*描述:处理游戏结果
*返回值:
*/
int process_result(block_t *block)
{
int i;
int x,y;
char buf[64];
for(i = 0; i < 4; i++) {
x = (*block->body_offset)[i][0] + block->position_x;
y = (*block->body_offset)[i][1] + block->position_y;
if(y >= GAME_MAP_Y) {
goto OVER;
}
game_map[x][y] = 1;
}
for(y = 0; y < GAME_MAP_Y; ) {
for(x = 0; x < GAME_MAP_X; x++) {
if(game_map[x][y] != 1) {
y++;
break;
}
}
if(x == GAME_MAP_X) {
clear_line(y); //消除行
grade += GAME_MAP_X; //计算得分
}
}
change_speed();
display_game_map();
display_grade();
return 0;
OVER: //游戏结束
sprintf(buf, "GAME OVER");
PC_DispStr( 15, 15, buf, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
sprintf(buf, "grade :%-3d", grade);
PC_DispStr( 15, 16, buf, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
while(1) {
get_ch();
}
}
/*描述:主任务进程
*返回值:
*/
void block_task(void *pdata)
{
int ret = 0;
char ch = 0;
block_t block, block_next;
int game_start = 0;
pdata = pdata;
memset(game_map, 0, GAME_MAP_X * (GAME_MAP_Y + 4));
display_game_map();
display_grade();
for(;;) {
if(game_start == 0) {
create_new_block(&block);
create_new_block(&block_next);
game_start = 1;
} else {
memcpy(&block, &block_next, sizeof(block_t));
create_new_block(&block_next);
}
display_next(&block_next);
for(;;) {
ch = get_ch();
switch(ch) {
case LEFT: block_move_left(&block); break;
case RIGHT: block_move_right(&block);break;
case DOWN:
ret = block_move_down(&block);
if(ret != TRUE) {
goto OVER;
}
break;
case CHANGE: block_spin(&block); break;
default:
ret = block_move_down(&block);
if(ret != TRUE) {
goto OVER;
}
my_sleep(speed);
break;
}
}
OVER:
process_result(&block);
}
}
/***=======================以下为ucosii的系统初始化代码============================**/
#define TASK_STK_SIZE 1024*10
OS_STK TaskStk[TASK_STK_SIZE]; /* Tasks stacks */
OS_STK TaskStartStk[TASK_STK_SIZE];
static void TaskStartDispInit (void)
{
PC_DispStr( 0, 22, "#Tasks : CPU Usage: % ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
PC_DispStr( 0, 23, "#Task switch/sec: ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);
PC_DispStr( 0, 24, " <-PRESS 'ESC' TO QUIT-> ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY + DISP_BLINK);
/* 1111111111222222222233333333334444444444555555555566666666667777777777 */
/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
}
static void TaskStartDisp (void)
{
char s[80];
sprintf(s, "%5d", OSTaskCtr); /* Display #tasks running */
PC_DispStr(18, 22, s, DISP_FGND_YELLOW + DISP_BGND_BLUE);
#if OS_TASK_STAT_EN > 0
sprintf(s, "%3d", OSCPUUsage); /* Display CPU usage in % */
PC_DispStr(36, 22, s, DISP_FGND_YELLOW + DISP_BGND_BLUE);
#endif
sprintf(s, "%5d", OSCtxSwCtr); /* Display #context switches per second */
PC_DispStr(18, 23, s, DISP_FGND_YELLOW + DISP_BGND_BLUE);
sprintf(s, "V%1d.%02d", OSVersion() / 100, OSVersion() % 100); /* Display uC/OS-II's version number */
PC_DispStr(75, 24, s, DISP_FGND_YELLOW + DISP_BGND_BLUE);
switch (_8087) { /* Display whether FPU present */
case 0:
PC_DispStr(71, 22, " NO FPU ", DISP_FGND_YELLOW + DISP_BGND_BLUE);
break;
case 1:
PC_DispStr(71, 22, " 8087 FPU", DISP_FGND_YELLOW + DISP_BGND_BLUE);
break;
case 2:
PC_DispStr(71, 22, "80287 FPU", DISP_FGND_YELLOW + DISP_BGND_BLUE);
break;
case 3:
PC_DispStr(71, 22, "80387 FPU", DISP_FGND_YELLOW + DISP_BGND_BLUE);
break;
}
}
static void TaskStartCreateTasks (void)
{
OSTaskCreate(block_task, 0, &TaskStk[TASK_STK_SIZE - 1], 1);
}
void TaskStart (void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
char s[100];
INT16S key;
pdata = pdata; /* Prevent compiler warning */
TaskStartDispInit(); /* Initialize the display */
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR); /* Install uC/OS-II's clock tick ISR */
PC_SetTickRate(OS_TICKS_PER_SEC); /* Reprogram tick rate */
OS_EXIT_CRITICAL();
OSStatInit(); /* Initialize uC/OS-II's statistics */
TaskStartCreateTasks(); /* Create all the application tasks */
for (;;) {
TaskStartDisp(); /* Update the display */
// if (PC_GetKey(&key) == TRUE) { /* See if key has been pressed */
if (key == 0x1B) { /* Yes, see if it's the ESCAPE key */
PC_DOSReturn(); /* Return to DOS */
}
//}
OSCtxSwCtr = 0; /* Clear context switch counter */
OSTimeDlyHMSM(0, 0, 1, 0); /* Wait one second */
}
}
void main (void)
{
PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK); /* Clear the screen */
OSInit(); /* Initialize uC/OS-II */
PC_DOSSaveReturn(); /* Save environment to return to DOS */
PC_VectSet(uCOS, OSCtxSw); /* Install uC/OS-II's context switch vector */
OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 0);
OSStart(); /* Start multitasking */
}