Unity实战之一个脚本实现雷达图

简介: Unity实战实现雷达图

前言

最近又接触到一个新名词——“雷达图”。还是第一次接触这个名词。所谓雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方法。轴的相对位置和角度通常是无信息的。 雷达图也称为网络图,蜘蛛图,星图,蜘蛛网图,不规则多边形,极坐标图或Kiviat图。它相当于平行坐标图,轴径向排列。
度娘一顿解释,听得脑子嗡嗡的,赶紧打开示意图一看,我草,原来是这玩意儿~
在这里插入图片描述

雷达图的重要性

在游戏中,一些游戏属性直接用文字展示的话,看上去不直观,以图片的方式展示会更加的形象。但是呢,这个图因人而异,
所以直接使用Image来代替会造成很多不必要的麻烦,并且,图片多了之后对内存的消耗也是可想而知。通常,这类属性图采用雷达图来实现

雷达图构成

那么,雷达图是由什么构成的呢?简单来说,雷达图是由顶点和边构成的多边形平面。所以,制作一个雷达图,我们首先要知道这个雷达图有几个顶点,在知道顶点数之后,我们由封闭图形的构成原理知道,边数+1 = 顶点数

C#代码

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

/// <summary>
/// UI多边形
/// </summary>
public class UIPolygon : MaskableGraphic
{
    [SerializeField]
    Texture m_Texture;
    /// <summary>
    /// 填充
    /// </summary>
    public bool fill = true;

    /// <summary>
    /// 边数
    /// </summary>
    [Range(3, 360)]
    public int sides = 3;
    /// <summary>
    /// 旋转角度
    /// </summary>
    [Range(0, 360)]
    public float rotation = 0;
    /// <summary>
    /// 顶点数组
    /// </summary>
    [Range(0, 1)]
    public float[] VerticesDistances = new float[3];

    private float size = 0;

    public override Texture mainTexture
    {
        get
        {
            return m_Texture == null ? s_WhiteTexture : m_Texture;
        }
    }

    public Texture texture
    {
        get
        {
            return m_Texture;
        }
        set
        {
            if (m_Texture == value) return;
            m_Texture = value;
            SetVerticesDirty();
            SetMaterialDirty();
        }
    }
    #region 提供外部的接口
    public void DrawPolygon(int _sides)
    {
        sides = _sides;
        VerticesDistances = new float[_sides + 1];
        for (int i = 0; i < _sides; i++) VerticesDistances[i] = 1;
    }

    public void DrawPolygonNew()
    {
         List<float> datas = new List<float>();

        for (int i = 0; i < VerticesDistances.Length; i++) 
        {
            datas.Add(VerticesDistances[i]);
        }
        
        DrawPolygon(datas);
    }

    public void DrawPolygon(List<float> datas)
    {
        List<float> finalDatas = new List<float>(datas);
        sides = finalDatas.Count;
        // 加上最后一个点,最后一个点与第一个点重合
        finalDatas.Add(finalDatas[0]);
        VerticesDistances = finalDatas.ToArray();
        // 触发重绘
        SetVerticesDirty();
    }
    #endregion

    public void SetDirty()
    {
        SetVerticesDirty();
    }

    void Update()
    {
        // 根据宽高适配尺寸
        size = rectTransform.rect.width;
        if (rectTransform.rect.width > rectTransform.rect.height)
            size = rectTransform.rect.height;
        else
            size = rectTransform.rect.width;
    }

    protected UIVertex[] SetVertexs(Vector2[] vertices, Vector2[] uvs)
    {
        UIVertex[] vbo = new UIVertex[4];
        for (int i = 0; i < vertices.Length; i++)
        {
            var vert = UIVertex.simpleVert;
            vert.color = color;
            vert.position = vertices[i];
            vert.uv0 = uvs[i];
            vbo[i] = vert;
        }
        return vbo;
    }

    /// <summary>
    /// 重写OnPopulateMesh方法
    /// </summary>
    /// <param name="vh"></param>
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        Vector2 prevX = Vector2.zero;
        Vector2 prevY = Vector2.zero;
        Vector2 uv0 = new Vector2(0, 0);
        Vector2 uv1 = new Vector2(0, 1);
        Vector2 uv2 = new Vector2(1, 1);
        Vector2 uv3 = new Vector2(1, 0);
        Vector2 pos0;
        Vector2 pos1;
        Vector2 pos2;
        Vector2 pos3;
        float degrees = 360f / sides;
        int vertices = sides + 1;
        if (VerticesDistances.Length != vertices)
        {
            VerticesDistances = new float[vertices];
            for (int i = 0; i < vertices - 1; i++) VerticesDistances[i] = 1;
        }
        // 最后一个顶点,也即是第一个顶点
        VerticesDistances[vertices - 1] = VerticesDistances[0];
        for (int i = 0; i < vertices; i++)
        {
            float outer = -rectTransform.pivot.x * size * VerticesDistances[i];
            float inner = -rectTransform.pivot.x * size * VerticesDistances[i];
            float rad = Mathf.Deg2Rad * (i * degrees + rotation);
            float c = Mathf.Cos(rad);
            float s = Mathf.Sin(rad);
            uv0 = new Vector2(0, 1);
            uv1 = new Vector2(1, 1);
            uv2 = new Vector2(1, 0);
            uv3 = new Vector2(0, 0);
            pos0 = prevX;
            pos1 = new Vector2(outer * c, outer * s);
            if (fill)
            {
                pos2 = Vector2.zero;
                pos3 = Vector2.zero;
            }
            else
            {
                pos2 = new Vector2(inner * c, inner * s);
                pos3 = prevY;
            }
            prevX = pos1;
            prevY = pos2;
            vh.AddUIVertexQuad(SetVertexs(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
        }
    }
}

UI界面

1.创建一个Image对象,最为雷达图的背景
在这里插入图片描述
2.假设雷达图当前有3个,创建3个Text,用于文本标记属性展示。
在这里插入图片描述
3.创建一个游戏对象,并挂载
UIPolygon.cs脚本。在这里插入图片描述

UIPolygon组件属性介绍在这里插入图片描述

Slider:多边形边数
VerticesDistances:顶点数组,后面数字代表数组大小,即顶点数
下方的Element代表每个顶点的比值,即属性百分比
。前面介绍到,边数与顶点的关系:边数+1 = 顶点数,即边数决定顶点数,当我们手动改变边数时,顶点数会随之改变,如下图:
在这里插入图片描述

代码

local att = {90,10,80}---测试数据,分别代表逃生,对抗,躲避
for i=1,3 do
    ui.polygon.VerticesDistances[i-1] = att[i] / 100
end
base.coroutine = coroutine.start(function()
    coroutine.wait(0.05)
    ui.polygon:SetVerticesDirty()
end)

在这里插入图片描述
请添加图片描述

相关文章
|
6月前
|
图形学
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
147 0
|
3月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
204 3
|
4月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
94 1
|
3月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
264 0
|
4月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
142 0
|
4月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
110 0
|
4月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
92 0
|
6月前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
181 2
|
6月前
|
人工智能 定位技术 图形学
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
162 1
|
6月前
|
安全 图形学
【unity实战】事件(Event)的基本实战使用
【unity实战】事件(Event)的基本实战使用
216 1