using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; /* 动物组件-野兔 */ public class Rabbit : TargetAnimal { //动画播放器 AnimationPlayer ap; //寻路代理 NavMeshAgent agent; //血量 [System.NonSerialized] public int hp = 1; [SerializeField] Material[] materials; [System.NonSerialized] public int colorType = -1; public void ChangeColorByType(int type) { colorType = type; GetComponentInChildren().material = materials[type - 1]; } #region 联机附加部分 public static HashSet rabbitSet = new HashSet(); //识别ID [System.NonSerialized] public int uid; //是否为镜像,即只负责渲染,还有作为接收器,接收到外部输入(比如被箭击中)会通知主机 [System.NonSerialized] public bool isMirror; public RabbitSyncData outputSyncData; private RabbitSyncData _inputSyncData; public RabbitSyncData 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; } } private Quaternion syncRotation; private Vector3 syncPosition; private bool hasUpdateBySyncData = false; [System.NonSerialized] public bool isInvalid = false; //外部运算用的 [System.NonSerialized] public string onHitData = null; [System.NonSerialized] public bool onDoNextShootWillDestroy = false; [System.NonSerialized] public int injuredID = 0; #endregion void Awake() { rabbitSet.Add(this); ap = GetComponent(); agent = GetComponent(); if (isMirror) { Destroy(agent); } if (GameMgr.ins) { GameObject stoneObstacle = GameMgr.ins.transform.Find("StoneObstacle").gameObject; if (!stoneObstacle.activeSelf) stoneObstacle.SetActive(true); } } void Start() { //不同个体动画播放速度差异化 ap.speed = Random.value * 0.2f + 0.8f; //初始动画 playAniForIdle(); //初始化自动策略 InitAutoStrategy(); } void OnDestroy() { rabbitSet.Remove(this); } void Update() { if (isMirror) { if (inputSyncData == null) return; if (!hasUpdateBySyncData) { transform.position = syncPosition; transform.rotation = syncRotation; hasUpdateBySyncData = true; } else { transform.position = Vector3.Lerp(transform.position, syncPosition, Time.deltaTime * 15); transform.rotation = Quaternion.Lerp(transform.rotation, syncRotation, Time.deltaTime * 15); } if (colorType != inputSyncData.ct) { ChangeColorByType(inputSyncData.ct); } if (inputSyncData.ai != curAnimIndex) { curAnimIndex = inputSyncData.ai; if (IsAniForIdle()) { ap.play(curAnimIndex, WrapMode.Loop); } else if (isAniJump()) { playAniJump(); } else if (isAniDie()) { playAniDie(); } } if (inputSyncData.ii != injuredID) { injuredID = inputSyncData.ii; AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject)); } return; } if (GlobalData.pkMatchType == PKMatchType.OnlinePK) { if (outputSyncData == null) outputSyncData = new RabbitSyncData(); outputSyncData.SetData(this); } //寻路过程监测 if (HasCloseToDestination()) { OnReachDestination(); } else { OnMovingToDestination(); } UpdateAction(); UpdateActionTime(); UpdateAutoStrategy(); } public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName) { arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f; arrow.Hit(); if (isMirror) { onHitData = uid.ToString() + "," + partName; return; } OnHitLogic(arrow, partName); } public void OnHitLogic(Arrow arrow, string partName) { int hurtValue = 0; if (partName == "Leg" || partName == "Ear") 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 (dead) return; if (arrow != null) { arrow.onDoNextShoot += delegate() { Destroy(this.gameObject); }; } else { //需要借住关卡的GameMode来清除 onDoNextShootWillDestroy = true; } dead = true; this.agent.enabled = false; PuaseAutoStrategy(); onDie?.Invoke(this); AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject)); injuredID++; } void Hurt() { RunAwayFromHunter(); addHurtFlag(); PuaseAutoStrategy(); AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject)); injuredID++; } JCUnityLib.CountLock hurtFlag = new JCUnityLib.CountLock(); void addHurtFlag() { hurtFlag.Lock(); Invoke("clearOneHurtFlag", 5); } void clearOneHurtFlag() { hurtFlag.Unlock(); if (hurtFlag.IsReleased()) { onHurtFlagTimeout(); } } void onHurtFlagTimeout() { if (!dead) ResumeAutoStrategy(); } //是否已经死亡 bool dead = false; //是否处于移动状态 bool _moving = false; bool moving { get { return _moving; } set { if (_moving && !value) { movingTime = 0; } if (!_moving && value) stayingTime = 0; _moving = value; } } //实时记录“单次移动的持续时间” float movingTime = 0; //实时停留时间 float stayingTime = 0; //启动寻路 void SetDestination(Vector3 pos) { moving = true; this.agent.destination = pos; } //寻路过程 void OnMovingToDestination() { if (!moving) return; } //寻路结束 void OnReachDestination() { if (!moving) return; moving = false; } //是否已经接近目的地(寻路完成判断) bool HasCloseToDestination() { if (!moving) return true; if (Vector3.Distance(this.agent.nextPosition, this.agent.destination) < 0.15f) { return true; } if (movingTime > 0.1f && this.agent.velocity.magnitude < 0.05f) { return true; } return false; } //更新动作 void UpdateAction() { if (dead) { if (!isAniDie()) playAniDie(); } else if (moving) { if (!isAniJump()) playAniJump(); } else { if (!IsAniForIdle()) { playAniForIdle(); } } } //记录动作时间 void UpdateActionTime() { if (moving) { movingTime += Time.deltaTime; } else { stayingTime += Time.deltaTime; } } float willStayTime; float willMoveTime; bool autoMoving = false; float autoMovingTime; bool autoStrategy = true; //自动策略的更新逻辑 void UpdateAutoStrategy() { if (!autoStrategy) return; if (stayingTime > willStayTime) { autoMoving = true; RandomMove(); RandomWillStayTime(); } if (autoMoving) { // if (moving) { // autoMovingTime += Time.deltaTime; // } else if (autoMovingTime < willMoveTime) { // RandomMove(); // } else if (autoMovingTime >= willMoveTime) { // Stay(); // RandomWillMoveTime(); // autoMoving = false; // autoMovingTime = 0; // } if (!moving) { Stay(); RandomWillMoveTime(); autoMoving = false; autoMovingTime = 0; } else { autoMovingTime += Time.deltaTime; } } } void InitAutoStrategy() { autoStrategy = true; this.willStayTime = 3 + Random.value * 4; RandomWillMoveTime(); } void PuaseAutoStrategy() { this.autoStrategy = false; } void ResumeAutoStrategy() { this.autoStrategy = true; RandomWillStayTime(); RandomWillMoveTime(); this.autoMoving = false; this.autoMovingTime = 0; } void RandomWillStayTime() { this.willStayTime = Random.value * 2 + 10; } void RandomWillMoveTime() { this.willMoveTime = Random.value * 2 + 3; } //逃跑远离猎人 void RunAwayFromHunter() { Vector3 backVec = GetPointerHunterToMe(); SetDestination(transform.position + backVec.normalized * 5); } [System.NonSerialized] public float baseDistance = 10; [System.NonSerialized] public float baseDistanceMoveRange = 3; //随机移动 void RandomMove() { Vector3 standardPointer = animalsBaseT.forward; Vector3 pointerWithLen = standardPointer.normalized * (baseDistance + Random.value * baseDistanceMoveRange); pointerWithLen = Quaternion.AngleAxis(Random.Range(-14f, 14f), Vector3.up) * pointerWithLen; Vector3 newPos = animalsBaseT.position + pointerWithLen; // GameObject.Find("BBAA").transform.position = newPos; // GameObject.Find("BBBA").transform.LookAt(GameObject.Find("BBAA").transform); SetDestination(newPos); } //停留 void Stay() { if (moving) { this.agent.destination = this.agent.nextPosition; OnReachDestination(); } } //当前动画索引 [System.NonSerialized] public int curAnimIndex = -1; void playAniEat() { ap.play(curAnimIndex = 0, WrapMode.Loop); } bool isAniEat() { return curAnimIndex == 0; } void playAniDie() { ap.play(curAnimIndex = 2, WrapMode.Once); } bool isAniDie() { return curAnimIndex == 2; } void playAniJump() { ap.play(curAnimIndex = 7, WrapMode.Loop); } bool isAniJump() { return curAnimIndex == 7; } bool IsAniForIdle() { return curAnimIndex == 0 || curAnimIndex == 4 || curAnimIndex == 5 || curAnimIndex == 6; } int[] idleIndexes = {0, 4, 5, 6}; void playAniForIdle() { curAnimIndex = idleIndexes[Random.Range(0, idleIndexes.Length)]; ap.play(curAnimIndex, WrapMode.Loop); } //委托 public System.Action onDie; public override int GetOnlineID() { return uid; } }