2-17 Player Melee Damage
今天要來製作玩家的範圍技!哈哈,不過還沒有動畫特效啦,先把程式碼的部分實作好。首先請大家下載課程提供的武器:
自己匯入。
匯入之後放在場景中。
然後請將武器物件放到Player中,結構如下圖。Player/Armature/Hips/Spine/Shoulder_R/Upper_Arm_R/Lower_Arm_R/Hand_R底下,簡言之就是右手下面啦。
然後請自己調整武器的位置,就像是握在手上。執行看看吧,開始遊戲後武器就會跟人物的動畫綁在一起。
以下提供程式碼,註解也寫在程式碼中嘍:
Player.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour, IDamageable {
[SerializeField] float maxHealthPoints = 100f;
[SerializeField] float damagePerHit = 50f;
[SerializeField] float minTimeBetweenHits = 0.5f;
[SerializeField] float maxAttackRange = 5f;
GameObject currentTarget;
float currentHealthPoint;
float lastHitTime;
CameraRaycaster cameraRaycaster;
public float healthAsPercentage{
get{ return currentHealthPoint / maxHealthPoints; }
}
void Start(){
// 初始化血量
currentHealthPoint = maxHealthPoints;
cameraRaycaster = FindObjectOfType ();
cameraRaycaster.notifyMouseClickObservers += OnMouseClick ;
}
void OnMouseClick(RaycastHit raycastHit, int layerHit){
const int enemyLayer = 9;
if (layerHit == enemyLayer) {
GameObject enemy = raycastHit.collider.gameObject;
// 確認敵人是否在範圍技的攻擊範圍內
if ((enemy.transform.position - transform.position).magnitude > maxAttackRange) {
return; // 超過攻擊範圍就跳出
}
// 控制攻擊頻率,若本次攻擊時間離上一次攻擊時間大於minTimeBetweenHits,才允許攻擊
// 相當於範圍技的CD時間,不能一直發動技能!
if (Time.time - lastHitTime > minTimeBetweenHits) {
currentTarget = enemy;
IDamageable enemyDamageable = enemy.GetComponent (typeof(IDamageable)) as IDamageable;
// 讓敵人損血
enemyDamageable.TakeDamage (damagePerHit);
// 紀錄目前攻擊的時間
lastHitTime = Time.time;
}
}
}
public void TakeDamage(float damage){
// Math.Clamp可以確保數值運算後不會低於最小值或者高於最大值
currentHealthPoint = Mathf.Clamp (currentHealthPoint - damage, 0f, maxHealthPoints);
}
}
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] float secondsBetweenShots = 0.5f;
[SerializeField] GameObject projectileToUse;
[SerializeField] GameObject projectileSocket;
[SerializeField] Vector3 aimOffset = new Vector3(0, 1f, 0);
bool isAttacking = false;
float currentHealthPoint = 100f;
AICharacterControl aiCharacterControl = null;
GameObject player;
IEnumerator coroutine;
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 && !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到Player之間的單位向量
Vector3 unitVectorToPlayer = (player.transform.position + aimOffset - 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);
// 敵人血量低於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);
}
}
開始執行遊戲後,玩家點擊敵人就會走到敵人前面,並且在進入玩家的範圍攻擊內(玩家的紅色框框)才可以讓敵人損血,而且攻擊敵人時有我設定的CD時間0.5秒。
將敵人打死後,敵人就會消失。






留言
張貼留言