基于QT实现的怪怪水族馆益智游戏

simpleLove

发布日期: 2019-02-23 17:08:15 浏览量: 1127
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

1.游戏简介

怪怪水族馆(Insaniquarium)是一款益智类游戏,其主要目标是通过养育赚取目标数量的金币并打败外星生物。

2.游戏界面示意

游戏主要由一下几个界面组成:加载界面,开始界面,宠物和关卡选择界面,以及游戏主界面。以下是各个界面的运行示意图:

加载界面

开始游戏的菜单界面

游戏主界面

七个不同关卡可供选择

关卡

宠物选择界面

重新开始界面

玩家的主要目标是通过养鱼赚取金币解锁后面的关卡和宠物,本游戏一共实现了七个不同的关卡,一共实现了六种宠物,除了必须实现的蜗牛以外,还实现了鱼骨,美人鱼,珍珠蚌,水母,古比鱼母亲这五种宠物,玩家最开始不能携带宠物,每解开一个新的关卡可以解锁一种新的宠物,每次最多只能携带三种宠物,以下是具体介绍:

  • 蜗牛:只能在地平面游动,可以自动捡金币等加成物,但是速度较慢,当外星人出现时会停止不动将头缩进壳中

  • 鱼骨:可定时产生金币,但不会被伤害

  • 珍珠蚌:可定期产生珍珠

  • 水母:在整个水域自由漂浮,可以帮助玩家拾取金币等加成物

  • 美人鱼:定时唱歌,每次唱歌时其他鱼类会产生大量加成物(由于素材原因,没有做唱歌的环节)

  • 古比鱼妈妈:可以定期产生一只小古比鱼

除了必要要求之外,本游戏还多实现了三只鱼类和两只外星人

  • 螃蟹:可自由游动,定期产生昆虫(加成物),以小古比鱼为食

  • 小丑鱼:可自由游动,以螃蟹产生的昆虫为食,定期产生珍珠

  • 古比鱼王:由大古比鱼升级而成,可定期产生钻石

  • 疯狂章鱼:外星人,具有红色和蓝色两种形态,红色时可以鼠标点击攻击导致章鱼掉血,蓝色时处于防御状态,点击攻击反而会给章鱼加血

  • 黄色狮身外星人:类似于蓝色外星人但是防御力更强

除此之外,游戏还实现了以下功能:

  • 一共有七个关卡 每一关卡可以自行选择宠物

  • 游戏具有背景音乐且每个关卡音乐不同,随关卡上升战斗难度增加而更加激昂,实现了鱼和宠物,外星人的各种动画界面,如移动,死亡,蜗牛躲藏等动画

  • 具有升级按钮可以升级不同种类的饲料和饲料最大量,一共有五种不同的饲料,对应的形态,经验和生命回升各不相同

3.游戏流程

首先进入游戏进行载入动画,然后进入菜单界面,选择开始游戏会进入选择宠物界面,但第一关时没有宠物,点击确认宠物按钮后,会进入游戏主界面,当由足够的金钱可以进行对蛋壳进行三次升级后,可以升级进入下一关选择宠物界面,每一关具有不同的外星人入侵,随关卡上升难度越来越大,当水箱里所有鱼都死亡后游戏失败进入重新开始界面。

4.代码介绍

本次开发是我第二次写一个稍微大的项目,第一次相关经验是在java课上完成一个有联网功能的打飞机游戏,因此有了一些相关经验,但是这是我第一次使用Qt平台。

本次我才用了较新的QGraphics平台,在查询了相关资料后,我了解到,该平台具有以下两点优势,一是对于局部和整体的平台化:及作为个体的图元(item)和作为整体和scene与view,通过这个平台,view可以通过scene对于item进行高效率的管理和访问,而且图元之间的互相交流也较为简单。第二方面在于该平台实现较为简单,平台已经提供了许多具有一定功能的图元类,而如果想要拓展只需继承重载即可,拓展性和可操作性较强。索引我选择了基于该平台开发。

我的整个项目属于一个标准的树状结构,其UML图如下:

