| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.AI;
- public class Wolf : TargetAnimal
- {
- //动画播放器
- AnimationPlayer ap;
- //寻路代理
- NavMeshAgent agent;
- void Awake()
- {
- ap = GetComponent<AnimationPlayer>();
- agent = GetComponent<NavMeshAgent>();
- }
- void Start()
- {
- initAniListener();
- InitAutoStrategy();
- }
- void Update()
- {
- if (HasCloseToDestination()) {
- OnReachDestination();
- }
- UpdateAutoStrategy();
- UpdateAction();
- }
- //可选皮肤材质
- [SerializeField] Material[] materials;
- public void ChangeColorByType(int type) {
- GetComponentInChildren<SkinnedMeshRenderer>().material = materials[type - 1];
- }
- public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName)
- {
- arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f;
- arrow.Hit();
- if (partName == "Leg" || partName == "Tail") {
- state.hp -= 2;
- }
- else if (partName == "Body") {
- state.hp -= 3;
- }
- else if (partName == "Head") {
- state.hp -= 100;
- }
- if (state.hp > 0) {
- Hurt();
- } else {
- Die(arrow);
- }
- }
- void Die(Arrow arrow) {
- if (state.dead) return;
- arrow.onDoNextShoot += delegate() { Destroy(this.gameObject); };
- state.ResetActionState();
- state.dead = true;
- this.agent.enabled = false;
- onDie?.Invoke(this);
- AudioMgr.ins.PlayAnimalEffect("wolf_die", AudioMgr.GetAudioSource(this.gameObject));
- }
- void Hurt() {
- state.lockingTarget = true;
- state.ResetActionState();
- AudioMgr.ins.PlayAnimalEffect("wolf_injured", AudioMgr.GetAudioSource(this.gameObject));
- }
-
- //启动寻路
- void SetDestination(Vector3 pos) {
- state.ResetActionState();
- state.moving = true;
- this.agent.destination = pos;
- }
- //寻路结束
- void OnReachDestination() {
- if (!state.moving) return;
- state.ResetActionState();
- }
- //是否已经接近目的地(寻路完成判断)
- bool HasCloseToDestination() {
- if (!state.moving) return true;
- if (Vector3.Distance(this.agent.nextPosition, this.agent.destination) < 0.25f) {
- return true;
- }
- if (state.movingTime > 0.1f && this.agent.velocity.magnitude < 0.05f) {
- return true;
- }
- return false;
- }
- float willStayTime;
- float willMoveTime;
- bool autoMoving = false;
- float autoMovingTime;
- bool willAttack = false;
- bool hasRunAround = false;
- bool hasRunToHunter = false;
- //帧更新逻辑-自动策略
- void UpdateAutoStrategy() {
- if (state.dead) return;
- if (state.lockingTarget) {
- if (state.attacking) {
- this.transform.LookAt(this.hunterPosition);
- }
- if (!hasRunToHunter) {
- hasRunToHunter = true;
- RunToAttackHunter();
- willAttack = true;
- return;
- }
- if (!state.moving && !state.attacking) {
- if (willAttack) {
- willAttack = false;
- Attack();
- return;
- }
- if (Random.value > 0.5f) {
- RunAroundHunter();
- hasRunAround = true;
- return;
- }
- if (hasRunAround) {
- hasRunAround = false;
- RunToAttackHunter();
- }
- willAttack = true;
- return;
- }
- return;
- }
- if (state.stayingTime > willStayTime) {
- //退出stay
- RandomWillStayTime();
- //进入move
- autoMoving = true;
- MoveSlowlyInZPath();
- }
- if (autoMoving) {
- if (state.moving) {
- autoMovingTime += Time.deltaTime;
- } else if (autoMovingTime < willMoveTime) {
- MoveSlowlyInZPath();
- }
- if (autoMovingTime >= willMoveTime) {
- //退出move
- RandomWillMoveTime();
- autoMoving = false;
- autoMovingTime = 0;
- //进入stay
- Stay();
- }
- }
- }
- void InitAutoStrategy() {
- this.willStayTime = 1f + Random.value * 2;
- RandomWillMoveTime();
- }
- void RandomWillStayTime() {
- this.willStayTime = Random.value * 2 + 3;
- }
- void RandomWillMoveTime() {
- this.willMoveTime = Random.value * 3 + 5;
- }
- //攻击
- void Attack() {
- state.ResetActionState();
- state.attacking = true;
- curAnimIndex = -1; /*注意:这样可避免狼两次使用同一攻击动作而第二次无法播放的情况 */
- int hurtValue = 2;
- if (Random.value < 0.5) {
- state.attackA = true;
- } else {
- state.attackB = true;
- hurtValue = 3;
- }
- onAttack?.Invoke(this, hurtValue);
- }
- //跑到能攻击玩家的坐标点
- void RunToAttackHunter() {
- Vector3 standardPointer = animalsBaseT.forward;
- Vector3 newPos = animalsBaseT.position + standardPointer * 1.5f;
- SetDestination(newPos);
- state.moveQuickly = true;
- agent.speed = 5f;
- }
- //在敌人身边奔跑徘徊
- void RunAroundHunter() {
- float baseDistance = 2;
- float baseDistanceMoveRange = 5;
- Vector3 standardPointer = animalsBaseT.forward;
- Vector3 pointerWithLen = standardPointer.normalized * (baseDistance + Random.value * baseDistanceMoveRange);
- pointerWithLen = Quaternion.AngleAxis(-80f + Random.value * 160f, Vector3.up) * pointerWithLen;
- Vector3 newPos = animalsBaseT.position + pointerWithLen;
- SetDestination(newPos);
- state.moveQuickly = true;
- agent.speed = 5f;
- }
- //Z字型路径缓慢移动
- Queue<Vector3> zPathPoints = new Queue<Vector3>();
- bool canCreateZPath = true;
- void MoveSlowlyInZPath() {
- if (zPathPoints.Count > 0) {
- SetDestination(zPathPoints.Dequeue());
- state.moveSlowly = true;
- agent.speed = 0.8f;
- return;
- }
- if (!canCreateZPath) {
- state.lockingTarget = true;
- return;
- }
- //构建Z字型路径
- zPathPoints.Clear();
- Vector3 standardPos = animalsBaseT.forward;
- Vector3 hunterPos = hunterPosition;
- Vector3 pointerToMe = GetPointerHunterToMe().normalized;
- Vector3 pointer1 = Quaternion.AngleAxis(120, Vector3.up) * pointerToMe;
- Vector3 pointer2 = Quaternion.AngleAxis(-120, Vector3.up) * pointerToMe;
- Vector3 myPos = this.transform.position;
- int[] pointerSeq = {1, 2, 1};
- bool isReverse = Random.value < 0.5;
- foreach (int seqID in pointerSeq)
- {
- Vector3 lastMyPos = myPos;
- if (seqID == 1) myPos = myPos + (isReverse ? pointer2 : pointer1) * 5;
- if (seqID == 2) myPos = myPos + (isReverse ? pointer1 : pointer2) * 10;
- hunterPos.y = myPos.y;
- Vector3 hunterToMe = myPos - hunterPos;
- float angle = Vector3.Angle(hunterToMe, standardPos);
- float minDistance = 8;
- //如果下一个构建的坐标在猎手身后或者距离猎手低于指定距离
- if (angle > 90 || Vector3.Distance(hunterPos, myPos) < minDistance) {
- Vector3 hunterToMe2 = lastMyPos - hunterPos;
- if (hunterToMe2.magnitude > minDistance + 2) {
- Vector3 displace = (hunterToMe2).normalized * minDistance;
- myPos = hunterPos + displace;
- zPathPoints.Enqueue(myPos);
- }
- canCreateZPath = false;
- break;
- } else {
- zPathPoints.Enqueue(myPos);
- }
- }
- }
- //停留
- void Stay() {
- if (state.moving) {
- this.agent.destination = this.agent.nextPosition;
- }
- state.ResetActionState();
- state.staying = true;
- }
- //动画播放
- int curAnimIndex = 0;
- void playAniStay() {
- ap.play(curAnimIndex = 3, WrapMode.Loop);
- }
- bool isAniStay() {
- return curAnimIndex == 3;
- }
- void playAniMoveSlowly() {
- ap.play(curAnimIndex = 5, WrapMode.Loop);
- }
- bool isAniMoveSlowly() {
- return curAnimIndex == 5;
- }
- void playAniMoveQuickly() {
- ap.play(curAnimIndex = 4, WrapMode.Loop);
- }
- bool isAniMoveQuickly() {
- return curAnimIndex == 4;
- }
- void playAniAttakA() {
- ap.play(curAnimIndex = 1, WrapMode.Once);
- }
- bool isAniAttakA() {
- return curAnimIndex == 1;
- }
- void playAniAttakB() {
- ap.play(curAnimIndex = 0, WrapMode.Once);
- }
- bool isAniAttakB() {
- return curAnimIndex == 0;
- }
- void playAniDie() {
- ap.play(curAnimIndex = 2, WrapMode.Once);
- }
- bool isAniDie() {
- return curAnimIndex == 2;
- }
- void initAniListener() {
- this.ap.completeCallback = delegate(AnimationPlayerCompleteResult res) {
- if (res.index == 1 || res.index == 0) {
- this.state.ResetActionState();
- }
- };
- }
- //帧更新逻辑-通过状态更新动作动画
- void UpdateAction() {
- if (state.staying) {
- state.stayingTime += Time.deltaTime;
- if (!isAniStay()) playAniStay();
- }
- else if (state.moving) {
- state.movingTime += Time.deltaTime;
- if (state.moveSlowly && !isAniMoveSlowly()) playAniMoveSlowly();
- if (state.moveQuickly && !isAniMoveQuickly()) playAniMoveQuickly();
- }
- else if (state.attacking) {
- if (state.attackA && !isAniAttakA()) playAniAttakA();
- if (state.attackB && !isAniAttakB()) playAniAttakB();
- }
- else if (state.dead) {
- if (!isAniDie()) playAniDie();
- }
- }
- //状态
- [System.Serializable]
- public class State {
- //数值区
- public int hp = 1;
- //动作区
- public bool staying = true;
- public bool moving = false;
- public bool moveSlowly = false; //慢走
- public bool moveQuickly = false; //跑动
- public bool attacking = false;
- public bool attackA = false; //扑击
- public bool attackB = false; //撕咬
- public bool dead = false;
- public float stayingTime = 0;
- public float movingTime = 0;
- //特定区
- public bool lockingTarget = false; //锁定目标
- //重置动作区状态
- public void ResetActionState() {
- this.staying = false;
- this.moving = false;
- this.moveSlowly = false;
- this.moveQuickly = false;
- this.attacking = false;
- this.attackA = false;
- this.attackB = false;
- this.dead = false;
- this.stayingTime = 0;
- this.movingTime = 0;
- }
- }
- [SerializeField] public State state = new State();
- //委托
- public System.Action<Wolf> onDie;
- public System.Action<Wolf, int> onAttack;
- }
|