2-28 Projectiles Discriminate
今天要來改進Enemy發射Projectile時也同樣會攻擊到Enemy的問題。解決方法是在Projectile中增加條件式,判斷發射Projectile的GameObject所處的Layer。比方說,敵人的Layer是Enemy,那由Enemy Layer的GameObject發射的Projectile,就不應該攻擊到同樣在Enemy Layer的Projectile。
所以首先我們先替玩家角色新增Layer,我們之前一直沒有新增Player。
所以首先我們先替玩家角色新增Layer,我們之前一直沒有新增Player。
然後修改Projectile.cs,我們新增一個GameObject名為Shooter,並判斷Collision GameObject的Layer是否不同於Shooter的Layer:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Projectile : MonoBehaviour { [SerializeField] float projectileSpeed; [SerializeField] GameObject shooter; float damageCaused; public void SetShooter(GameObject shooter){ this.shooter = shooter; } public void SetDamage(float damage){ damageCaused = damage; } public float GetDefaultLaunchSpeed(){ return projectileSpeed; } void OnCollisionEnter(Collision collision){ int layerCollidedWith = collision.gameObject.layer; // 若被碰撞的物體所處的Layer跟shooter的Layer不同,才會觸發攻擊機制 // 如敵人就不會攻擊到敵人 if (layerCollidedWith != shooter.layer) { DamageIfDamageable (collision); } } private void DamageIfDamageable(Collision collision){ // 取得Component為IDamageable Component damageableComponent = collision.gameObject.GetComponent (typeof(IDamageable)); // 若IDamageable存在 if (damageableComponent) { // 呼叫damageableComponent的TakeDamage方法 (damageableComponent as IDamageable).TakeDamage (damageCaused); } // 自我消滅 Destroy(gameObject); } }
接著,因為Enemy發射Projectile,所以修改Enemy.cs,呼叫Projectile的SetShooter方法:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; using UnityStandardAssets.Characters.ThirdPerson; public class Enemy : MonoBehaviour, IDamageable { [SerializeField] float maxHealthPoints = 100f; [SerializeField] float attackRadius = 3.0f; [SerializeField] float chaseRadius = 10.0f; [SerializeField] float damagePerShot = 9f; [SerializeField] float secondsBetweenShots = 0.5f; [SerializeField] GameObject projectileToUse; [SerializeField] GameObject projectileSocket; [SerializeField] Vector3 aimOffset = new Vector3(0, 1f, 0); bool isAttacking = false; float currentHealthPoint; AICharacterControl aiCharacterControl = null; GameObject player; IEnumerator coroutine; public float healthAsPercentage{ get{ return currentHealthPoint / maxHealthPoints; } } void Start(){ currentHealthPoint = maxHealthPoints; aiCharacterControl = GetComponent(); player = GameObject.FindGameObjectWithTag ("Player"); } void Update(){ // 計算Player跟Enemy的距離 float distanceToPlayer = Vector3.Distance (player.transform.position, transform.position); // 若彼此之間的距離小於attackRadius,就讓Enemy開始攻擊Player if (distanceToPlayer <= attackRadius && !isAttacking) { isAttacking = true; coroutine = SpawnProjectile (); StartCoroutine (coroutine); } if (distanceToPlayer > attackRadius && isAttacking) { isAttacking = false; StopCoroutine (coroutine); } // 若彼此之間的距離小於chaseRadius,就讓Enemy開始追蹤Player if (distanceToPlayer <= chaseRadius) { aiCharacterControl.SetTarget (player.transform); } else { aiCharacterControl.SetTarget (transform); } } IEnumerator SpawnProjectile(){ while (true) { yield return new WaitForSeconds (secondsBetweenShots); // Instantiate可以生成GameObject,Quaternion.identity為方向不進行任何轉向 GameObject newProjectile = Instantiate(projectileToUse, projectileSocket.transform.position, Quaternion.identity); // 取得Projectile Projectile projectileComponent = newProjectile.GetComponent (); // 設定Projectile的攻擊威力 projectileComponent.SetDamage(damagePerShot); // 設定Projectile的Shooter為自己 projectileComponent.SetShooter (gameObject); // 計算發射Projectile到Player之間的單位向量 Vector3 unitVectorToPlayer = (player.transform.position + aimOffset - projectileSocket.transform.position).normalized; float projectileSpeed = projectileComponent.GetDefaultLaunchSpeed(); // 將單位向量乘以發射速度,透過velocity將Projectile發射出去吧! newProjectile.GetComponent ().velocity = unitVectorToPlayer * projectileSpeed; } } public void TakeDamage(float damage){ // Math.Clamp可以確保數值運算後不會低於最小值或者高於最大值 currentHealthPoint = Mathf.Clamp (currentHealthPoint - damage, 0f, maxHealthPoints); // 敵人血量低於0就會消失 if (currentHealthPoint <= 0) { Destroy (gameObject); } } void OnDrawGizmos(){ //繪製攻擊範圍 Gizmos.color = new Color(255f, 0f, 0f, 0.5f); Gizmos.DrawWireSphere (transform.position, attackRadius); //繪製移動範圍 Gizmos.color = new Color(0f, 0f, 255f, 0.5f); Gizmos.DrawWireSphere (transform.position, chaseRadius); } }
最後,測試遊戲看看Enemy的Projectile是否會攻擊到Enemy。
留言
張貼留言