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

发表于2017-05-07
评论1 3k浏览

很多游戏在创建角色之初可以看到该职业的一个属性值,这个功能在unity开发过程中是如何去实现的呢,也就是本篇文章要和大家介绍的在选/创建角色界面中实现职业能力图六角形的三个方法,


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

 

 

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

      

 http://blog.csdn.NET/u010019717/

 

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

[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2.   
  3. using System.Collections;  
  4.   
  5.    
  6.   
  7. public class MeshTest : MonoBehaviour {  
  8.   
  9.    
  10.   
  11.     privateMeshFilter m_MeshFilter;  
  12.   
  13.    
  14.   
  15.     void Start() {  
  16.   
  17.         Meshmesh = new Mesh();  
  18.   
  19.    
  20.   
  21.        mesh.vertices = new Vector3[] {  
  22.   
  23.            new Vector3(0, 0, 0),       // 顶点:0  
  24.   
  25.            new Vector3(1, 0, 0),       // 顶点:1  
  26.   
  27.            new Vector3(1.5f, 1, 0),    // 顶点:2  
  28.   
  29.            new Vector3(0.6f, 1.5f, 0), // 顶点:3  
  30.   
  31.            new Vector3(-0.8f, 1, 0),    //顶点:4  
  32.   
  33.         };  
  34.   
  35.    
  36.   
  37.         //遵循顺时针三顶点确定一面  
  38.   
  39.        mesh.triangles = new int[] {  
  40.   
  41.            0, 2, 1, // 面:0, 2, 1  
  42.   
  43.            0, 4, 2, // 面:0, 4, 2  
  44.   
  45.            4, 3, 2, // 面:4, 3, 2  
  46.   
  47.         };  
  48.   
  49.    
  50.   
  51.    
  52.   
  53.        m_MeshFilter = GetComponent();  
  54.   
  55.        m_MeshFilter.mesh = mesh;  
  56.   
  57.     }  
  58.   
  59. }  

 

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

 

 

这个功能肯定是 放在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()   这个方法,其实跟刷新差不多。

 

直接上代码:

[csharp] view plain copy
 print?
  1. /// CreditCiaccoDavide  
  2.   
  3. /// Sourced from - http://ciaccodavi.de/unity/UIPolygon  
  4.   
  5.    
  6.   
  7. namespace UnityEngine.UI.Extensions  
  8.   
  9. {  
  10.   
  11.    [AddComponentMenu("UI/Extensions/Primitives/UI Polygon")]  
  12.   
  13.    public class UIPolygon : UIPrimitiveBase  
  14.   
  15.    {  
  16.   
  17.         public bool fill = true;  
  18.   
  19.         public float thickness = 5;  
  20.   
  21.         [Range(3, 360)]  
  22.   
  23.         public int sides = 3;  
  24.   
  25.         [Range(0, 360)]  
  26.   
  27.         public float rotation = 0;  
  28.   
  29.         [Range(0, 1)]  
  30.   
  31.         public float[] VerticesDistances = newfloat[3];  
  32.   
  33.         private float size = 0;  
  34.   
  35.    
  36.   
  37.         public void DrawPolygon(int _sides)  
  38.   
  39.         {  
  40.   
  41.             sides = _sides;  
  42.   
  43.             VerticesDistances = newfloat[_sides + 1];  
  44.   
  45.             for (int i = 0; i < _sides; i++)VerticesDistances[i] = 1; ;  
  46.   
  47.             rotation = 0;  
  48.   
  49.         }  
  50.   
  51.         public void DrawPolygon(int _sides,float[] _VerticesDistances)  
  52.   
  53.         {  
  54.   
  55.             sides = _sides;  
  56.   
  57.             VerticesDistances =_VerticesDistances;  
  58.   
  59.             rotation = 0;  
  60.   
  61.         }  
  62.   
  63.         public void DrawPolygon(int _sides,float[] _VerticesDistances, float _rotation)  
  64.   
  65.         {  
  66.   
  67.             sides = _sides;  
  68.   
  69.             VerticesDistances =_VerticesDistances;  
  70.   
  71.             rotation = _rotation;  
  72.   
  73.         }  
  74.   
  75.         void Update()  
  76.   
  77.         {  
  78.   
  79.             size = rectTransform.rect.width;  
  80.   
  81.             if (rectTransform.rect.width >rectTransform.rect.height)  
  82.   
  83.                 size =rectTransform.rect.height;  
  84.   
  85.             else  
  86.   
  87.                 size =rectTransform.rect.width;  
  88.   
  89.             thickness =(float)Mathf.Clamp(thickness, 0, size / 2);  
  90.   
  91.         }  
  92.   
  93.    
  94.   
  95.         protected override voidOnPopulateMesh(VertexHelper vh)  
  96.   
  97.         {  
  98.   
  99.             vh.Clear();  
  100.   
  101.    
  102.   
  103.             Vector2 prevX = Vector2.zero;  
  104.   
  105.             Vector2 prevY = Vector2.zero;  
  106.   
  107.             Vector2 uv0 = new Vector2(0, 0);  
  108.   
  109.             Vector2 uv1 = new Vector2(0, 1);  
  110.   
  111.             Vector2 uv2 = new Vector2(1, 1);  
  112.   
  113.             Vector2 uv3 = new Vector2(1, 0);  
  114.   
  115.             Vector2 pos0;  
  116.   
  117.             Vector2 pos1;  
  118.   
  119.             Vector2 pos2;  
  120.   
  121.             Vector2 pos3;  
  122.   
  123.             float degrees = 360f / sides;  
  124.   
  125.             int vertices = sides + 1;  
  126.   
  127.             if (VerticesDistances.Length !=vertices)  
  128.   
  129.             {  
  130.   
  131.                 VerticesDistances = newfloat[vertices];  
  132.   
  133.                 for (int i = 0; i < vertices- 1; i++) VerticesDistances[i] = 1;  
  134.   
  135.             }  
  136.   
  137.             // last vertex is also the first!  
  138.   
  139.             VerticesDistances[vertices - 1] =VerticesDistances[0];  
  140.   
  141.             for (int i = 0; i < vertices;i++)  
  142.   
  143.             {  
  144.   
  145.                 float outer =-rectTransform.pivot.x * size * VerticesDistances[i];  
  146.   
  147.                 float inner =-rectTransform.pivot.x * size * VerticesDistances[i] + thickness;  
  148.   
  149.                 float rad = Mathf.Deg2Rad * (i* degrees + rotation);  
  150.   
  151.                 float c = Mathf.Cos(rad);  
  152.   
  153.                 float s = Mathf.Sin(rad);  
  154.   
  155.                 uv0 = new Vector2(0, 1);  
  156.   
  157.                 uv1 = new Vector2(1, 1);  
  158.   
  159.                 uv2 = new Vector2(1, 0);  
  160.   
  161.                 uv3 = new Vector2(0, 0);  
  162.   
  163.                 pos0 = prevX;  
  164.   
  165.                 pos1 = new Vector2(outer * c,outer * s);  
  166.   
  167.                 if (fill)  
  168.   
  169.                 {  
  170.   
  171.                     pos2 = Vector2.zero;  
  172.   
  173.                     pos3 = Vector2.zero;  
  174.   
  175.                 }  
  176.   
  177.                 else  
  178.   
  179.                 {  
  180.   
  181.                     pos2 = new Vector2(inner *c, inner * s);  
  182.   
  183.                     pos3 = prevY;  
  184.   
  185.                 }  
  186.   
  187.                 prevX = pos1;  
  188.   
  189.                 prevY = pos2;  
  190.   
  191.                 vh.AddUIVertexQuad(SetVbo(new[]{ pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));  
  192.   
  193.             }  
  194.   
  195.         }  
  196.   
  197.    }  
  198.   
  199. }  

 

它继承自封装的基类:

[csharp] view plain copy
 print?
  1. using System;  
  2.   
  3.    
  4.   
  5. namespaceUnityEngine.UI.Extensions  
  6.   
  7. {  
  8.   
  9.     public class UIPrimitiveBase :MaskableGraphic, ILayoutElement, ICanvasRaycastFilter  
  10.   
  11.     {  
  12.   
  13.    
  14.   
  15.         [SerializeField]  
  16.   
  17.         private Sprite m_Sprite;  
  18.   
  19.         public Sprite sprite { get { returnm_Sprite; } set { if (SetPropertyUtility.SetClass(ref m_Sprite, value))SetAllDirty(); } }  
  20.   
  21.    
  22.   
  23.         [NonSerialized]  
  24.   
  25.         private Sprite m_OverrideSprite;  
  26.   
  27.         public Sprite overrideSprite { get {return m_OverrideSprite == null ? sprite : m_OverrideSprite; } set { if(SetPropertyUtility.SetClass(ref m_OverrideSprite, value)) SetAllDirty(); } }  
  28.   
  29.    
  30.   
  31.         // Not serialized until we supportread-enabled sprites better.  
  32.   
  33.         internal float m_EventAlphaThreshold =1;  
  34.   
  35.         public float eventAlphaThreshold { getreturn m_EventAlphaThreshold; } set { m_EventAlphaThreshold = value; } }  
  36.   
  37.    
  38.   
  39.    
  40.   
  41.    
  42.   
  43.         ///   
  44.   
  45.         /// Image's texture comes from theUnityEngine.Image.  
  46.   
  47.         ///   
  48.   
  49.         public override Texture mainTexture  
  50.   
  51.         {  
  52.   
  53.             get  
  54.   
  55.             {  
  56.   
  57.                 if (overrideSprite == null)  
  58.   
  59.                 {  
  60.   
  61.                     if (material != null&& material.mainTexture != null)  
  62.   
  63.                     {  
  64.   
  65.                         returnmaterial.mainTexture;  
  66.   
  67.                     }  
  68.   
  69.                     return s_WhiteTexture;  
  70.   
  71.                 }  
  72.   
  73.    
  74.   
  75.                 return overrideSprite.texture;  
  76.   
  77.             }  
  78.   
  79.         }  
  80.   
  81.    
  82.   
  83.         public float pixelsPerUnit  
  84.   
  85.         {  
  86.   
  87.             get  
  88.   
  89.             {  
  90.   
  91.                 float spritePixelsPerUnit =100;  
  92.   
  93.                 if (sprite)  
  94.   
  95.                     spritePixelsPerUnit =sprite.pixelsPerUnit;  
  96.   
  97.    
  98.   
  99.                 float referencePixelsPerUnit =100;  
  100.   
  101.                 if (canvas)  
  102.   
  103.                     referencePixelsPerUnit =canvas.referencePixelsPerUnit;  
  104.   
  105.    
  106.   
  107.                 return spritePixelsPerUnit /referencePixelsPerUnit;  
  108.   
  109.             }  
  110.   
  111.         }  
  112.   
  113.    
  114.   
  115.    
  116.   
  117.         protected UIVertex[] SetVbo(Vector2[]vertices, Vector2[] uvs)  
  118.   
  119.         {  
  120.   
  121.             UIVertex[] vbo = new UIVertex[4];  
  122.   
  123.             for (int i = 0; i   < span="">
  124.   
  125.             {  
  126.   
  127.                 var vert = UIVertex.simpleVert;  
  128.   
  129.                 vert.color = color;  
  130.   
  131.                 vert.position = vertices[i];  
  132.   
  133.                 vert.uv0 = uvs[i];  
  134.   
  135.                 vbo[i] = vert;  
  136.   
  137.             }  
  138.   
  139.             return vbo;  
  140.   
  141.         }  
  142.  
  143.   
  144.  
  145.   
  146.  
  147.         #region ILayoutElement Interface  
  148.   
  149.    
  150.   
  151.         public virtual voidCalculateLayoutInputHorizontal() { }  
  152.   
  153.         public virtual voidCalculateLayoutInputVertical() { }  
  154.   
  155.    
  156.   
  157.         public virtual float minWidth { get {return 0; } }  
  158.   
  159.    
  160.   
  161.         public virtual float preferredWidth  
  162.   
  163.         {  
  164.   
  165.             get  
  166.   
  167.             {  
  168.   
  169.                 if (overrideSprite == null)  
  170.   
  171.                     return 0;  
  172.   
  173.                 returnoverrideSprite.rect.size.x / pixelsPerUnit;  
  174.   
  175.             }  
  176.   
  177.         }  
  178.   
  179.    
  180.   
  181.         public virtual float flexibleWidth {get { return -1; } }  
  182.   
  183.    
  184.   
  185.         public virtual float minHeight { get {return 0; } }  
  186.   
  187.    
  188.   
  189.         public virtual float preferredHeight  
  190.   
  191.         {  
  192.   
  193.             get  
  194.   
  195.             {  
  196.   
  197.                 if (overrideSprite == null)  
  198.   
  199.                     return 0;  
  200.   
  201.                 returnoverrideSprite.rect.size.y / pixelsPerUnit;  
  202.   
  203.             }  
  204.   
  205.         }  
  206.   
  207.    
  208.   
  209.         public virtual float flexibleHeight {get { return -1; } }  
  210.   
  211.    
  212.   
  213.         public virtual int layoutPriority { getreturn 0; } }  
  214.  
  215.   
  216.  
  217.         #endregion  
  218.  
  219.   
  220.  
  221.         #region ICanvasRaycastFilter Interface  
  222.   
  223.         public virtual boolIsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)  
  224.   
  225.         {  
  226.   
  227.             if (m_EventAlphaThreshold >= 1)  
  228.   
  229.                 return true;  
  230.   
  231.    
  232.   
  233.             Sprite sprite = overrideSprite;  
  234.   
  235.             if (sprite == null)  
  236.   
  237.                 return true;  
  238.   
  239.    
  240.   
  241.             Vector2 local;  
  242.   
  243.            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,screenPoint, eventCamera, out local);  
  244.   
  245.    
  246.   
  247.             Rect rect = GetPixelAdjustedRect();  
  248.   
  249.    
  250.   
  251.             // Convert to have lower leftcorner as reference point.  
  252.   
  253.             local.x += rectTransform.pivot.x *rect.width;  
  254.   
  255.             local.y += rectTransform.pivot.y *rect.height;  
  256.   
  257.    
  258.   
  259.             local = MapCoordinate(local, rect);  
  260.   
  261.    
  262.   
  263.             // Normalize local coordinates.  
  264.   
  265.             Rect spriteRect =sprite.textureRect;  
  266.   
  267.             Vector2 normalized = newVector2(local.x / spriteRect.width, local.y / spriteRect.height);  
  268.   
  269.    
  270.   
  271.             // Convert to texture space.  
  272.   
  273.             float x = Mathf.Lerp(spriteRect.x,spriteRect.xMax, normalized.x) / sprite.texture.width;  
  274.   
  275.             float y = Mathf.Lerp(spriteRect.y,spriteRect.yMax, normalized.y) / sprite.texture.height;  
  276.   
  277.    
  278.   
  279.             try  
  280.   
  281.             {  
  282.   
  283.                 returnsprite.texture.GetPixelBilinear(x, y).a >= m_EventAlphaThreshold;  
  284.   
  285.             }  
  286.   
  287.             catch (UnityException e)  
  288.   
  289.             {  
  290.   
  291.                 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);  
  292.   
  293.                 return true;  
  294.   
  295.             }  
  296.   
  297.         }  
  298.   
  299.    
  300.   
  301.         ///   
  302.   
  303.         /// Return image adjusted position  
  304.   
  305.         /// **Copied from Unity's Imagecomponent for now and simplified for UI Extensions primatives  
  306.   
  307.         ///   
  308.   
  309.         ///   
  310.   
  311.         ///   
  312.   
  313.         ///   
  314.   
  315.         private Vector2 MapCoordinate(Vector2local, Rect rect)  
  316.   
  317.         {  
  318.   
  319.             Rect spriteRect = sprite.rect;  
  320.   
  321.                 return new Vector2(local.x *spriteRect.width / rect.width, local.y * spriteRect.height / rect.height);  
  322.   
  323.         }  
  324.   
  325.    
  326.   
  327.         Vector4 GetAdjustedBorders(Vector4border, Rect rect)  
  328.   
  329.         {  
  330.   
  331.             for (int axis = 0; axis <= 1;axis++)  
  332.   
  333.             {  
  334.   
  335.                 float combinedBorders =border[axis] + border[axis + 2];  
  336.   
  337.                 if (rect.size[axis]   < span="">
  338.   
  339.                 {  
  340.   
  341.                     float borderScaleRatio =rect.size[axis] / combinedBorders;  
  342.   
  343.                     border[axis] *=borderScaleRatio;  
  344.   
  345.                     border[axis + 2] *=borderScaleRatio;  
  346.   
  347.                 }  
  348.   
  349.             }  
  350.   
  351.             return border;  
  352.   
  353.         }  
  354.  
  355.   
  356.  
  357.         #endregion  
  358.   
  359.    
  360.   
  361.    
  362.   
  363.     }  
  364.   
  365. }  

 

 

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

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

 

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

 

 

 

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

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

 

