Unity中,飞金币效果

作者: 全新的饭 | 来源:发表于2022-06-14 10:09 被阅读0次

    需求

    从a点生成一些金币飞往b点。
    a、b可以是3D世界中的点,也可以是UI中的点。

    用途:获得金币后,出现金币效果飞往UI中显示金币数量的地方,表示获得了金币。

    效果示意

    如图,方块是3D世界中的起点,圆球是3D世界中的终点。白色正方形是UI中的起点,红色正方形是UI中的终点。
    效果图中演示了起点和终点分别是3D世界中的点和UI中的点的各种情况。


    飞金币效果.gif

    游戏对象结构

    EndPos是默认的终点(外界不传入终点时,使用该点作为终点)。
    Canvas的RenderMode必须是:Camera。因为FlyObj是3d物体。


    image.png
    image.png

    用法

     UIFlyElementSys.Instance.PlayFlyCoinEffect(起点, 终点)
    

    具体代码

    说明:需要用到插件 DOTween

    using DG.Tweening;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// UI中,生成金币飞行效果:一串金币从起点飞到终点
    /// </summary>
    
    public class UIFlyElementController : MonoBehaviour
    {
        [SerializeField]
        private GameObject _coinTemplateGo;
        [SerializeField]
        private RectTransform _endPosTrans;
        public Vector3 EndPos{ get { return _endPosTrans.transform.position; } }
    
        private List<GameObject> _coinGos;
        [SerializeField]
        private Canvas _canvas;
        public Canvas Canvas{ get { return _canvas; } }
        [SerializeField]
        private Camera _cam;
        public Camera Camera{ get { return _cam; } }
        public void Init()
        {
            _coinTemplateGo.SetActive(false);
            _coinGos = new List<GameObject>();
            gameObject.SetActive(true);
        }
        private void OnDestroy() 
        {
            _coinGos.Clear();
            _coinGos = null;
        }
    
        public GameObject GetCoinGo()
        {
            if (_coinGos.Count==0)
            {
                _coinGos.Add(Instantiate(_coinTemplateGo));
            }
    
            var go = _coinGos[0];
            _coinGos.Remove(go);
            return go;
        }
    
        public void RecyleCoinGo(GameObject coinGo)
        {
            coinGo.SetActive(false);
            coinGo.transform.SetParent(GetCoinGoParent());
            coinGo.transform.localPosition = Vector3.zero;
            coinGo.transform.localRotation = Quaternion.identity;
            coinGo.transform.localScale = Vector3.one;
            _coinGos.Add(coinGo);
        }
    
        public Transform GetCoinGoParent()
        {
            return _coinTemplateGo.transform.parent;
        }
    }
    
    public class UIFlyElementSys
    {
        private static UIFlyElementSys _instance;
        public static UIFlyElementSys Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UIFlyElementSys();
                }
    
                return _instance;
            }
        }
    
        private UIFlyElementController _uiFlyElementController;
        private UIFlyElementController UIFlyElementController
        {
            get
            {
                if (_uiFlyElementController == null)
                {
                    _uiFlyElementController = GameObject.FindObjectOfType<UIFlyElementController>();
                    _uiFlyElementController.Init();
                }
    
                return _uiFlyElementController;
            }
        }
    
        private UIFlyElementSys()
        {
    
        }
    
        public void Destroy()
        {}
    
        private Vector2 WorldPosToUiLocalPos(Vector3 worldPos)
        {
            var screenPos = UIFlyElementController.Camera.WorldToScreenPoint(worldPos);
            RectTransformUtility.ScreenPointToLocalPointInRectangle(UIFlyElementController.Canvas.transform as RectTransform, screenPos, UIFlyElementController.Camera, out Vector2 localPos);
            return localPos;
        }
    
        // 起始点:世界坐标
        public float PlayFlyCoinEffect(Vector3 beginPos)
        {
            return PlayFlyCoinEffect(beginPos, UIFlyElementController.EndPos);
        }
        public float PlayFlyCoinEffect(Vector3 beginPos, Vector3 endPos, int cnt = 10)
        {
            return PlayFlyCoinEffect(WorldPosToUiLocalPos(beginPos), WorldPosToUiLocalPos(endPos), cnt);
        }
        
        // 播放一个金币飞行效果。返回值:效果持续时间
        private float PlayFlyCoinEffect(Vector2 beginPos, Vector2 endPos, int cnt = 10)
        {
            // TODO:可以直接在此处调用播放音效:金币飞行
    
            var seq = GetFlyCoinEffectSeq(beginPos, endPos, cnt);
            seq.Play();
            return seq.Duration(false);
        }
    
        private Sequence GetFlyCoinEffectSeq(Vector2 beginPos, Vector2 endPos, int cnt)
        {
            var step = Mathf.Clamp(cnt, 10, 30);
            Sequence seq = DOTween.Sequence();
            for (int i = 0; i < step; i++)
            {
                GameObject cell = UIFlyElementController.GetCoinGo();
                Transform flyObjTf = cell.transform;
                flyObjTf.SetParent(UIFlyElementController.GetCoinGoParent(), false);
                flyObjTf.localPosition = endPos;
                var endPos3d = new Vector3(flyObjTf.localPosition.x, flyObjTf.localPosition.y, -100f);
    
                flyObjTf.localPosition = beginPos;
                flyObjTf.localPosition = new Vector3(flyObjTf.localPosition.x, flyObjTf.localPosition.y, -100f);
                flyObjTf.gameObject.SetActive(true);
    
                var path = GetPath(flyObjTf.localPosition, endPos3d);
    
                var tempSeq = DOTween.Sequence();
    
                var randomStartPos = new Vector2(flyObjTf.localPosition.x, flyObjTf.localPosition.y) + Vector2.up * 50 + UnityEngine.Random.insideUnitCircle * new Vector2(500, 200);
                Tween startMove = flyObjTf.DOLocalMove(new Vector3(randomStartPos.x, randomStartPos.y, -100f), 0.1f).SetUpdate(true);
                tempSeq.Append(startMove);
                tempSeq.AppendInterval(0.01f);
    
                Tween moveT = flyObjTf.DOLocalPath(path, 0.6f, PathType.CatmullRom).SetEase(Ease.InSine).SetUpdate(true);
                Tween scaleT = flyObjTf.DOScale(new Vector3(0.5f, 0.5f, 0.5f), 0.6f).SetEase(Ease.InBack).SetUpdate(true);
                Tween rotateT = flyObjTf.DOLocalRotate(new Vector3(0, 360, 0), 0.25f, RotateMode.FastBeyond360).SetLoops(-1, LoopType.Restart).SetEase(Ease.Linear).SetUpdate(true);
                tempSeq.Append(moveT);
                tempSeq.Join(scaleT);
                tempSeq.Join(rotateT);
    
                tempSeq.SetDelay(0.01f * i);
                tempSeq.SetUpdate(true);
                tempSeq.onComplete = () =>
                {
                    GameObject ttObj = cell;
                    UIFlyElementController.RecyleCoinGo(ttObj);
                };
                //加入总序列
                seq.Join(tempSeq);
            }
            seq.SetUpdate(true);
            return seq;
        }
        private Vector3[] GetPath(Vector3 start, Vector3 end)
        {
            var middle = (start + end) / 2;
            middle += UnityEngine.Random.Range(-0.2f, 0.2f) * 5.4f * Vector3.right;
            return new Vector3[] { middle, end };
        }
    }
    

    相关文章

      网友评论

        本文标题:Unity中,飞金币效果

        本文链接:https://www.haomeiwen.com/subject/kexzmrtx.html