我们用一个Image控件,绘制多个动态图,效果如下
先说一下主要思路
我们创建一个Image控件会看到有个CanvasRenderer的组件,这个组件是负责渲染的。
首先我们准备一个图集
关于如何打图集,请参考我的上一篇文章
然后我们创建一个SpriteGraphicHelper.cs脚本这个脚本中主要有我们自定义的一个Mesh,我们将用这个mesh中的数据渲染图片,在自定义的Mesh中我们需要设置mesh.vertices顶点数据,是要在图片那些顶点上绘制,mesh.triangles顶点的三角形索引顺序,mesh.uv要绘制的图片在图集中的uv坐标。
然后我们创建一个脚本SpriteGraphic.cs继承自MaskableGraphic,MaskableGraphic方法中有UGUI具体绘制时的一些参数和方法,比如mainTexture属性是主纹理,这里我们设置为我们的图集.UGUI绘制时用到的Shader会总我们设置的mainTexture取值,然后我们调用MaskableGraphic中的UpdateMaterial刷新材质,一个图片就会支出来了。
我们想要绘制动态图片只需要在Update函数中把mesh.uv uv坐标改变即可,想要回执多个图片在mesh.vertices中传入多个顶点和每个顶点的uv值,然后给mesh.triangles顶点的三角形索引顺序赋值即可。
下面是具体的代码
首先是一个辅助类SpriteInfo.cs,用于存储每个小图片的一些信息
using UnityEngine;
using System.Collections;
public class SpriteInfo{
/// <summary>
/// 名称
/// </summary>
public string name;
/// <summary>
///坐标&宽高
/// </summary>
public Rect rect;
/// <summary>
/// 精灵
/// </summary>
public Sprite sprite;
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpriteGraphicHelper : MonoBehaviour {
// Use this for initialization
//图集
public Texture2D texture2D;
//单个小图的信息
public List<SpriteInfo> m_sprites = new List<SpriteInfo>();
//渲染器
private CanvasRenderer m_spriteCanvasRenderer;
//设置图片渲染的一些参数 比如主纹理 mainTexture
private SpriteGraphic m_spriteGraphic;
int index = 0;
float time = 0;
Rect rtRect;
void Awake() {
m_spriteCanvasRenderer = GetComponent<CanvasRenderer>();
m_spriteGraphic = GetComponent<SpriteGraphic>();
RectTransform rectTransform = GetComponent<RectTransform>();
rtRect = rectTransform.rect;
}
void Start () {
InitInfo();
}
// Update is called once per frame
void Update () {
time += Time.deltaTime;
if (time > 0.3f) {
if (index < m_sprites.Count)
{
DrawSprite(index);
index++;
}
else
{
index = 0;
DrawSprite(index);
}
time = 0;
}
}
void InitInfo() {
Object[] objs = Resources.LoadAll("Atlas");
for (int i = 0; i < objs.Length; i++) {
if(objs[i].GetType() == typeof(Texture2D)) {
texture2D = objs[i] as Texture2D;
}
else if (objs[i].GetType() == typeof(Sprite)) {
SpriteInfo info = new SpriteInfo();
Sprite sprite = objs[i] as Sprite;
info.name = sprite.name;
info.rect = sprite.rect;
info.sprite = sprite;
m_sprites.Add(info);
}
}
m_spriteGraphic.SetTexture(texture2D);
}
public void DrawSprite(int index) {
int imageWidth = 100;//图片宽度
int imageHeight = 100;//图片高度
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[8];
Vector2[] uv = new Vector2[8];
//设置第一个图片的uv值
SpriteInfo spriteInfo = m_sprites[index];
Rect rect = spriteInfo.rect;
uv[0] = new Vector2(rect.x /(float)texture2D.width, rect.y / (float)texture2D.height);
uv[1] = new Vector2(rect.x / (float)texture2D.width, (rect.y+rect.height) / (float)texture2D.height);
uv[2] = new Vector2((rect.x+rect.width) / (float)texture2D.width, (rect.y+rect.height) / (float)texture2D.height);
uv[3] = new Vector2((rect.x + rect.width) / (float)texture2D.width, rect.y / (float)texture2D.height);
//设置第一个图片的顶点
vertices[0] = new Vector3(rtRect.x, rtRect.y, 0);
vertices[1] = new Vector3(rtRect.x, rtRect.y + imageHeight, 0);
vertices[2] = new Vector3(rtRect.x + imageWidth, rtRect.y + imageHeight, 0);
vertices[3] = new Vector3(rtRect.x + imageWidth, rtRect.y, 0);
//设置第二个图片的uv值 这里为了和第一个图片显示的不同,选取了index的下一张图片
if (index < m_sprites.Count - 1)
{
spriteInfo = m_sprites[index + 1];
rect = spriteInfo.rect;
}
uv[4] = new Vector2(rect.x / (float)texture2D.width, rect.y / (float)texture2D.height);
uv[5] = new Vector2(rect.x / (float)texture2D.width, (rect.y + rect.height) / (float)texture2D.height);
uv[6] = new Vector2((rect.x + rect.width) / (float)texture2D.width, (rect.y + rect.height) / (float)texture2D.height);
uv[7] = new Vector2((rect.x + rect.width) / (float)texture2D.width, rect.y / (float)texture2D.height);
//设置第二个图片的顶点
Vector2 startPos = new Vector2(rtRect.x+imageWidth,rtRect.y);
vertices[4] = new Vector3(startPos.x, startPos.y, 0);
vertices[5] = new Vector3(startPos.x, startPos.y + imageHeight, 0);
vertices[6] = new Vector3(startPos.x + imageWidth, startPos.y + imageHeight, 0);
vertices[7] = new Vector3(startPos.x + imageWidth, startPos.y, 0);
//设置mesh
mesh.vertices = vertices;
mesh.uv = uv;
mesh.triangles = new int[] { 0, 1, 2, 2, 3, 0,4,5,6,6,7,4};
m_spriteCanvasRenderer.SetMesh(mesh);
//刷新材质
m_spriteGraphic.UpdateMaterial();
}
}
然后是SpriteGraphic.cs,用于设置UGUI绘制时用到的主纹理mainTexture和刷新材质用的
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
public class SpriteGraphic : MaskableGraphic
{
private Texture2D texture2D;
//主纹理
public override Texture mainTexture
{
get
{
if (texture2D == null)
return s_WhiteTexture;
else
return texture2D;
}
}
//设置纹理
public void SetTexture(Texture2D texture) {
texture2D = texture;
}
/// <summary>
/// 更新材质
/// </summary>
public new void UpdateMaterial()
{
base.UpdateMaterial();
}
protected override void OnEnable()
{
//调用base.OnEnable()第一帧会绘制出整个图片
//base.OnEnable();
}
}
我们在工程中创建一个Image控件,把Image控件上的的Image组件去掉,然后挂上SpriteGraphic.cs脚本和SpriteGraphicHelper.cs脚本。然后把我们大的图集Atlas放在Resources文件夹下,就可以实现上面的效果。