Unity游戏选/创建角色界面中 职业能力图六角形

Posted u010019717

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity游戏选/创建角色界面中 职业能力图六角形相关的知识,希望对你有一定的参考价值。

2016.8.22               孙广东

游戏选/创建角色界面中 职业能力图六角形

        主要说的是 UGUI 的实现方式!!!!!!

 

     下面这个六边形在很多游戏中都存在了(随便在网上找的, 一会就使用这个图片)。:

 

 

在  Asset Store 上搜索,  Chart  会得到相关的结果

     

 http://blog.csdn.net/u010019717/

 

先使用最简单的方式绘制Mesh多边形。

using UnityEngine;

using System.Collections;

 

public class MeshTest : MonoBehaviour 

 

    privateMeshFilter m_MeshFilter;

 

    void Start() 

        Meshmesh = new Mesh();

 

       mesh.vertices = new Vector3[] 

           new Vector3(0, 0, 0),       // 顶点:0

           new Vector3(1, 0, 0),       // 顶点:1

           new Vector3(1.5f, 1, 0),    // 顶点:2

           new Vector3(0.6f, 1.5f, 0), // 顶点:3

           new Vector3(-0.8f, 1, 0),    //顶点:4

        ;

 

        //遵循顺时针三顶点确定一面

       mesh.triangles = new int[] 

           0, 2, 1, // 面:0, 2, 1

           0, 4, 2, // 面:0, 4, 2

           4, 3, 2, // 面:4, 3, 2

        ;

 

 

       m_MeshFilter = GetComponent<MeshFilter>();

       m_MeshFilter.mesh = mesh;

    



 

顶点和三角面 就组成这个多边形。 

 

 

这个功能肯定是 放在UI上,  对 UGUI

           首先大概介绍下uGUI的体系结构。在uGUI中,所有的UI组件都要放置在Canvas组件下,由Canvas来管理它的渲染和自适应屏幕等。uGUI提供了Graphic基类,运行时,Canvas会使用CanvasRenderer来渲染它的子级中全部的Graphic组件。所以,如果要自定义外观的控件,从Graphic继承是一个不错的选择。

 

 

        我们都知道,在unity中3d物体最终是转化成若干网格数据来渲染的,其实ui的渲染也是一样的方法(注意 是Unity5.3之后UGUI才引入  Mesh这个东东)。比如一个Image组件,内部其实是使用4个顶点构成的2个三角形网格外加一个Texture贴图来渲染的。那么要改变控件的外形,只要改变网格数据就可以了,对,就是这么个思路。

 

 

Graphic提供了一个虚方法

           protected virtual void OnPopulateMesh(VertexHelper vh);

 

           通过重写这个方法,即可修改或重新生成控件的网格数据,从而达到自定义控件显示外观的需求(Unity4为另一个接口OnFillVBO,不过原理是一致的)。而VertexHelper是unity提供的简化网格操作的辅助类,它提供的接口也很简单,诸如添加顶点、添加三角形、添加Quad等。

 

             需要注意的一点是,顶点的坐标是由控件的位置、大小和锚点等决定的,计算时需要综合考虑这些因素。

 http://blog.csdn.net/u010019717/

 

看 UGUI的源代码 :

               说的是当该控件(例如Text,Image,RawImage)需要改变顶点的时候,就会自动调用  OnPopulateMesh

            不过该函数是只有在该Craphic组件需要修改的时候才会调用,比如你修改Image的大小,或者它加载的时候才会调用。

          这样就导致我们没法及时在编辑器状态下看到我们对mesh的修改,  比如用是将一张Image的四个角分别用四个对象表示,这四个对象的移动,会让这种Image发生形变。但是没法及时更新就没办法了。

还好有   SetNativeSize()   这个方法,其实跟刷新差不多。

 

直接上代码:

/// CreditCiaccoDavide

/// Sourced from - http://ciaccodavi.de/unity/UIPolygon

 

