以上代码块相当直观 - 但是它分解的有些细致了.

首先,敌人通过传递HelloWorldLayer对象的引用而初始化.在init方法里,少数重要的变量被设置:

  • maxHP:定义敌人有多经打(Tough guy,eh?)
  • wakingSpeed:定义敌人移动的有多快
  • mySprite:存储敌人可视化的表示
  • destinationWaypoint:存储下一个路径点的引用.

其中update方法是真正见证奇迹的地方(where the magic happens),它每一帧被调用,并且首先检查自身是否到达了目的路径点,使用的方法是你在前面写过的collisionWithCircle方法.如果到达了,它将向下一个路径点前进 - 除非敌人达到终点或者被玩家摧毁了.

然后它沿着到目的路径点的直线移动精灵,用它自己特定的速度前进.它用接下来的算法达到此目的:

  • 计算出一个当前位置到目标位置的向量点,然后使它的长度为1以便于处理(normalized变量).
  • 将normalized向量乘以移动速度得到在一帧中移动的距离.累加到当前位置上最后得到新的位置.

最终,draw方法简单的在精灵之上实现一个血条.它后续绘制一个红色背景,然后在它之上覆盖一个表示当前敌人HP的绿色矩形条.

现在Enemy类完成了,你可以把它们显示在屏幕上了!

切换至HelloWorldLayer.m文件,完成如下修改:

//At the top of the file:
#import "Enemy.h"

//Add the following methods:
-(BOOL)loadWave {
    NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"Waves" ofType:@"plist"];
    NSArray * waveData = [NSArray arrayWithContentsOfFile:plistPath];

    if(wave >= [waveData count])
    {
        return NO;
    }

    NSArray * currentWaveData =[NSArray arrayWithArray:[waveData objectAtIndex:wave]];

    for(NSDictionary * enemyData in currentWaveData)
    {
        Enemy * enemy = [Enemy nodeWithTheGame:self];
        [enemies addObject:enemy];
        [enemy schedule:@selector(doActivate)
               interval:[[enemyData objectForKey:@"spawnTime"]floatValue]];
    }

    wave++;
    [ui_wave_lbl setString:[NSString stringWithFormat:@"WAVE: %d",wave]];

    return YES;

}

-(void)enemyGotKilled {
    if ([enemies count]<=0) //If there are no more enemies.
    {
        if(![self loadWave])
        {
            NSLog(@"You win!");
            [[CCDirector sharedDirector] replaceScene:[CCTransitionSplitCols
                                                       transitionWithDuration:1
                                                       scene:[HelloWorldLayer scene]]];
        }
    }
}

// Add the following to the end of the init method:
// 5 - Add enemies
enemies = [[NSMutableArray alloc] init];
[self loadWave];
// 6 - Create wave label
ui_wave_lbl = [CCLabelBMFont labelWithString:[NSString stringWithFormat:@"WAVE: %d",wave]
                                             fntFile:@"font_red_14.fnt"];
[self addChild:ui_wave_lbl z:10];
[ui_wave_lbl setPosition:ccp(400,winSize.height-12)];
[ui_wave_lbl setAnchorPoint:ccp(0,0.5)];

所有这些代码的改变需要一些解释.最重要的部分是loadWave方法;他从Waves.plist文件读取数据.

