Qt实现贪吃蛇(二)
上一篇中说到蛇有两个属性。一个是身体,另一个是前进方向。接下来再看看蛇的行为,想想这只蛇除了会前进外就只会转弯前进了。先看看它是如何前进的:
E_GO_RET goAhead(); //前进一步
enum E_GO_RET{//前进一步的结果 E_NOTHING,//无异常 E_GETFOOD,//吃到食物 E_DIE //死亡 };
由于蛇每走一步都有三种可能。因此我们定义了一个枚举E_GO_RET,表示走一步的结果。接着看看goAhead里有什么?
CSnake::E_GO_RET CSnake::goAhead() { //前进一步是否会吃到食物 s_body firstBody = f_snake.at(f_snake.size() - 1); //向量的最后一个值作为蛇的头部 s_body nextfirstBody = goStep(firstBody.bx,firstBody.by,f_goDir); //获取前进一步时头部的坐标 if(nextfirstBody.bx == f_game->getFoodRow() && nextfirstBody.by == f_game->getFoodCol()){ f_snake.push_back(nextfirstBody); return E_GETFOOD; } else if(containsBody(nextfirstBody.bx,nextfirstBody.by)){ //碰撞到自己 return E_DIE; } else if(f_game->outOfRange(nextfirstBody.bx,nextfirstBody.by)){ //出界 return E_DIE; } else{ //啥也没发生,除头部外每一节身体变化到它的前一节位置,头部变化为根据方向计算出的位置。 for(int i = 0; i < f_snake.size() - 1; ++i) { s_body nextBody = f_snake.at(i + 1); f_snake[i] = nextBody; } f_snake[f_snake.size() - 1] = nextfirstBody; return E_NOTHING; } }
在函数中,首先获取头部的位置。为了方便计算,取vector的最后一个值作为头部,因此蛇的顺序和vector是相反的。接着根据头部的位置和前进方向计算出前进一步时头部的位置。最后根据计算出新的头部位置判断前进一步的后果。如果新头部和食物的位置相同则吃到了食物,食物位置作为新的头部;如果撞到了自己或者出界了则死亡;如果什么也没发生,身体位置全部改变。
这里有用到一个变量f_game,是封装的游戏类的对象。对象记录了游戏区域和食物的位置,后面会讲到。除了这个还有两个函数都很容易理解。
CSnake::s_body CSnake::goStep(int bx, int by, E_DIR dir) { s_body newBody(bx,by); //根据方向来判断坐标x,y的增量 switch(dir) { case E_UP: newBody.bx -= 1; break; case E_DOWN: newBody.bx += 1; break; case E_LEFT: newBody.by -= 1; break; case E_RIGHT: newBody.by += 1; break; default: break; } return newBody; }
bool CSnake::containsBody(int x, int y) { for(int i = 0; i < f_snake.size(); ++i){ if(f_snake.at(i).bx == x && f_snake.at(i).by == y) { return true; } } return false; } //遍历f_snake