namespace UnityEngine.UI.Extensions



   [AddComponentMenu("UI/Extensions/Primitives/UI Polygon")]

   public class UIPolygon : UIPrimitiveBase

   

        public bool fill = true;

        public float thickness = 5;

        [Range(3, 360)]

        public int sides = 3;

        [Range(0, 360)]

        public float rotation = 0;

        [Range(0, 1)]

        public float[] VerticesDistances = newfloat[3];

        private float size = 0;

 

        public void DrawPolygon(int _sides)

        

            sides = _sides;

            VerticesDistances = newfloat[_sides + 1];

            for (int i = 0; i < _sides; i++)VerticesDistances[i] = 1; ;

            rotation = 0;

        

        public void DrawPolygon(int _sides,float[] _VerticesDistances)

        

            sides = _sides;

            VerticesDistances =_VerticesDistances;

            rotation = 0;

        

        public void DrawPolygon(int _sides,float[] _VerticesDistances, float _rotation)

        

            sides = _sides;

            VerticesDistances =_VerticesDistances;

            rotation = _rotation;

        

        void Update()

        

            size = rectTransform.rect.width;

            if (rectTransform.rect.width >rectTransform.rect.height)

                size =rectTransform.rect.height;

            else

                size =rectTransform.rect.width;

            thickness =(float)Mathf.Clamp(thickness, 0, size / 2);

        

 

        protected override voidOnPopulateMesh(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 = newfloat[vertices];

                for (int i = 0; i < vertices- 1; i++) VerticesDistances[i] = 1;

            

            // last vertex is also the first!

            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] + thickness;

                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(SetVbo(new[] pos0, pos1, pos2, pos3 , new[]  uv0, uv1, uv2, uv3 ));

            

        

   



 

它继承自封装的基类:

using System;

 

namespaceUnityEngine.UI.Extensions



    public class UIPrimitiveBase :MaskableGraphic, ILayoutElement, ICanvasRaycastFilter

    

 

        [SerializeField]

        private Sprite m_Sprite;

        public Sprite sprite  get  returnm_Sprite;  set  if (SetPropertyUtility.SetClass(ref m_Sprite, value))SetAllDirty();  

 

        [NonSerialized]

        private Sprite m_OverrideSprite;

        public Sprite overrideSprite  get return m_OverrideSprite == null ? sprite : m_OverrideSprite;  set  if(SetPropertyUtility.SetClass(ref m_OverrideSprite, value)) SetAllDirty();  

 

        // Not serialized until we supportread-enabled sprites better.

        internal float m_EventAlphaThreshold =1;

        public float eventAlphaThreshold  get return m_EventAlphaThreshold;  set  m_EventAlphaThreshold = value;  

 

 

 

        /// <summary>

        /// Image's texture comes from theUnityEngine.Image.

        /// </summary>

        public override Texture mainTexture

        

            get

            

                if (overrideSprite == null)

                

                    if (material != null&& material.mainTexture != null)

                    

                        returnmaterial.mainTexture;

                    

                    return s_WhiteTexture;

                

 

                return overrideSprite.texture;

            

        

 

        public float pixelsPerUnit

        

            get

            

                float spritePixelsPerUnit =100;

                if (sprite)

                    spritePixelsPerUnit =sprite.pixelsPerUnit;

 

                float referencePixelsPerUnit =100;

                if (canvas)

                    referencePixelsPerUnit =canvas.referencePixelsPerUnit;

 

                return spritePixelsPerUnit /referencePixelsPerUnit;

            

        

 

 

        protected UIVertex[] SetVbo(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;

        

 

 

        #region ILayoutElement Interface

 

        public virtual voidCalculateLayoutInputHorizontal()  

        public virtual voidCalculateLayoutInputVertical()  

 

        public virtual float minWidth  get return 0;  

 

        public virtual float preferredWidth

        

            get

            

                if (overrideSprite == null)

                    return 0;

                returnoverrideSprite.rect.size.x / pixelsPerUnit;

            

        

 

        public virtual float flexibleWidth get  return -1;  

 

        public virtual float minHeight  get return 0;  

 

        public virtual float preferredHeight

        

            get

            

                if (overrideSprite == null)

                    return 0;

                returnoverrideSprite.rect.size.y / pixelsPerUnit;

            

        

 

        public virtual float flexibleHeight get  return -1;  

 

        public virtual int layoutPriority  get return 0;  

 

        #endregion

 

        #region ICanvasRaycastFilter Interface

        public virtual boolIsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)

        

            if (m_EventAlphaThreshold >= 1)

                return true;

 

            Sprite sprite = overrideSprite;

            if (sprite == null)

                return true;

 

            Vector2 local;

           RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,screenPoint, eventCamera, out local);

 

            Rect rect = GetPixelAdjustedRect();

 

            // Convert to have lower leftcorner as reference point.

            local.x += rectTransform.pivot.x *rect.width;

            local.y += rectTransform.pivot.y *rect.height;

 

            local = MapCoordinate(local, rect);

 

            // Normalize local coordinates.

            Rect spriteRect =sprite.textureRect;

            Vector2 normalized = newVector2(local.x / spriteRect.width, local.y / spriteRect.height);

 

            // Convert to texture space.

            float x = Mathf.Lerp(spriteRect.x,spriteRect.xMax, normalized.x) / sprite.texture.width;

            float y = Mathf.Lerp(spriteRect.y,spriteRect.yMax, normalized.y) / sprite.texture.height;

 

            try

            

                returnsprite.texture.GetPixelBilinear(x, y).a >= m_EventAlphaThreshold;

            

            catch (UnityException e)

            

                Debug.LogError("UsingclickAlphaThreshold lower than 1 on Image whose sprite texture cannot be read." + e.Message + " Also make sure to disable sprite packing for thissprite.", this);

                return true;

            

        

 

        /// <summary>

        /// Return image adjusted position

        /// **Copied from Unity's Imagecomponent for now and simplified for UI Extensions primatives

        /// </summary>

        /// <paramname="local"></param>

        /// <paramname="rect"></param>

        /// <returns></returns>

        private Vector2 MapCoordinate(Vector2local, Rect rect)

        

            Rect spriteRect = sprite.rect;

                return new Vector2(local.x *spriteRect.width / rect.width, local.y * spriteRect.height / rect.height);

        

 

        Vector4 GetAdjustedBorders(Vector4border, Rect rect)

        

            for (int axis = 0; axis <= 1;axis++)

            

                float combinedBorders =border[axis] + border[axis + 2];

                if (rect.size[axis] <combinedBorders && combinedBorders != 0)

                

                    float borderScaleRatio =rect.size[axis] / combinedBorders;

                    border[axis] *=borderScaleRatio;

                    border[axis + 2] *=borderScaleRatio;

                

            

            return border;

        

 

        #endregion

 

 

    



 

 

