为什么 WaitForSeconds 导致我的精灵被改变?
Why is WaitForSeconds causing my sprite to be changed?
在我的游戏中,我播放动画,等待动画结束,然后更改精灵图像。接下来我淡出精灵,等待淡入淡出结束,然后禁用游戏对象。这是代码:
IEnumerator UnlockSequence()
{
anim.Play("unlock");
unlocking = false; // stops UnlockSequence from being called again
yield return new WaitForSeconds(1.7f);
sr.sprite = sprite1; //change sprite
StartCoroutine(FadeTo(0.0f, 2.0f));
yield return new WaitForSeconds(2f);
gameObject.SetActive(false);
}
IEnumerator FadeTo(float aValue, float aTime)
{
float alpha = sr.color.a;
for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / aTime)
{
Color newColor = new Color(sr.color.r, sr.color.g, sr.color.b, Mathf.Lerp(alpha, aValue, t));
sr.color = newColor;
yield return null;
}
}
这很好用,除了当我到达 yield return new WaitForSeconds(2f);
时,sprite 图像回到动画之前的原始图像。我不知道为什么会这样。我知道 sr.sprite = sprite1;
有效,因为当我取出 yield return new WaitForSeconds(2f);
时,精灵是正确的。任何解决此问题的帮助将不胜感激。
编辑:
这是问题的 gif,很抱歉质量很差,但希望您能看到问题。
the problem
如果不看动画很难判断,但我的理论是您的动画正在循环播放或导致 sprite 重置为其原始 sprite。 Animator 根据创建关键帧时它们在时间轴中的状态复制 GameObject 的属性。我刚刚复制了您的代码,一切都按预期工作(等待 1.5 秒,更改 sprite,在 2.0 秒后淡出并进入非活动状态)。我唯一没有的是你正在使用的动画剪辑。当我稍后有时间时,我可以通过添加动画来验证,但我会看一下。如果您可以分享 AnimationClip 的屏幕截图,那将会很有帮助。
绝对不是 WaitForSeconds
改变了精灵,而是你的 Animator
!
原因
如果在任何 AnimatorState
中的某处,对于某个 属性,您只有 一个关键帧(就像在您的情况下显然是 Sprite
) Animator
获得了对这个 属性 的完全控制,你可以 不再通过脚本覆盖它 !
此外 AnimatorState
有一个选项 Write Defaults
UnityTechnologies 在 this thread
中提到
In 5.0 we have added a property on the State to Write back default values
. Meaning that if turned on, it will write back the default values of all animated properties ( on a Controller wide-basis) that are not animated in that State.
By default, its "on", so we don't change the behavior that we had before.
So if you want the non-animated properties of a State to keep the value it had previously, simply turn it off.
这意味着对于每个 属性 在这个 AnimatorState 中有 没有关键帧 它使用对象在没有 Animator
就可以了。
一个解决方案
因此,如果您希望 Default
状态不覆盖 Sprite
,因为在该状态下 Sprite
没有关键帧,那么只需关闭此选项即可。
纯动画解决方案
但是,我认为您可以设置 Animator,它实际上可以处理整个事情,而不需要您的脚本,除了启动动画一次。
你说你的 Animator 设置看起来像
Entry → Default ← Unlock
所以请允许我问:
为什么不简单地删除该转换回到 Default
?这将使它保持 unlock
状态,直到您以其他方式告诉它。通过将 Loop Time
关闭,这意味着它停留在最后一个关键帧,并且无论如何都不会跳回到默认值。
为什么不简单地将淡出也包含到您的 unlock
动画中呢?也只需为 color
属性 设置关键帧。这样你就不需要为此使用脚本了。
或者,如果您想独立于(解锁)锁控制淡入淡出,您可以使用多个 Animation Layers!在主层上,您进行(解锁)锁定。在不同的图层上,您通过 Color
属性.
进行淡入淡出
一般来说,我通常会建议使用 bool
Animation Parameters 进行过渡的 Animator 设置。然后使用多层它可能会像
parameters
Bool "Open"
Bool "FadeOut"
layers
Base Layer
Entry -------------------> StateClosed
StateClosed --(if Open==true)--> AnimOpening
AnimOpening --(Exit time 1)----> StateOpen
StateOpen --(if Open==false)-> AnimClosing
AnimClosing --(Exit time 1)----> StateClosed
FadeingLayer (make sure to set Weight to `1` - its `0` by default)
Entry -----------------------> StateFadedIn
StateFadedIn --(if FadeOut==true)---> AnimFadingOut
AnimFaidingOut --(Exit time 1)--------> StateFadedOut
StateFadedOut --(if FadeOut==false)--> AnimFadingIn
AnimFadingIn --(Exit time 1)--------> StateFadedIn
如果您想确保在所有状态(包括单个关键帧状态)中为所有相应属性设置关键帧。意思例如在您设置的 FadingLayer 中
StateFadedIn: Color.a = 1
StateFadedOut: Color.a = 0
AnimFadingOut: Color.a = well your keyframes here ;)
AnimFadingIn: Color.a = well your keyframes here ;)
和BaseLayer同理
这样 Animator
就不会在通过脚本在状态之间强制跳转时搞砸了。
然后在代码中简单地设置
anim.SetBool("Open", true);
然后
anim.SetBool("FadeOut", true);
最后,您可以进一步设置 Animation Events 而不是最后一个脚本调用,它会在完成后自动调用 FadeOut
更改。然后您仍然可以通过脚本控制它,但不必 "manually" 等到解锁动画完成后再开始淡出。
我知道这是很多信息,但我希望您能清楚地理解这个想法,并且您可以通过文档找到自己的方法 ;)
在我的游戏中,我播放动画,等待动画结束,然后更改精灵图像。接下来我淡出精灵,等待淡入淡出结束,然后禁用游戏对象。这是代码:
IEnumerator UnlockSequence()
{
anim.Play("unlock");
unlocking = false; // stops UnlockSequence from being called again
yield return new WaitForSeconds(1.7f);
sr.sprite = sprite1; //change sprite
StartCoroutine(FadeTo(0.0f, 2.0f));
yield return new WaitForSeconds(2f);
gameObject.SetActive(false);
}
IEnumerator FadeTo(float aValue, float aTime)
{
float alpha = sr.color.a;
for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / aTime)
{
Color newColor = new Color(sr.color.r, sr.color.g, sr.color.b, Mathf.Lerp(alpha, aValue, t));
sr.color = newColor;
yield return null;
}
}
这很好用,除了当我到达 yield return new WaitForSeconds(2f);
时,sprite 图像回到动画之前的原始图像。我不知道为什么会这样。我知道 sr.sprite = sprite1;
有效,因为当我取出 yield return new WaitForSeconds(2f);
时,精灵是正确的。任何解决此问题的帮助将不胜感激。
编辑:
这是问题的 gif,很抱歉质量很差,但希望您能看到问题。
the problem
如果不看动画很难判断,但我的理论是您的动画正在循环播放或导致 sprite 重置为其原始 sprite。 Animator 根据创建关键帧时它们在时间轴中的状态复制 GameObject 的属性。我刚刚复制了您的代码,一切都按预期工作(等待 1.5 秒,更改 sprite,在 2.0 秒后淡出并进入非活动状态)。我唯一没有的是你正在使用的动画剪辑。当我稍后有时间时,我可以通过添加动画来验证,但我会看一下。如果您可以分享 AnimationClip 的屏幕截图,那将会很有帮助。
绝对不是 WaitForSeconds
改变了精灵,而是你的 Animator
!
原因
如果在任何 AnimatorState
中的某处,对于某个 属性,您只有 一个关键帧(就像在您的情况下显然是 Sprite
) Animator
获得了对这个 属性 的完全控制,你可以 不再通过脚本覆盖它 !
此外 AnimatorState
有一个选项 Write Defaults
UnityTechnologies 在 this thread
In 5.0 we have added a property on the State to
Write back default values
. Meaning that if turned on, it will write back the default values of all animated properties ( on a Controller wide-basis) that are not animated in that State.By default, its "on", so we don't change the behavior that we had before.
So if you want the non-animated properties of a State to keep the value it had previously, simply turn it off.
这意味着对于每个 属性 在这个 AnimatorState 中有 没有关键帧 它使用对象在没有 Animator
就可以了。
一个解决方案
因此,如果您希望 Default
状态不覆盖 Sprite
,因为在该状态下 Sprite
没有关键帧,那么只需关闭此选项即可。
纯动画解决方案
但是,我认为您可以设置 Animator,它实际上可以处理整个事情,而不需要您的脚本,除了启动动画一次。
你说你的 Animator 设置看起来像
Entry → Default ← Unlock
所以请允许我问:
为什么不简单地删除该转换回到
Default
?这将使它保持unlock
状态,直到您以其他方式告诉它。通过将Loop Time
关闭,这意味着它停留在最后一个关键帧,并且无论如何都不会跳回到默认值。为什么不简单地将淡出也包含到您的
unlock
动画中呢?也只需为color
属性 设置关键帧。这样你就不需要为此使用脚本了。或者,如果您想独立于(解锁)锁控制淡入淡出,您可以使用多个 Animation Layers!在主层上,您进行(解锁)锁定。在不同的图层上,您通过
Color
属性. 进行淡入淡出
一般来说,我通常会建议使用 bool
Animation Parameters 进行过渡的 Animator 设置。然后使用多层它可能会像
parameters
Bool "Open"
Bool "FadeOut"
layers
Base Layer
Entry -------------------> StateClosed
StateClosed --(if Open==true)--> AnimOpening
AnimOpening --(Exit time 1)----> StateOpen
StateOpen --(if Open==false)-> AnimClosing
AnimClosing --(Exit time 1)----> StateClosed
FadeingLayer (make sure to set Weight to `1` - its `0` by default)
Entry -----------------------> StateFadedIn
StateFadedIn --(if FadeOut==true)---> AnimFadingOut
AnimFaidingOut --(Exit time 1)--------> StateFadedOut
StateFadedOut --(if FadeOut==false)--> AnimFadingIn
AnimFadingIn --(Exit time 1)--------> StateFadedIn
如果您想确保在所有状态(包括单个关键帧状态)中为所有相应属性设置关键帧。意思例如在您设置的 FadingLayer 中
StateFadedIn: Color.a = 1
StateFadedOut: Color.a = 0
AnimFadingOut: Color.a = well your keyframes here ;)
AnimFadingIn: Color.a = well your keyframes here ;)
和BaseLayer同理
这样 Animator
就不会在通过脚本在状态之间强制跳转时搞砸了。
然后在代码中简单地设置
anim.SetBool("Open", true);
然后
anim.SetBool("FadeOut", true);
最后,您可以进一步设置 Animation Events 而不是最后一个脚本调用,它会在完成后自动调用 FadeOut
更改。然后您仍然可以通过脚本控制它,但不必 "manually" 等到解锁动画完成后再开始淡出。
我知道这是很多信息,但我希望您能清楚地理解这个想法,并且您可以通过文档找到自己的方法 ;)