如何实现场景中 "kill" 事件的感知

How to achieve awareness of "kill" events in a scene

我一直在用 C# 在 Unity 中做一个 RPG 游戏,当做一个任务系统时,特别是那些杀死一定数量敌人的系统时,我发现场景中有 3 个敌人并成为目标的问题任务:杀死 3 个敌人。如果我在激活任务之前杀死他们,然后再激活任务,则任务不会给我奖励(在这种情况下是经验)。如果任务检测到我已经杀死了必要的敌人来获得任务,我该如何告诉敌人并让我平分奖励?


这是我认为需要的两个脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class QuestObject : MonoBehaviour {

    public int questNumber;

    public QuestManager qManager;

    public string startText;
    public string endText;

    public bool isItemQuest;
    public string targetItem;

    public bool isEnemyQuest;
    public string targetEnemy;
    public int enemiesToKill;
    private int enemyKillCount;

    private PlayerStats playerStats;
    public int EXPToGive;

    void Start () {
        playerStats = FindObjectOfType <PlayerStats> ();
    }

    void Update () {

        if (isItemQuest) {

            if (qManager.itemCollected == targetItem) {

                qManager.itemCollected = null;
                EndQuest ();
            }
        }


        if (isEnemyQuest) {

            if (qManager.enemyKilled == targetEnemy) {

                qManager.enemyKilled = null;

                enemyKillCount++;

            }

            if (enemyKillCount >= enemiesToKill) {

                EndQuest ();

            }
        }
    }

    public void StartQuest (){
        qManager.ShowQuestText (startText);



    }

    public void EndQuest (){
        qManager.ShowQuestText (endText);
        playerStats.AddEXP (EXPToGive);
        qManager.questCompleted [questNumber] = true;
        gameObject.SetActive (false);


    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyHealth : MonoBehaviour {

    public int startingHealth;                                  
    public int currentHealth;                                   
    public GameObject damageBurst;
    private PlayerStats playerStats;
    public int EXPToGive;

    public string enemyQuestName;
    private QuestManager qManager;




    void Start ()
    {
        // Setting up the references.
        //anim = GetComponent <Animator> ();
        //enemyAudio = GetComponent <AudioSource> ();
        //enemyMovement = GetComponent <EnemyMovement> ();
        //enemyAttacking = GetComponentInChildren <EnemyAttack> ();
        // Set the initial health of the player.
        currentHealth = startingHealth;
        playerStats = FindObjectOfType <PlayerStats> ();
        qManager = FindObjectOfType <QuestManager> ();
    }



    void Update ()
    {
        if (currentHealth <= 0) {

            qManager.enemyKilled = enemyQuestName;

            Destroy (gameObject);
            playerStats.AddEXP (EXPToGive);
        }
    } 


    public void TakeDamage (int amountDamage)
    {
        // Reduce the current health by the damage amount.
        currentHealth -= amountDamage;
        Instantiate (damageBurst, transform.position, transform.rotation);


    }

    public void SetMaxHelth () {
        currentHealth = startingHealth;
    }


}

一种方法是创建某种类型的 "WorldManager" 来计算每个被杀死的敌人。当开始一个任务时,这个任务可以检查 WorldManagers 杀戮计数并将其添加到它自己的计数中。

   public void StartQuest (){
        qManager.ShowQuestText (startText);
        this.enemyKillCount += worldManager.GetKillCount();
    }

在你的敌人中 class 你必须向你的 worldManager 添加杀戮。

 void Update ()
    {
        if (currentHealth <= 0) {

            qManager.enemyKilled = enemyQuestName;
            this.worldManager.AddKill(this)
            Destroy (gameObject);
            playerStats.AddEXP (EXPToGive);
        }
    } 

选择:

让您的 QManager 了解场景中的每一次杀戮。 您可以通过多种方式实现这一目标。 其中之一是将您的 EnemyObject 传递给您的 Qmanager 的引用并执行与上面提供的 "WorldManager" 相同的操作,或者您使用消息传递并在敌人被杀死时针对 QManager 发射消息。

方案二: 当敌人被杀死时发起一个事件并在你的 QManager/WorldManager 上订阅它。这样你就可以在每场比赛中重用你的敌人class。从我的角度来看,静态依赖是邪恶的,但有很多讨论和 SO 以及互联网上到处都是。

您可以采用多种方法。最直接的是使用静态。

static 的目的是让 variable/method 属于 class 而不是 class 的实例。

在你的情况下,你希望每个敌人都有自己的生命值,这不能是静态的。 并且您想从 class 中计算场景中有多少个实例。所以静态没问题。

public class Enemy:MonoBehaviour
{
     private static int enemyCount = 0;
     public static int EnemyCount {get{ return enemyCount;} }
     public event Action<int> RaiseEnemyDeath;
     public static void ResetEnemyCount(){
          enemyCount = 0;
     }

     private int health;
     public void Damage(int damage)
     { 
         CheckForDamage(); // here you check that damage is not neg or too big...
         this.health -= damage;
         if(this.health <= 0)
         { 
             OnDeath(); 
         }
     }
     void OnActivate() 
     { 
         enemyCount++; 
         this.health = 20;
     }
     void OnDeath()
    { 
         enemyCount--; 
         RaiseEnemyDeath(enemyCount); // Should check for nullity...
    }
}

这个相当简单。第一部分是静态的,与 class 有关。第二部分与实例相关。如果您使用一个敌人池,然后多次重复使用同一个实例,当您让敌人在场景中存活时,将调用 OnActivate 方法(它可能已经有一段时间处于非活动状态)。然后当生命值下降时,杀死敌人(那里没有所有需要的动作......)并触发事件。

使用 public 静态 属性,你可以从 GameManager 知道敌人的数量(敌人不应该影响游戏,只照顾敌人)。

public class GameManager:MonoBehaviour
{
    void Start()
    {
         Enemy.RaiseEnemyDeath += Enemy_RaiseEnemyDeath;
    }
    void Enemy_RaiseEnemyDeath(int count)
    {
        if(count < 0){ // End of level }
        // You can also access enemyCount
        int count = Enemy.EnemyCount;
    }
}

使用这个原理的好处是Enemy对GameManager一无所知,无需任何修改就可以在另一个游戏中重复使用。 GameManager 是一个更高级别的实体并且了解它。