使用增量时间手动滑入动画

时间:2015-06-15 02:45:07

标签: c# animation unity3d

我正在为我的游戏创建一个简单的幻灯片动画。该框显示在底部,带有字符对话框。

动画应该如下所示:

一个正方形从左边滑入,然后稍等一下,然后扩展到它的全宽。

该框使用Unity的GUI Box制作。延长时间用于调试目的(我需要能够清楚地看到动画)。一切都按照我想要的方式工作,除非它最初从正方形到矩形的动画,它似乎“跳跃”而不是像动画的其余部分那样相对平滑地过渡。

enter image description here

我做错了什么吗?我知道它没有被编码得那么惊人(我在第一种方式中用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);
    }
}   

3 个答案:

答案 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;  
}