C++编写的linux shell上可运行的贪吃蛇游戏

无意中浏览到网页 blog.csdn.net/jjzhoujun2010/article/details/6709827 ,一看是置顶的文章,是用C语言写的贪吃蛇游戏,觉得很好完,就看了看,粗略看了一下,代码量不是很大,而且关键的算法也给了详细的说明,由于自己更偏重C++,所以就有了用C++来改写此游戏的想法,于是就行动起来。前后大约一天半的时间把整个程序调试通过。

整个代码可以从https://github.com/lmdyyh/Snake 下载。下面就说说各个文件的作用:

Timer.h和Timer.cpp定义了游戏中的定时器,时间到时会向内核发送SIGALRM信号,测试程序testSnake.cpp中定义了SIGALRM的信号处理程序,整个游戏中只需要一个定时器,所以Timer采用了单例模式编写。

Timer.h

#ifndef TIMER_H#define TIMER_Hclass Timer{public: static void wrapUp(); static int set_ticker(int n_msecs); static Timer* getInstance(); Timer();private: static Timer* _instance;};#endif

Food.h和Food.cpp定义游戏中蛇的食物,当food被蛇吃了后,会随机生成另一个位置,模拟生成另一个food,而实际游戏中就只有一个food,于是还是采用单例模式。Food是个静态类,里面只能包含静态成员,而我们又需要设置food的位置,于是就需要两个set函数,set函数作为static类成员函数时,会出现问题,因为静态类成员参数中会默认插入const Food作为this的实参,此时就丢弃了const限定符,编译器会报错,于是就需要在set函数后加上const修饰符,可是加上const修饰符后就不能设置数据成员了,此时就需要将位置数据成员用mutable修饰。

Food.h

#ifndef FOOD_H#define FOOD_Hclass Food{public: static Food* getInstance(); void dispFood()const; int getXPos()const; int getYPos()const; void setXPos(int)const; void setYPos(int)const;protected: Food(int,int);private: static Food* _instance; mutable int fx_pos; mutable int fy_pos;};#endif

核心程序是Snake.h和Snake.cpp。把一些与所有游戏都相关的函数抽象到Game.h中形成一个抽象类,使Snake类继承至Game类,Snake采用STL中的list双向链表实现,构造函数中首先生成一个空链表,然后push_back一个std::pair<int,int>数据成员作为蛇的初始位置,并且生成一个Food和一个Timer,Snake和Food、Timer采用组合的方式耦合。

Game.h

#ifndef GAME_H#define GAME_Hclass Game{public: virtual void gameStart()=0; virtual void gameOver(int)=0; virtual void initGame()=0; virtual void keyControl()=0;};#endif

Snake.h

#ifndef SNAKE_H#define SNAKE_H#include <boost/noncopyable.hpp>#include <list>#include <utility>#include <boost/shared_ptr.hpp>#include "Game.h"#include "Timer.h"#include "Food.h"#include <signal.h>using namespace std;class Snake :public Game ,boost::noncopyable{public: Snake(int ,int ); ~Snake(); void insertSnake(int,int); void shrinkSnake(); void moveSnake(); void gameOver(int); void gameStart(); void initGame(); void keyControl();private: void initSnake(); int x_pos; //position int y_pos; int length;//pairList’s size int x_dir; int y_dir; int ttm; int ttg; bool moved; bool ate; typedef list<pair<int,int> > pairList; pairList* snakeNode; Timer *timer; Food *food;};#endif

具体的算法参考链接原文。这里timer和food应该使用boost::shared_ptr来管理,防止资源泄漏。

最后说一下这个C++代码中最困难的一点,就是在每当定时器时间到,向系统发射SIGALRM信号,这时就会调用我们用signal设置的信号处理函数,此处信号处理函数是使蛇移动,也就是调用Snake的moveSnake()函数,signal需要的是void (*)(int)的回调函数,而我们传给signal的是void (Snake::*)(int)的回调函数,编译器会报错。这里耽误了很长时间,反复实验了几种方法,最后通过将信号处理函数包装才得以解决,如:

testSnake.cpp

#include "Snake.h"#include <iostream>using namespace std;void Snake_memberFn_Wrapper(int n);Snake snake(5,10);int main(){ signal(SIGALRM,Snake_memberFn_Wrapper); snake.gameStart();}void Snake_memberFn_Wrapper(int n){ snake.moveSnake(); }声明一个全局的snake,将真正的信号处理函数包装进Snake_memberFn_Wrapper中,并将其作为signal的处理函数即可,这样内核收到SIGALRM后就会调用moveSnake了。

又用了一个下午加一个晚上给游戏加了一个背景音乐,用的irrklang库,详见www.ambiera.com/irrklang/docu/index.html#tipsandtricks ,在主线程中开了一个子线程运行音乐。

奋斗令我们的生活充满生机,责任让我们的生命充满意义!

C++编写的linux shell上可运行的贪吃蛇游戏

相关文章:

你感兴趣的文章:

标签云: