如何在unity中制作塔防游戏 —— 瞄准敌人

当游戏运行时,在Hierarchy 中扩展一个Enemy(Clone) 对象并选择它的子集HealthBar 。改变它的Current Health 值并查看生命条的改变。

追踪射程内的敌人

现在怪兽需要知道要锁定哪个敌人为目标。在实现之前需要对怪兽和敌人做一些准备工作。

在Project Browser中选择Prefabs\Monster 并在Inspector中为它添加一个Circle Collider 2D 碰撞器。

将碰撞器的Radius 设置为2.5 ——这个设置了怪兽的火力范围。

检查Is Trigger 以便对象可以通过这个区域而不是撞上它。

最后,在Inspector顶部,将怪兽的Layer 设置为Ignore Raycast。在对话框中点击 Yes, change children。如果不忽略光线投射,碰撞器会对点击事件作出反应。这个问题是因为怪兽阻挡了用于它们下方Openspots的事件。

为了检测敌人在触发区域内,需要给它添加一个碰撞器和刚体,因为只有碰撞器被附加了刚体unity才能发出触发事件。

在Project Browser中,选择Prefabs\Enemy。添加有 Is Kinematic 检测的RigidBody 2D 组件。这意味着物体不会被物理效果影响。

添加一个Radius 为 1的Circle Collider 2D 。重复这些步骤来完成Prefabs\Enemy 2。

触发现在设置好了,当敌人在射程内怪兽就会发现。现在还需要再准备一件事:一个当敌人被摧毁时通知怪兽的脚本,这样它们就不用再进行额外的射击了。创建一个名为EnemyDestructionDelegate 的脚本并将它添加给Enemy和 Enemy2 两个预制件。

在MonoDevelop中打开EnemyDestructionDelegate.cs ,添加下边的委托定义:

Public delegatevoid EnemyDelegate (GameObject enemy);
public EnemyDelegate enemyDelegate;

现在创建了一个delegate,一个可以像变量一样被传递的函数容器。

注:当想要一个游戏对象主动通知其他游戏对象的变化时使用委托。在 from the Unity documentation可学习更多有关委托的使用。

添加下边的方法:

void OnDestroy (){
if(enemyDelegate !=null){
    enemyDelegate (gameObject);
}
}

基于游戏对象的摧毁,unity自动呼叫方法,并检查委托是否为null。这种情况下,将gameObject 作为参数呼叫它。这个允许所有作为委托被注册的侦听器知道敌人被摧毁了。

保存文件并回到unity

给怪兽杀死敌人的许可

现在怪兽能察觉射程内的敌人了。给Monster 预制件添加一个新脚本并命名为ShootEnemies。

在MonoDevelop中打开ShootEnemies.cs并添加如下using 声明以便可以访问Generics。

usingSystem.Collections.Generic;

添加一个变量来记录所有在射程内的敌人:

public List<GameObject> enemiesInRange;

在enemiesInRange,将会存储所有在射程内的敌人。

在Start()中初始化字段。

// 1
void OnEnemyDestroy (GameObject enemy){
  enemiesInRange.Remove(enemy);
}
  
void OnTriggerEnter2D (Collider2D other){
// 2
if(other.gameObject.tag.Equals("Enemy")){
    enemiesInRange.Add(other.gameObject);
    EnemyDestructionDelegate del =
        other.gameObject.GetComponent<EnemyDestructionDelegate>();
    del.enemyDelegate+= OnEnemyDestroy;
}
}
// 3
void OnTriggerExit2D (Collider2D other){
if(other.gameObject.tag.Equals("Enemy")){
    enemiesInRange.Remove(other.gameObject);
    EnemyDestructionDelegate del =
        other.gameObject.GetComponent<EnemyDestructionDelegate>();
    del.enemyDelegate-= OnEnemyDestroy;
}
}
  1. 在OnEnemyDestroy中,从enemiesInRange将敌人移除。当敌人走入触发区域是怪兽的OnTriggerEnter2D 被呼叫。
  2. 然后将敌人添加到enemiesInRange 列表并将OnEnemyDestroy 添加到EnemyDestructionDelegate。这个用来确保当敌人被摧毁时OnEnemyDestroy 会被呼叫。现在不想让怪兽在死掉的敌人身上浪费子弹——是吧?
  3. 在OnTriggerExit2D 从列表移除敌人并注销委托。现在知道哪些敌人在射程内了。

保存文件并在Unity中运行游戏。为了检测它是否工作,放置一个怪兽,选中它并在Inspector中观察enemiesInRange 列表的变化。

选择目标

现在怪兽知道哪个敌人在射程内了。不过如有有很多敌人在射程内他们该怎么做?

当然,他们要攻击距离曲奇最近的敌人!

在MonoDevelop中打开MoveEnemy.cs ,添加下边方法来计算这个:

public float distanceToGoal(){
float distance =0;
  distance += Vector3.Distance(
      gameObject.transform.position, 
      waypoints [currentWaypoint +1].transform.position);
for(int i = currentWaypoint +1; i < waypoints.Length-1; i++){
    Vector3 startPosition = waypoints .transform.position;
    Vector3 endPosition = waypoints [i +1].transform.position;
    distance += Vector3.Distance(startPosition, endPosition);
}
return distance;
}

这个代码计算敌人还没有走过的路程距离。通过用 Distance来实现,用来计算两个Vector3 物体间差距。
稍后会用这个方法来计算攻击哪个目标。然而,怪兽还没有武装起来,它们并没有什么用,所以先修复这点。

下一次我们会讲解设置子弹并完成这个游戏。

标签: 新手入门, unity, unity2d

?>