俄罗斯方块 linux c

本博客介绍了一个基于控制台的游戏开发项目,使用C语言实现了一款类似俄罗斯方块的游戏。通过控制台API实现了游戏界面的绘制、键盘输入检测等功能,并详细展示了如何通过控制台命令进行光标的移动、颜色设置等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


#include <string.h>

#include <stdlib.h>

#include <stdio.h>

#include <termios.h>

#include <sys/time.h>

#include <sys/ioctl.h>

//#include <unistd.h>

//#include <sys/types.h>

//#include <stropts.h>

//#include <sys/select.h>

/*"▣" "▣" "▊" "■" */

#define NONE          "\33[m"   

#define RED           "\33[0;32;31m"   

#define LIGHT_RED     "\33[1;31m"   

#define GREEN         "\33[0;32;32m"   

#define LIGHT_GREEN   "\33[1;32m"   

#define BLUE          "\33[0;32;34m"   

#define LIGHT_BLUE    "\33[1;34m"   

#define DARY_GRAY     "\33[1;30m"   

#define CYAN          "\33[0;36m"   

#define LIGHT_CYAN    "\33[1;36m"   

#define PURPLE        "\33[0;35m"   

#define LIGHT_PURPLE "\33[1;35m"   

#define BROWN         "\33[0;33m"   

#define YELLOW        "\33[1;33m"   

#define LIGHT_GRAY    "\33[0;37m"   

#define WHITE         "\33[1;37m"   


#define ENTER "\n"


// 清除屏幕

#define CLEAR() printf("\33[2J") 

//清除从光标位置到行末的内容

#define CLEAR_TAIL() printf("\33[K"); 

// 上移光标 

#define MOVE_UP(x) printf("\33[%dA", (x)) 

// 下移光标 

#define MOVE_DOWN(x) printf("\33[%dB", (x)) 

// 左移光标 

#define MOVE_LEFT(y) printf("\33[%dD", (y)) 

// 右移光标 

#define MOVE_RIGHT(y) printf("\33[%dC",(y)) 

// 定位光标 

#define MOVETO(x,y) printf("\33[%d;%dH", (x), (y)) 

// 光标复位 

#define RESET_CURSOR() printf("\33[H") 

// 隐藏光标 

#define HIDE_CURSOR() printf("\33[?25l") 

// 显示光标 

#define SHOW_CURSOR() printf("\33[?25h") 

//反显

#define HIGHT_LIGHT() printf("\33[7m")

#define UN_HIGHT_LIGHT() printf("\33[27m")



#define STDIN 0

#define NUM_MAX_KEY 25

#define TIME_SLEEP (500 * 1000) //ms

#define NUM_MAX_Y 20

#define NUM_MAX_X 10

#define NUM_BOX 4

#define CHAR_A 'a'

#define CHAR_D 'd'

#define CHAR_S 's'

#define CHAR_Q 'q'

#define CHAR_SPACE ' '

#define CHAR_LEFT 0x44

#define CHAR_RIGHT 0x43

#define CHAR_DOWN 0x42

#define STR_BOX "▣"

#define STR_FRAME_X "-"

#define STR_FRAME_Y "|"

#define STR_POINT "."


typedef struct t_box

{

int x; 

int y;

}t_box;        //坐标


static t_box box[NUM_BOX]; 


static int s_score;

static struct termios st_tr_save;

static char s_buf_point[NUM_MAX_Y][NUM_MAX_X];


static void termios_init()

{

struct termios tmp;

tcgetattr(STDIN, &st_tr_save);

tmp=st_tr_save;


tmp.c_lflag &= ~ECHO;

tmp.c_lflag &= ~ICANON;


tcsetattr(STDIN, TCSANOW, &tmp);

}


static void termios_recover()

{

tcsetattr(STDIN, TCSANOW, &st_tr_save);

}


static int get_key(char *key, int *num_key)

