如何实现场景中 "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 是一个更高级别的实体并且了解它。
我一直在用 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 是一个更高级别的实体并且了解它。