| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- 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;
- bool _firstSetFlyHeight = true;
- public void SetFlyHeight(float value) {
- if (toFlyHeight.Equals(float.NaN)) toFlyHeight = value;
- currentHeight = value;
- float agentBaseOffset = value - flyPlaneHeight;
- this.agent.baseOffset = agentBaseOffset / GetScaleY();//因为agent的baseoffset会受节点的scale影响
- if (_firstSetFlyHeight) {
- _firstSetFlyHeight = false;
- state.flying = currentHeight > GetLandHeight();
- }
- }
- private float GetLandHeight() {
- if (stoneRecorder.IsStoneLocker(this)) return stoneRecorder.GetStoneYOffLand();
- return 0f;
- }
- float _scaleY = -1;
- private float GetScaleY() {
- if (_scaleY < 0) _scaleY = transform.localScale.y;
- return _scaleY;
- }
- 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);
- stoneRecorder.TryRelease(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 = 2;
- 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;
- float minH = GetLandHeight();
- if (nextH <= minH) { //下降完成
- nextH = minH;
- 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 (stoneRecorder.IsStoneLocker(this)) {
- state.down = true;
- } else if (Random.value < 0.5 && tryOccupyTree()) {
- // } else if (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;
- }
- //可以飞向石头
- bool isOnStone = stoneRecorder.IsOnStone(this);
- if (!isOnStone && Random.value < 0.7f && stoneRecorder.TryLock(this)) {
- // if (!stoneRecorder.IsOnStone(this) && stoneRecorder.TryLock(this)) {
- var newPos1 = stoneRecorder.GetLockPosition(animalsBaseT, flyPlaneHeight);
- SetDestination(newPos1);
- needCheckFlyDown = true;
- 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());
- int treeFindStartIndex = 1;
- if (isOnStone) treeFindStartIndex = 0;
- TreeAreaRecorder.AreaInfo areaInfo = areaInfos[Random.Range(treeFindStartIndex, 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();
- stoneRecorder.TryRelease(this);
- }
- 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;
- }
- static StoneRecorder stoneRecorder = new StoneRecorder();
- }
- public class StoneRecorder {
- private object locker;
- public bool TryLock(object locker) {
- if (this.locker == null) {
- this.locker = locker;
- return true;
- }
- return false;
- }
- public bool TryRelease(object locker) {
- if (this.locker == locker) {
- this.locker = null;
- return true;
- }
- return false;
- }
- public bool IsStoneLocker(object locker) {
- return this.locker == locker;
- }
- float stoneX = 158.981f;
- float stoneZ = 140.848f;
- public float GetStoneYOffLand() {
- return 0.35f;
- }
- public Vector3 GetLockPosition(Transform animalsBaseT, float flyPlaneHeight) {
- return new Vector3(stoneX, animalsBaseT.position.y + flyPlaneHeight, stoneZ);
- }
- public bool IsOnStone(MonoBehaviour animal) {
- Vector3 pos = animal.transform.position;
- float distance = Mathf.Sqrt(Mathf.Pow(stoneX - pos.x, 2) + Mathf.Pow(stoneZ - pos.z, 2));
- return distance < 0.6f;
- }
- }
|