{

int ret, num, i, cnt = 0;

fd_set fds;

struct timeval tv;

char buf[NUM_MAX_KEY] = {0};

*num_key = 0;

FD_ZERO(&fds);

FD_SET(STDIN, &fds);   //文件描述符0表示STDIN键盘输入

tv.tv_sec = 0;

tv.tv_usec = TIME_SLEEP;

ret = select(STDIN + 1, &fds, NULL, NULL, &tv); //第一个参数是监控句柄号+1

if(0 >= ret) 

return ret;

if(!FD_ISSET(STDIN, &fds)) //监控输入的确是已经发生了改变

return ret;

num = read(STDIN, buf, NUM_MAX_KEY);                 //从键盘读取输入

for (i = 0; i < num; i++) { /* a s d 空格 */

if ((CHAR_A == buf[i]) || (CHAR_S == buf[i]) || (CHAR_D == buf[i]) || (CHAR_SPACE == buf[i]) || (CHAR_Q == buf[i]))

key[cnt++] = buf[i];

/*0x1b5b 方向键控制符,thinkpad是 0x5b 0x1b5b41 up(完整键值) 42 down 43 right  44 left*/

else if (0x5b == buf[i]) {

if ((CHAR_DOWN <= buf[i + 1]) && (CHAR_LEFT >= buf[i + 1]))

key[cnt++] = buf[++i];

}

}

*num_key = cnt;

return ret;

}



static int deal_score()

{

int i, j, flg;

for (i = 0; i < NUM_MAX_Y; i++) {

flg = 1;

for (j = 0; j < NUM_MAX_X; j++) {

if (0 == s_buf_point[i][j]) {

flg = 0;

break;

}

}

if (flg) {

s_score++;

for (j = i; j > 0; j--) {

memcpy(s_buf_point[j], s_buf_point[j - 1], sizeof(s_buf_point[j]));

}

memset(s_buf_point[0], '\0', sizeof(s_buf_point[0]));

}

}

return 0;

}



static int cp_box()

{

int i;

for (i = 0; i < NUM_BOX; i++) {

s_buf_point[box[i].y][box[i].x] = 1;

box[i].x = 0;

box[i].y = 0;

}

return 0;

}


static int key_left()

{

int i;

t_box tmp[NUM_BOX]; 

memcpy(tmp, box, sizeof(box));

for (i = 0; i < NUM_BOX; i++) {

tmp[i].x--;

if (0 > tmp[i].x) 

return -1;

if (1 == s_buf_point[tmp[i].y][tmp[i].x])

return -1;

}

for (i = 0; i < NUM_BOX; i++) {

box[i].x--;

}

return 0;

}


static int key_right()

{

int i;

t_box tmp[NUM_BOX]; 

memcpy(tmp, box, sizeof(box));

for (i = 0; i < NUM_BOX; i++) {

tmp[i].x++;

if (NUM_MAX_X <= tmp[i].x) 

return -1;

if (1 == s_buf_point[tmp[i].y][tmp[i].x])

return -1;

}

for (i = 0; i < NUM_BOX; i++) {

box[i].x++;

}

return 0;

}


static int key_down()

{

int i, k, ret = 0;

t_box tmp[NUM_BOX]; 

memcpy(tmp, box, sizeof(box));

for (i = 0; i < NUM_BOX; i++) {

tmp[i].y++;

if (NUM_MAX_Y <= tmp[i].y) {

cp_box();

deal_score();

return 1;

}

if (1 == s_buf_point[tmp[i].y][tmp[i].x]) {

if (1 == tmp[i].y)

return -1;

cp_box();

deal_score();

return 1;

}

}

for (i = 0; i < NUM_BOX; i++) {

box[i].y++;

}

return 0;

}


static int key_revolve()

{

int i, x, y;

t_box tmp[NUM_BOX], center; 

memcpy(tmp, box, sizeof(box));

center = box[0];

for (i = 0; i < NUM_BOX; i++) {

x = tmp[i].x - center.x; 

y = tmp[i].y - center.y;

tmp[i].x = center.x + y; 

tmp[i].y = center.y - x;

}

for (i = 0; i < NUM_BOX; i++) {

if (NUM_MAX_X <= tmp[i].x || 0 > tmp[i].x) 

return -1;

if (1 == s_buf_point[tmp[i].y][tmp[i].x])

return -1;

}

for (i = 0; i < NUM_BOX; i++) {

x = box[i].x - center.x; 

y = box[i].y - center.y;

box[i].x = center.x + y; 

box[i].y = center.y - x;

}

return 0;

}

 


static int deal_key(char *buf, int num)

