Linux下使用Curses库+时钟信号编写视频小游戏:对战贪吃蛇

来源:互联网 发布:智能提醒软件 编辑:程序博客网 时间:2024/06/05 14:08

#include <iostream>#include <stdio.h>#include <curses.h>#include <sys/time.h>#include <signal.h>#include <string.h>#include <unistd.h>#include <stdlib.h>


这些是用g++编译所需要的头文件,其实用c和c++都可以,我用g++编译的,其实也没用到什么c++的东西,如果用gcc,需要的头文件可能会有变化,反正试一下就好了。

编译命令:

g++ /home/parker/Desktop/double_snake/main.cpp -lcurses -o snake

执行:./snake

虽然我在我的Ubuntu上也装了codeblocks,但是Curses的相关内容,没法在IDE里直接编译运行,必须要到terminal里,执行这句话,用-lcurses来调用系统的编译库,如果还没装curses库就先去下一个。-o后面命名一下。如果是c文件了话,就用gcc,后面.cpp变成.c。

我的主函数:

int main(){    initscr();    initcolor();    cbreak();// keyboard event at once    noecho();    clear();    signal(SIGALRM, update);init();countrol();    endwin();    return 0;}

initscr()是curses自带的,初始化。

initcolor()是我自己写的,后面说。

cbreak()也是自带的,为了使键入的字母迅速被监听执行

noecho()也是自带的,避免字母回显,按下字母后不在屏幕显示

clear()清屏

signal(SIGALRM,update);这是一个信号,根据时钟,不断的唤醒执行update函数,update是自己写的函数。

init()是自己写的。

countrol()也是自己写的,在里面有个while(1),相当于键盘事件的监听。

endwin()表示结束curses。


int set_ticker( int n_msecs ){//program by teacher,about time countrol        struct itimerval new_timeset;        long    n_sec, n_usecs;        n_sec = n_msecs / 1000 ;/* int part*/        n_usecs = ( n_msecs % 1000 ) * 1000L ;/* remainder*/        new_timeset.it_interval.tv_sec  = n_sec;        /* set reload       */        new_timeset.it_interval.tv_usec = n_usecs;      /* new ticker value */        new_timeset.it_value.tv_sec     = n_sec  ;      /* store this       */        new_timeset.it_value.tv_usec    = n_usecs ;     /* and this         */return setitimer(ITIMER_REAL, &new_timeset, NULL);}

上面这是时钟程序,后面只要调用这个函数,就可以规定signal里唤醒函数的频率。

下面这里是update函数,要注意一点,里面的参数不可以省略。

void update(int signum){}
可以set_ticker(100)就代表update()函数会每100ms被唤醒一次,游戏进行时,主函数就一直卡在control的键盘监听里,然后通过update函数不断更新画面,实现动态效果。

下面有些函数也是必须的:

move(i,j)把光标移动到ij的位置,

addch(),addstr(),打印一个char或者string

refresh()更新,每一帧的最后都运行一次就可以


色彩控制:

void initcolor(){    start_color();    init_pair(1,COLOR_BLUE,COLOR_WHITE);//color_pair_ID,color_of_words,color_of_background    init_pair(2,COLOR_RED,COLOR_WHITE);//for player 1    init_pair(3,COLOR_YELLOW,COLOR_WHITE);//for player 2    init_pair(4,COLOR_GREEN,COLOR_WHITE);//for menu    attron(COLOR_PAIR(1));}
先start_color()这是系统自带的。

然后init_pair()这也是系统自带的,相当于规定好一个pair的ID编号,字的颜色和背景色,以后要用到直接用attron调用这个pair就行


算法和数据结构:

int boundx=23;int boundy=50;int condition=-1;//0 is main menu,1 is choosing map,2 is playing,3 is pause during playing,4.game overint game_model;//kind of mapint d[4][2]={0,1,1,0,0,-1,-1,0};//toward right,down,left,upconst int Right=0,Down=1,Left=2,Up=3;int speed=500;const int maxspeed=100;const int minspeed=1000;const int model1=0,model2=1,model3=2;//ID of mapint times=5;//become longger every x timesint longer=0;//record x times passedint updated1=0;//only if updated==1,the direction can be changed ,int updated2=0;//char Field[24][51];

struct point{//    int x,y;    point(){};    point(int X,int Y){        x=X;        y=Y;    }};struct snake{    int direction;//0,1,2,3    point head;    point last;    point body[1000];    int alive;    int len;};snake s1;snake s2;

在Control里监听键盘,改变蛇头的方向,在update里根据蛇头的方向,移动蛇就好了。

这里需要注意一个细节,就是在control里要限制蛇头方向的移动,比如当蛇头向上时,不能允许其方向改向下。这个问题一行代码就解决了,但是我们会发现,当这种情况下,快速的按一下左再按下,蛇头就变成向下的了,就是说在一帧里改变两次方向,这是我们不允许的。所以我们给这个程序加一个“锁”,在收到一个合法的方向改变请求后,方向就被锁定了,直到update函数运行完,才会解除这个锁定,允许玩家改变方向。

if(ch=='w'){//snake 1 wsad                if((s1.direction==Left||s1.direction==Right)&&updated1==0){                    s1.direction=Up;                    updated1=1;                }            }

想做这个游戏,最初是因为在北京参加的一次ACM区域赛,在颁奖典礼前,他们办了一个对战贪吃蛇AI大赛,选手们拿自己写的AI互相PK,看谁能活下来,我觉得非常有意思,于是也想自己写个AI,但是这个事一直没有实践,正好借这个机会,我把这个双人对战的程序写出来了,后面可以开发一个AI,跟自己玩了。。。





2 0