最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
unity 2d Texture 动态获取序列帧
在本篇文章中,我将为大家分享在 Unity 中实现 2D Texture 动态获取序列帧的相关内容。我昨天编写了一个便捷的方法,你只需将图片放置在 Resources 文件夹下的 AniEffect 目录中(你也可以根据需求修改文件夹路径)。
用法
通过调用静态方法 SpriteAniTool.AddEffect 并传入多个参数,就可以在场景中添加序列帧特效。
原理
该方法会根据特效的名称(需与图片名称一致)访问一个全局字典。如果该特效已经被加载过,会直接从字典中取出对应的材质球,并赋予新创建的特效面片;若该特效从未被使用过,则会到 Resources 文件夹下查找对应的资源。关于序列帧的播放,主要是通过计算 UV 的 tiling 和 offset 来实现。其中,offset 存储在一个数组里,在播放序列帧时,会根据设定的速度从数组中获取一个 Vector2 类型的值,从而实现特效的播放。
注意事项
特效有两种显示方式,这取决于最后一个参数 bool OnGround:
- 若
OnGround为true,特效将与地面平行。 - 若
OnGround为false,特效将与摄像机平行。
代码实现
工具类 SpriteAniTool
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpriteAniTool
{
// 全局特效材质球字典
public static Dictionary<string, Material> EffectLib = new Dictionary<string, Material>();
/// <summary>
/// 在场景中添加一个特效,按位置添加
/// 参数说明:
/// name: 特效名称,需与图片名称一致
/// time: 特效持续时间
/// clomn: 序列帧的列数
/// row: 序列帧的行数
/// speed: 播放速度(帧)
/// position: 特效的位置
/// OnGround: 特效是否与地面平行
/// </summary>
public static void AddEffect(string name, float time, int clomn, int row, int speed, Vector3 position, bool OnGround)
{
// 创建一个 Quad 面片作为特效载体
GameObject newEffect = GameObject.CreatePrimitive(PrimitiveType.Quad);
newEffect.name = name;
newEffect.transform.position = position;
// 根据 OnGround 参数设置特效的旋转角度
newEffect.transform.eulerAngles = OnGround ? new Vector3(90f, 0, 0) : Camera.main.transform.rotation.eulerAngles;
// 为特效对象添加 AniEffect 组件
AniEffect aniEffect = newEffect.AddComponent<AniEffect>();
aniEffect.SetEffect(name, time, clomn, row, speed);
}
}
特效类 AniEffect
// 特效类
public class AniEffect : MonoBehaviour
{
// 特效是否开始播放的标志
public bool isStarted = false;
private float _time;
private string _name;
private int _clomn;
private int _row;
private float _speed;
private float ScaleX;
private float ScaleY;
private Texture2D _Texture;
private Material _Material;
private Vector2[] sequence; // 序列帧偏移数组
// 设置特效的参数
public void SetEffect(string name, float time, int clomn, int row, int speed)
{
_Material = GetComponent<Renderer>().material;
_time = time;
_name = name;
_clomn = clomn;
_row = row;
_speed = speed;
// 计算 UV 缩放比例
ScaleX = 1f / row;
ScaleY = 1f / clomn;
// 计算序列帧偏移数组
SetSequence();
// 获取特效资源
GetEffectResource();
}
private float index;
void Update()
{
if (index >= sequence.Length)
{
index = 0f;
}
if (isStarted)
{
// 更新材质的 UV 偏移
GetComponent<Renderer>().material.mainTextureOffset = sequence[(int)index];
index += _speed * Time.deltaTime;
}
}
// 计算每一个具体帧的 UV 偏移位置
private void SetSequence()
{
sequence = new Vector2[_clomn * _row];
for (int i = 0; i < _clomn; i++)
{
for (int j = 0; j < _row; j++)
{
sequence[i * _row + j] = new Vector2(ScaleX * j, ScaleY * (_clomn - i - 1));
}
}
}
// 为特效图片赋值
private void GetEffectResource()
{
// 已经加载过的,去全局字典中寻找,没有加载过的从 Resource 读取
if (SpriteAniTool.EffectLib.ContainsKey(_name))
{
_Material = SpriteAniTool.EffectLib[_name];
}
else
{
_Texture = Resources.Load<Texture2D>("AniEffect/" + _name);
_Material.shader = Shader.Find("Unlit/Transparent");
_Material.mainTexture = _Texture;
SpriteAniTool.EffectLib.Add(_name, _Material);
}
GetComponent<Renderer>().material = _Material;
GetComponent<Renderer>().material.mainTextureScale = new Vector2(ScaleX, ScaleY);
// 启动协程,在特效持续时间结束后销毁特效对象
StartCoroutine(DestroyAni(_time));
}
// 协程方法,用于在特效持续时间结束后销毁特效对象
IEnumerator DestroyAni(float time)
{
isStarted = true;
yield return new WaitForSeconds(time);
// 卸载未使用的资源
Resources.UnloadUnusedAssets();
Destroy(gameObject);
}
}
以上代码实现了在 Unity 中动态获取 2D Texture 序列帧并播放特效的功能,脚本加注释约 100 行。你可以根据实际需求对代码进行调整和扩展。