[转帖]如何设计开发iPhone塔防游戏10 –整装待发_VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3771 | 回复: 0   主题: [转帖]如何设计开发iPhone塔防游戏10 –整装待发        下一篇 
baijiang.lu
注册用户
等级:少校
经验:947
发帖:81
精华:0
注册:2013-9-2
状态:离线
发送短消息息给baijiang.lu 加好友    发送短消息息给baijiang.lu 发消息
发表于: IP:您无权察看 2013-9-10 15:26:05 | [全部帖] [楼主帖] 楼主

在继续学习下面的教程之前,我们需要对之前的项目代码做一些调整。

而从下一部分的教程开始,我们将逐渐引入范围攻击,炮塔升级(实时)等内容。

以下是相关的代码变动:

1.有时在敌人被消灭后,炮塔会朝(0,0)的位置发射炮弹。这是因为我们已经清除了炮塔的目标,但还没有通知炮塔停止设计。在Xcode中切换到Tower.m,并找到finishFiring方法,修改如下:

-(void)finishFiring {
      2
      if (self.target != NULL) {
            3
            // 保持原有代码不变Keep all pre-existing code
            4
      } }


2.我们希望炮塔每次只瞄准一个敌人,直到它被消灭或是冲出了火力范围。但此时炮塔只会朝着最近的敌人攻击。因此在每个Tower分类中添加以下方法:

-(void)checkTarget {
      2
      double curDistance = ccpDistance(self.position, self.target.position);
      3
      if (self.target.hp <= 0 || curDistance > self.range){
            4
      self.target = [self getClosestTarget]; } }


在+(id)tower方法中添加对该方法的调用:

[tower schedule:@selector(checkTarget) interval:0.5];


然后在towerLogic方法中更改代码如下:

-(void)towerLogic:(ccTime)dt {
      4
      if (self.target == nil) {
            5
            self.target = [self getClosestTarget];
            6
      }
      7
      //其它代码保持不变:All other code stays the same
      8
}
float rotateSpeed = 0.25 / M_PI; // 1/4 second to rotate 180 degrees and in finished


3.增加炮塔旋转和子弹的速度。在towerLogic方法中更改rotateSpeed:

并ccTime delta =0.5;修改delta值:

4.此时我们可以在同一位置修建两个炮塔,这显然是不合理的。在TutorialScne.m中更改canBuildOnTilePosition方法如下:

-(BOOL) canBuildOnTilePosition:(CGPoint) pos
02
{
      03
      CGPoint towerLoc = [self tileCoordForPosition: pos];
      04
      int tileGid = [self.background tileGIDAt:towerLoc];
      05
      NSDictionary *props = [self.tileMap propertiesForGID:tileGid];
      06
      NSString *type = [props valueForKey:@"buildable"];
      07
      08
      bool occupied = NO;
      09
      DataModel *m = [DataModel getModel];
      10
      11
      for (Tower *tower in m._towers) {
            12
            CGRect towerRect = CGRectMake(tower.position.x - (tower.contentSize.width/2), tower.position.y - (tower.contentSize.height/2), tower.contentSize.width, tower.contentSize.height);
            13
            if (CGRectContainsPoint(towerRect, pos)) {
                  14
                  occupied = YES;
                  15
            }
            16
      }
      17
      18
      if([type isEqualToString: @"1"] && occupied == NO) {
            19
            return YES;
            20
      }
      21
      return NO;
      22
}


类似的,在addTower方法中switch语句前添加以下代码:

