前几日在windows下写了一个简单的2048小游戏,然后再linux下运行,了解到了一些函数的使用
头文件 curses.h
若没有该头文件需要下载
参考博客
curses工作在屏幕,窗口和子窗口之上。屏幕是设备全部可用显示面积(对终端是该窗口内所有可用字符位置),窗口与具体例程有关。
若要在屏幕上进行输出字符等信息,我们需要划分一个矩形窗口
用WINDOW创建一个窗口指针
//指向数字窗口
WINDOW *w_2048=NULL; //2048游戏窗口
WINDOW *message=NULL; //信息窗口
WINDOW *score_mode_frame = NULL; //分数和模式窗口
WINDOW *choose = NULL; //菜单选择窗口
WINDOW *over_frame = NULL; //结束窗口
WINDOW *newwin(int lines, int cols, int start_y, int start_x); //创建从(start_y, start_x)开始的lines行,cols列的窗口。
w_2048 = newwin(N, N*6, w_2048_y0, w_2048_x0);
choose = newwin(10,3,12,27);
message = newwin(1,36,6,16);
score_mode_frame = newwin(1,36,8,16);
over_frame = newwin(6,30,20,22);
当我们窗口构建完以后,我们就开始对特定坐标处进行填写字符
其中涉及到的几个函数为:
实现步骤:
1.先利用函数wmove将光标移动到需要填写的坐标开始处
2.然后用函数waddstr添加需要显示的字符串,也可以用waddch添加需要的显示的单个字符
3.用函数wrefresh刷新
wmove(over_frame,2,0);
waddstr(over_frame,"PRESS ENTER GO TO MENU ");
wrefresh(over_frame);
其实通过这些函数我们在显示这一部分就差不多可以完成了,剩下的就是移动
当然移动部分的函数也是在curses.h函数中
keypad函数打开或关闭指定窗口的功能键
wgetch函数是从指定窗口获得输入
keypad(w_2048, TRUE); //表示w_2048这个窗口,有功能键
int ch = wgetch(w_2048); //若没有输入则会一直等待
keypad(w_2048, FALSE);
switch(ch)
{
case 'w':
case 'W':
case KEY_UP:
return UP;
case 's':
case 'S':
case KEY_DOWN:
return DOWN;
case 'a':
case 'A':
case KEY_LEFT:
return LEFT;
case 'd':
case 'D':
case KEY_RIGHT:
return RIGHT;
case 'q':
case 'Q':
return QUIT;
}
其中返回值我们是在另外一个文件进行宏定义了的
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
#define ENTER 5
#define QUIT 100
这样我们的移动也就基本完成了,我们就根据移动的返回值来进行相对应的操作
屏幕部分是我们最开始和结束的时候需要使用的,涉及的头文件还是curses.h
这些函数一般不需要过多理解,直接调用就行
/*
open_screen: 初始化字符窗口相关的功能
参数:无
返回值:
无
*/
void open_screen(void)
{
initscr(); //初始化字符屏幕
cbreak(); //Ctrl + c
noecho(); //不用回显
keypad(stdscr, TRUE); //使用功能键
}
/*
close_screen:关闭字符窗口
参数:无
返回值:
无
*/
void close_screen(void)
{
endwin(); //关闭字符窗口
}
1.菜单(上下键移动,ENTER选择)
<1> 游戏开始
<2> 设置
<3> 退出
2.游戏界面
<1> 得分score(当合成一个数值后,分数加上这个数值)
<2> MAX是指合成的最大数值,则胜利(可设置更改)
<3> mode游戏模式(可设置更改)
<4> 2048游戏矩阵4*4
3.游戏胜利
没移动一次,就会在0处随机产生一个数,当最大数值达到MAX则胜利,按ENTER返回菜单
4.游戏失败
当无可移动以及无可合成的数时,代表游戏失败
其实整个主逻辑很简单,就是用过移动改变一些数组,变量的值,然后循环体中不断调用刷新函数。主要就是几个函数的实现的一些算法
首先我们需要一个2048矩阵即二维数组,我们会不断更改二维数组的值,并刷新屏幕
int matrix_2048[N][N]; //2048矩阵 N宏定义为4
//定义指向矩阵的指针
int (*matrix)[N]= matrix_2048;
1.随机数列表
int rand_list_all[7]={0,0,0,2,4,8,16}; //初始化的随机填充数列
int rand_list_a[14]={2,2,2,2,2,2,4,4,4,4,8,8,8,32};//移动后随机填充单个数字的数列
2.游戏初始随机数的产生
void fill_all_number(void)
{
int row,col;
for(row=0;row<N;row++)
{
for(col=0;col<N;col++)
{
*(*(matrix+row)+col) = rand_list_all[random() % 7];
}
}
}
3.移动后的随机填充一个数
既然是随机填充,我们需要知道随机位置,所以我们先知道矩阵中0的个数
```c
//获取矩阵中0的个数
//返回值 num:0的个数
int get_zero_num(void)
{
int row,col;
int num =0;
for(row=0;row<N;row++)
{
for(col=0;col<N;col++)
{
if(*(*(matrix+row)+col) == 0)
num++;
}
}
return num;
}
//随机一个位置用于移动的时候
//返回值 0:生成失败 1:生成成功
int fill_a_number(void)
{
int row,col;
int n=0;
int zero_num =get_zero_num();
if(zero_num == 0)
return 0;
int pos = random() % zero_num + 1;
for(row=0;row<N;row++)
{
for(col=0;col<N;col++)
{
if(*(*(matrix+row)+col) == 0)
{
n++;
if(n == pos)
*(*(matrix+row)+col) = rand_list_a[random() % 14];
}
}
}
return 1;
}
1.通过移动的方向来调用不同的函数
switch(mv)
{
case LEFT:
move_left();
break;
case RIGHT:
move_right();
break;
case UP:
move_up();
break;
case DOWN:
move_down();
break;
}
2.实现函数
其实我们只需要懂得一个方向的原理就知道其他的了
我们以move_left为例,如果我们把0看过空白的话,相邻的且相同的数会合在一起,放在左边的那个数中,右边的数则会清0,若不满足条件则会紧接着放在左边
我们有两个变量
index:数组下标,指向往左边放数值的位置
temp:临时变量,用于保存下一个非0数或者用于与下一个非0数值进行比较
<1>首先我们操作的数是非0数
if (*(*(matrix+row)+col) != 0)
<2> 然后将第一个非0数放在临时容器变量里面,或者已经移动后,用于存储下一个非0数,存储后该坐标下的值应该清0
if (*(*(matrix+row)+col) != 0)
{
if (temp == 0)
{
temp = *(*(matrix+row)+col);
*(*(matrix+row)+col) = 0;
}
<3> 如果temp里面有值,那么就有两种情况
1> temp与下一个非0数相同
相同则代表我们需要合成,然后将合成的值往左边移动,然后将该坐标值清0,temp清0
if (*(*(matrix+row)+col) == temp)
{
//合并,再移动
temp += *(*(matrix+row)+col); //合并
if(temp == max_number) win_sign =1; //胜利标志
score += temp; //分数
*(*(matrix+row)+col) = 0; //清0
*(*(matrix+row)+ index++) = temp; //移动
temp = 0; //清0
}
2> temp与下一个非0数不相同
else
{
//相邻但不相等
//先移动x,然后把matrix[i][k]->temp
*(*(matrix+row)+ index++) = temp; //移动
temp = *(*(matrix+row)+col); //更换
*(*(matrix+row)+col) = 0; //清0
}
然后每一行都这样判断循环下去就可以了,对于其他方向注意行和列
当我们移动后,如果数值并无变换,我们就得需要考虑一下,是不是达到了结束的条件:无空白(0)的地方,无可合成的数对(每个数的两个垂直方向没有与之相同的数)
//判断游戏是否结束
//返回值 1: 游戏结束,无可移动 0:游戏未结束
int game_over(void)
{
int row,col;
if(get_zero_num())
{
return 0; //空白位置个数>0,游戏肯定不结束
}
for(row = 0;row < N;row++)
{
for(col = 0;col < N;col++)
{
//j < N - 1 表示这个元素不是这一行的最后一个元素!!
if(col < N-1 && *(*(matrix+row)+col) == *(*(matrix+row)+(col+1)))
{
return 0;
}
// i < N - 1 表示i不是最后一行
if(row < N -1 && *(*(matrix+row)+col) == *(*(matrix+(row+1))+col))
{
return 0;
}
}
}
return 1;
}
链接:https://pan.baidu.com/s/1iy6vR-hPTxTdf8hkTF3DPw
提取码:8jab
用的时候我们需要通过虚拟机在windows创建一个共享文件夹,然后将文件放入共享文件夹,在linux下才行访问得到这些文件
如果有疑问记得留言,谢谢你的观看!!!