最近 Unity 发布了他们新的 UI 工具包,到目前为止它一直很棒。我的文档中有一个倒计时元素,我计划在数字达到阈值后将其设置为脉冲。
这是当前的过渡:
我怎样才能无限循环播放动画?
当前的 USS 代码如下。我尝试过类似的 css 属性,例如
animation-iteration-count: infinite;
但到目前为止没有运气,而且文档似乎还不完整。
#timer-countdown:hover {
scale: 1.2 1.1;
color: rgba(255, 170, 170, 255);
transition-duration: 1s;
transition-timing-function: ease-in-out-cubic;
}
我在论坛和其他地方看到的关于 Unity 的建议是在 C# 中控制动画和其他行为,而 uss 还不够发达。
简单的解决方案
为每次转换结束时注册回调,并切换活动的类。注意:每个班级应该只有 1 个转换。
//Put this in the constructor, call once.
RegisterCallback<TransitionEndEvent>((e) => PlayNext());
ToggleInClassList("$"{previousClass}");
public void PlayNext()
{
// These should be "offset": One is off while the other is on.
ToggleInClassList("$"{previousClass}");
ToggleInClassList($"{nextClass}");
}
自定义元素解决方案
稍微更完整的解决方案是创建自定义视觉元素。
using UnityEngine;
using UnityEngine.UIElements;
public class LoopingAnimation : VisualElement
{
#region boilerplate
// Required for the UI Builder
public new class UxmlFactory : UxmlFactory<LoopingAnimation, UxmlTraits>
{}
public new class UxmlTraits : VisualElement.UxmlTraits
{
UxmlStringAttributeDescription m_className = new UxmlStringAttributeDescription { name = "class-name", defaultValue = "animation-class" };
UxmlIntAttributeDescription m_classCount = new UxmlIntAttributeDescription { name = "classCount", defaultValue = 1 };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var ate = ve as LoopingAnimation;
ate.className = m_className.GetValueFromBag(bag, cc);
ate.classCount = m_classCount.GetValueFromBag(bag, cc);
}
}
#endregion
int index = 0;
public bool isPlaying = true;
public string className { get; set; }
public int classCount { get; set; }
public VisualElement child = new VisualElement() { name =
“动画目标”};
public LoopingAnimation() : base()
{
RegisterCallback<GeometryChangedEvent>(OnGeometryChangedEvent);
}
void OnGeometryChangedEvent(GeometryChangedEvent e)
{
Add(child);
RegisterCallback<TransitionEndEvent>((e) => PlayNext());
RegisterCallback<PointerEnterEvent>((e) => Play()); //Only here to get the ball rolling in Preview Mode
UnregisterCallback<GeometryChangedEvent>(OnGeometryChangedEvent);
}
public void PlayNext()
{
if(!isPlaying ) return;
Debug.Log($"Looping {index} {className}{index %classCount}");
child.RemoveFromClassList($"{className}{index %classCount}");
index++;
child.AddToClassList($"{className}{index %classCount}");
}
public void Play()
{
isPlaying = true;
style.display = DisplayStyle.Flex;
PlayNext();
}
public void Stop()
{
isPlaying = false;
child.ClearClassList();
style.display = DisplayStyle.None;
}
}
使用方法
在 UI Builder 中,将此元素拖放到场景中。在右侧的检查器中,插入这些值:
类名像这样递增:
您可以在预览模式下编辑和测试动画(!)
#animation-target {
width: 100%;
height: 100%;
background-color: rgba(255, 32, 32, 0.25);
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
}
.animation-0 {
background-color: rgb(229, 107, 107);
transition-duration: 800ms;
transition-property: scale;
border-left-width: 21px;
border-right-width: 21px;
border-top-width: 21px;
border-bottom-width: 21px;
scale: 2 2;
transition-timing-function: ease-out-sine;
border-right-color: rgb(0, 26, 255);
}
.animation-1 {
background-color: rgb(229, 107, 107);
transition-duration: 800ms;
border-left-color: rgb(255, 0, 0);
transition-property: scale;
border-left-width: 21px;
border-right-width: 21px;
border-top-width: 21px;
border-bottom-width: 21px;
scale: 1 1;
transition-timing-function: ease-in-sine;
transition-delay: 0s;
}
.animation-2 {
rotate: 180deg;
transition-property: rotate;
transition-duration: 600ms;
border-left-width: 21px;
border-right-width: 21px;
border-top-width: 21px;
border-bottom-width: 21px;
border-left-color: rgba(0, 22, 255, 255);
}