-(void)addTower: (CGPoint)pos: (int)towerTag {
      02
      DataModel *m = [DataModel getModel];
      03
      Tower *target = nil;
      04
      CGPoint towerLoc = [self tileCoordForPosition: pos];
      05
      06
      int tileGid = [self.background tileGIDAt:towerLoc];
      07
      NSDictionary *props = [self.tileMap propertiesForGID:tileGid];
      08
      NSString *type = [props valueForKey:@"buildable"];
      09
      10
      bool occupied = NO;
      11
      12
      for (Tower *tower in m._towers) {
            13
            CGRect towerRect = CGRectMake(tower.position.x - (tower.contentSize.width/2), tower.position.y - (tower.contentSize.height/2), tower.contentSize.width, tower.contentSize.height);
            14
            if (CGRectContainsPoint(towerRect, pos)) {
                  15
                  occupied = YES;
                  16
            }
            17
      }
      18
      19
      if([type isEqualToString: @"1"] && occupied == NO) {
      20
      switch (towerTag) {
      21
      //Leave all other code the same.


5.当放置炮塔时,因为手指的遮挡,玩家没法看到炮塔。因此我们需要将炮塔向上移动一点,这样在放置炮塔时就可以看到了。首先切换到GameHUD.m,找到ccTouchBegan方法,修改设置newSprite.position的代码如下:

newSprite.position = ccpAdd(sprite.position, ccp(0, 50));


然后切换到TutorialScene.m,找到canBuildOnTilePosition方法,并在实现代码的开始添加以下代码:

pos = ccpAdd(pos, ccp(0, 50));


类似的,还可以在addTower方法的开始处添加这行代码。编译运行游戏,看看是否正常。

6. 此前,敌人会根据路点的间距来加速或减速。实际上我们希望看到的是敌人以相同的速度在地图上前进。在Xcode中切换到Creeps.m,然后添加以下方法:

(float) moveDurScale {
      02
      DataModel *m = [DataModel getModel];
      03
      04
      WayPoint *waypoint0 = (WayPoint *) [m._waypoints objectAtIndex:0];
      05
      WayPoint *waypoint1 = (WayPoint *) [m._waypoints objectAtIndex:1];
      06
      07
      firstDistance = ccpDistance(waypoint0.position, waypoint1.position);
      08
      WayPoint *waypoint2 = (WayPoint *) [m._waypoints objectAtIndex:(self.curWaypoint-1)];
      09
      WayPoint *waypoint3 = (WayPoint *) [m._waypoints objectAtIndex:(self.curWaypoint)];
      10
      11
      float thisDistance = ccpDistance(waypoint2.position, waypoint3.position);
      12
      float moveScale = thisDistance/firstDistance; return (self.moveDuration * moveScale);
      13
}
14
15
//Add to Creep.h interface float firstDistance;
16
(float) moveDurScale;


在以上的代码中,将当前路点间距作为前一个路点间距的f分数。然后使用该分数来调整moveDuration。

接下来切换到TutorialScene.m,并找到FollowPath方法,然后将

int moveDuration = creep.moveDuration;


替换为:

float moveDuration = [creep moveDurScale];


然后找到ResumePath方法,将

float moveDuration = creep.moveDuration * distFraction;


替float durScale = [creep moveDurScale];

2

换为:

float moveDuration = durScale * distFraction;


7. 添加Boss 如果每一波敌人都平淡无奇,就有点无趣了,我们也可以加点Boss。

在Xcode中切换到Creep.m,并添加以下类:

@implementation BossBrownCreep
02
03
+ (id)creep {
      04
      BossBrownCreep *creep = nil;
      05
      06
      if ((creep = [[[super alloc] initWithFile:@"Enemy3.png"] autorelease])) {
            07
            creep.hp = creep.initHp = 500;
            08
            creep.moveDuration = 10;
            09
            creep.curWaypoint = 0; [creep schedule:@selector(creepLogic:) interval:0.2];
            10
            11
            [creep schedule:@selector(healthBarLogic:)];
            12
      }
      13
      14
      return creep;
      15
}
16
@end
wave = [[Wave alloc] initWithCreep:[FastRedCreep creep] SpawnRate:1.0 RedCreeps:5
2
GreenCreeps:0 BrownCreeps:0];


接下来替换addTarget方法的内容如下:

-(void)addTarget {
      02
      DataModel *m = [DataModel getModel];
      03
      Wave * wave = [self getCurrentWave];
      04
      05
      if (wave.redCreeps <= 0 && wave.greenCreeps <= 0 && wave.brownCreeps <= 0) {
            06
            return; //
            07
      }
      08
      09
      //wave.totalCreeps--;
      10
      Creep *target = nil;
      11
      int creepChoice = (arc4random() % 3);
      12
      13
      int layer;
      14
      switch (creepChoice) {
            15
            case 0:
            16
            if (wave.redCreeps > 0) {
                  17
                  target = [FastRedCreep creep];
                  18
                  target.tag = 1;
                  19
                  wave.redCreeps--;
                  20
                  layer = 1;
                  21
            }
            22
            else {
                  23
                  [self addTarget];
                  24
                  return;
                  25
            }
            26
            break;
            27
            28
            case 1:
            29
            if (wave.greenCreeps >0) {
                  30
                  target = [StrongGreenCreep creep];
                  31
                  target.tag = 2;
                  32
                  wave.greenCreeps--;
                  33
                  layer = 1;
                  34
            }
            35
            else {
                  36
                  [self addTarget];
                  37
                  return;
                  38
            }
            39
            break;
            40
            41
            case 2:
            42
            if (wave.brownCreeps >0) {
                  43
                  target = [BossBrownCreep creep];
                  44
                  target.tag = 3;
                  45
                  wave.brownCreeps--;
                  46
                  layer = 2;
                  47
            }
            48
            else{
                  49
                  [self addTarget];
                  50
                  return;
                  51
            }
            52
            break;
            53
            54
            default:
            55
            break;
            56
      }
      57
      58
      WayPoint *waypoint = [target getCurrentWaypoint];
      59
      60
      target.position = waypoint.position;
      61
      waypoint = [target getNextWaypoint ];
      62
      63
      [self addChild:target z:layer];
      64
      float moveDuration = target.moveDuration;
      65
      id actionMove = [CCMoveTo actionWithDuration:moveDuration position:waypoint.position];
      66
      id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:@selector(FollowPath:)];
      67
      68
      [target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]]; // Add to targets array
      69
      [m._targets addObject:target];
      70
      return;
      71
}


最后找到update方法,并使用以下代码替代if判断语句:

if ([m._targets count] ==0 && wave.redCreeps <= 0 && wave.greenCreeps <= 0 && wave.brownCreeps <= 0)


8.关于敌人的血条。如果可以在敌人的头上显示血条,那么就可以看到每个敌人受到的伤害值是多少。在Creep.h中添加新的实例变量声明:

CCProgressTimer *healthBar;
2
int _totalHp;


别忘了添加相关的@property和@synthesize语句。

接下来切换到Creep.m,在creepLogic方法下添加以下方法:

-(void)healthBarLogic:(ccTime)dt {
      02
      03
      //Update health bar pos and percentage.
      04
      healthBar.position = ccp(self.position.x, (self.position.y+20));
      05
      healthBar.percentage = ((float)self.hp/(float)self.totalHp) *100;
      06
      07
      if (healthBar.percentage <= 0) {
            08
            [self removeChild:healthBar cleanup:YES];
            09
      }
      10
}


以上方法的作用是在敌人头上放置血条,并根据敌人的hp值来更新bar.percentage。此外在+(id)crep方法中添加对该方法的调用:

creep.hp = creep.totalHp = setRedHp;
2
[creep schedule:@selector(healthBarLogic:)];


最后在TutorialScene.m中的addTarget方法中添加以下代码:

//Under [self addChild:target z:1];
2
target.healthBar = [CCProgressTimer progressWithFile:@"health_bar_red.png"];
3
target.healthBar.type = kCCProgressTimerTypeHorizontalBarLR;
4
target.healthBar.percentage = 100;
5
[target.healthBar setScale:0.1];
6
target.healthBar.position = ccp(target.position.x,(target.position.y+20));
7
8
[self addChild:target.healthBar z:3];


然后找到upgrade方法,并更改以下代码

if (creep.hp <= 0) {
      2
      [targetsToDelete addObject:target];
      3
      [gameHUD updateResources:1];
      4
      [self removeChild:creep.healthBar cleanup:YES];//添加本行代码Add this
      5
}


这样一来,敌人的头上也有血条了。

9.波次速度调整:

在TutorialScene.m中添加以下方法:

-(void)waveWait {
      2
      [self unschedule:@selector(waveWait)];
      3
      [self getNextWave]; [gameHUD updateWaveCount];
      4
}


然后在更新方法中将[self getNextWave]和[gameHUD updateWaveCount]语句更改如下:

[self schedule:@selector(waveWait) interval:3.0];


现在每个波次间就会存在一定的间隔时间了。

10.告诉玩家波次的来临。

切换到GameHUD.h,并添加一个实例变量声明:

CCLabelTTF *newWaveLabel;


然后切换到GameHUD.m,并添加以下代码:

//Add to init
02
// Set up new Wave label
03
newWaveLabel = [CCLabelTTF labelWithString:@"" dimensions:CGSizeMake(300, 50)
04
alignment:UITextAlignmentRight fontName:@"TrebuchetMS-Bold" fontSize:30];
05
newWaveLabel.position = ccp((winSize.width/2)-20, (winSize.height/2)+30);
06
newWaveLabel.color = ccc3(255,50,50); [self addChild:newWaveLabel z:1];
07
08
//add new methods & define them in the header file
09
-(void) newWaveApproaching {
      10
      [newWaveLabel setString:[NSString stringWithFormat: @"HERE THEY COME!"]];
      11
}
12
13
-(void) newWaveApproachingEnd {
      14
      [newWaveLabel setString:[NSString stringWithFormat: @" "]];
      15
}


11.最后的最后,当游戏开始时,敌人立马就出现了,这个我可不太喜欢。因此这里也需要使用waveWait方法。

切换到TutorialScene.m,找到addWaves方法,并在开始处添加一个空的波次。

Wave *wave = nil;
2
wave = [[Wave alloc] initWithCreep:[FastRedCreep creep] SpawnRate:1.0 RedCreeps:0 GreenCreeps:0];
3
[m._waves addObject:wave];


在getNextWave中将最大波次修改为6,然后切换到GameHUD.m,在init方法中更改waveCount:

waveCount =0;


好了,以上就是所有的优化调整工作。

从下一部分开始,我们将添加新的炮塔类型,还会添加一些新的特征。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论