A história de uma linha (pacote de desenho baseado em LineRenderer)

As etapas gerais para usar o LineRenderer para desenhar segmentos de linha no desenvolvimento do Unity:
1. Crie um objeto
2. Adicione o componente LineRenderer
3. Escreva um script para especificar o LineRenderer para desenhar segmentos de linha através do LineRenderer especificado.
Na verdade, se você gastar apenas uma linha , não parece tão complicado. Mas se eu tiver um requisito e precisar sacar 100 itens, essa operação seria muito pervertida. . .
Talvez alguns estudantes inteligentes digam: então posso transformá-lo em uma casa pré-fabricada, e cada casa pré-fabricada tem um objeto para desenhar linhas. Obviamente, isso é muito mais simples do que o método acima.
Mas também surge a questão: se ainda preciso gerenciar a adição, exclusão, modificação e verificação desses segmentos de linha, preciso escrever um gerente para gerenciar todos os segmentos de linha?
Deixe-me simplesmente escrever um LineManager para gerenciar todas as funções de desenho de linha do projeto. . .

Vamos começar com o objeto Line. Primeiro de tudo, temos que pensar sobre quais métodos ou atributos um gerenciamento de segmento de linha mais básico deve ter. . .
Não pense nisso, deixe-me apresentá-lo. Dê uma olhada na interface ILine abaixo. Claro, se você acha que pode adicionar outros atributos ou métodos, você pode tentar implementá-lo sozinho. . .

using UnityEngine;

namespace S
{
    public interface ILine
    {
        ILineManager lineManager { get; }
        /// <summary>
        /// 材质
        /// </summary>
        Material material { get; set; }
        /// <summary>
        /// 开始颜色
        /// </summary>
        Color startColor { get; set; }
        /// <summary>
        /// 结束颜色
        /// </summary>
        Color endColor { get; set; }
        /// <summary>
        /// 开始宽度
        /// </summary>
        float startWidth { get; set; }
        /// <summary>
        /// 结束宽度
        /// </summary>
        float endWidth { get; set; }
        /// <summary>
        /// 是否使用世界坐标
        /// </summary>
        bool useWorldSpace { get; set; }

        /// <summary>
        /// 是否循环
        /// </summary>
        bool loop { get; set; }

        /// <summary>
        /// 坐标点的数量
        /// </summary>
        int positionCount { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="lineManager">管理者</param>
        void Init(ILineManager lineManager);

        /// <summary>
        /// 增加一个坐标
        /// </summary>
        void AddPosition(Vector3 position);

        /// <summary>
        /// 减少一个坐标
        /// </summary>
        /// <param name="index">索引</param>
        void RemovePosition(int index);

        /// <summary>
        /// 设置一个坐标
        /// </summary>
        /// <param name="index">索引</param>
        /// <param name="position">坐标</param>
        void SetPosition(int index,Vector3 position);
        
        /// <summary>
        /// 设置多个坐标
        /// </summary>
        /// <param name="positions">坐标数组</param>
        void SetPositions(Vector3[] positions);

        /// <summary>
        /// 得到一个坐标
        /// </summary>
        /// <param name="index">索引</param>
        /// <returns></returns>
        Vector3 GetPosition(int index);

        /// <summary>
        /// 得到所有的坐标
        /// </summary>
        /// <returns></returns>
        Vector3[] GetPositions();

        /// <summary>
        /// 清空绘制内容
        /// </summary>
        void Clear();

        /// <summary>
        /// 释放对象
        /// </summary>
        void Dispose();
    }
}

É semelhante às propriedades e métodos do LineRenderer? Sim, porque os métodos e propriedades do LineRenderer já são muito abrangentes.Existem mais métodos do que o LineRenerer, nomeadamente AddPosition, RemovePosition, Clear e Dispose. Outros não são tão abrangentes quanto o LineRenderer. Se necessário posteriormente, você pode adicionar propriedades e métodos à interface. Aqui listamos apenas os mais usados.

Depois escrevemos a interface do segmento de linha e começaremos a escrever o LineManager.

using System.Collections.Generic;
using UnityEngine;

namespace S
{
    public interface ILineManager
    {
        public GameObject gameObject { get; }
        public Transform transform { get; }
        int lineCount { get; }

