1
|
CC_SYNTHESIZE(
float, _nextDecisionTime, NextDecisionTime);
|
1
|
_nextDecisionTime =
0;
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#pragma once
#include "cocos2d.h" // 1 - convenience measurements #define SCREEN CCDirector::sharedDirector()->getWinSize() #define CENTER ccp(SCREEN.width / 2, SCREEN.height / 2) #define CURTIME GetCurTime() // 2 - convenience functions #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 // 3 - enumerations typedef enum _ActionState { kActionStateNone = 0, kActionStateIdle, kActionStateAttack, kActionStateWalk, kActionStateHurt, kActionStateKnockedOut } ActionState; // 4 - structures typedef struct _BoundingBox { cocos2d::CCRect actual; cocos2d::CCRect original; } BoundingBox; inline float GetCurTime(){ timeval time; gettimeofday(&time, NULL); unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec / 1000); return ( float)millisecs; }; |
打开GameLayer.cpp文件,添加如下方法:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
void GameLayer::updateRobots(
float dt)
{ int alive = 0; float distanceSQ; int randomChoice = 0; CCObject *pObject = NULL; CCARRAY_FOREACH(_robots, pObject) { Robot *robot = (Robot*)pObject; robot->update(dt); if (robot->getActionState() != kActionStateKnockedOut) { //1使用一个计数来保存仍然存活着的机器人数量。一个机器人只要不是死亡状态,就被认为仍然存活着。这将用于判断游戏是否应该结束 alive++; //2检查当前应用程序时间的推移是否超过了机器人的下一次决定时间。如果超过了,意味着机器人需要作出一个新的决定。 if (CURTIME > robot->getNextDecisionTime()) { distanceSQ = ccpDistanceSQ(robot->getPosition(), _hero->getPosition()); //3检查机器人是否足够接近英雄,以便于有机会出拳攻击落在英雄身上。如果接近英雄了,那么就进行一个随机选择,看是要朝着英雄出拳,还是要继续空闲着。 if (distanceSQ <= 50 * 50) { robot->setNextDecisionTime(CURTIME + frandom_range( 0. 1, 0. 5) * 1000); randomChoice = random_range( 0, 1); if (randomChoice == 0) { if (_hero->getPosition().x > robot->getPosition().x) { robot->setScaleX( 1. 0); } else { robot->setScaleX(- 1. 0); } //4假如机器人决定攻击,我们就用之前检测英雄攻击时相同的方式来进行检测碰撞。只是这一次,英雄和机器人的角色互换了。 robot->setNextDecisionTime(robot->getNextDecisionTime() + frandom_range( 0. 1, 0. 5) * 2000); robot->attack(); if (robot->getActionState() == kActionStateAttack) { if (fabsf(_hero->getPosition().y - robot->getPosition().y) < 10) { if (_hero->getHitbox().actual.intersectsRect(robot->getAttackBox().actual)) { _hero->hurtWithDamage(robot->getDamage()); //end game checker here } } } } else { robot->idle(); } } else if (distanceSQ <= SCREEN.width * SCREEN.width) { //5如果机器人和英雄之间的距离小于屏幕宽度,那么机器人将作出决定,要么朝着英雄移动,要么继续空闲。机器人的移动基于英雄位置和机器人位置产生的法向量。 robot->setNextDecisionTime(CURTIME + frandom_range( 0. 5, 1. 0) * 1000); randomChoice = random_range( 0, 2); if (randomChoice == 0) { CCPoint moveDirection = ccpNormalize(ccpSub(_hero->getPosition(), robot->getPosition())); robot->walkWithDirection(moveDirection); } else { robot->idle(); } } } } } //end game checker here } |
这是一个漫长的代码片段。将代码分解为一段段。对于游戏中的每个机器人:
①.使用一个计数来保存仍然存活着的机器人数量。一个机器人只要不是死亡状态,就被认为仍然存活着。这将用于判断游戏是否应该结束。
②.检查当前应用程序时间的推移是否超过了机器人的下一次决定时间。如果超过了,意味着机器人需要作出一个新的决定。
③.检查机器人是否足够接近英雄,以便于有机会出拳攻击落在英雄身上。如果接近英雄了,那么就进行一个随机选择,看是要朝着英雄出拳,还是要继续空闲着。
④.假如机器人决定攻击,我们就用之前检测英雄攻击时相同的方式来进行检测碰撞。只是这一次,英雄和机器人的角色互换了。
⑤.如果机器人和英雄之间的距离小于屏幕宽度,那么机器人将作出决定,要么朝着英雄移动,要么继续空闲。机器人的移动基于英雄位置和机器人位置产生的法向量。
每当机器人作出决定,它的下一个决定的时间被设定为在未来的一个随机时间。在此期间,它将继续执行上次作出决定时所做出的动作。接着在update函数里,this->updatePositions();前添加如下代码:
1
|
this->updateRobots(dt);
|
1
2 3 4 5 6 7 8 9 10 |
CCObject *pObject =
NULL;
CCARRAY_FOREACH(_robots, pObject) { Robot *robot = (Robot*)pObject; posX = MIN(_tileMap->getMapSize().width * _tileMap->getTileSize().width - robot->getCenterToSides(), MAX(robot->getCenterToSides(), robot->getDesiredPosition().x)); posY = MIN( 3 * _tileMap->getTileSize().height + robot->getCenterToBottom(), MAX(robot->getCenterToBottom(), robot->getDesiredPosition().y)); robot->setPosition(ccp(posX, posY)); } |
9.编译运行,将会看到沿着走廊过来的机器人。效果如下图所示:

10.为游戏添加重新开始的按钮。打开 GameLayer.cpp 文件,添加头文件引用:
1
|
#include
"GameScene.h"
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
void GameLayer::endGame()
{ CCLabelTTF *restartLabel = CCLabelTTF::create( "RESTART", "Arial", 30); CCMenuItemLabel *restartItem = CCMenuItemLabel::create(restartLabel, this, menu_selector(GameLayer::restartGame)); CCMenu *menu = CCMenu::create(restartItem, NULL); menu->setPosition(CENTER); menu->setTag( 5); _hud->addChild(menu, 5); } void GameLayer::restartGame(CCObject* pSender) { CCDirector::sharedDirector()->replaceScene(GameScene::create()); } |
第一个方法创建显示一个重新开始的按钮,当按下它时,触发第二个方法。后者只是命令导演用新的GameScene实例替换当前场景。接着在updateRobots函数里面,在第一个end game checker here注释后面,添加如下代码:
1
2 3 4 |
if (_hero->getActionState() == kActionStateKnockedOut && _hud->getChildByTag(
5) ==
NULL)
{ this->endGame(); } |
1
2 3 4 |
if (alive ==
0 && _hud->getChildByTag(
5) ==
NULL)
{ this->endGame(); } |
11.编译运行,可以看到游戏结束时的样子,如下图所示:

12.音乐和音效。打开GameLayer.cpp文件,添加头文件引用:
1
|
#include
"SimpleAudioEngine.h"
|
1
2 3 4 5 6 7 |
// Load audio CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic( "latin_industries.aifc"); CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic( "latin_industries.aifc"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "pd_hit0.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "pd_hit1.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "pd_herodeath.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "pd_botdeath.wav"); |
1
|
#include
"SimpleAudioEngine.h"
|
1
2 |
int randomSound = random_range(
0,
1);
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(CCString::createWithFormat( "pd_hit%d.wav", randomSound)->getCString()); |
1
|
virtual
void knockout();
|
1
|
#include
"SimpleAudioEngine.h"
|
1
2 3 4 5 |
void Hero::knockout()
{ ActionSprite::knockout(); CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "pd_herodeath.wav"); } |
1
|
#include
"SimpleAudioEngine.h"
|
1
2 3 4 5 |
void Robot::knockout()
{ ActionSprite::knockout(); CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "pd_botdeath.wav"); } |