1、AI即Artificial Intelligence(人工智能),因为我们的这个游戏如果机器人只是站在那儿让玩家攻击,游戏的趣味性会很低。因此,我们希望机器人也能够自动地执行一些动作,譬如像玩家精灵移动,攻击玩家精灵等等。要实现这些动作,需要一个简单的AI逻辑,来确定机器人的动作序列。
2、前面我们已经将玩家精灵和机器人的5个动作都实现了,现在在计时器的update函数中写一个简单的AI函数,用于确定机器人在某一时间段内的动作(为增加可变性,配合随机数效果更好)。
3、下面贴出这个函数以及游戏结束的处理函数:
void GameBasicLayer::updateRobots(float dt)
{
int alive = 0;
float distanceSQ;
int randomChoice = 0;
CCObject *pObject = NULL;
CCARRAY_FOREACH(_spriteRobot, pObject)
{
SpriteRobot *pRobot = (SpriteRobot*)pObject;
pRobot->update(dt);
if (pRobot->getSpriteState() != STATE_DEAD)
{
//1
alive++;
//2
if (CURTIME> pRobot->getNextDecisionTime())
{
distanceSQ = ccpDistanceSQ(pRobot->getPosition(), _spritePlayer->getPosition());
//3
if (distanceSQ <= 50 * 50)
{
pRobot->setNextDecisionTime(CURTIME + frandom_range(0.1, 0.5) * 1000);
randomChoice = random_range(0, 1);
if (randomChoice == 0)
{
if (_spritePlayer->getPosition().x > pRobot->getPosition().x)
{
pRobot->setScaleX(1.0);
}
else
{
pRobot->setScaleX(-1.0);
}
//4
pRobot->setNextDecisionTime(pRobot->getNextDecisionTime() + frandom_range(0.1, 0.5) * 2000);
pRobot->Attack();
if (pRobot->getSpriteState() == STATE_ATTACK)
{
if (fabsf(_spritePlayer->getPosition().y - pRobot->getPosition().y) < 10)
{
if (_spritePlayer->getCollosionDetectionRect().bodyRect.intersectsRect(pRobot->getCollosionDetectionRect().punchesRect))
{
_spritePlayer->Hurt_WithDamage(pRobot->getOnceDamage());
// progressBar changed(Hero)
//float cu = _spritePlayer->getProbressBar()->getPercentage();
//cu = cu + pRobot->getDamage();
//_spritePlayer->getProbressBar()->setPercentage(cu);
//end game checker here
if (_spritePlayer->getSpriteState() == STATE_DEAD && _directionConSpLayer->getChildByTag(5) == NULL)
{
this->endGame();
}
}
}
}
}
else
{
pRobot->Normal();
}
}
else if (distanceSQ <= SCREEN.width * SCREEN.width)
{
//5
pRobot->setNextDecisionTime(CURTIME + frandom_range(0.5, 1.0) * 1000);
randomChoice = random_range(0, 2);
if (randomChoice == 0)
{
CCPoint moveDirection = ccpNormalize(ccpSub(_spritePlayer->getPosition(), pRobot->getPosition()));
pRobot->Walk_WithDirection(moveDirection);
}
else
{
pRobot->Normal();
}
}
}
}
}
//end game checker here
if (alive == 0 && _directionConSpLayer->getChildByTag(5) == NULL)
{
this->endGame();
}
}
void GameBasicLayer::endGame()
{
CCLabelTTF *restartLabel = CCLabelTTF::create("RESTART", "Arial", 30);
CCMenuItemLabel *restartItem = CCMenuItemLabel::create(restartLabel, this, menu_selector(GameBasicLayer::restartGame));
CCMenu *menu = CCMenu::create(restartItem, NULL);
menu->setPosition(CENTER);
menu->setTag(5);
_directionConSpLayer->addChild(menu, 5);
}
void GameBasicLayer::restartGame(cocos2d::CCObject* pSender)
{
CCDirector::sharedDirector()->replaceScene(GamePlayScene::create());
}
4、另外,将一些反复使用的量定义在GameDefines.h中:
#pragma once
#include "cocos2d.h"
// 精灵状态
enum SpriteState
{
STATE_NORMAL,
STATE_WALK,
STATE_ATTACK,
STATE_HURT,
STATE_DEAD
};
typedef struct _SurroundRect
{
cocos2d::CCRect bodyRect; // 身体的矩形区域
cocos2d::CCRect punchesRect; // 出拳的矩形区域
}SurroundRect;
#define SCREEN CCDirector::sharedDirector()->getWinSize()
#define CENTER ccp(SCREEN.width / 2, SCREEN.height / 2)
#define CURTIME GetCurTime()
inline float GetCurTime(){
timeval time;
gettimeofday(&time, NULL);
unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec / 1000);
return (float)millisecs;
};
#ifndef UINT64_C
#define UINT64_C(val) val##ui64
#endif
#define random_range(low, high) (rand() % (high - low + 1)) + low
#define frandom (float)rand() / UINT64_C(0x100000000)
#define frandom_range(low, high) ((high - low) * frandom) + low
5、至此,这个游戏大体框架已经基本完成,由于是一块一块写的,而且还没有在全局上优化整合过,所以代码比较粗糙。
6、游戏开发到这一步,其实只算是完成了20%的工作,后面的优化性能以及客户体验是重中之重。
7、另外,关于后续功能的几点建议:
(1)背景音乐,游戏音效;
(2)添加血量条;
(3)添加游戏开始时的选择菜单(包括开始新游戏,游戏选项,帮助等内容);
8、因为最近时间比较紧,所以这个游戏暂时可能就到此为止了,因为源码比较乱,所以暂时不上传了。等我整理后在追加在本文后面。