有一款回合制战略游戏 名字我忘记过去的名字了 里...

“指”上谈兵-如何使用Cocos2D制作一款iPhone回合制策略游戏PART-2 | 泰然网
本文由eseedo翻译,泰然授权转载,其他转载请通知原版权方!
继续上一部分的学习,我们很快就会搞定一个完整的简单回合制策略游戏了!
在第一部分的教程中,我们学习了如何加载瓦片地图,初始化军事单位(陆战队员,大炮和直升机),以及如何使用A*寻路算法让他们在瓦片地图上运动。
而在这部分的教程中(同时也是最后一部分),我们将让这些军事单位完成自己的使命-开战!
在接下来的内容里,我们将向地图中添加建筑,然后添加游戏的赢输机制。此外,我们还将添加逻辑机制来切换玩家的操控顺序,同时还会增加一些锦上添花的音乐和音效。
当然,最让人开心的是,这个项目预留了扩展的空间,这样你就可以基于它来制作属于自己的回合制策略游戏!
在继续学习之前,确保你已经准备好了上一部分教程结束时的工程()。
然后,前进!冲锋!
“给我上,你们这帮猿人!想他妈活一辈子老不死吗?”
—— 一位无名副排长,1918年
添加弹出菜单
在进入战斗之前,让我们先花个几分钟时间来添加一个弹出菜单。当玩家移动完某个军事单位后,可以使用弹出菜单来选择其行为,如停留在新的位置无所事事,返回原来的位置,或者(可能的话)攻击旁边的敌军单位。
首先来添加一些辅助方法。当然,在此之前还是要先添加几个实例变量的声明。在Xcode中切换到HelloWorldLayer.h,然后添加以下实例变量:
CCMenu *actionsM
CCSprite *contextMenuB
以上我们定义了一个代表弹出菜单的CCMenu实例变量,并创建了一个精灵实例变量,指向菜单的背景。
为了从Unit类中访问菜单和前一个选中的军事单位,我们需要将actionMenu和selectedUnit定义为属性变量:
@property(nonatomic,assign) Unit *selectedU
@property(nonatomic,assign) CCMenu *actionsM
当然,别忘了在HelloWorldLayer.m中合成这两个属性:
@synthesize selectedU
@synthesize actionsM
再次切换到HelloWorldLayer.h,并添加两个辅助方法的定义:
-(void) showActionsMenu:(Unit*)unit canAttack:(BOOL)canA
-(void) removeActionsM
接下来在HelloWorldLayer.m中实现这两个方法:
-(void)showActionsMenu:(Unit *)unit canAttack:(BOOL)canAttack {
// 1 - Get the window size
CGSize wins = [[CCDirector sharedDirector] winSize];
// 2 - Create the menu background
contextMenuBck = [CCSprite spriteWithFile:@&popup_bg.png&];
[self addChild:contextMenuBck z:19];
// 3 - Create the menu option labels
CCLabelBMFont * stayLbl = [CCLabelBMFont labelWithString:@&Stay& fntFile:@&Font_dark_size15.fnt&];
CCMenuItemLabel * stayBtn = [CCMenuItemLabel itemWithLabel:stayLbl target:unit selector:@selector(doStay)];
CCLabelBMFont * attackLbl = [CCLabelBMFont labelWithString:@&Attack& fntFile:@&Font_dark_size15.fnt&];
CCMenuItemLabel * attackBtn = [CCMenuItemLabel itemWithLabel:attackLbl target:unit selector:@selector(doAttack)];
CCLabelBMFont * cancelLbl = [CCLabelBMFont labelWithString:@&Cancel& fntFile:@&Font_dark_size15.fnt&];
CCMenuItemLabel * cancelBtn = [CCMenuItemLabel itemWithLabel:cancelLbl target:unit selector:@selector(doCancel)];
// 4 - Create the menu
actionsMenu = [CCMenu menuWithItems:nil];
// 5 - Add Stay button
[actionsMenu addChild:stayBtn];
// 6 - Add the Attack button only if the current unit can attack
if (canAttack) {
[actionsMenu addChild:attackBtn];
// 7 - Add the Cancel button
[actionsMenu addChild:cancelBtn];
// 8 - Add the menu to the layer
[self addChild:actionsMenu z:19];
// 9 - Position menu
[actionsMenu alignItemsVerticallyWithPadding:5];
if (unit.mySprite.position.x & wins.width/2) {
[contextMenuBck setPosition:ccp(100,wins.height/2)];
[actionsMenu setPosition:ccp(100,wins.height/2)];
[contextMenuBck setPosition:ccp(wins.width-100,wins.height/2)];
[actionsMenu setPosition:ccp(wins.width-100,wins.height/2)];
-(void)removeActionsMenu {
// Remove the menu from the layer and clean up
[contextMenuBck.parent removeChild:contextMenuBck cleanup:YES];
contextMenuBck =
[actionsMenu.parent removeChild:actionsMenu cleanup:YES];
actionsMenu =
以上两个方法分别用于创建弹出菜单,以及在不再需要的时候删除它。现在该菜单仅允许玩家取消或确认军事单位的行动,但最后将提供第三个选项以攻击某个敌军单位。很快我们就会添加该功能。
在Xcode中切换到Unit.m,找到popStepAndAnimate:方法,并使用以下代码替代if循环部分:
// Check if there remain path steps to go through
if ([movementPath count] == 0) {
moving = NO;
[self unMarkPossibleMovement];
BOOL enemiesAreInRange = NO;
// You'll determine later if there is a nearby enemy to attack.
[theGame showActionsMenu:self canAttack:enemiesAreInRange];
// Get the next step to move toward
在以上代码中,我们调用showActionsMenu:canAttack:这个辅助方法来显示弹出菜单。此时我们将enemiesAreInRange的属性硬性规定为NO,这样就不会在菜单中显示Attack选项。
接下来在ccTouchBegan:方法的顶部添加以下代码:
/ If the action menu is showing, do not handle any touches on unit
if (theGame.actionsMenu)
return NO;
// If the current unit is the selected unit, do not handle any touches
if (theGame.selectedUnit == self)
return NO;
// If this unit has moved already, do not handle any touches
if (movedThisTurn)
return NO;
然后我们需要添加新的方法,以便处理玩家通过弹出菜单所选的行动。不够有一种行动需要我们判断当前的军事单位是否属于Solider(很快我们就会接触这段代码)。所以我们需要在Unit.m的顶部导入Solider单位的头文件:
#import &Unit_Soldier.h&
最后让我们在Unit.m的底部添加以下方法来实现弹出菜单中设定的各种行为:
// Stay on the current tile
-(void)doStay {
// 1 - Remove the context menu since we've taken an action
[theGame removeActionsMenu];
movedThisTurn = YES;
// 2 - Turn the unit tray to indicate that it has moved
[mySprite setColor:ccGRAY];
[theGame unselectUnit];
// 3 - Check for victory conditions
if ([self isKindOfClass:[Unit_Soldier class]]) {
// If this is a Soldier unit and it is standing over an enemy building, the player wins.
// We'll handle this situation in detail later
// Attack another unit
-(void)doAttack {
// You'll handle attack later
// Cancel the move for the current unit and go back to previous position
-(void)doCancel {
// Remove the context menu since we've taken an action
[theGame removeActionsMenu];
// Move back to the previous tile
mySprite.position = [theGame positionForTileCoord:tileDataBeforeMovement.position];
[theGame unselectUnit];
搞定收工!
编译运行项目,现在我们可以在单位移动完成后看到该菜单,并和它进行交互。
解决回合制的问题
如果你足够细心,会发现几个让人不爽的事情。首先,一旦你移动完某个单位后,就再也不能移动它了。而且你没法在玩家间切换,也就是说两方的单位都可以随时移动!
虽然这些不会影响游戏性,但这篇教程的主题是回合制策略游戏。所以,为了让这个主题得以实现,我们将在屏幕的顶部添加一个HUD,用于说明当前该哪个玩家来操控。HUD中还会提供一个按钮,从而把控制权交给另一个玩家。当然,每个玩家只能操控属于自己的单位。
为了实现上面的目的,我们需要添加几个实例变量。切换到HelloWorldLayer.h,并添加以下代码:
CCMenuItemImage *endTurnB
CCLabelBMFont *turnL
然后添加以下方法的定义:
-(void)addM
-(void)doEndT
-(void)setPlayerTurnL
-(void)showEndTurnT
-(void)beginT
-(void)removeLayer:(CCNode *)n;
-(void)activateUnits:(NSMutableArray *)
切换到HelloWorldLayer.m,并在init的底部添加以下代码:
//Set up turns
playerTurn = 1;
[self addMenu];
接下来,在文件的底部添加以上方法的实现代码:
// Add the user turn menu
-(void)addMenu {
// Get window size
CGSize wins = [[CCDirector sharedDirector] winSize];
// Set up the menu background and position
CCSprite * hud = [CCSprite spriteWithFile:@&uiBar.png&];
[self addChild:hud];
[hud setPosition:ccp(wins.width/2,wins.height-[hud boundingBox].size.height/2)];
// Set up the label showing the turn
turnLabel = [CCLabelBMFont labelWithString:[NSString stringWithFormat:@&Player %d's turn&,playerTurn] fntFile:@&Font_dark_size15.fnt&];
[self addChild:turnLabel];
[turnLabel setPosition:ccp([turnLabel boundingBox].size.width/2 + 5,wins.height-[hud boundingBox].size.height/2)];
// Set the turn label to display the current turn
[self setPlayerTurnLabel];
// Create End Turn button
endTurnBtn = [CCMenuItemImage itemFromNormalImage:@&uiBar_button.png& selectedImage:@&uiBar_button.png& target:self selector:@selector(doEndTurn)];
CCMenu * menu = [CCMenu menuWithItems:endTurnBtn, nil];
[self addChild:menu];
[menu setPosition:ccp(0,0)];
[endTurnBtn setPosition:ccp(wins.width - 3 - [endTurnBtn boundingBox].size.width/2, wins.height - [endTurnBtn boundingBox].size.height/2 - 3)];
// End the turn, passing control to the other player
-(void)doEndTurn {
// Do not do anything if a unit is selected
if (selectedUnit)
// Switch players depending on who's currently selected
if (playerTurn ==1) {
playerTurn = 2;
} else if (playerTurn ==2) {
playerTurn = 1;
// Do a transition to signify the end of turn
[self showEndTurnTransition];
// Set the turn label to display the current turn
[self setPlayerTurnLabel];
// Set the turn label to display the current turn
-(void)setPlayerTurnLabel {
// Set the label value for the current player
[turnLabel setString:[NSString stringWithFormat:@&Player %d's turn&,playerTurn]];
// Change the label colour based on the player
if (playerTurn ==1) {
[turnLabel setColor:ccRED];
} else if (playerTurn == 2) {
[turnLabel setColor:ccBLUE];
// Fancy transition to show turn switch/end
-(void)showEndTurnTransition {
// Create a black layer
ccColor4B c = {0,0,0,0};
CCLayerColor *layer = [CCLayerColor layerWithColor:c];
[self addChild:layer z:20];
// Add a label showing the player turn to the black layer
CCLabelBMFont * turnLbl = [CCLabelBMFont labelWithString:[NSString stringWithFormat:@&Player %d's turn&,playerTurn] fntFile:@&Font_silver_size17.fnt&];
[layer addChild:turnLbl];
[turnLbl setPosition:ccp([CCDirector sharedDirector].winSize.width/2,[CCDirector sharedDirector].winSize.height/2)];
// Run an action which fades in the black layer, calls the beginTurn method, fades out the black layer, and finally removes it
[layer runAction:[CCSequence actions:[CCFadeTo actionWithDuration:1 opacity:150],[CCCallFunc actionWithTarget:self selector:@selector(beginTurn)],[CCFadeTo actionWithDuration:1 opacity:0],[CCCallFuncN actionWithTarget:self selector:@selector(removeLayer:)], nil]];
// Begin the next turn
-(void)beginTurn {
// Activate the units for the active player
if (playerTurn ==1) {
[self activateUnits:p2Units];
} else if (playerTurn ==2) {
[self activateUnits:p1Units];
// Remove the black layer added for the turn change transition
-(void)removeLayer:(CCNode *)n {
[n.parent removeChild:n cleanup:YES];
此时你会发现我们少了一个方法activateUnits:的实现代码,这是因为该方法将激活所有属于当前玩家的军事单位。遗憾的是在Unit类中还没有方法实现它。
所以让我们切换到Unit.h,添加一个新的辅助方法的定义:
-(void)startT
接下来当然是在Unit.m中添加该方法的实现代码:
// Activate this unit for play
-(void)startTurn {
// Mark the unit as not having moved for this turn
movedThisTurn = NO;
// Mark the unit as not having attacked this turn
attackedThisTurn = NO;
// Change the unit overlay colour from gray (inactive) to white (active)
[mySprite setColor:ccWHITE];
现在辅助方法就绪了,接下来让我们切换回HelloWorldLayer.m,并在文件的最后添加activateUnits:的实现代码:
// Activate all the units in the specified array (called from beginTurn passing the units for the active player)
-(void)activateUnits:(NSMutableArray *)units {
for (Unit *unit in units) {
[unit startTurn];
如你所见,该方法将会遍历当前玩家的军事单位数组,并使用startTurn方法来依次激活每个军事单位。
现在搞定了没?差不多了~不过还有一个小小的问题需要解决,此时我们还无法阻止玩家选择不属于自己的军事单位。
要修复这个问题很简单。在Xcode中切换到Unit.m,然后在ccTouchBegan:方法的顶部添加以下代码:
// Was a unit belonging to the non-active player touched? If yes, do not handle the touch
if (([theGame.p1Units containsObject:self] && theGame.playerTurn == 2) || ([theGame.p2Units containsObject:self] && theGame.playerTurn == 1))
return NO;
以上代码的作用是检查所触碰的单位是否属于玩家1或2,如果所触碰的单位不属于当前的玩家,则什么也不做。
编译运行游戏,我们会看到右上角有个按钮,可以让当前玩家将操控权交给下一个玩家。每个玩家都可以在自己的操控时间内移动属于自己的某个单位,然后该单位在下一回合前将不可用。
当你结束一个回合时,将可以看到切换效果。
攻击其它军事单位
搞了大半天,我们的战争机器还没有真正运转起来,不打仗还叫军事单位?首先我们来设定下逻辑:
1.当某个军事单位移动完成后,如果它在攻击范围内(临近某个敌军单位,大炮除外,因为其攻击范围很广),那么它可以攻击到的单位将使用红色标出。
2.如果玩家选择某个使用红色标出的单位,则战斗开始。
3.攻击单位将会首先开火,而如果防御单位幸免于难,则将开火反击。
4.每个单位所造成的伤害将由双方的单位类型来决定,和剪刀石头布的游戏有点像,每种单位都有自己的克星,同时也克制着另外几种单位。
首先要做的事情就是在移动完成后检查周边的敌军单位。为此,切换到Unit.m,并使用以下代码替换popStepAndAnimate:方法的#1部分:
// 1 - Check if the unit is done moving
if ([movementPath count] == 0) {
// 1.1 - Mark the unit as not moving
moving = NO;
[self unMarkPossibleMovement];
// 1.2 - Mark the tiles that can be attacked
[self markPossibleAction:kACTION_ATTACK];
// 1.3 - Check for enemies in range
BOOL enemiesAreInRange = NO;
for (TileData *td in theGame.tileDataArray) {
if (td.selectedForAttack) {
enemiesAreInRange = YES;
// 1.4 - Show the menu and enable the Attack option if there are enemies in range
[theGame showActionsMenu:self canAttack:enemiesAreInRange];
在以上代码中的1.3部分,我们检查了tileDataArray,该数组保存了背景层中所有显示的瓦片,并判断是否有瓦片被标记为selectedForAttack。那么一个瓦片是如何被设置为selectedForAttack的呢?实际上在1.2部分中当我们调用markPossibleAction:时就已完成了设置。不过既然我们到现在为止还没有真正实施攻击,就必须将该功能添加到markPossibleAction:方法中。
在实际修改该方法前,还需要添加一些辅助方法。为什么呢?因为目前我们还没办法来检查包含敌军单位的瓦片。和之前一样,当我们所需的辅助方法在游戏区域中时,会把这些方法添加到HelloWorldLayer中。
首先在HelloWorldLayer.h中添加以下方法定义:
-(BOOL)checkAttackTile:(TileData *)tData unitOwner:(int)
-(BOOL)paintAttackTile:(TileData *)tD
-(void)unPaintAttackT
-(void)unPaintAttackTile:(TileData *)tileD
然后切换到HelloWorldLayer.m,并在文件的最后添加方法的实现代码如下:
// Check the specified tile to see if it can be attacked
-(BOOL)checkAttackTile:(TileData *)tData unitOwner:(int)owner {
// Is this tile already marked for attack, if so, we don't need to do anything further
// If not, does the tile contain an enemy unit? If yes, we can attack this tile
if (!tData.selectedForAttack && [self otherEnemyUnitInTile:tData unitOwner:owner]!= nil) {
tData.selectedForAttack = YES;
return NO;
return YES;
// Paint the given tile as one that can be attacked
-(BOOL)paintAttackTile:(TileData *)tData {
CCSprite * tile = [bgLayer tileAt:tData.position];
[tile setColor:ccRED];
return YES;
// Remove the attack marking from all tiles
-(void)unPaintAttackTiles {
for (TileData * td in tileDataArray) {
[self unPaintAttackTile:td];
// Remove the attack marking from a specific tile
-(void)unPaintAttackTile:(TileData *)tileData {
CCSprite * tile = [bgLayer tileAt:tileData.position];
[tile setColor:ccWHITE];
ok辅助方法已经完全准备好了,接下来我们可以让Unit对象调用checkAttackTile:unitOwner方法,以检查完成移动的军事单位附近的每个瓦片。
我们需要在Unit.m的markPossibleAction:方法中几次调用该方法。首先,将之前注释的else if(action ==kAction_ATTACK)语句替换为以下语句:
else if (action == kACTION_ATTACK) {
[theGame checkAttackTile:startTileData unitOwner:owner];
然后替换for循环中的被注释的else if条件语句:
else if (action == kACTION_ATTACK) {
[theGame checkAttackTile:_neighbourTile unitOwner:owner];
最后,紧接着上面的语句还有一个else if条件语句,不过它并没有被注释,使用以下语句替换其中的内容:
else if (action == kACTION_ATTACK) {
// Is the tile not in attack range?
if ([_neighbourTile getGScoreForAttack]& attackRange) {
// Ignore it
我们还需要实现doAttack:方法,当玩家从弹出菜单中选择Attack选项时将调用该方法。使用以下代码替换doAttack方法的内容:
// Attack another unit
-(void)doAttack {
// 1 - Remove the context menu since we've taken an action
[theGame removeActionsMenu];
// 2 - Check if any tile has been selected for attack
for (TileData *td in theGame.tileDataArray) {
if (td.selectedForAttack) {
// 3 - Mark the selected tile as attackable
[theGame paintAttackTile:td];
selectingAttack = YES;
一旦某个军事单位完成了当前的回合,我们将会取消瓦片上的可攻击标记。让我们来添加一个方法来实现这一点。和之前一样,首先在Unit.h中添加一个方法定义:
-(void)unMarkPossibleA
然后在Unit.m中添加该方法的实现代码:
// Remove attack selection marking from all tiles
-(void)unMarkPossibleAttack {
for (TileData *td in theGame.tileDataArray) {
[theGame unPaintAttackTile:td];
td.parentTile =
td.selectedForAttack = NO;
最后,在unselectUnit方法的结尾处添加代码调用刚才的方法:
[self unMarkPossibleAttack];
编译运行游戏。如果你移动某个单位靠近敌军单位,并从弹出菜单中选择attack,敌军单位就会变红。
可是现在又有了一些小问题。当我们触碰要攻击的敌军单位时,并没有发生其它事情。此外,一旦某个单位被选择用于攻击,就无法结束当前的回合。
接下来,我们将学习如何处理真实的火力交锋,伤害计算和单位的损伤,以及解决回合结束的问题。
首先还是要在HelloWorldLayer中添加一个新的辅助方法,用于判断攻击中所受到的伤害。在HelloWorldLayer.h中添加以下方法定义:
-(int)calculateDamageFrom:(Unit *)attacker onDefender:(Unit *)
然后切换到HelloWorldLayer.m,首先导入所需的单位类型头文件:
#import &Unit_Soldier.h&
#import &Unit_Tank.h&
#import &Unit_Cannon.h&
#import &Unit_Helicopter.h&
然后添加该方法的实现代码:
// Calculate the damage inflicted when one unit attacks another based on the unit type
-(int)calculateDamageFrom:(Unit *)attacker onDefender:(Unit *)defender {
if ([attacker isKindOfClass:[Unit_Soldier class]]) {
if ([defender isKindOfClass:[Unit_Soldier class]]) {
} else if ([defender isKindOfClass:[Unit_Helicopter class]]) {
} else if ([defender isKindOfClass:[Unit_Tank class]]) {
} else if ([defender isKindOfClass:[Unit_Cannon class]]) {
} else if ([attacker isKindOfClass:[Unit_Tank class]]) {
if ([defender isKindOfClass:[Unit_Soldier class]]) {
} else if ([defender isKindOfClass:[Unit_Helicopter class]]) {
} else if ([defender isKindOfClass:[Unit_Tank class]]) {
} else if ([defender isKindOfClass:[Unit_Cannon class]]) {
} else if ([attacker isKindOfClass:[Unit_Helicopter class]]) {
if ([defender isKindOfClass:[Unit_Soldier class]]) {
} else if ([defender isKindOfClass:[Unit_Helicopter class]]) {
} else if ([defender isKindOfClass:[Unit_Tank class]]) {
} else if ([defender isKindOfClass:[Unit_Cannon class]]) {
} else if ([attacker isKindOfClass:[Unit_Cannon class]]) {
if ([defender isKindOfClass:[Unit_Soldier class]]) {
} else if ([defender isKindOfClass:[Unit_Helicopter class]]) {
} else if ([defender isKindOfClass:[Unit_Tank class]]) {
} else if ([defender isKindOfClass:[Unit_Cannon class]]) {
接下来,我们需要在Unit类中添加方法来执行攻击和处理攻击。切换到Unit.h,并添加以下方法定义:
-(void)doMarkedAttack:(TileData *)targetTileD
-(void)attackedBy:(Unit *)attacker firstAttack:(BOOL)firstA
-(void)dealDamage:(NSMutableDictionary *)damageD
-(void)removeExplosion:(CCSprite *)e;
然后切换到Unit.m,并在文件的最后添加以上方法的实现代码:
// Attack the specified tile
-(void)doMarkedAttack:(TileData *)targetTileData {
// Mark the unit as having attacked this turn
attackedThisTurn = YES;
// Get the attacked unit
Unit *attackedUnit = [theGame otherEnemyUnitInTile:targetTileData unitOwner:owner];
// Let the attacked unit handle the attack
[attackedUnit attackedBy:self firstAttack:YES];
// Keep this unit in the curren location
[self doStay];
// Handle the attack from another unit
-(void)attackedBy:(Unit *)attacker firstAttack:(BOOL)firstAttack {
// Create the damage data since we need to pass this information on to another method
NSMutableDictionary *damageData = [NSMutableDictionary dictionaryWithCapacity:2];
[damageData setObject:attacker forKey:@&attacker&];
[damageData setObject:[NSNumber numberWithBool:firstAttack] forKey:@&firstAttack&];
// Create explosion sprite
CCSprite *explosion = [CCSprite spriteWithFile:@&explosion_1.png&];
[self addChild:explosion z:10];
[explosion setPosition:mySprite.position];
// Create explosion animation
CCAnimation *animation = [CCAnimation animation];
for (int i=1;i
需要注意的是,buildingInTile:会返回它在指定瓦片上找到的第一个建筑。如果两个建筑在同一个瓦片上,这样做可能会导致麻烦。好在我们的游戏不是这样设定的,所以暂且无需为这一点而担忧。
最后一步是确保当陆战队单位移动到敌军总部时让游戏结束。切换到Unit.m,在doStay:方法的#3部分的if循环中添加以下代码:
// Get the building on the current tile
Building *buildingBelow = [theGame buildingInTile:[theGame getTileData:[theGame tileCoordForPosition:mySprite.position]]];
// Is there a building?
if (buildingBelow) {
// Is the building owned by the other player?
if (buildingBelow.owner != self.owner) {
NSLog(@&Building captured!!!&);
// Show end game message
[theGame showEndGameMessageWithWinner:self.owner];
终于搞定了!编译运行游戏,你会看到屏幕的两端都会出现敌军总部。试着把某个陆战队员单位移动到敌军总部上,游戏届时将会结束。
音乐和音效
整个项目差不多完工了。不过如果一款游戏没有音乐和音效,对玩家的吸引力也会大打折扣。我从中搞了点音乐,然后使用CXFR制作了音效。
首先在HelloWorldLayer.m中导入SimpleAudioEngine的头文件:
#import &SimpleAudioEngine.h&
在init方法的最后,在[self addMenu]语句之后添加以下代码:
// Play background music
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&Five Armies.mp3& loop:YES];
最后让我们给不同事件添加一些音效。
首先是当玩家选择”End Turn”按钮的时候,在doEndTurn方法的第一个if语句后添加以下代码:
// Play sound
[[SimpleAudioEngine sharedEngine] playEffect:@&btn.wav&];
然后在Unit.m的顶部添加代码:
#import &SimpleAudioEngine.h&
,并在attackedBy:firstAttack:方法的最后一行代码(播放爆炸动画)前添加以下代码:
// Play damage sound
[[SimpleAudioEngine sharedEngine] playEffect:@&hurt.wav&];
在dealDamage:方法的#4部分的开始处添加以下代码:
// Unit destroyed sound
[[SimpleAudioEngine sharedEngine] playEffect:@&explosion.wav&];
最后的最后的最后,在doStay,doAttack和doCancel方法的顶部添加以下代码:
// Play menu selection sound
[[SimpleAudioEngine sharedEngine] playEffect:@&btn.wav&];
于是,终于,我们完全搞定了!编译运行游戏,一款简单但完整的回合制策略游戏就大功告成了!
接下来做什么?
首先这里是本教程的完整示例:
不过现在还不是自鸣得意的时候。即便游戏的雏形已经有了,但如果要把它变成一款真正的产品,还需要很多事情要做:
1.何不添加一些新的更有趣的单位?比如,只能在水里移动的舰艇,可以搭载士兵的单位,可以治疗其它单位的医护兵或救护车,等等。
2.何不添加一些其它类型的建筑,比如可以使用现金来修建坦克的工厂,或是医院。
3.何不多提供几种地图选择?玩家可以选择其它地形,或是可以被摧毁的物体?
4.你也可以完全改变游戏的风格,比如一个中世纪魔幻风格的游戏,或是充满了外星异形战士的科幻题材游戏。
尽情发挥你的创意和想象力吧,期待着你的佳作!
Cocos2d-x核心开发者
2 1 1 1 1 1
2091 1823 1756 1513 1479 1359 1311 1225 1219 1160
18 泰然处之
14 angelalek
12 weiblue

我要回帖

更多关于 忘记过去的名字 的文章

 

随机推荐