| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using DG.Tweening;
- namespace DuckHunter
- {
- public class Duck : MonoBehaviour
- {
- public static List<Duck> DuckList = new List<Duck>();
- RectTransform _arrowRectTransform;
- RectTransform _parentRectTransform;
- RectTransform _rectTransform;
- DragonBones.UnityArmatureComponent _armature;
- [NonSerialized] public bool dead = false;
- float _direction = 1;
- public Action<Duck> onExit;
- public Action<Duck> onHitDead;
- public Action<Duck> onFallDonwStart;
- public Action<Duck> onFallDonwEnd;
- public DuckConfig config;
- void Start()
- {
- DuckList.Add(this);
- //获取基本组件
- _arrowRectTransform = transform.Find("Arrow") as RectTransform;
- _parentRectTransform = transform.parent as RectTransform;
- _rectTransform = transform as RectTransform;
- //初始化皮肤
- int useSkinIndex = config.type - 1;
- for (int i = 0; i < _rectTransform.childCount; i++)
- {
- GameObject skin = _rectTransform.GetChild(i).gameObject;
- bool needActive = i == useSkinIndex;
- skin.SetActive(needActive);
- //获取龙骨动画组件
- if (needActive) _armature = skin.GetComponent<DragonBones.UnityArmatureComponent>();
- }
- //初始化角度
- _flyAngle = config.flyAngle;
- //初始化速度
- _flySpeed = config.flySpeed;
- //初始化坐标
- _rectTransform.anchoredPosition = Vector2.right * config.positionX;
- //初始化动作
- StartActionCoroutine(Fly());
- }
- void OnDestroy()
- {
- DuckList.Remove(this);
- }
- void Update()
- {
- }
- Sequence _sequenceRotateForever;
- string _lastPlayAnimationName;
- void PlayAnimation(string animationName = null)
- {
- if (animationName == _lastPlayAnimationName) return;
- _lastPlayAnimationName = animationName;
- _armature.animation.Play(animationName, 0);
- //不是射箭状态不处理箭
- if (GlobalData.MyDeviceMode != DeviceMode.Archery) return;
- if (_sequenceRotateForever != null)
- {
- _sequenceRotateForever.Kill();
- _sequenceRotateForever = null;
- }
- if (animationName == "03")
- {
- _arrowRectTransform.gameObject.SetActive(true);
- _arrowRectTransform.localPosition = new Vector3(-20, -55);
- _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 145);
- }
- else if (animationName == "04")
- {
- _arrowRectTransform.gameObject.SetActive(true);
- _arrowRectTransform.localPosition = new Vector3(0, 35);
- _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 0);
- _sequenceRotateForever = DOTween.Sequence();
- _sequenceRotateForever.Append(_arrowRectTransform.DOLocalRotate(Vector3.up * 180, 0.2f));
- _sequenceRotateForever.Append(_arrowRectTransform.DOLocalRotate(Vector3.up * 360, 0.2f));
- _sequenceRotateForever.SetLoops(-1);
- }
- else if (animationName == "05")
- {
- _arrowRectTransform.gameObject.SetActive(true);
- _arrowRectTransform.localPosition = new Vector3(34, -77);
- _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 232);
- }
- else
- {
- _arrowRectTransform.gameObject.SetActive(false);
- };
- }
- static string Event_HitDead_Finish = "Event_HitDead_Finish";
- static string Event_FallDown_Finish = "Event_FallDown_Finish";
- static string Event_FlyTouchBound = "Event_FlyTouchBound";
- static string Event_FlyAway = "Event_FlyAway";
- void OnEvent(string eventName)
- {
- if (eventName == Event_HitDead_Finish)
- {
- StartActionCoroutine(FallDown());
- }
- else if (eventName == Event_FallDown_Finish)
- {
- onExit?.Invoke(this);
- }
- else if (eventName == Event_FlyTouchBound)
- {
- if (_touchBoundCount >= config.touchBoundCount)
- {
- StartActionCoroutine(FlyAway());
- }
- else
- {
- _flyAngle = CalculateTurnbackAngle();
- StartActionCoroutine(Fly());
- }
- }
- else if (eventName == Event_FlyAway)
- {
- Destroy(gameObject);
- onExit?.Invoke(this);
- }
- }
- Coroutine _actionCoroutine = null;
- void StartActionCoroutine(IEnumerator routine)
- {
- StopActionCoroutine();
- _actionCoroutine = StartCoroutine(routine);
- }
- void StopActionCoroutine()
- {
- if (_actionCoroutine != null)
- {
- StopCoroutine(_actionCoroutine);
- _actionCoroutine = null;
- }
- }
- float _flyAngle = 60;
- float _flySpeed = 60;
- Vector2 _flyVelocity;
- /// <summary>
- /// 计算飞行速度
- /// </summary>
- Vector2 CalculateFlyVelocity()
- {
- return new Vector2(Mathf.Cos(_flyAngle * Mathf.Deg2Rad), Mathf.Sin(_flyAngle * Mathf.Deg2Rad)) * _flySpeed;
- }
- /// <summary>
- /// 计算折返后的角度
- /// </summary>
- float CalculateTurnbackAngle()
- {
- Vector2 dc = _BoundChangeVelocityDirections[_touchBoundType];
- Vector3 v = _flyVelocity;
- Vector3 v_dc = v * dc;
- Vector3 c = Vector3.Cross(v, v_dc);
- return _flyAngle + 180 + (c.z > 0 ? -1 : 1) * 90;
- }
- /// <summary>
- /// 飞行动作表现
- /// </summary>
- IEnumerator Fly()
- {
- _flyVelocity = CalculateFlyVelocity();
- if (_flyVelocity.y > 0) _armature.animation.Play("01", 0);
- else _armature.animation.Play("02", 0);
- Vector2 ap = _rectTransform.anchoredPosition;
- UpdateTouchBoundType();
- int firstTouchBoundType = _touchBoundType;
- float t = 0;
- while (_touchBoundType == firstTouchBoundType || _touchBoundType == 0)
- {
- t += Time.deltaTime;
- _rectTransform.anchoredPosition = ap + _flyVelocity * t;
- _direction = _flyVelocity.x > 0 ? 1 : -1;
- UpdateAnglesByDirection();
- UpdateTouchBoundType();
- yield return null;
- }
- CorrectWithinTheBound();
- _touchBoundCount++;
- OnEvent(Event_FlyTouchBound);
- }
- /// <summary>
- /// 碰到边界后用它来改变速度方向
- /// </summary>
- static Vector2[] _BoundChangeVelocityDirections =
- {
- Vector2.one,
- new Vector2(-1, 1),
- new Vector2(1, -1),
- new Vector2(-1, 1),
- new Vector2(1, -1),
- };
- int _touchBoundCount;
- int _touchBoundType;
- /// <summary>
- /// 更新触碰边界的标志
- /// </summary>
- void UpdateTouchBoundType()
- {
- Vector2 ap = _rectTransform.anchoredPosition;
- Rect mr = _rectTransform.rect;
- Rect pr = _parentRectTransform.rect;
- Vector2 mrMin = ap + mr.min;
- Vector2 mrMax = ap + mr.max;
- bool hitBottom = false;
- Collider2D[] hitColliders = Physics2D.OverlapPointAll(transform.position);
- foreach (var item in hitColliders)
- {
- if (item.name.StartsWith("BottomCollider"))
- {
- hitBottom = true;
- break;
- }
- }
- if (hitBottom) _touchBoundType = 2;
- else if (mrMin.x <= 0) _touchBoundType = 1; //left
- else if (mrMin.y <= 0) _touchBoundType = 2; //bottom
- else if (mrMax.x >= pr.width) _touchBoundType = 3; //right
- else if (mrMax.y >= pr.height) _touchBoundType = 4; //top
- else _touchBoundType = 0; //within
- }
- /// <summary>
- /// 把自己纠正回边界内,避免下一次边界检测可能会出问题
- /// </summary>
- void CorrectWithinTheBound()
- {
- Vector2 ap = _rectTransform.anchoredPosition;
- Rect mr = _rectTransform.rect;
- Rect pr = _parentRectTransform.rect;
- Vector2 mrMin = ap + mr.min;
- Vector2 mrMax = ap + mr.max;
- if (mrMin.x <= 0) ap.x = -mr.min.x + 0.1f;
- if (mrMin.y <= 0) ap.y = -mr.min.y + 0.1f;
- if (mrMax.x >= pr.width) ap.x = pr.width - mr.max.x - 0.1f;
- if (mrMax.y >= pr.height) ap.y = pr.height - mr.max.y - 0.1f;
- _rectTransform.anchoredPosition = ap;
- }
- void UpdateAnglesByDirection()
- {
- var ag = _rectTransform.localEulerAngles;
- ag.y = _direction < 0 ? -180 : 0;
- _rectTransform.localEulerAngles = ag;
- }
- IEnumerator HitDead()
- {
- PlayAnimation("03");
- UpdateAnglesByDirection();
- onHitDead?.Invoke(this);
- yield return new WaitForSeconds(0.1f);
- AudioManager.Instance.PlayDuckHit(gameObject);
- yield return new WaitForSeconds(0.4f);
- OnEvent(Event_HitDead_Finish);
- }
- IEnumerator FallDown()
- {
- onFallDonwStart?.Invoke(this);
- PlayAnimation("04");
- UpdateAnglesByDirection();
- Vector2 speed = Vector2.zero;
- while (_rectTransform.anchoredPosition.y > 0)
- {
- speed += Vector2.down * 500f * Time.deltaTime;
- _rectTransform.anchoredPosition += speed * Time.deltaTime;
- yield return null;
- }
- OnEvent(Event_FallDown_Finish);
- onFallDonwEnd?.Invoke(this);
- }
- bool _hasFlyAway = false;
- public Action onStartFlyAway;
- IEnumerator FlyAway()
- {
- _hasFlyAway = true;
- onStartFlyAway?.Invoke();
- bool intersect = true;
- while (intersect)
- {
- _rectTransform.anchoredPosition += _flyVelocity * Time.deltaTime;
- Rect mr = _rectTransform.rect;
- mr.position = _rectTransform.anchoredPosition + mr.min;
- Rect pr = _parentRectTransform.rect;
- pr.position = Vector2.zero;
- intersect = Intersects(mr, pr);
- yield return null;
- }
- OnEvent(Event_FlyAway);
- }
- bool Intersects(Rect a, Rect b)
- {
- float maxax = a.x + a.width,
- maxay = a.y + a.height,
- maxbx = b.x + b.width,
- maxby = b.y + b.height;
- return !(maxax < b.x || maxbx < a.x || maxay < b.y || maxby < a.y);
- }
- //活着的时候击中才会返回ture
- public bool Hit()
- {
- if (_hasFlyAway) return false;
- if (dead) return false;
- dead = true;
- StartActionCoroutine(HitDead());
- return true;
- }
- public void PlayDeadForDogHand(int direction)
- {
- _direction = direction;
- UpdateAnglesByDirection();
- PlayAnimation("05");
- }
- public void NotifyFlyAway()
- {
- if (_hasFlyAway) return;
- if (dead) return;
- _flyVelocity *= 1000f / _flyVelocity.magnitude;
- StartActionCoroutine(FlyAway());
- }
- }
- }
|