我正在为我的游戏创建一个简单的幻灯片动画。该框显示在底部,带有字符对话框。
动画应该如下所示:
一个正方形从左边滑入,然后稍等一下,然后扩展到它的全宽。
该框使用Unity的GUI Box制作。延长时间用于调试目的(我需要能够清楚地看到动画)。一切都按照我想要的方式工作,除非它最初从正方形到矩形的动画,它似乎“跳跃”而不是像动画的其余部分那样相对平滑地过渡。
我做错了什么吗?我知道它没有被编码得那么惊人(我在第一种方式中用5分钟写了它),但我很确定我的逻辑是正确的。也许我的计时器造成了问题?
private string boxString = "Hello, world! I am sample character dialog.";
private float elapsedTime = 0.0f;
private float initialSlideInDuration = 1.333f;
private float waitBetweenSlideAndExpand = 0.666f;
private float expansionDuration;
private float boxHeightPercentage = 0.10f;
private float boxWidthPercentage = 0.95f;
private float positionFromLeft;
private float positionFromBottom;
private float boxWidth;
private float boxHeight;
// instantiate variables before any frames are drawn
void Start () {
expansionDuration = initialSlideInDuration + waitBetweenSlideAndExpand + 3.333f;
boxWidth = Screen.width*boxWidthPercentage;
boxHeight = Screen.height*boxHeightPercentage;
positionFromLeft = (Screen.width - (Screen.width * boxWidthPercentage)) / 2;
positionFromBottom = Screen.height - (positionFromLeft + boxHeight);
}
// called once per frame
void Update () {
elapsedTime += Time.deltaTime;
}
// render and handle GUI events
void OnGUI() {
// slide in square
if (elapsedTime <= initialSlideInDuration) {
float initialLeftPadding = -positionFromLeft - boxHeight;
float finalLeftPadding = positionFromLeft;
float movementDistance = (2 * positionFromLeft) + boxHeight;
float progress = elapsedTime / initialSlideInDuration;
GUI.Box (new Rect ((progress * movementDistance) + initialLeftPadding, positionFromBottom, boxHeight, boxHeight), boxString);
}
// if square is ready and we have waited, animate to rectangle
else if (elapsedTime > initialSlideInDuration+waitBetweenSlideAndExpand && elapsedTime <= expansionDuration) {
float initialWidth = boxHeight;
float finalWidth = boxWidth;
float growth = finalWidth - initialWidth;
float progress = elapsedTime / expansionDuration;
GUI.Box(new Rect(positionFromLeft, positionFromBottom, (progress * growth) + initialWidth, boxHeight), boxString);
}
// stay as full width rectangle
else if(elapsedTime > expansionDuration){
GUI.Box (new Rect (positionFromLeft, positionFromBottom, boxWidth, boxHeight), boxString);
}
// we are waiting, display the square with left padding
else {
GUI.Box (new Rect (positionFromLeft, positionFromBottom, boxHeight, boxHeight), boxString);
}
}
答案 0 :(得分:1)
如果你真的想要与帧速率无关,你应该使用一个协程,我就是这样做的:
float startWidth = 1f;
float endWidth = 10f;
float startPosition = 1f;
float endPosition = 10f;
float positionX, widthX;
IEnumerator SlideInAnimation(float slideTime = 0.3f, float expandTime = 1f) {
float t = slideTime;
while (t>0) {
positionX = Mathf.Lerp(startPosition,endPosition,1-(t/slideTime));
t-=Time.deltaTime;
yield return null; //Wait for end of Frame (almost)
}
positionX = endPosition;
t = expandTime;
while (t>0) {
widthX = Mathf.Lerp(startWidth,endWidth,1-(t/expandTime));
t-=Time.deltaTime;
yield return null; //Wait for end of Frame (almost)
}
widthX = endWidth;
}
void OnGUI() {
GUI.Box (new Rect (positionX , positionFromBottom, widthX , boxHeight), boxString);
}
你以这种方式运行:
IEnumerator Start() {
positionX = startPosition;
widthX = startWidth;
yield return StartCoroutine(SlideInAnimation());
//All stuff happening after that line will be run when the animation finishes
}
以下是这里发生的事情:
我摆脱了OnGUI,因为你想要随着时间的推移发生的事情,并且GUI调用的增量时间是不可预测的。好的是你只是在这里处理动画而不是逻辑,所以你只需要每帧发生一次事情(在渲染之前不需要移动东西两次)。
很好的解决方案是创建一个协程来处理所有
答案 1 :(得分:1)
您可以考虑使用AssetStore中的简单且非常有用的资产 - LeanTween。我有类似GUI动画的问题,简单的事情让我的工作更轻松。
答案 2 :(得分:0)
每帧都会调用更新函数,无论其他人都在运行。
正在运行的所有其他人被编译器或运行时视为不同的执行。
代码中的问题是更新超前于elapsedTime
计算,让OnGUI中的逻辑更新为elapsedTime
值。
您需要做的就是删除Update()函数并在OnGUI中移动elapsedTime
增量。
void Update () {
elapsedTime += Time.deltaTime;
}