        /// <summary>
        /// 创建一条ILine
        /// </summary>
        /// <returns></returns>
        T CreateLine<T>()where T:ILine,new();

        /// <summary>
        /// 管理器中是否存在指定ILine
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        bool HasLine(ILine line);

        /// <summary>
        /// 删除一条ILine
        /// </summary>
        /// <param name="line">目标ILine</param>
        void DeleteLine(ILine line);

        /// <summary>
        /// 删除一些ILine
        /// </summary>
        void DeleteLines(ILine[] lines);

        /// <summary>
        /// 删除一些ILine
        /// </summary>
        /// <param name="lines"></param>
        void DeleteLines(List<ILine> lines);

        /// <summary>
        /// 删除所有ILine
        /// </summary>
        void DeleteAll();
    }
}

Sim, as funções atuais do LineManager são relativamente poucas e são basicamente usadas para lidar com a criação e exclusão, ah! Há também uma contagem lineCount.Durante o processo de desenvolvimento posterior, se forem necessárias funções de gerenciamento mais complexas, você poderá adicioná-las lentamente.

Agora que escrevemos os modelos para segmentos de linha e gerentes, a próxima etapa é implementar essas duas interfaces e pronto.

Linha:

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

namespace S
{
    public static class LineRendererPool
    {
        private static Queue<LineRenderer> queue= new Queue<LineRenderer>();
        public static int Count => queue.Count;
        public static int maxCount = 10;

        public static LineRenderer Dequeue()
        {
            LineRenderer lr = null;
            while (lr==null&&Count>0)
            {
                lr = queue.Dequeue();
            }
            if (lr==null)lr = new GameObject("Line").AddComponent<LineRenderer>();
            return lr;
        }

        public static void EnQueue(LineRenderer lr)
        {
            if (lr == null) return;
            if (queue.Contains(lr)) return;
            if (Count>=maxCount)
            {
                UnityEngine.Object.Destroy(lr.gameObject);
                return;
            }
            queue.Enqueue(lr);
        }
    }

    public class Line : ILine
    {
        protected LineRenderer lineRenderer { get; private set; }
        public ILineManager lineManager { get; private set; }

        public Material material
        {
            get => lineRenderer.material;
            set => lineRenderer.material = value;
        }

        public Color startColor
        {
            get => lineRenderer.startColor;
            set => lineRenderer.startColor = value;
        }

        public Color endColor
        {
            get => lineRenderer.endColor;
            set => lineRenderer.endColor = value;
        }

        public float startWidth
        {
            get => lineRenderer.startWidth;
            set => lineRenderer.startWidth = value;
        }

        public float endWidth
        {
            get => lineRenderer.endWidth;
            set => lineRenderer.endWidth = value;
        }

        public bool useWorldSpace
        {
            get => lineRenderer.useWorldSpace;
            set => lineRenderer.useWorldSpace = value;
        }

        public bool loop
        {
            get => lineRenderer.loop;
            set => lineRenderer.loop = value;
        }

        public int positionCount
        {
            get => lineRenderer.positionCount;
            set => lineRenderer.positionCount = value;
        }

        public void Init(ILineManager lineManager)
        {
            if (lineManager==null)throw new Exception("Line Init 失败,LineManager不可为null");
            this.lineManager = lineManager;
            lineRenderer = LineRendererPool.Dequeue();
            lineRenderer.transform.SetParent(lineManager.transform);
            lineRenderer.transform.localScale=Vector3.one;
            lineRenderer.transform.localPosition=Vector3.zero;
            Clear();
            Inited();
        }
        
