首页 > 解决方案 > 为什么可变高度值是 0?

问题描述

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(UnityEngine.LineRenderer))]
public class DrawCircle : MonoBehaviour
{
    public enum CircleHeight
    {
        Center, Bottom, Top
    };

    public CircleHeight circleheight;
    [Range(0, 50)]
    public int segments = 50;
    [Range(1, 50)]
    public float xradius = 1.5f;
    [Range(1, 50)]
    public float yradius = 1.5f;
    [Range(-10, 10)]
    public float height = 0;
    public bool changeBothRadius = false;
    [Range(0.1f, 2)]
    public float lineThickness = 0.1f;
    public bool minimumRadius = false;
    public bool draw = false;
    public bool animateCircle = false;
    public float animationSpeed = 0.5f;

    private LineRenderer line;
    private Renderer renderer;
    private float Bottom;
    private float Top;
    private float Center = 0;
    private float t = 0f;

    void Start()
    {
        circleheight = CircleHeight.Center;

        line = gameObject.GetComponent<UnityEngine.LineRenderer>();
        line.positionCount = segments + 1;
        line.useWorldSpace = false;
        renderer = gameObject.GetComponent<Renderer>();

        Bottom = transform.InverseTransformPoint(renderer.bounds.min).y + 0.1f;
        Top = transform.InverseTransformPoint(renderer.bounds.max).y + 0.1f;
    }

    void Update()
    {
        line.startWidth = lineThickness;
        line.endWidth = lineThickness;

        if (draw)
        {
            line.enabled = true;
            CreatePoints();
        }
        else
        {
            line.enabled = false;
        }
    }

    bool animStart = true;
    void CreatePoints()
    {
        float x;
        float z;

        float angle = 20;

        if (animateCircle == false)
        {
            switch (circleheight)
            {
                case CircleHeight.Center:
                    height = Center;
                    break;
                case CircleHeight.Bottom:
                    height = Bottom;
                    break;
                case CircleHeight.Top:
                    height = Top;
                    break;
            }
        }
        else
        {
            AnimateCircle(Top, Bottom);
        }

        for (int i = 0; i < (segments + 1); i++)
        {
            x = Mathf.Sin(Mathf.Deg2Rad * angle) * xradius;
            z = Mathf.Cos(Mathf.Deg2Rad * angle) * yradius;

            line.SetPosition(i, new Vector3(x, height, z));

            angle += (360f / segments + 1);
        }
    }

    private void AnimateCircle(float From, float To)
    {
        if (animStart)
        {
            if (height == Center)
            {
                height = Mathf.Lerp(Center, From, t);
                t += animationSpeed * Time.deltaTime;
                if (height == From)
                {
                    animStart = false;
                }
            }
        }
    }
}

我正在使用 animateCircle 标志来防止枚举始终将高度重置为 Center:

if (animateCircle == false)

然后我添加了一个断点,它没有再次传入它一直在做其他部分:

else
            {
                AnimateCircle(Top, Bottom);
            }

在 AnimateCircle 方法中执行该过程后,我看到高度值为 0.6。

但后来我也在行上添加了一个断点:

line.SetPosition(i, new Vector3(x, height, z));

第一个循环高度为 0.6,但在 i = 50 时循环结束并且循环重新开始后,我看到高度为 0。但我没有在其他任何地方重置高度。

这是 AnimateCircle 方法未使用的代码,只是为了展示我尝试过的和打算做的事情:

private void AnimateCircle(float From, float To)
    {
        // From = Top To = Bottom
        // height = Center

        if (animStart)
        {
            if (height != From)
            {
                height = Mathf.Lerp(height, From, t);
            }
            else
            {
                height = Mathf.Lerp(From, To, t);
            }
            t += animationSpeed * Time.deltaTime;
            if (height == From || height == To)
                animStart = false;
        }
        else
        {
            height = Mathf.Lerp(From, To, t);
            t += animationSpeed * Time.deltaTime;

            if (t > 1.0f)
            {
                if (To == Top)
                {
                    float temp = To;
                    To = From;
                    From = temp;
                    t = 0.0f;
                }
                if(To == Bottom)
                {
                    float temp = From;
                    From = To;
                    To = temp;
                    t = 0.0f;
                }
            }

            if (To == Top)
            {
                height = Mathf.Lerp(Bottom, Top, t);
                t += animationSpeed * Time.deltaTime;

                if (t > 1.0f)
                {
                    float temp = Top;
                    Top = Bottom;
                    Bottom = temp;
                    t = 0.0f;
                }
            }

            if(To == Bottom)
            {
                height = Mathf.Lerp(Top, Bottom, t);
                t += animationSpeed * Time.deltaTime;

                if (t > 1.0f)
                {
                    float temp = Bottom;
                    Bottom = Top;
                    Top = temp;
                    t = 0.0f;
                }
            }
        }
    }*/