[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2.   
  3. using UnityEngine.UI;  
  4.   
  5. using System.Collections.Generic;  
  6.   
  7.    
  8.   
  9.    
  10.   
  11. [ExecuteInEditMode]  
  12.   
  13. public class SimpleImage : Graphic   
  14.   
  15. {  
  16.   
  17.    
  18.   
  19. protected override voidOnFillVBO (List vbo)  
  20.   
  21. {  
  22.   
  23. Vector2 corner1 =Vector2.zero;  
  24.   
  25. Vector2 corner2 =Vector2.zero;  
  26.   
  27.    
  28.   
  29. corner1.x = 0f;  
  30.   
  31. corner1.y = 0f;  
  32.   
  33. corner2.x = 1f;  
  34.   
  35. corner2.y = 1f;  
  36.   
  37.    
  38.   
  39. corner1.x -=rectTransform.pivot.x;  
  40.   
  41. corner1.y -=rectTransform.pivot.y;  
  42.   
  43. corner2.x -=rectTransform.pivot.x;  
  44.   
  45. corner2.y -=rectTransform.pivot.y;  
  46.   
  47.    
  48.   
  49. corner1.x *=rectTransform.rect.width;  
  50.   
  51. corner1.y *=rectTransform.rect.height;  
  52.   
  53. corner2.x *=rectTransform.rect.width;  
  54.   
  55. corner2.y *=rectTransform.rect.height;  
  56.   
  57.    
  58.   
  59. vbo.Clear();  
  60.   
  61.    
  62.   
  63. UIVertex vert =UIVertex.simpleVert;  
  64.   
  65.    
  66.   
  67. vert.position = newVector2(corner1.x, corner1.y);  
  68.   
  69. vert.color = color;  
  70.   
  71. vbo.Add(vert);  
  72.   
  73.    
  74.   
  75. vert.position = newVector2(corner1.x, corner2.y);  
  76.   
  77. vert.color = color;  
  78.   
  79. vbo.Add(vert);  
  80.   
  81.    
  82.   
  83. vert.position = newVector2(corner2.x, corner2.y);  
  84.   
  85. vert.color = color;  
  86.   
  87. vbo.Add(vert);  
  88.   
  89.    
  90.   
  91. vert.position = newVector2(corner2.x, corner1.y);  
  92.   
  93. vert.color = color;  
  94.   
  95. vbo.Add(vert);  
  96.   
  97. }  
  98.   
  99. }  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论