先上效果:
原理
图片闪烁可以采取很多底层逻辑实现,像一些早期的街机游戏受击闪烁的实现机制是在受击的那一帧让模型变成白色。在这里我们采取透明度循环变化的方案实现。
逐帧动画实现
这个方案相对于另外两个方案是比较繁琐的,要有一组透明度循环变化的图片。
注意是循环变化也就是说要变到最值后在变回去
示例里的透明度分别为:
0.4 0.6 0.8 1 0.8 0.6 0.4
首先将素材导入
然后如果是3D模板的话要设置下图片的参数。
全选全部图片→在Inspector面板上设置Texture Type为Sprite→设置SpriteMode为Single→在面板往下拉,找到并点击Apply
剩下的就是正常制作帧动画的流程了
速度的话在Animator里可以调
Animation录制
这个方案只需要一张图片。
导入素材和上面一样。
3D模板的话也要设置下参数。
对Animation不是很熟悉的朋友可以先补补这方面的知识。
唤出Animation窗口
也可以直接Ctrl+6唤出窗口
创建AnimationClip
开始录制
在中间插入关键帧首先使其变化到极值
在末尾插入关键帧使其回到原样
到这Animation就做完了
c#脚本实现
这个方案也只需要一张图片。
这是笔者推荐的做法,也是本文的重点讨论对象。
这个方案相对于前两个方案有着明显的通用性和灵活性。但是弊端是需要占用一定算力资源。
我这里采用的写法有点像Update计时器,还不太了解的朋友可以移步Unity计时的实现,其中的第一种计时方式就是Update计时器。
现在这是开始写这个工具脚本:
首先给组件加上RequireComponent特性确保健壮性
[RequireComponent(typeof(Image))]
缓存Image组件的对象
private Image image;
private void OnEnable()
{
image = GetComponent<Image>();
}
将透明度的边界和变化速度暴露到Inspector面板,并定义一个变量来记录变化方向
//Range特性指定参数在Inspector中的变化范围
//Unity中用描述色值用的是RGB 0-1.0
//所有色彩通道0为完全不具有1为完全具有
//所以在这里0是全透明,1是全不透明
[Range(0,1)]
public float rangeLeft;
[Range(0,1)]
public float rangeRight;
public float speed = 1;
private int direction = 1;
现在是核心代码,在Update里逐帧更新组件
private void Update()
{
//先区别两个边界的大小
float small;
float big;
if (rangeLeft > rangeRight)
{
big=rangeLeft;
small=rangeRight;
}
else
{
big=rangeRight;
small=rangeLeft;
}
//这一帧透明度应该变化多少
float pre=speed*direction*Time.deltaTime;
//本帧的透明度应变为多少
float target = image.color.a + pre;
//方向大于0即向更大的边界变化时
//大于大边界为越界
if (direction > 0)
{
//如果越界了
if (target > big)
{
//将应为的透明度设为边界以避免越界
target= big;
//逆转方向,从下一帧开始朝另一个边界靠近
direction *= -1;
}
}
//方向小于0
//小于小边界为越界
else
{
//如果越界了则同上
if(target < small)
{
target= small;
direction *= -1;
}
}
//获取image原来的颜色
Color oColor= image.color;
//除了Alpha通道外其他通道的值要保留原样
//target是上面计算出的应变为的透明度
image.color = new(oColor.r, oColor.g, oColor.b, target);
}
完整版
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Image))]
public class Twiklable : MonoBehaviour
{
private Image image;
[Range(0,1)]
public float rangeLeft;
[Range(0,1)]
public float rangeRight;
public float speed = 1;
public float delay = 0;
private int direction = 1;
private void OnEnable()
{
image = GetComponent<Image>();
}
private void Update()
{
float small;
float big;
if (rangeLeft > rangeRight)
{
big=rangeLeft;
small=rangeRight;
}
else
{
big=rangeRight;
small=rangeLeft;
}
float pre=speed*direction*Time.deltaTime;
float target = image.color.a + pre;
if (direction > 0)
{
if (target > big)
{
target= big;
direction *= -1;
}
}
else
{
if(target < small)
{
target= small;
direction *= -1;
}
}
Color oColor= image.color;
image.color = new(oColor.r, oColor.g, oColor.b, target);
}
}
本人初来乍到,许多不足之处,欢迎大家斧正。