lvjincheng před 3 roky
rodič
revize
eee25c901b
1 změnil soubory, kde provedl 512 přidání a 0 odebrání
  1. 512 0
      代码备份/野鸡-2022-10-18/Yeji.cs

+ 512 - 0
代码备份/野鸡-2022-10-18/Yeji.cs

@@ -0,0 +1,512 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.AI;
+/* 动物组件-野鸡 */
+public class Yeji : TargetAnimal
+{
+    //动画播放器
+    Animator animator;
+    //寻路代理
+    NavMeshAgent agent;
+    //血量
+    [System.NonSerialized] public int hp = 3;
+    [System.NonSerialized] public TreeAreaRecorder treeAreaRecorder;
+    [System.NonSerialized] public float flyPlaneHeight = 5;
+    float currentHeight = 0;
+    float toFlyHeight = float.NaN;
+    public void SetFlyHeight(float value) {
+        if (toFlyHeight.Equals(float.NaN)) toFlyHeight = value;
+        currentHeight = value;
+        float agentBaseOffset = value - flyPlaneHeight;
+        this.agent.baseOffset = agentBaseOffset / transform.localScale.y;//因为agent的baseoffset会受节点的scale影响
+        state.flying = currentHeight > 0;
+    }
+
+    void Awake()
+    {
+        yejiSet.Add(this);
+        state = new State();
+        state.animal = this;
+        animator = GetComponent<Animator>();
+        agent = GetComponent<NavMeshAgent>();
+        this.agent.avoidancePriority = avoidancePriority;
+        this.onlineHandler.InitOnAwake(this);
+    }
+    static int _avoidancePriority = 0;
+    static int avoidancePriority {
+        get {
+            if (_avoidancePriority < 50) {
+                _avoidancePriority++;
+            } else {
+                _avoidancePriority = 1;
+            }
+            return _avoidancePriority;
+        }
+    }
+
+    void OnDestroy() {
+        yejiSet.Remove(this);
+        tryReleaseOccupyTree();
+        ReleasePreHeight(this);
+    }
+
+    void Update()
+    {
+        this.onlineHandler.Update();
+        if (this.onlineHandler.isMirror) return;
+        //寻路过程监测
+        if (HasCloseToDestination()) {
+            OnReachDestination();
+        } else {
+            OnMovingToDestination();
+        }
+        UpdateAutoStrategy();
+    }
+
+    #region 被击触发
+        public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName)
+        {
+            arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f;
+            arrow.Hit();
+            if (onlineHandler.isMirror) {
+                onlineHandler.onHitData = onlineHandler.uid.ToString() + "," + partName;
+                return;
+            }
+            OnHitLogic(arrow, partName);
+        }
+
+        public void OnHitLogic(Arrow arrow, string partName) {
+            int hurtValue = 0;
+            if (partName == "Wing") {
+                hurtValue = 1;
+            }
+            else if (partName == "Body") hurtValue = 2;
+            else if (partName == "Head") hurtValue = 3;
+            hp -= hurtValue;
+            GameEventCenter.ins.onTargetAnimalHurt?.Invoke(this, hurtValue);
+            if (hp <= 0) {
+                Die(arrow);
+            } else {
+                Hurt();
+            }
+        }
+
+        void Die(Arrow arrow) {
+            if (state.dead) return;
+            if (arrow != null) {
+                arrow.onDoNextShoot += delegate() {
+                    Destroy(this.gameObject);
+                };
+            } else {
+                //需要借住关卡的GameMode来清除
+                onlineHandler.onDoNextShootWillDestroy = true;
+            }
+            this.animator.speed = 1;
+            state.dead = true;
+            this.agent.enabled = false;
+            ReleasePreHeight(this);
+            onDie?.Invoke(this);
+            AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.gameObject));
+            this.onlineHandler.injuredID++;
+            if (currentHeight < 1.5f) {
+                if (arrow != null) arrow.arrowCameraComp.arrowCameraTemplate.SendMsg(0, null);
+            }
+        }
+
+        void Hurt() {
+            CancelStand();
+            CancelFlyStay();
+            AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.gameObject));
+            this.onlineHandler.injuredID++;
+        }
+    #endregion
+
+    #region 寻路导航
+        bool _moving;
+        bool moving {
+            get { return _moving; }
+            set {
+                movingTime = 0;
+                _moving = value;
+            }
+        } 
+        float movingTime;
+        //启动寻路
+        void SetDestination(Vector3 pos) {
+            moving = true;
+            this.agent.destination = pos;
+        }
+        //寻路过程
+        void OnMovingToDestination() {
+            if (!moving) return;
+            movingTime += Time.deltaTime;
+        }
+        //寻路结束
+        void OnReachDestination() {
+            if (!moving) return;
+            moving = false;
+        }
+        //是否已经接近目的地(寻路完成判断)
+        bool HasCloseToDestination() {
+            if (!moving) return true;
+            return movingTime > 0.1 && this.agent.velocity.magnitude < 0.05f;
+        }
+        //停止寻路
+        void StopNavigation() {
+            if (!moving) return;
+            this.agent.destination = this.agent.nextPosition;
+            this.agent.velocity = Vector3.zero;
+            this.transform.position = this.agent.destination;
+            OnReachDestination();
+        }
+    #endregion
+
+    #region 自动逻辑
+        //自动策略的更新逻辑
+        void UpdateAutoStrategy() {
+            if (state.dead) return;
+            UpdateFlyUpDown();
+            UpdateBehavior();
+        }
+        
+        float canStandTime = 3f;
+        float canFlyStayTime = 3f;
+        //能够在前几棵树徘徊
+        [System.NonSerialized] public int canFlyTreeCount = 3;
+        const float downSpeed = 2.0f;
+        //更新逻辑-起飞降落
+        void UpdateFlyUpDown() {
+            if (state.up && state.landing) { //起飞阶段
+                AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
+                bool isTakeOff = animatorStateInfo.IsName("FlyFromGround");
+                if (isTakeOff) {
+                    if (animatorStateInfo.normalizedTime >= 1.0) {
+                        state.landing = false;
+                        state.flying = true;
+                    }
+                }
+                return;
+            }
+            if (state.up && state.flying) { //上升阶段
+                float surplusHeight = toFlyHeight - currentHeight;
+                float smoothValue = surplusHeight / toFlyHeight;
+                float nextFlyHeight = currentHeight + Time.deltaTime * (1f + 2.5f * smoothValue);
+                this.animator.speed = 1f + 2f * smoothValue;
+                if (nextFlyHeight >= toFlyHeight) { //上升完成
+                    nextFlyHeight = toFlyHeight;
+                    this.animator.speed = 1;
+                    state.up = false;
+                }
+                SetFlyHeight(nextFlyHeight);
+                return;
+            }
+            if (state.down && state.flying) { //下降阶段
+                float nextH = currentHeight - Time.deltaTime * downSpeed;
+                if (nextH <= 0) { //下降完成
+                    nextH = 0;
+                    state.landing = true;
+                    state.flying = false;
+                    StopNavigation();
+                }
+                SetFlyHeight(nextH);
+                return;
+            }
+            if (state.down && state.landing) { //着落阶段
+                AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
+                bool isLand = animatorStateInfo.IsName("LandOnGround");
+                if (isLand) {
+                    if (animatorStateInfo.normalizedTime >= 1.0) {
+                        state.down = false;
+                        //进入站立状态
+                        state.standing = true;
+                        canStandTime = 8f + Random.value * 2f;
+                        animator.CrossFade("IdleOnGround2", 0.2f);
+                    }
+                }
+                return;
+            }
+        }
+
+        TreeAreaRecorder.AreaInfo targetAreaInfo;
+        bool needCheckFlyDown = false;
+        bool willStayOnTree = false;
+        void UpdateBehavior() {
+            if (state.flyStaying) {
+                canFlyStayTime -= Time.deltaTime;
+                if (canFlyStayTime <= 0) {
+                    state.flyStaying = false;
+                }
+                return;
+            }
+
+            if (state.standing) {
+                canStandTime -= Time.deltaTime;
+                if (canStandTime <= 0) {
+                    CancelStand();
+                }
+                return;
+            }
+
+            if (state.landing) return;
+
+            if (state.flying && !state.down && !state.up) {
+                if (needCheckFlyDown) {
+                    float downNeedTime = currentHeight / downSpeed;
+                    float keyDistance = this.agent.speed * downNeedTime; //触发下降的水平距离阈值
+                    Vector3 myP = this.transform.position;
+                    Vector3 desP = this.agent.destination;
+                    desP.y = myP.y;
+                    float distance = Vector3.Distance(myP, desP);
+                    if (distance < keyDistance) {
+                        needCheckFlyDown = false;
+                        if (Random.value < 0.5 && tryOccupyTree()) {
+                            state.down = true;
+                        } else {
+                            willStayOnTree = true;
+                        }
+                    }
+                }
+            }
+            
+            if (moving) return;
+
+            if (willStayOnTree) {
+                willStayOnTree = false;
+                state.flyStaying = true;
+                canFlyStayTime = 9f + Random.value * 1f;
+                return;
+            }
+            
+            AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
+            if (animatorStateInfo.IsName("Yeji Fly Form Tree") || animatorStateInfo.IsName("Yeji Idle On Tree 01") || animatorStateInfo.IsName("Yeji Land On Tree")) {
+                //该动作期间还不能适合执行移动,所以先返回
+                return;
+            }
+
+            //飞向别的树
+            #region 
+                Vector3 myPos = this.transform.position; 
+                TreeAreaRecorder.AreaInfo[] areaInfos = treeAreaRecorder.copyAreaInfos(canFlyTreeCount); 
+                for (int i = 0; i < canFlyTreeCount; i++) {
+                    areaInfos[i].teamCompareValue = areaInfos[i].distanceInHorizontal(myPos);
+                }
+                System.Array.Sort(areaInfos, new ComparerAreaInfosByDistance());
+                TreeAreaRecorder.AreaInfo areaInfo = areaInfos[Random.Range(1, canFlyTreeCount)];
+                Vector3 newPos = YejiHuntGameMode.CalculateNewPosByTreePos(animalsBaseT, flyPlaneHeight, areaInfo);
+                SetDestination(newPos);
+                targetAreaInfo = areaInfo;
+                needCheckFlyDown = true;
+            #endregion
+        }
+
+        class ComparerAreaInfosByDistance : IComparer {
+            public int Compare(object x, object y) {
+                TreeAreaRecorder.AreaInfo a = (TreeAreaRecorder.AreaInfo)x;
+                TreeAreaRecorder.AreaInfo b = (TreeAreaRecorder.AreaInfo)y;
+                if (a.teamCompareValue - b.teamCompareValue > 0) return 1;
+                if (a.teamCompareValue - b.teamCompareValue < 0) return -1;
+                else return 0;
+            }
+        }
+        void CancelStand() {
+            if (!state.standing) return;
+            state.standing = false;
+            state.up = true;
+            animator.CrossFade("FlyFromGround", 0.1f);
+            tryReleaseOccupyTree();
+        }
+
+        void CancelFlyStay() {
+            if (!state.flyStaying) return;
+            canFlyStayTime = 0;
+        }
+
+        bool tryOccupyTree() {
+            if (targetAreaInfo == null) return false;
+            if (targetAreaInfo.occupy != null) return false;
+            else {
+                targetAreaInfo.occupy = this;
+                return true;
+            }
+        }
+
+        void tryReleaseOccupyTree() {
+            if (targetAreaInfo != null && targetAreaInfo.occupy != null && targetAreaInfo.occupy.Equals(this)) {
+                targetAreaInfo.occupy = null;
+            }
+        }
+
+        static float[] preFlyHeights;
+        static object[] preFlyHeightCools;
+        public static void InitPreHeights() {
+            preFlyHeights = new float[]{1.3f, 2.3f};
+            preFlyHeightCools = new object[]{null, null};
+        }
+        public static float RandomOnePreHeight(Yeji yeji) {
+            for (int i = 0; i < preFlyHeightCools.Length; i++) {
+                if (preFlyHeightCools[i] == null) {
+                    preFlyHeightCools[i] = yeji;
+                    return preFlyHeights[i];
+                }
+            }
+            return 2.5f;
+        }
+        public static void ReleasePreHeight(Yeji yeji) {
+            for (int i = 0; i < preFlyHeightCools.Length; i++) {
+                if (yeji.Equals(preFlyHeightCools[i])) {
+                    preFlyHeightCools[i] = null;
+                }
+            }
+        }
+    #endregion
+
+    //状态
+    [System.Serializable]
+    public class State {
+        public bool standing = false;
+        [SerializeField] private bool _flyStaying = false;
+        public bool flyStaying {
+            get { return _flyStaying; }
+            set {
+                _flyStaying = value;
+                animal.animator.SetBool("flyStaying", value);
+            }
+        }
+        [SerializeField] private bool _dead;
+        public bool dead {
+            get { return _dead; }
+            set {
+                _dead = value;
+                animal.animator.SetBool("dead", value);
+            }
+        }
+        [SerializeField] private bool _down;
+        public bool down {
+            get { return _down; }
+            set {
+                _down = value;
+                animal.animator.SetBool("down", value);
+            }
+        }
+        [SerializeField] private bool _landing;
+        public bool landing {
+            get { return _landing; }
+            set {
+                _landing = value;
+                animal.animator.SetBool("landing", value);
+            }
+        }
+        [SerializeField] private bool _up;
+        public bool up {
+            get { return _up; }
+            set {
+                _up = value;
+                animal.animator.SetBool("up", value);
+            }
+        }
+        [SerializeField] private bool _flying;
+        public bool flying {
+            get { return _flying; }
+            set {
+                _flying = value;
+                animal.animator.SetBool("flying", value);
+            }
+        }
+        public Yeji animal;
+    }
+    [SerializeField] public State state;
+
+    //委托
+    public System.Action<Yeji> onDie;
+
+    #region 联机附加部分
+        public static HashSet<Yeji> yejiSet = new HashSet<Yeji>();
+        public OnlineHandler onlineHandler = new OnlineHandler();
+        public class OnlineHandler {
+            Yeji animal;
+            public int uid;
+            public bool isMirror;
+            public int mirrorState = 0;
+            public float animatroSpeed = 1;
+            public YejiSyncData outputSyncData;
+            public void InitOnAwake(Yeji animal) {
+                this.animal = animal;
+                if (isMirror) {
+                    GameObject.Destroy(this.animal.agent);
+                    this.animal.animator.SetLayerWeight(1, 1);
+                }
+            }
+            public void Update() {
+                if (isMirror) {
+                    if (inputSyncData == null) return;
+                    if (!hasUpdateBySyncData) {
+                        this.animal.transform.position = syncPosition;
+                        this.animal.transform.rotation = syncRotation;
+                        hasUpdateBySyncData = true;
+                    } else {
+                        this.animal.transform.position = Vector3.Lerp(this.animal.transform.position, syncPosition, Time.deltaTime * 15);
+                        this.animal.transform.rotation = Quaternion.Lerp(this.animal.transform.rotation, syncRotation, Time.deltaTime * 15);     
+                    }
+                    this.animal.animator.SetInteger("mirrorState", mirrorState);
+                    this.animal.animator.speed = animatroSpeed;
+                    if (inputSyncData.ii != injuredID) {
+                        injuredID = inputSyncData.ii;
+                        AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.animal.gameObject));
+                    }
+                    return;
+                }
+                if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
+                    if (outputSyncData == null) outputSyncData = new YejiSyncData();
+                    int curStateHash = this.animal.animator.GetCurrentAnimatorStateInfo(0).fullPathHash;
+                    mirrorState = System.Array.IndexOf(stateHashList, curStateHash);
+                    animatroSpeed = this.animal.animator.speed;
+                    outputSyncData.SetData(this.animal);
+                }
+            }
+            private YejiSyncData _inputSyncData;
+            public YejiSyncData inputSyncData {
+                get {
+                    return _inputSyncData;
+                }
+                set {
+                    _inputSyncData = value;
+                    uid = value.id;
+                    syncRotation.x = value.rx;
+                    syncRotation.y = value.ry;
+                    syncRotation.z = value.rz;
+                    syncRotation.w = value.rw;
+                    syncPosition.x = value.px;
+                    syncPosition.y = value.py;
+                    syncPosition.z = value.pz;
+                    mirrorState = value.ms;
+                    animatroSpeed = value.asp;
+                }
+            }
+            private Quaternion syncRotation;
+            private Vector3 syncPosition;
+            private bool hasUpdateBySyncData = false;
+            public bool isInvalid = false;  //外部运算用的
+            public string onHitData = null;
+            public bool onDoNextShootWillDestroy = false;
+            public int injuredID = 0;
+            private int[] stateHashList = {
+                Animator.StringToHash("Base Layer.Fly"),
+                Animator.StringToHash("Base Layer.FlyUp"),
+                Animator.StringToHash("Base Layer.FlyFromGround"),
+                Animator.StringToHash("Base Layer.FlyDown"),
+                Animator.StringToHash("Base Layer.LandOnGround"),
+                Animator.StringToHash("Base Layer.IdleOnGround2"),
+                Animator.StringToHash("Base Layer.Yeji Idle On Tree 01"),
+                Animator.StringToHash("Base Layer.Yeji Land On Tree"),
+                Animator.StringToHash("Base Layer.Yeji Fly Form Tree"),
+                Animator.StringToHash("Base Layer.DeadOnSky"),
+                Animator.StringToHash("Base Layer.DeadOnGround")
+            };
+        }
+    #endregion
+
+    public override int GetOnlineID() {
+        return onlineHandler.uid;
+    }
+}