2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 【无标题】用ubuntu通过c语言实现俄罗斯方块小游戏的方案及改进思路

【无标题】用ubuntu通过c语言实现俄罗斯方块小游戏的方案及改进思路

时间:2020-09-17 20:47:22

相关推荐

【无标题】用ubuntu通过c语言实现俄罗斯方块小游戏的方案及改进思路

实现俄罗斯方块

功能列表:

1 出边框

2 能在顶部随机出一个图形

3 图形共 (7种), 每种由4个方块组成

4 图形自动向下落

5 左移,右移,下移加速

6 旋转

7 当方块铺满1行,消行(上面下落)

8 当方块落到最下面时,出一个新的,原来的保留不动

9 加分、加等级、加速

10 提示下一个图形

11 暂停

12 触顶结束

13 颜色(变换)

14 计时

15 存档(以后实现)

实现方法:

显示带颜色的 俄罗斯方块

○■

属性列表如下:

通用格式控制:

0 重置所有属性 (恢复默认值)

1 高亮/加粗

2 暗淡

4 下划线

5 闪烁

7 反转

8 隐藏

前景色:

30 黑色

31 红色

32 绿色

33 黄色

34 蓝色

35 品红

36 青色

37 白色

如何指定光标位置打印

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

/// \033 打印属性设置

}如何打印出颜色

