Unity中,飞金币效果
2022-06-14 本文已影响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 };
}
}