第十二章:怪物系統
12.1 小狼的狀態切換和移動
using UnityEngine;
using System.Collections;
public enum WolfBabyState{ //幾種枚舉狀態,對應怪物的不同形態
Idle,
Walk,
Attack,
Death
}
public class WolfBaby : MonoBehaviour {
public WolfBabyState state = WolfBabyState.Idle; //默認動畫爲站立
public string aniName_death; //對應不同的動畫
public string aniName_walk;
public string aniName_idle;
public string currentAniName; //當前播放的動畫
public float changeTime = 3; //動畫改變的時間間隔
public float timer = 0; //定時器
void Awake()
{
currentAniName = aniName_idle;
}
void Update()
{
if (state == WolfBabyState.Death) //根據state判斷當前的狀態,並做出相應操作
{
animation.CrossFade(aniName_death);
}
else if(state == WolfBabyState.Attack) //爲攻擊狀態
{
//todo,對應下文的AutoAttack
}
else //巡邏狀態
{
animation.CrossFade(currentAniName);
timer += Time.deltaTime; 定時器開始工作
if(timer >= changeTime) //當定時器大於3秒時
{
timer = 0;
RandomState(); //隨機生成一種動畫
animation.CrossFade(currentAniName);
}
}
}
void RandomState()
{
int value = Random.Range (0, 2);
if (value == 0)
{
currentAniName = aniName_idle;
} else
{
currentAniName = aniName_walk;
}
}
}
private CharacterController cc;
public float speed = 0.5f;
void Awake()
{
cc = this.GetComponent<CharacterController> ();
}
if(currentAniName == aniName_walk)
{
cc.SimpleMove(transform.forward * speed);
}
void RandomState()
{
int value = Random.Range (0, 2);
if (value == 0)
{
currentAniName = aniName_idle;
} else
{
if(currentAniName != aniName_walk) //當value爲1時,即下一個播放狀態爲Walk,但當前狀態仍爲Idle的時候,改變小狼朝向的角度
{
transform.Rotate(transform.up * Random.Range(0,361)); //隨機一個角度,改變朝向
}
currentAniName = aniName_walk;
}
}
12.2 小狼遭受攻擊
public int hp = 100; //怪物血量
public float missRate = 0.2; //怪物閃避率
public void BeDamaged(int attackValue)
{
int value = Random.Range (0f, 1f); //生成一個0~1之間的隨機數,與missRate比較,若小於,則產生miss
if (value > this.missRate)
{
this.hp -= attackValue; //扣除血量
if(hp <= 0)
{
state = WolfBabyState.Death; //播放死亡動畫,2秒後銷燬
Destroy(this.gameObject,2);
}
}
}
private Color normalColor; //存儲原始的顏色,當被擊效果結束後可以返回原樣
private GameObject wolfBody;
void Awake()
{
wolfBody = transform.Find ("Wolf_Baby").gameObject; //訪問到控制顏色的子物體Wolf_Baby
normalColor = wolfBody.renderer.material.color;
}
IEnumerator ShowWolfRed() //通過協程代替計時器,更加簡單,協程的概念見https://blog.csdn.net/jasonwang18/article/details/55519165
{
wolfBody.renderer.material.color = Color.red;
yield return new WaitForSeconds (1f);
wolfBody.renderer.material.color = normalColor;
}
12.3 MISS效果
AudioSource.PlayClipAtPoint(missSound,transform.position);
private GameObject wolfHUDTextGO; //WolfBaby下的HUD Text
private GameObject HUDTextGO; //UI root下的HUDTextParent下的HUD Text
public GameObject HUDTextPrefab; //HUD Text的prefab,直接導入即可
private HUDText showText; //HUDTextGO下的Text信息,控制顯示
private UIFollowTarget followTarget; //HUDTextGO下的位置信息,控制位置
void Awake()
{
wolfHUDTextGO = transform.Find ("WolfHUDText").gameObject;
}
void Start()
{
HUDTextGO = GameObject.Instantiate (HUDTextPrefab, Vector3.zero, Quaternion.identity) as GameObject; //HUDTextParent下的HUD Text由Prefab得到
HUDTextGO.transform.parent = HUDTextParent._instance.gameObject.transform; //並將這一Prefab作爲HUDTextParent的子類
showText = HUDTextGO.GetComponent<HUDText> (); //取得文本和位置信息
followTarget = HUDTextGO.GetComponent<UIFollowTarget> ();
followTarget.target = wolfHUDTextGO.transform; //followTarget中的位置跟隨小狼的移動
followTarget.gameCamera = Camera.main; //followTarget中的Camera爲main Camera
followTarget.uiCamera = UICamera.current.GetComponent<Camera> (); //followTarget中的UICamera爲current Camera
}
public void BeDamaged(int attackValue)
{
if (value > this.missRate)
{
}
else
{
AudioSource.PlayClipAtPoint(missSound,transform.position);
showText.Add("Miss",Color.gray,1); //添加顯示的文本、顏色和時間
}
}
if (Input.GetKeyDown (KeyCode.A))
{
BeDamaged(1);
}
HUDTextGO = GameObject.Instantiate (HUDTextPrefab, Vector3.zero, Quaternion.identity) as GameObject;
HUDTextGO.transform.parent = HUDTextParent._instance.gameObject.transform;
HUDTextGO = NGUITools.AddChild (HUDTextParent._instance.gameObject, HUDTextPrefab);
if (hp <= 0)
{
state = WolfBabyState.Death;
Destroy (this.gameObject, 2);
GameObject.Destroy(HUDTextGO);
}
12.4 敵人的自動攻擊部分
自動攻擊的設計關係到AI的智商,這裏只涉及基本的AI操作,一些高端的“拉怪”操作不在考慮範圍內。。。
12.4.1 自動攻擊邏輯
public int attackValue; //攻擊傷害
public string aniName_normalAttack; //正常攻擊
public string aniName_crazyAttack; //瘋狂攻擊,提升attackRate,即攻擊速率
public string aniName_nowAttack; //當前攻擊的種類
public float normalAttackTime; //普通攻擊消耗時間
public float crazyAttackTime; //瘋狂攻擊消耗時間
public float crazyAttackRate; //瘋狂攻擊觸發的概率
public int attackRate = 1; //攻擊速率,默認爲1秒1次
public float attackTimer = 0; //攻擊的計時器,決定attackRate
public Transform target; //攻擊目標,當觸發BeDamage函數時獲取目標
- 當人物與小狼的距離小於可攻擊距離時,進行攻擊 (distance < acceptAttackDistance ,攻擊)
- 當人物與小狼的距離大於可攻擊距離並且小於最大攻擊距離時,移動到最小距離之內,再攻擊 (acceptAttackDistance < distance < maxAcceptAttackDistance,,移動再攻擊)
- 當人物與小狼距離大於最大攻擊距離時,返回巡邏狀態 (distance > maxAcceptAttackDistance ,取消攻擊狀態)
public float minAttackDistance = 2f;
public float maxAttackDistance = 5f;
void AutoAttack()
{
if (target != null) //取得目標
{
float distance = Vector3.Distance(target.position,transform.position); //計算距離
if(distance > maxAttackDistance) //大於最大攻擊距離時,切換到巡邏狀態
{
target = null;
state = WolfBabyState.Idle;
}
else if(distance <= minAttackDistance) //小於最小攻擊距離時,攻擊
{
}
else //介於最小與最大攻擊距離時,移動到攻擊距離內再攻擊
{
transform.LookAt(target);
cc.SimpleMove(transform.forward * speed);
animation.CrossFade(aniName_walk);
}
}
else
{
state = WolfBabyState.Idle;
}
}
12.4.2 攻擊行爲的切換與播放
else if(distance <= minAttackDistance)
{
attackTimer += Time.deltaTime; //計時器開啓
animation.CrossFade(aniName_nowAttack); //先播放當前攻擊動畫
if(aniName_nowAttack == aniName_normalAttack) //判斷當前攻擊動畫的種類
{
if(attackTimer >= normalAttackTime) //大於播放時間後,造成傷害
{
//todo,造成傷害
animation.CrossFade(aniName_idle);
}
}
else if(aniName_nowAttack == aniName_crazyAttack)
{
if(attackTimer >= crazyAttackTime)
{
//todo
animation.CrossFade(aniName_idle);
}
}
if(attackTimer > (1f/attackRate)) //如果大於攻擊休息間隔時,隨機一種攻擊動畫並重置計時器,實現一個攻擊的循環
{
RandomAttack();
attackTimer = 0;
}
}
void RandomAttack()
{
float value = Random.Range (0f, 1f);
if (value > crazyAttackRate)
{
aniName_nowAttack = aniName_normalAttack;
} else
{
aniName_nowAttack = aniName_crazyAttack;
}
}
ps:(5月3日補充)中型狼和Boss狼的創建。