之前关于贪吃蛇的内容参见:面向对象方法编一个简易的控制台版贪吃蛇(一)点击打开链接 和 面向对象方法编一个简易的控制台版贪吃蛇(二)点击打开链接
现在,我们开始写碰撞。
一说起增加什么功能,我首先想到的还是写一个新的方法。但是这个方法写在哪个类里面似乎永远都是一门学问,你可以写在一个现有的类里面,也可以再创建一个类。即使对于这样一款小游戏也需要考虑,因为如果写的不科学的话,可能后续实现起来就会显得很困难。
一开始,我采取的办法是是额外创建一个类,取名叫GameFunction,专门用来实现游戏当中的功能。但是,这样做的话。我想要调用GameFunction里的函数的话,就不能用现有主函数里的各个来调用GameFunction里面的方法了(也调用不到)。那怎么办,我就想把主函数改一下,直接new 一个GameFunction类的对象,同时在GameFunction的构造函数内部将地图、蛇和食物初始化。但是这样的话,刚刚创建的GameFunction对象又无法访Map、Food和Snake里各自的show函数,这样就无法将东西显示在控制台上。又该怎么办?个人能力有限,这个问题我没能解决,得想其他的办法,如果有哪位朋友能够给我提个意见,我将不胜感激。
那就只能在现有的类里面添加这些方法了。
我又选取了一个方法,那就是将用来判断是否碰撞的方法(isCollide)分别写在Map类和Food类里面。之所以分开写的原因,是因为当蛇碰到Map和Food时的操作不尽相同,分开写便于写主函数。
Map.cpp中的isCollide方法,其实也不难,就是把所有map结点都遍历一遍,看有没有结点和它重合。bool Map::isCollide(BaseNode* node)
{
for (auto Map : m_map)
{
if (Map->x == node->x&&Map->y == node->y)
{
return true;
}
}
return false;
}
同理,Food.cpp当中的isCollide方法:
bool Food::isCollide(BaseNode* node)
{
for (auto Food : m_food)
{
if (Food->x == node->x&&Food->y == node->y)
{
return true;
}
}
return false;
}
现在需要处理的是当蛇碰撞到不同的东西时所产生的不同效果。当蛇碰到地图Map的时候,蛇就死了,这个比较好处理,只需当碰上之后,直接break掉跳出主函数中的while循环就行了;当蛇碰到食物的时候,蛇身子增加,同时当前食物消失并随机生成另外一个食物。
先考虑蛇身子增加的问题。我们可以在Snake类里面增加一个函数getLonger专门用来实现蛇身子增加的功能。
void Snake::getLonger() //在蛇的尾部增加一个结点
{
m_snake.push_back(new BaseNode(m_snake.back()->x, m_snake.back()->y, TYPE_SNAKE));
}
现在我们对主函数进行一下修改,然后测试一下,看看碰撞是否管用。写主函数的时候我们又发现一个问题:isCollide函数的参数是BaseNode*类型,主函数中的类型没有BaseNode*类型,因此传参的时候存在类型不匹配的问题。我们这样解决这个问题:在Snake类里面定义一个getSnake函数,专门用来获取蛇的结点。
vector<BaseNode*>* getSnake() { return &m_snake;}
等我们在主函数调用isCollide函数的时候,我们就可以这么写:
1.当判断地图和蛇碰撞时:
if( map->isCollide(snake->getSnake()->front())
{
……
}
碰撞的时候,只需判断蛇头是否碰上就可以了(因为按照正常的玩法,蛇的其它部位也不可能碰到)
2.同理当判断食物和蛇是否碰撞时:
if(food->isCollide(snake->getSnake()->front()))
{
……
}
这样,主函数就被修改成了这样:
#include<iostream>
#include"Controller.h"
#include"baseNode.h"
#include"Map.h"
#include"Snake.h"
#include"Food.h"
#include<Windows.h>
void main()
{
Snake* snake = new Snake(5, 6);
Food* food = new Food(10, 9);
Map* map = new Map();
snake->showSnake();
snake->setKey(VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT);
food->showFood();
map->showMap();
while (true)
{
Sleep(150);
snake->controlSnake();
if (map->isCollide(snake->getSnake()->front()))
{
break;
}
if(food->isCollide(snake->getSnak