printf(“\033[1;33m★\033[0m”);

\033 打印属性设置

[1; 打印亮度 (1 高亮 2 暗淡)

#include <stdio.h>

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int main()

{

system(“clear”); //调用linux的 clear 命令

gotoxy(10, 15); //光标跳转到 x = 10, y = 15处

printf(“\033[1;31m○○○○\033[0m”);

gotoxy(30, 15);

printf(“\033[1;33m■■■■\033[0m”);

}

俄罗斯方块map(地图)

21 行 12列

int block[21][12] = { 0 };

1----> 边框○

2----> 方块■

0----> 空格

#include <stdio.h>

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int block[21][12] = { 0 }; //1----> 边框 //2----> 方块 //0----> 空格

void init_block() //初始化地图

{

int i;

for(i = 0; i < 21; i++)

{

block[i][0] = 1;

block[i][11] = 1;

}

for(i = 0; i < 12; i++)

{

block[0][i] = 1;

block[20][i] = 1;

}

}

void display_all() //显示地图

{

int i, j;

gotoxy(0, 0);

for(i = 0; i < 21; i++)

{

for(j = 0; j < 12; j++)

{

if(block[i][j] == 1)

printf(“\033[1;31m○ \033[0m”);

else if(block[i][j] == 2)

printf(“■ “);

else if(block[i][j] == 0)

printf(” “);

}

printf(”\n”);

}

}

int main()

{

system(“clear”);

init_block();

display_all();

}

英文字母: 8 * 16(横向8个点,纵向16个点),高是宽的2倍

AB

例1: “hello world” 自动往下走(每隔1秒钟,向下走一个坐标点)

x , y-----> gotoxy 指定坐标点 ----> 隔1秒,y++, 重新打印

#include <unistd.h>

sleep(1); //延时1秒

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int main()

{

int x = 0, y = 0;

while(1)

{

system(“clear”); //清屏, system linux系统库函数,它可以调用linux命令

gotoxy(x, y);

printf(“\033[1;31m○○○○○○\033[0m”);

fflush(stdout); //刷新屏幕

y++;

sleep(1); //延时1秒

}

}

如何实现非阻塞I/O

程序运行时不断打印hello world, 同时扫描键盘

要实现 hello world 每隔1秒往下走,同时扫描键盘,如果按下了 a, 左, 按下了d 右

例2: 用getchar实现接收键盘数据, 按下a, hello world左移, 按下 d, hello world右移 ,

同时 hello world自动 往下走

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int main()

{

int x = 5, y = 0, c;

while(1)

{

system(“clear”); //清屏, system linux系统库函数,它可以调用linux命令

gotoxy(x, y);

printf(“\033[1;31m○○○○○○\033[0m”);

fflush(stdout); //刷新屏幕

y++;

c = getchar(); //scanf(“%c”, &c); 他们都是阻塞I/O, 程序执行到这就停下来,等待输入

//getchar 不行,我们应该用非阻塞I/O, 即使没输入任何按键,程序仍然能往下走

if(c == ‘a’)

x–;

else if(c == ‘d’)

x++;

sleep(1); //延时1秒,时间有点长

}

}

阻塞I/O讲解 (程序运行到这个函数,就停下来)

getchar scanf

改成非阻塞I/O

#include <stdio.h>

#include <stdlib.h>

#define TTY_PATH “/dev/tty”

#define STTY_US "stty raw -echo -F "

#define STTY_DEF "stty -raw echo -F "

static int get_char() //能实现非阻塞IO, 如果没有按下按键,程序继续往下走

{

fd_set rfds;

struct timeval tv;

int ch = 0;

FD_ZERO(&rfds);FD_SET(0, &rfds);tv.tv_sec = 0;tv.tv_usec = 10; //设置等待超时时间//检测键盘是否有输入if (select(1, &rfds, NULL, NULL, &tv) > 0){ch = getchar(); }return ch;//返回按键值

}

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int main()

{

int x = 0, y = 0;

char ch;

system(STTY_US TTY_PATH); //不用理解

while(1)

{

system(“clear”);

gotoxy(x, y);

printf(“\033[1;31m○○○○○○\033[0m”);

fflush(stdout); //刷新屏幕

ch = get_char(); //换成get_char 非阻塞IO

if(ch == ‘d’)

x++;

else if(ch == 3) //ctrl + c

{

system(STTY_DEF TTY_PATH); //恢复非阻塞IO设置 //不用理解

return 0; //程序结束

}

y++;

//sleep(1); //延时1秒, 因为需要调速,此函数不行

usleep(300000); //以微妙为单位延时, 300ms (1s = 1000 ms 1ms = 1000us)

}

}

整合方案

#include <stdio.h>

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

int block[21][12] = { 0 }; //1----> 边框 //2----> 方块 //0----> 空格

void init_block() //初始化地图

{

int i;

for(i = 0; i < 21; i++)

{

block[i][0] = 1;

block[i][11] = 1;

}

for(i = 0; i < 12; i++)

{

block[0][i] = 1;

block[20][i] = 1;

}

}

void display_all() //显示地图

{

int i, j;

gotoxy(0, 0);

for(i = 0; i < 21; i++)

{

for(j = 0; j < 12; j++)

{

if(block[i][j] == 1)

printf(“\033[1;31m○ \033[0m”);

else if(block[i][j] == 2)

printf(“■ “);

else if(block[i][j] == 0)

printf(” “);

}

printf(”\n”);

}

}

int current_line = 1; //当前行

void new_point() //出一个新的方块 point 点

{

block[1][4] = 2;

block[1][5] = 2;

block[1][6] = 2;

block[1][7] = 2;

}

void point_move_down() //方块下落 ( y++ )

{

block[current_line][4] = 0;

block[current_line][5] = 0;

block[current_line][6] = 0;

block[current_line][7] = 0;

current_line++;

block[current_line][4] = 2;

block[current_line][5] = 2;

block[current_line][6] = 2;

block[current_line][7] = 2;

}

int main()

{

system(“clear”);

init_block();

new_point();

while(1)

{

display_all();

usleep(300000);

point_move_down();

}

}

方案改进

现在方案是通过填充二维数组实现的,但是在变形时,消除原来的图形是一个难点(工作量大)

新方案:

图形分成两部分

静态图形(边框, 当方块落到下面,就变成静态的)

用二维数组动态图形(新出的,向下落的,可以变换的)

用结构体数组

struct point_pos

{

int x;

int y;

};

struct point_pos point[4];

//更改之后的方案/

#include <stdio.h>

#include <stdlib.h>

#define TTY_PATH “/dev/tty”

#define STTY_US "stty raw -echo -F "

#define STTY_DEF "stty -raw echo -F "

static int get_char() //能实现非阻塞IO, 如果没有按下按键,程序继续往下走

{

fd_set rfds;

struct timeval tv;

int ch = 0;

FD_ZERO(&rfds);FD_SET(0, &rfds);tv.tv_sec = 0;//设置非阻塞I/O 等待时长(秒值)tv.tv_usec = 10; //设置等待超时时间 (微秒值)//检测键盘是否有输入if (select(1, &rfds, NULL, NULL, &tv) > 0){ch = getchar(); }return ch;//返回按键值

}

void gotoxy(int x, int y)

{

printf(“\033[%d;%dH”, y + 1, x + 1);

}

struct point_pos

{

int x;

int y;

};

struct point_pos point[4];

int speed = 10; //速度 值越大,越慢

int score = 0; //分数,每消1行 + 100分

int level = 1;

int block[21][12] = { 0 }; //1----> 边框 //2----> 方块 //0----> 空格

void init_block() //初始化地图

{

int i;

for(i = 0; i < 21; i++)

{

block[i][0] = 1;

block[i][11] = 1;

}

for(i = 0; i < 12; i++)

{

block[20][i] = 1;

}

}

void display_all() //显示地图

{

int i, j;

gotoxy(0, 0);

for(i = 0; i < 21; i++)

{

for(j = 0; j < 12; j++)

{

if(block[i][j] == 1)

printf(“\033[1;31m○ \033[0m”);

else if(block[i][j] == 2)

printf(“■ “);

else if(block[i][j] == 0)

printf(” “);

}

printf(”\r\n”);

}

}

int current_point = 0;

int current_status = 0; //对于横线来说 0(横) 1(竖)

void new_point() //出一个新的方块 point 点

{

current_point = rand() % 2; //current = 0 ####

if(current_point == 0) // = 1 ##

{ // ##

current_status = 0;

point[0].x = 4;

point[0].y = 0;

point[1].x = 5;

point[1].y = 0;

point[2].x = 6;

point[2].y = 0;

point[3].x = 7;

point[3].y = 0;

}

else if(current_point == 1)

{

point[0].x = 5;

point[0].y = 0;

point[1].x = 6;

point[1].y = 0;

point[2].x = 5;

point[2].y = 1;

point[3].x = 6;

point[3].y = 1;

}

}

void draw_point()

{

int i;

for(i = 0; i < 4; i++)

{

gotoxy(point[i].x * 2, point[i].y);

printf("■ ");

}

}

//将动态图形添加到静态二维数组中

void add_point_to_block()

{

int i;

for(i = 0; i < 4; i++)

{

block[point[i].y][point[i].x] = 2;

}

}

void clear_one_line(int line) //line 将要消除的行

{ //从被消除的行开始,每行往下移

int i, j;

for(i = line; i > 0; i–)

{

for(j = 0; j < 12; j++)

{

block[i][j] = block[i - 1][j];

}

}

}

void judge_clear_line() //判断是否消行

{ //从 下往上扫描,如果某一行满了(某行二维数组全是2 (10个)),消除

int i, j;

for(i = 19; i > 0; i–) //? i >= 0 or i > 0

{

int n = 0; //每次重新计数

for(j = 1; j < 11; j++)

{

if(block[i][j] == 2)

{

n++;

}

}

if(n == 10)

{

score += 100;

if(score % 500 == 0)

{

level++;

speed–;

if(speed < 1)

speed = 1;

}

clear_one_line(i); //消除一行

i++;

}

}

}

void point_move_down() //方块下落 ( y++ )

{

int i;

for(i = 0; i < 4; i++) //限制: 当y+1 的那个点如果正好碰到静态图形,就不下落

{

if(block[point[i].y + 1][point[i].x] != 0) //不好理解

{

add_point_to_block();

judge_clear_line(); //判断是否需要消行

new_point();

return; //结束整个函数

}

}

for(i = 0; i < 4; i++)

{

point[i].y++;

}

}

void point_move_left() //方块左移 ( x-- )

{

int i;

for(i = 0; i < 4; i++) //限制: 当y+1 的那个点如果正好碰到静态图形,就不下落

{

if(block[point[i].y][point[i].x - 1] != 0) //不好理解

return; //结束整个函数

}

for(i = 0; i < 4; i++)

{

point[i].x–;

}

}

void point_move_right() //方块右移 ( x++ )

{

int i;

for(i = 0; i < 4; i++) //限制: 当y+1 的那个点如果正好碰到静态图形,就不下落

{

if(block[point[i].y][point[i].x + 1] != 0) //不好理解

return; //结束整个函数

}

for(i = 0; i < 4; i++)

{

point[i].x++;

}

}

void change_point()

{

if(current_point == 0)

{

if(current_status == 0)

{

current_status = 1;

point[0].x++;

point[0].y–;

point[2].x–;

point[2].y++;

point[3].x -= 2;

point[3].y += 2;

}

else

{

current_status = 0;

point[0].x–;

point[0].y++;

point[2].x++;

point[2].y–;

point[3].x += 2;

point[3].y -= 2;

}

}

}

int game_over() //第一行如果有方块,游戏结束

{

int i;

for(i = 1; i < 11; i++)

{

if(block[0][i] == 2)

{

return 1;

}

}

return 0;

}

int main()

{

int i;

char ch;

srand(time(0));

system(STTY_US TTY_PATH); //不用理解

system(“clear”);

init_block();

new_point();

while(1)

{

display_all();

draw_point();

gotoxy(30, 0);

printf(“score:%d”, score);

gotoxy(30, 1);

printf(“level:%d”, level);

fflush(stdout); //刷新屏幕

for(i = 0; i < speed; i++) //speed = 10

{

ch = get_char(); //换成get_char 非阻塞IO

if(ch == ‘a’) //左移

{

point_move_left(); //左移

break;

}

else if(ch == ‘d’)

{

point_move_right(); //右移

break;

}

else if(ch == ‘s’)

{

break;

}

else if(ch == ‘w’)

{

change_point();

break; //如果不加break 会丢掉一个中间状态

}

else if(ch == 3) //ctrl + c

{

system(STTY_DEF TTY_PATH); //恢复非阻塞IO设置 //不用理解

return 0; //程序结束

}

usleep(50000); //以微妙为单位延时, 300ms (1s = 1000 ms 1ms = 1000us)

}

if(ch != 'a' && ch != 'd' && ch != 'w')point_move_down();if(game_over() == 1){gotoxy(0, 10);printf("-------game over-------\n");system(STTY_DEF TTY_PATH);//恢复非阻塞IO设置 //不用理解return 0;//程序结束}}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。