使用Unity自带的对象池实现飘字(如怪物受创时显示伤害数字)

2024-01-08  本文已影响0人  全新的饭

示意

如图,每次点击屏幕时,将Player(球)设置到随机位置,并在其位置处显示一个随机类型的飘字。


飘字示意.gif

使用

初始化FloatValueSys时,需传入相应Model。


FloatValueModel
FloatValueObj

可调用FloatValueSys.Show方法显示飘字。

代码

FloatValueSys.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

public enum FloatValueType
{
    None,
    MonsterGetHit,
    MonsterGetCritHit,
    MonsterGetPoisonHit,
}

[System.Serializable]
public class FloatValueTypeAndObjTemplate
{
    [SerializeField]
    private FloatValueType _type;
    public FloatValueType Type => _type;
    [SerializeField]
    private FloatValueObj _template;
    public FloatValueObj Template => _template;
}

[System.Serializable]
public class FloatValueModel
{
    public Transform Parent;
    public FloatValueTypeAndObjTemplate[] ObjAndTemplates;
    public Camera UICam;

}
public class FloatValueSys
{
    private FloatValueModel _model;
    private RectTransform _root;
    private Dictionary<FloatValueType, FloatValueObjPool> _poolDict;

    public FloatValueSys(FloatValueModel model)
    {
        _model = model;
        CreateRoot();
        InitPoolDict();

        void CreateRoot()
        {
            _root = new GameObject(nameof(FloatValueSys)).AddComponent<RectTransform>();
            _root.SetParent(_model.Parent);
            _root.SetAsFirstSibling();
            SetRectTransAsFullScreen(_root);
        }
        void InitPoolDict()
        {
            _poolDict = new Dictionary<FloatValueType, FloatValueObjPool>();
            foreach (var o in _model.ObjAndTemplates)
            {
                _poolDict.Add(o.Type, new FloatValueObjPool(o.Template, _root));
            }
        }
        void SetRectTransAsFullScreen(RectTransform rectTrans)
        {
            rectTrans.localPosition = Vector3.zero;
            rectTrans.sizeDelta = Vector2.zero;
            rectTrans.localScale = Vector3.one;
            rectTrans.anchorMin = Vector2.zero;
            rectTrans.anchorMax = Vector2.one;
        }
    }
    public void Destroy()
    {
        DestroyPoolDict();
        DestroyRoot();
        _model = null;

        void DestroyPoolDict()
        {
            foreach (var v in _poolDict.Values)
            {
                v.Destroy();
            }
            _poolDict.Clear();
            _poolDict = null;
        }
        void DestroyRoot()
        {
            if (_root != null && _root.gameObject != null)
            {
                GameObject.Destroy(_root.gameObject);
                _root = null;
            }
        }
    }

    public void Show(FloatValueType type, string content, Vector3 pos)
    {
        var pool = _poolDict[type];
        var obj = pool.Get();
        obj.Init();
        obj.Show(content, ConvertWorldPosToUIPos(pos));
        MonoSys.Instance.DelayCall(pool.LifeSeconds, () =>
        {
            obj.Destroy();
            pool.Release(obj);
        });


        Vector3 ConvertWorldPosToUIPos(Vector3 worldPos)
        {
            return _model.UICam.ScreenToWorldPoint(Camera.main.WorldToScreenPoint(worldPos));
        }
    }

    private class FloatValueObjPool
    {
        private Transform _root;
        private FloatValueObj _template;
        public float LifeSeconds => _template.LifeSeconds;
        private IObjectPool<FloatValueObj> _pool;

        public FloatValueObjPool(FloatValueObj template, Transform root)
        {
            _template = template;
            _root = root;
            _pool = new ObjectPool<FloatValueObj>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject);
        }
        public void Destroy()
        {
            _pool.Clear();
            _pool = null;
            _root = null;
            _template = null;
        }
        public FloatValueObj Get()
        {
            return _pool.Get();
        }
        public void Release(FloatValueObj obj)
        {
            _pool.Release(obj);
        }

        private FloatValueObj CreatePooledItem()
        {
            var obj = GameObject.Instantiate(_template.gameObject).GetComponent<FloatValueObj>();
            obj.transform.SetParent(_root);
            obj.transform.localScale = Vector3.one;
            return obj;
        }
        private void OnReturnedToPool(FloatValueObj obj)
        {
            obj.gameObject.SetActive(false);
        }
        private void OnTakeFromPool(FloatValueObj obj)
        { }
        void OnDestroyPoolObject(FloatValueObj obj)
        {
            if (obj != null && obj.gameObject != null)
            {
                GameObject.Destroy(obj.gameObject);
            }
        }

    }
}

FloatValueObj.cs

using UnityEngine;
using UnityEngine.UI;

// 飘字
public class FloatValueObj : MonoBehaviour
{
    [SerializeField]
    private Text _content;
    [SerializeField]
    private float _lifeSeconds;
    public float LifeSeconds => _lifeSeconds;
    public void Init()
    { }
    public void Show(string content, Vector3 pos)
    {
        _content.text = content;
        transform.position = pos;
        gameObject.SetActive(true);
    }
    public void Destroy()
    { }
}

MyTest.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyTest : MonoBehaviour
{
    private FloatValueSys _floatValueSys;
    [SerializeField]
    private FloatValueModel _model;

    [SerializeField]
    private Transform _minTrans;
    [SerializeField]
    private Transform _maxTrans;
    [SerializeField]
    private Transform _playerTrans;

    private void Start()
    {
        Init();
    }

    private void Update()
    {
        MyUpdate();
    }

    private void OnDestroy()
    {
        MyDestroy();
    }

    private void Init()
    {
        _floatValueSys = new FloatValueSys(_model);
    }

    private void MyUpdate()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 随机设置player位置
            SetPlayerPosInAreaRandomly();
            // 在player处飘一种随机类型的字
            CreateFloatValueOnPlayerRandomly();
        }

        void SetPlayerPosInAreaRandomly()
        {
            var minPos = _minTrans.position;
            var maxPos = _maxTrans.position;
            var pos = new Vector3(UnityEngine.Random.Range(minPos.x, maxPos.x),
                                  _playerTrans.position.y,
                                  UnityEngine.Random.Range(minPos.z, maxPos.z));
            _playerTrans.position = pos;
        }
        void CreateFloatValueOnPlayerRandomly()
        {
            var allTypes = Enum.GetValues(typeof(FloatValueType)) as FloatValueType[];
            var curType = FloatValueType.None;
            while (curType == FloatValueType.None)
            {
                curType = allTypes[UnityEngine.Random.Range(0, allTypes.Length)];
            }
            var value = UnityEngine.Random.Range(10, 100);
            _floatValueSys.Show(curType, value.ToString(), _playerTrans.position);
        }
    }

    private void MyDestroy()
    {
        _floatValueSys.Destroy();
        _floatValueSys = null;
    }
}
上一篇下一篇

猜你喜欢

热点阅读