例如,当枚举默认状态为 Start 中的 Center 时游戏开始。如果我打电话AnimateStart(Top, Bottom);AnimateStart(Bottom, Top);

然后在 AnimateCircle 内部,我想将圆从中心移动到顶部或底部,具体取决于我如何称呼它。所以从可以是顶部或底部。

在圆圈从中心移动一次到顶部或底部之后,然后在顶部和底部(或底部顶部)之间开始一个不间断的乒乓球。

如果游戏以枚举默认状态为底部或顶部开始,那么只需在顶部和底部之间开始一个乒乓球,而无需中心。

编辑:

这是我现在使用的 AnimateCircle 的代码:

private void AnimateCircle(float From, float To)
    {
        if (animStart)
        {
            // prevent t from exceeding tGoal
            if (t > tGoal)
            {
                t = tGoal;
            }

            // end animation when t reaches goal
            if (t == tGoal)
            {
                animStart = false;
            }

            // advance height according to t
            height = Mathf.Lerp(Bottom, Top, Mathf.PingPong(t, 1f));

            // advance height according to time & speed
            t += animationSpeed * Time.deltaTime;
        }
    }

CreatePoints 没有改变:

    bool animStart = true;
    void CreatePoints()
    {
        float x;
        float z;

        float angle = 20;

        if (animateCircle == false)
        {
            switch (circleheight)
            {
                case CircleHeight.Center:
                    // t=0.5f, tGoal=1f to go to top first then stop at top
                    // t=0.5f, tGoal=2f to go to top first then stop at bottom
                    // t=1.5f, tGoal=2f to go to bottom first then stop at bottom
                    // t=1.5f, tGoal=3f to go to bottom first then stop at top

                    t = 0.5f;
                    tGoal = 2f;
                    height = Center;
                    break;
                case CircleHeight.Bottom:
                    t = 0f;
                    tGoal = 1f;
                    height = Bottom;
                    break;
                case CircleHeight.Top:
                    t = 1f;
                    tGoal = 2f;
                    height = Top;
                    break;
            }
        }
        else
        {
            AnimateCircle(Bottom, Top);
        }

        for (int i = 0; i < (segments + 1); i++)
        {
            x = Mathf.Sin(Mathf.Deg2Rad * angle) * xradius;
            z = Mathf.Cos(Mathf.Deg2Rad * angle) * yradius;

            line.SetPosition(i, new Vector3(x, height, z));

            angle += (360f / segments + 1);
        }
    }

为了首先移动到顶部,我这样调用 AnimateCircle:

AnimateCircle(Top, Bottom);

在 AnimateCircle 内部也是这样的 Top、Bottom:

height = Mathf.Lerp(Top, Bottom, Mathf.PingPong(t, 1f));

在开关盒部分t = 0.5ftGoal = 2f

但相反,它首先移动到顶部,然后快速移动到底部,然后从底部移动到顶部。

但是,如果我更改t = 1.5ftGoal = 3f;然后它将首先移动到顶部,然后从顶部移动到底部,这很好。但是 0.5 和 2 并没有先向上移动它。

如果 t = 1.5f 且 tGoal = 2f; 它将向上移动到顶部并停在那里。

但是我找不到如何制作底部部分,所以它会首先移动到底部并停止或首先移动到底部并移动到顶部。

标签: c#unity3d

解决方案


添加一个名为 tGoal 的浮点字段:

private float tGoal;

根据您希望它开始的位置设置 t,并在您希望它停止动画的位置设置 tGoal。如果您希望它从 开始Center,则必须确定适当的 lerp 值以开始:

        switch (circleheight)
        {
            case CircleHeight.Center:
                float centerT = Mathf.InverseLerp(Bottom, Top, Center);

                // t=0f+centerT, tGoal=1f to go to top first then stop at top
                // t=0f+centerT, tGoal=2f to go to top first then stop at bottom
                // t=2f-centerT, tGoal=2f to go to bottom first then stop at bottom
                // t=2f-centerT, tGoal=3f to go to bottom first then stop at top

                t = 2f - centerT; 
                tGoal = 3f;
                height = Center;
                break;
            case CircleHeight.Bottom:
                t= 0f;
                tGoal = 1f;
                height = Bottom;
                break;
            case CircleHeight.Top:
                t = 1f;
                tGoal = 2f;
                height = Top;
                break;
        }

然后使用Mathf.PingPong变成t一个 lerp 值,乒乓球。当 t 等于 tGoal 时停止,确保 tGoal 永远不会超过它:

private void AnimateCircle()
{
    if (animStart)
    {
        // prevent t from exceeding tGoal
        if (t > tGoal) {
            t = tGoal;
        }

        // end animation when t reaches goal
        if (t == tGoal) {
            animStart = false;
        }

        // advance height according to t
        height = Mathf.Lerp(Bottom, Top, Mathf.PingPong(t,1f));

        // advance height according to time & speed
        t += animationSpeed * Time.deltaTime;

    }
}

推荐阅读