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

2017-01-13 10:50:42来源:csdn作者:u010019717人点击

第七城市

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;elsesize =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 Interfacepublic 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/


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台