Cocos2D:塔防游戏制作之旅(十二)的更多相关文章

  1. Cocos2D:塔防游戏制作之旅(十八)

    在Enemy.m的getDamaged:方法只给你添加如下1行(在if条件内): [theGame awardGold:200]; 现在运行游戏你将注意到你不能放置超出你资源金币的炮塔了.当然杀死敌人 ...

  2. Cocos2D:塔防游戏制作之旅(十六)

    编译运行你的app,放置一些炮塔在你的地图上吧!你将看到炮塔在敌人移动如攻击范围时如何立即开始攻击,并且敌人的血条将随着攻击不断减少知道它们被人道毁灭!胜利即将来临了! 哦!Okay,这里只有少数细节 ...

  3. Cocos2D:塔防游戏制作之旅(十四)

    塔之战:炮塔的攻击 炮塔就位了?检查.敌人前进中?再次检查 - 它们看起来就是如此!看起来到了击溃这些家伙的时候了!这里我们将智能置入炮塔的代码中去. 每一个炮塔检查是否有敌人在其攻击范围.(炮塔一次 ...

  4. Cocos2D:塔防游戏制作之旅(十)

    最终,draw方法显示这些路径点被放置在哪里,并且绘制出路径点之间的连线,它们仅仅被用作调试.一个成品游戏不应该绘制敌人的路径 - 那对于玩家来说太过容易了! 创建路径点的列表.打开HelloWorl ...

  5. Cocos2D:塔防游戏制作之旅(十五)

    Yes,貌似添加了好多的代码啊 ;] ,在你添加更多代码时,你可能注意到一些Xcode中的一些警告.首先你先忽略这些警告,我们先添加少量最终缺失的部分,然后再来解释上面代码做了什么! 在Enemy.m ...

  6. Cocos2D:塔防游戏制作之旅(一)

    原文地址:http://www.raywenderlich.com/37701/how-to-make-a-tower-defense-game-tutorial 由Pablo Ruiz写的入门教程, ...

  7. Cocos2D:塔防游戏制作之旅(二)

    一个象牙塔的视图 如果你并不熟悉此类型的游戏,塔防游戏是一个战略游戏,你需要购买和将武装塔放置在战略位置,去阻止一波又一波的敌人到达并摧毁你的基地 每一波敌人都更强,这些更强的对手有着更快的速度和对于 ...

  8. Cocos2D:塔防游戏制作之旅(十七)

    getHpDamage方法当敌人到达基地时被调用.你需要添加该方法到Enemy.m的update:方法中去,以便检查当敌人到达基地是会发生什么.幸运的是,你已经在之前的代码中实现这些了,你可以接着往下 ...

  9. Cocos2D:塔防游戏制作之旅(八)

    如果所有东西通过检查,则创建一个新炮塔,将它放置在基座上,然后添加到towers数组中. 注意:在方法最后的bridge语法需要做一些解释.你下载的初始项目已经为一 些文件打开ARC,但不是Cocos ...

随机推荐

  1. vue拦截器实现统一token,并兼容IE9验证

    项目中使用vue搭建前端页面,并通过axios请求后台api接口,完成数据交互.如果验证口令token写在在每次的接口中,也是个不小的体力活,而且也不灵活.这里分享使用vue自带拦截器,给每次请求的头 ...

  2. Java类加载器的工作原理

    Java类加载器的作用就是在运行时加载类.Java类加载器基于三个机制:委托.可见性和单一性.委托机制是指将加载一个类的请求交给父类加载 器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它. ...

  3. zookeeper工作机制

    Zookeeper Zookeeper概念简介: Zookeeper是为用户的分布式应用程序提供协调服务的 zookeeper是为别的分布式程序服务的 Zookeeper本身就是一个分布式程序(只要有 ...

  4. vue项目开发中遇到的问题总结--内部分享

     1.路由变化页面数据不刷新问题 这种情况一般出现在vue-router的history模式下,初次进入会执行钩子函数,再次进入时则不会. 解决方案: 监听路由变化 watch : { "$ ...

  5. 异常处理&RandomAccessFile&节奏感

    异常处理 异常处理方面的知识,下面是学习中记的笔记: try尝试捕获异常 catch对捕获的异常进行处理 多个catch要注意的问题: 一.顺序问题,先小后大,也就是先子类后父类.因为当异常出现的时候 ...

  6. 利用Filter和拦截器,将用户信息动态传入Request方法

    前言: 在开发当中,经常会验证用户登录状态和获取用户信息.如果每次都手动调用用户信息查询接口,会非常的繁琐,而且代码冗余.为了提高开发效率,因此就有了今天这篇文章. 思路: 用户请求我们的方法会携带一 ...

  7. Node.js 系统

    稳定性: 4 - API 冻结 提供一些基本的操作系统相关函数. 使用 require('os') 访问这个模块. os.tmpdir() 返回操作系统的默认临时文件夹 os.endianness() ...

  8. WebRTC 音频算法 附完整C代码

    WebRTC提供一套音频处理引擎, 包含以下算法: AGC自动增益控制(Automatic Gain Control) ANS噪音抑制(Automatic Noise Suppression) AEC ...

  9. 在查询语句中使用 NOLOCK 和 READPAST

    对于非银行等严格要求事务的行业,搜索记录中出现或者不出现某条记录,都是在可容忍范围内,所以碰到死锁,应该首先考虑,我们业务逻辑是否能容忍出现或者不出现某些记录,而不是寻求对双方都加锁条件下如何解锁的问 ...

  10. Bootstrap3 栅格系统-嵌套列

    为了使用内置的栅格系统将内容再次嵌套,可以通过添加一个新的 .row 元素和一系列 .col-sm-* 元素到已经存在的 .col-sm-* 元素内.被嵌套的行(row)所包含的列(column)的个 ...