        protected virtual void Inited()
        {
        }

        public void AddPosition(Vector3 position)
        {
            int index = positionCount;
            positionCount++;
            SetPosition(index,position);
        }

        public void RemovePosition(int index)
        {
            if (index < 0 || index >= positionCount) return;
            if (index == positionCount - 1)
            {
                positionCount--;
                return;
            }
            for (int i = index+1; i < positionCount; i++)
            {
                SetPosition(i-1,GetPosition(i));
            }
            positionCount--;
        }

        public void SetPosition(int index, Vector3 position)
        {
            lineRenderer.SetPosition(index,position);
        }

        public void SetPositions(Vector3[] positions)
        {
            lineRenderer.SetPositions(positions);
        }

        public Vector3 GetPosition(int index)
        {
            return lineRenderer.GetPosition(index);
        }

        public Vector3[] GetPositions()
        {
            Vector3[] points=new Vector3[lineRenderer.positionCount];
            lineRenderer.GetPositions(points);
            return points;
        }

        public void Clear()
        {
            if (lineRenderer == null) return;
            positionCount = 0;
        }

        void ILine.Dispose()
        {
            Clear();
            LineRendererPool.EnQueue(lineRenderer);
            lineRenderer = null;
            lineManager = null;
        }
    }
}

Gerente de linha:

using System.Collections.Generic;
using UnityEngine;

namespace S
{
    public class LineManager : MonoBehaviour,ILineManager
    {
        private static LineManager _instance;

        public static LineManager instance
        {
            get
            {
                if (_instance==null)
                {
                    _instance = FindObjectOfType<LineManager>();
                    if (_instance==null)
                    {
                        _instance=new GameObject("LineManager").AddComponent<LineManager>();
                        DontDestroyOnLoad(_instance.gameObject);
                    }
                }
                return _instance;
            }
        }

        public int lineCount => lines.Count;
        private List<ILine> lines= new List<ILine>();
        
        public T CreateLine<T>()where T:ILine,new()
        {
            T line = new T();
            line.Init(this);
            lines.Add(line);
            return line;
        }

        public bool HasLine(ILine line)
        {
            if (line==null||lineCount == 0) return false;
            return lines.Contains(line);
        }

        public void DeleteLine(ILine line)
        {
            if (!HasLine(line)) return;
            lines.Remove(line);
            line.Dispose();
        }

        public void DeleteLines(ILine[] lines)
        {
            int Count = lines == null ? 0 : lines.Length;
            if (Count == 0) return;
            for (int i = 0; i < Count; i++)
            {
                DeleteLine(lines[i]);
            }
        }

        public void DeleteLines(List<ILine> lines)
        {
            int Count = lines == null ? 0 : lines.Count;
            if (Count == 0) return;
            for (int i = 0; i < Count; i++)
            {
                DeleteLine(lines[i]);
            }
        }

        public void DeleteAll()
        {
            DeleteLines(lines);
        }
    }
}

Ah, a propósito, a reciclagem do Line recicla apenas o LineRenderer. Eu criei um pool de objetos simples LineRendererPool para o LineRenderer. Você quer perguntar
por que recicla o LineRenderer em vez de reciclar o Line? Porque temo que alguns fofos ainda retenham a referência à reciclagem Linha após Linha e depois usem essa referência reciclada para fazer algumas operações porque não sei, o que pode afetar a nova Linha criada através do pool de objetos. estou preocupado. ah. . .

Não, não posso te dizer como usá-lo. Tudo bem. Deixe-me escrever sobre como criar uma linha! ! !
Olhe com atenção, é uma grande jogada. . . . . . . . . . . .
Linha linha = LineManager.instance.CreateLine<Line>();
Concluído.

Acho que você gosta

Origin blog.csdn.net/weixin_42498461/article/details/130644382
Recomendado
Clasificación