将脚本拖拽到  Canvas 下的一个空对象上。

            然后设置参数(六边形,随便着色、为了和背景图一直旋转了一下,然后就是六个值的设定)

 

效果就和一开始的截图一样了!

 

 

 

提到的  OnFillVBO  的实现方式(这个方法是 Unity5.3 之前的版本和 SetNativeSize一个原理

file:///D:/Program%20Files/Unity%205.2.0b4/Unity/Editor/Data/Documentation/en/ScriptReference/UI.Graphic.html

 

using UnityEngine;

using UnityEngine.UI;

using System.Collections.Generic;

 

 

[ExecuteInEditMode]

public class SimpleImage : Graphic 



 

protected override voidOnFillVBO (List<UIVertex> vbo)



Vector2 corner1 =Vector2.zero;

Vector2 corner2 =Vector2.zero;

 

corner1.x = 0f;

corner1.y = 0f;

corner2.x = 1f;

corner2.y = 1f;

 

corner1.x -=rectTransform.pivot.x;

corner1.y -=rectTransform.pivot.y;

corner2.x -=rectTransform.pivot.x;

corner2.y -=rectTransform.pivot.y;

 

corner1.x *=rectTransform.rect.width;

corner1.y *=rectTransform.rect.height;

corner2.x *=rectTransform.rect.width;

corner2.y *=rectTransform.rect.height;

 

vbo.Clear();

 

UIVertex vert =UIVertex.simpleVert;

 

vert.position = newVector2(corner1.x, corner1.y);

vert.color = color;

vbo.Add(vert);

 

vert.position = newVector2(corner1.x, corner2.y);

vert.color = color;

vbo.Add(vert);

 

vert.position = newVector2(corner2.x, corner2.y);

vert.color = color;

vbo.Add(vert);

 

vert.position = newVector2(corner2.x, corner1.y);

vert.color = color;

vbo.Add(vert);





 

 http://blog.csdn.net/u010019717/

http://blog.csdn.net/u010019717/

 








以上是关于Unity游戏选/创建角色界面中 职业能力图六角形的主要内容,如果未能解决你的问题,请参考以下文章

unity游戏启动如何调出

Unity2D游戏角色动画教程-使用Photoshop创建2D游戏角色素材

怎么把unity游戏界面加到c# 项目中

Unity3D_(游戏)卡牌03_选关界面

游戏开发教程BehaviorDesigner插件制作AI行为树(Unity | 保姆级教程 | 动态图演示 | Unity2021最新版)

游戏开发教程BehaviorDesigner插件制作AI行为树(Unity | 保姆级教程 | 动态图演示 | Unity2021最新版)