Related Posts Plugin for WordPress, Blogger...

2-17 Player Melee Damage

今天要來製作玩家的範圍技!哈哈,不過還沒有動畫特效啦,先把程式碼的部分實作好。首先請大家下載課程提供的武器:

自己匯入。

匯入之後放在場景中。

然後請將武器物件放到Player中,結構如下圖。Player/Armature/Hips/Spine/Shoulder_R/Upper_Arm_R/Lower_Arm_R/Hand_R底下,簡言之就是右手下面啦。

然後請自己調整武器的位置,就像是握在手上。執行看看吧,開始遊戲後武器就會跟人物的動畫綁在一起。

以下提供程式碼,註解也寫在程式碼中嘍:
Player.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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> ();
  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);
 }
}
 
</cameraraycaster>

Enemy.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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<aicharactercontrol> ();
  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> ();
   // 設定Projectile的攻擊威力
   projectileComponent.SetDamage(damagePerShot);
   // 計算發射Projectile到Player之間的單位向量
   Vector3 unitVectorToPlayer = (player.transform.position + aimOffset - projectileSocket.transform.position).normalized;
   float projectileSpeed = projectileComponent.projectileSpeed;
   // 將單位向量乘以發射速度,透過velocity將Projectile發射出去吧!
   newProjectile.GetComponent<rigidbody> ().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);
 }
}
 
</rigidbody></projectile></aicharactercontrol>

開始執行遊戲後,玩家點擊敵人就會走到敵人前面,並且在進入玩家的範圍攻擊內(玩家的紅色框框)才可以讓敵人損血,而且攻擊敵人時有我設定的CD時間0.5秒。

將敵人打死後,敵人就會消失。

留言