可以看到,除了主控制类Insaniquarium继承自QGraphicsView意外,其余所有类都由GameObject类派生而成。而GameObject类本身则同时继承自QGraphicsItem类和QObject类,这样做的目的是为了同时享受这两个强大的基类的功能:图元管理和信号槽机制。由于QGraphicsItem本身不具有信号槽机制,因此想要实现这样的功能就需要同时继承QObject类。我通过查阅资料了解到QGraphicsObject类具有以上两种特性,但是功能较为冗余,效率不高,因此选择自己继承。

  1. class GameObject :public QObject,public QGraphicsItem
  2. {
  3. Q_OBJECT
  4. Q_INTERFACES(QGraphicsItem)
  5. public:
  6. GameObject(qreal l,qreal w,QString name,QGraphicsScene *scene,QGraphicsItem *parent=nullptr);
  7. virtual ~GameObject(){}
  8. QString GetName() const;
  9. qreal GetWidth();
  10. qreal GetHeight();
  11. virtual void Act(int step)=0;
  12. virtual void CollideDetect()=0;
  13. bool need_deleted_=false;
  14. QString kind_="";
  15. protected:
  16. QString name_;
  17. qreal height_=0;
  18. qreal width_=0;
  19. int img_index_=0;
  20. int img_state_index_=0;
  21. QPixmap img_;
  22. pixmap_matrix img_matrix_;
  23. int img_x=0; //图片行数
  24. int img_y=0; //图片列数
  25. int real_width_=0;
  26. int real_height_=0;
  27. signals:
  28. void sgn_Deleted();
  29. };

以上是GameObject类的声明代码,其构成非常简单,而其中最重要的两个函数就是两个纯虚函数: void Act(int step)和 void CollideDetect()函数,这两个函数在其余的大部分类中都起着重要的作用。

GameObject类下派生出了具体的元素类别,Alien,Bonus,Button,Fish,Food,Pet类都由其直接派生,代表游戏中的不同模块,并进一步构造出了具体对象。在此就不做过多介绍。

随后介绍下逻辑。作为游戏乃至程序的核心,逻辑的设计非常重要。在我的理解中,这个游戏的逻辑非常清楚,主要核心就是画面刷新,数据更新的循环和碰撞判定的实现。分别对应上文中的Act函数和CollideDetect函数。

Act函数的主要用处就是执行主逻辑循环。在主游戏运行时,主控类内部实际上是在运行一个timer的计时器循环,每0.02秒进行一次循环,而每次循环,QGraphicsScene对象会遍历每一个Item并执行每个对象的Act函数,完成一个回合的数据更新和操作,循环往复就形成了逻辑的驱动。

  1. foreach (QGraphicsItem *item, scene_->items())
  2. {
  3. GameObject*gm=dynamic_cast<GameObject*>(item);
  4. gm->Act(step);
  5. }
  6. if(step%10==0)
  7. {
  8. foreach (QGraphicsItem *item, scene_->items())
  9. {
  10. GameObject*gm=dynamic_cast<GameObject*>(item);
  11. if(gm->need_deleted_)
  12. {
  13. scene_->removeItem(item);
  14. delete item;
  15. qDebug()<<"delete item";
  16. }
  17. }
  18. }

以上代码就是主逻辑类中对于所有Item的Act函数的执行以及定期对需要清理的对象的析构。

而另外一个函数CollideDetect()则是Act函数执行中的一个重要部分,大多数对象的Act函数主要在执行碰撞检测函数以及更新位置的Move。通过这两个主要函数的梳理,编写游戏的目标就一下子简单了很多:重构子类的Act函数和CollideDetect()。这就是游戏的主要逻辑。

最后我想谈一下开发过程中的两个主要BUG:

  • 第一个主要的BUG是在于碰撞函数中的“找目标”过程,当找到目标后,对象会将一个target指针指向目标。但是这里的陷阱是同一个目标可能对多个对象指向,而如果协调机制没有做好的话,会出现一个对象对该目标进行了操作(例如吃掉它)然后其余对象就出现了野指针的情况,而这样的错误是致命的。最后我采取的办法是采取信号槽机制,让被指向的的目标在被析构前发出“声明”,告知全局并解锁。

  • 第二个主要陷阱在于主逻辑循环中。因为Act函数是我自己声明并且定义的函数,而整个车程序的架构都是基于我自己编写的GameObject类上,因此QGraphics架构中的原声类别是无法直接参与Timer循环的,因为从上面的代码可以看到,循环会调用每个Item的Act函数,而原生类中没有,就会出现崩溃的情况。最后的解决办法有两个,一是重写需要的类,而是采用架构自身自带的Advance函数进行每个对象的逻辑推进。而我采用了前一种。

上传的附件 cloud_download 基于QT实现的怪怪水族馆益智游戏.7z ( 11.86mb, 8次下载 )
error_outline 下载需要13点积分

发送私信

成功一定有方法,失败一定有原因

12
文章数
9
评论数
eject