Unity 生存射击游戏无伤害
No Damage in Unity Survival Shooter Game
我一直在关注 Unity 提供的 Shooter Survival 教程。我一直在使用它来了解某些代码如何在 c# 的不同脚本中相互交互和相互调用。最近我 运行 遇到了一个问题,我没有受到敌人攻击的伤害;我仍然可以伤害他们。
我的球员健康码
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.SceneManagement;
namespace CompleteProject
{
public class PlayerHealth : MonoBehaviour
{
public int startingHealth = 100; // The amount of health the player starts the game with.
public int currentHealth; // The current health the player has.
public Slider healthSlider; // Reference to the UI's health bar.
public Image damageImage; // Reference to an image to flash on the screen on being hurt.
public AudioClip deathClip; // The audio clip to play when the player dies.
public float flashSpeed = 5f; // The speed the damageImage will fade at.
public Color flashColour = new Color(1f, 0f, 0f, 0.1f); // The colour the damageImage is set to, to flash.
Animator anim; // Reference to the Animator component.
AudioSource playerAudio; // Reference to the AudioSource component.
PlayerMovement playerMovement; // Reference to the player's movement.
PlayerShooting playerShooting; // Reference to the PlayerShooting script.
bool isDead; // Whether the player is dead.
bool damaged; // True when the player gets damaged.
void Awake ()
{
// Setting up the references.
anim = GetComponent <Animator> ();
playerAudio = GetComponent <AudioSource> ();
playerMovement = GetComponent <PlayerMovement> ();
playerShooting = GetComponentInChildren <PlayerShooting> ();
// Set the initial health of the player.
currentHealth = startingHealth;
}
void Update ()
{
// If the player has just been damaged...
if(damaged)
{
// ... set the colour of the damageImage to the flash colour.
damageImage.color = flashColour;
}
// Otherwise...
else
{
// ... transition the colour back to clear.
damageImage.color = Color.Lerp (damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
}
// Reset the damaged flag.
damaged = false;
}
public void TakeDamage (int amount)
{
// Set the damaged flag so the screen will flash.
damaged = true;
// Reduce the current health by the damage amount.
currentHealth -= amount;
// Set the health bar's value to the current health.
healthSlider.value = currentHealth;
// Play the hurt sound effect.
playerAudio.Play ();
// If the player has lost all it's health and the death flag hasn't been set yet...
if(currentHealth <= 0 && !isDead)
{
// ... it should die.
Death ();
}
}
void Death ()
{
// Set the death flag so this function won't be called again.
isDead = true;
// Turn off any remaining shooting effects.
playerShooting.DisableEffects ();
// Tell the animator that the player is dead.
anim.SetTrigger ("Die");
// Set the audiosource to play the death clip and play it (this will stop the hurt sound from playing).
playerAudio.clip = deathClip;
playerAudio.Play ();
// Turn off the movement and shooting scripts.
playerMovement.enabled = false;
playerShooting.enabled = false;
}
public void RestartLevel ()
{
// Reload the level that is currently loaded.
SceneManager.LoadScene (0);
}
}
}
我的敌人攻击代码
using UnityEngine;
using System.Collections;
namespace CompleteProject
{
public class EnemyAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 10; // The amount of health taken away per attack.
Animator anim; // Reference to the animator component.
GameObject player; // Reference to the player GameObject.
PlayerHealth playerHealth; // Reference to the player's health.
EnemyHealth enemyHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
void Awake ()
{
// Setting up the references.
player = GameObject.FindGameObjectWithTag ("Player");
playerHealth = player.GetComponent <PlayerHealth> ();
enemyHealth = GetComponent<EnemyHealth>();
anim = GetComponent <Animator> ();
}
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
// If the exiting collider is the player...
if(other.gameObject == player)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
{
// ... attack.
Attack ();
}
// If the player has zero or less health...
if(playerHealth.currentHealth <= 0)
{
// ... tell the animator the player is dead.
anim.SetTrigger ("PlayerDead");
}
}
void Attack ()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if(playerHealth.currentHealth > 0)
{
// ... damage the player.
playerHealth.TakeDamage (attackDamage);
}
}
}
}
我的一个使用 C++ 的朋友告诉我,他觉得奇怪的是,在 Player 层次结构中,Player Health 是一项资产,可能必须以某种方式直接调用。
问题可能出在这里:
if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
{
// ... attack.
Attack ();
}
要让玩家被敌人攻击,必须同时满足三个条件。
timer
必须 大于 或等于 0.5f。 playerInRange
也必须是 true
。最后enemyHealth.currentHealth
一定要大于0.
一旦您的代码超过 30 行包含太多 C# 脚本,您必须知道如何调试 你自己的代码。
我最好的猜测是 playerInRange
永远不会 true
,这就是为什么 不会 被调用的原因。在 Attack ();
之前添加 Debug.Log("Attacked Player");
并检查当 Enemy 攻击玩家时是否显示“Attacked Player”。如果不是,则其中之一是 false
.
同时添加 Debug.Log("Player is in Range");
以查看是否完全检测到玩家
void OnTriggerEnter (Collider other);
函数如下:
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
Debug.Log("Player is in Range");
}
}
这些会告诉您场景中发生了什么。
我可以确认代码按照您提供的方式工作,但需要一组特定的环境才能使 EnemyAttack
成功调用 PlayerHealth.TakeDamage()
:
- 你的
EnemyAttack
附加到的游戏对象需要一个 Rigidbody
,你可能需要设置 IsKinematic = true
- 任何类型的
Collider
组件 - 标记为 IsTrigger = true
- 您的
PlayerHealth
所附加的游戏对象需要 Rigidbody
和 Collider
,游戏对象的标签设置为 'Player',正如您在屏幕截图中所证明的那样你提供了
我相信你的 EnemyAttack
无法伤害玩家,因为标志 playerInRange
总是错误的。当通过 OnTriggerEnter()
但不是在 OnTriggerExit()
之前时,此标志设置为 true。由于组件在场景中没有正确设置,OnTriggerEnter()
将永远不会被调用。
我一直在关注 Unity 提供的 Shooter Survival 教程。我一直在使用它来了解某些代码如何在 c# 的不同脚本中相互交互和相互调用。最近我 运行 遇到了一个问题,我没有受到敌人攻击的伤害;我仍然可以伤害他们。
我的球员健康码
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.SceneManagement;
namespace CompleteProject
{
public class PlayerHealth : MonoBehaviour
{
public int startingHealth = 100; // The amount of health the player starts the game with.
public int currentHealth; // The current health the player has.
public Slider healthSlider; // Reference to the UI's health bar.
public Image damageImage; // Reference to an image to flash on the screen on being hurt.
public AudioClip deathClip; // The audio clip to play when the player dies.
public float flashSpeed = 5f; // The speed the damageImage will fade at.
public Color flashColour = new Color(1f, 0f, 0f, 0.1f); // The colour the damageImage is set to, to flash.
Animator anim; // Reference to the Animator component.
AudioSource playerAudio; // Reference to the AudioSource component.
PlayerMovement playerMovement; // Reference to the player's movement.
PlayerShooting playerShooting; // Reference to the PlayerShooting script.
bool isDead; // Whether the player is dead.
bool damaged; // True when the player gets damaged.
void Awake ()
{
// Setting up the references.
anim = GetComponent <Animator> ();
playerAudio = GetComponent <AudioSource> ();
playerMovement = GetComponent <PlayerMovement> ();
playerShooting = GetComponentInChildren <PlayerShooting> ();
// Set the initial health of the player.
currentHealth = startingHealth;
}
void Update ()
{
// If the player has just been damaged...
if(damaged)
{
// ... set the colour of the damageImage to the flash colour.
damageImage.color = flashColour;
}
// Otherwise...
else
{
// ... transition the colour back to clear.
damageImage.color = Color.Lerp (damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
}
// Reset the damaged flag.
damaged = false;
}
public void TakeDamage (int amount)
{
// Set the damaged flag so the screen will flash.
damaged = true;
// Reduce the current health by the damage amount.
currentHealth -= amount;
// Set the health bar's value to the current health.
healthSlider.value = currentHealth;
// Play the hurt sound effect.
playerAudio.Play ();
// If the player has lost all it's health and the death flag hasn't been set yet...
if(currentHealth <= 0 && !isDead)
{
// ... it should die.
Death ();
}
}
void Death ()
{
// Set the death flag so this function won't be called again.
isDead = true;
// Turn off any remaining shooting effects.
playerShooting.DisableEffects ();
// Tell the animator that the player is dead.
anim.SetTrigger ("Die");
// Set the audiosource to play the death clip and play it (this will stop the hurt sound from playing).
playerAudio.clip = deathClip;
playerAudio.Play ();
// Turn off the movement and shooting scripts.
playerMovement.enabled = false;
playerShooting.enabled = false;
}
public void RestartLevel ()
{
// Reload the level that is currently loaded.
SceneManager.LoadScene (0);
}
}
}
我的敌人攻击代码
using UnityEngine;
using System.Collections;
namespace CompleteProject
{
public class EnemyAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 10; // The amount of health taken away per attack.
Animator anim; // Reference to the animator component.
GameObject player; // Reference to the player GameObject.
PlayerHealth playerHealth; // Reference to the player's health.
EnemyHealth enemyHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
void Awake ()
{
// Setting up the references.
player = GameObject.FindGameObjectWithTag ("Player");
playerHealth = player.GetComponent <PlayerHealth> ();
enemyHealth = GetComponent<EnemyHealth>();
anim = GetComponent <Animator> ();
}
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
// If the exiting collider is the player...
if(other.gameObject == player)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
{
// ... attack.
Attack ();
}
// If the player has zero or less health...
if(playerHealth.currentHealth <= 0)
{
// ... tell the animator the player is dead.
anim.SetTrigger ("PlayerDead");
}
}
void Attack ()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if(playerHealth.currentHealth > 0)
{
// ... damage the player.
playerHealth.TakeDamage (attackDamage);
}
}
}
}
我的一个使用 C++ 的朋友告诉我,他觉得奇怪的是,在 Player 层次结构中,Player Health 是一项资产,可能必须以某种方式直接调用。
问题可能出在这里:
if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
{
// ... attack.
Attack ();
}
要让玩家被敌人攻击,必须同时满足三个条件。
timer
必须 大于 或等于 0.5f。 playerInRange
也必须是 true
。最后enemyHealth.currentHealth
一定要大于0.
一旦您的代码超过 30 行包含太多 C# 脚本,您必须知道如何调试 你自己的代码。
我最好的猜测是 playerInRange
永远不会 true
,这就是为什么 不会 被调用的原因。在 Attack ();
之前添加 Debug.Log("Attacked Player");
并检查当 Enemy 攻击玩家时是否显示“Attacked Player”。如果不是,则其中之一是 false
.
同时添加 Debug.Log("Player is in Range");
以查看是否完全检测到玩家
void OnTriggerEnter (Collider other);
函数如下:
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
Debug.Log("Player is in Range");
}
}
这些会告诉您场景中发生了什么。
我可以确认代码按照您提供的方式工作,但需要一组特定的环境才能使 EnemyAttack
成功调用 PlayerHealth.TakeDamage()
:
- 你的
EnemyAttack
附加到的游戏对象需要一个Rigidbody
,你可能需要设置 IsKinematic = true - 任何类型的
Collider
组件 - 标记为 IsTrigger = true - 您的
PlayerHealth
所附加的游戏对象需要Rigidbody
和Collider
,游戏对象的标签设置为 'Player',正如您在屏幕截图中所证明的那样你提供了
我相信你的 EnemyAttack
无法伤害玩家,因为标志 playerInRange
总是错误的。当通过 OnTriggerEnter()
但不是在 OnTriggerExit()
之前时,此标志设置为 true。由于组件在场景中没有正确设置,OnTriggerEnter()
将永远不会被调用。