{

int i, ret;

for (i = 0; i < num; i++) {

switch(buf[i]) {

case CHAR_A:

case CHAR_LEFT:

key_left();

break;

case CHAR_D:

case CHAR_RIGHT:

key_right();

break;

case CHAR_SPACE:

key_revolve();

break;

case CHAR_S:

case CHAR_DOWN:

ret = key_down();

if (0 > ret)

return ret;

break;

case CHAR_Q:

return -1;

default:

break;

}

}

if (0 >= num){

ret = key_down();

if (0 > ret)

return ret;

}

return 0;

}





static int paint_box(int y, int x)

{

int i;

if (box[0].x == box[1].x && box[0].y == box[1].y)

return -1;

for(i = 0; i < NUM_BOX; i++) {

if (x == box[i].x && y == box[i].y) {

printf(BLUE STR_BOX NONE);

return 0;

}

}

return -1;

}

static int paint()

{

int i, j, k, ret;


//printf("\033[0;0H\033[K");

MOVETO(0,0);

for(i = 0; i < NUM_MAX_X + 2; i++) 

printf(RED STR_FRAME_X NONE);

//printf("\33[0;%dH\33[K-",i);

CLEAR_TAIL();

printf(ENTER);

for(i = 0; i < NUM_MAX_Y; i++) {

printf(RED STR_FRAME_Y NONE);

for(j=0; j < NUM_MAX_X; j++) {

if(0 == s_buf_point[i][j]) {

ret = paint_box(i, j);

if (ret)

printf(STR_POINT);

} else 

printf(BLUE STR_BOX NONE);

}

if(10 == i)

printf(RED STR_FRAME_Y "    得分: %d" NONE, s_score);

else if(7 == i)

printf(RED STR_FRAME_Y NONE LIGHT_BLUE"    Press 'q' to quit!" NONE);

else

printf(RED STR_FRAME_Y NONE);

CLEAR_TAIL();

printf(ENTER);

}

for(i = 0; i < NUM_MAX_X + 2; i++) 

printf(RED STR_FRAME_X NONE);

CLEAR_TAIL();


fflush(stdout);

return 0;

}



static int create_box()

{

int i;

for (i = 0; i < NUM_BOX; i++) {

if (box[i].x || box[i].y) 

return -1;

}

srand((unsigned)time(NULL)); 

i = 1+ rand() % 7;

switch(i) {

case 1: //L

box[0].x = NUM_MAX_X / 2; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2; 

box[1].y = 1;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 2;

box[3].x = NUM_MAX_X / 2 + 1;

box[3].y = 2; 


break;

case 2: //反L

box[0].x = NUM_MAX_X / 2; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2 + 1; 

box[1].y = 0;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 1;

box[3].x = NUM_MAX_X / 2;

box[3].y = 2;  


break;

case 3: //Z

box[0].x = NUM_MAX_X / 2 - 1; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2; 

box[1].y = 0;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 1;

box[3].x = NUM_MAX_X / 2 + 1;

box[3].y = 1;  


break;

case 4: //反Z

box[0].x = NUM_MAX_X / 2; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2 + 1; 

box[1].y = 0;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 1;

box[3].x = NUM_MAX_X / 2 - 1;

box[3].y = 1;  


break;

case 5: //田

box[0].x = NUM_MAX_X / 2; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2 + 1; 

box[1].y = 0;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 1;

box[3].x = NUM_MAX_X / 2 + 1;

box[3].y = 1;  


break;

case 6: //1

box[0].x = NUM_MAX_X / 2; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2; 

box[1].y = 1;

box[2].x = NUM_MAX_X / 2; 

box[2].y = 2;

box[3].x = NUM_MAX_X / 2;

box[3].y = 3;  


break;

case 7: //山

box[0].x = NUM_MAX_X / 2 - 1; 

box[0].y = 0;

box[1].x = NUM_MAX_X / 2; 

box[1].y = 0;

box[2].x = NUM_MAX_X / 2 + 1; 

box[2].y = 0;

box[3].x = NUM_MAX_X / 2;

box[3].y = 1;  


break;

default: 

break;

}


return 0;

}



int main()

{

int ret, num;

char key[NUM_MAX_KEY];


fflush(stdout);

//system("clear");

CLEAR();

HIDE_CURSOR();

fflush(stdout);


termios_init();

while(1)

{

create_box();

ret = get_key(key, &num);

if (0 > ret) {

printf("err\n");

break;

}

ret = deal_key(key, num);

if (0 > ret) {

printf("game over!\n");

break;

}

// 保存光标貌似无效 printf光标移位好像0和1是一样的

ret = paint();

}

termios_recover();

return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值