2-15 Enemy Attack Spheres And Spawning Enemy Projectile
本章要來介紹當Player進入Enemy的攻擊範圍後,要自動召喚出Projectile攻擊Player。上一章已經跟大家講過如何製作Projectile以及Interface的功用,如不清楚請先閱讀上一章的內容唷。
2-14 Using Interfaces In C#
接下來,將Projectile的Rigidbody設為Use Gravity並把Is Kinematic關掉。
以下提供程式碼:
Enemy.cs:
Projectile.cs:
最後執行遊戲,大家可以看見玩家進入紅色的攻擊範圍後,敵人開始發射Projectile攻擊玩家。
2-14 Using Interfaces In C#
首先,我們可以撰寫Gizmos程式碼畫出攻擊範圍跟移動範圍,方便我們在遊戲中進行調整。原本程式碼中的變數只有attackRadius,請大家在自己新增chaseRadius。
如下圖,當玩家進入藍色框線的位置 時敵人就會靠近,進入到紅色框線的範圍時就會開始進行攻擊。
接下來,將Projectile的Rigidbody設為Use Gravity並把Is Kinematic關掉。
並在Projectile中新增Projectile Speed變數,用作發射Projectile時的速度。
然後在Enemy中新增一個Empty GameObject取名為Projectile Spawn Point,這是用來生成Projectile的定位座標。
我將Projectile Spawn Point放置在頭頂上方。
然後,在Enemy中建立ProjecilteToUse跟ProjectileSocket兩個變數,並將Projectile跟Projectile Spawn Point拉進去。
Enemy.cs:
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] GameObject projectileToUse;
[SerializeField] GameObject projectileSocket;
float currentHealthPoint = 100f;
AICharacterControl aiCharacterControl = null;
GameObject player;
public float healthAsPercentage{
get{ return currentHealthPoint / maxHealthPoints; }
}
void Start(){
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) {
SpawnProjectile();
}
// 若彼此之間的距離小於chaseRadius,就讓Enemy開始追蹤Player
if (distanceToPlayer <= chaseRadius) {
aiCharacterControl.SetTarget (player.transform);
} else {
aiCharacterControl.SetTarget (transform);
}
}
void SpawnProjectile(){
// Instantiate可以生成GameObject,Quaternion.identity為方向不進行任何轉向
GameObject newProjectile = Instantiate(projectileToUse, projectileSocket.transform.position, Quaternion.identity);
// 取得Projectile
Projectile projectileComponent = newProjectile.GetComponent ();
// 設定Projectile的攻擊威力
projectileComponent.damageCaused = damagePerShot;
// 計算發射Projectile到Player之間的單位向量
Vector3 unitVectorToPlayer = (player.transform.position - projectileSocket.transform.position).normalized;
float projectileSpeed = projectileComponent.projectileSpeed;
// 將單位向量乘以發射速度,透過velocity將Projectile發射出去吧!
newProjectile.GetComponent ().velocity = unitVectorToPlayer * projectileSpeed;
}
public void TakeDamage(float damage){
// Math.Clamp可以確保數值運算後不會低於最小值或者高於最大值
currentHealthPoint = Mathf.Clamp (currentHealthPoint - damage, 0f, maxHealthPoints);
}
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);
}
}
Projectile.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Projectile : MonoBehaviour {
public float damageCaused;
public float projectileSpeed;
void OnTriggerEnter(Collider collider){
// 取得Component為IDamageable
Component damageableComponent = collider.gameObject.GetComponent (typeof(IDamageable));
// 若IDamageable存在
if (damageableComponent) {
// 呼叫damageableComponent的TakeDamage方法
(damageableComponent as IDamageable).TakeDamage (damageCaused);
}
}
}
最後執行遊戲,大家可以看見玩家進入紅色的攻擊範圍後,敵人開始發射Projectile攻擊玩家。








留言
張貼留言