Daniel Lip
Daniel Lip

Reputation: 11325

Why the variable height value is rest to 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;
                }
            }
        }
    }
}

I'm using the animateCircle flag to prevent from the enum to reset the height to Center all the time:

if (animateCircle == false)

Then I added a breakpoint and it's not passing in again it's doing all the time the else part:

else
            {
                AnimateCircle(Top, Bottom);
            }

And I see that height value is 0.6 after doing the process inside AnimateCircle method.

But then I added a breakpoint also on the line:

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

First loop height is 0.6 but then after the loop end when i = 50 and the loop start over again I see that height is 0. But I'm not reseting height any where else.

This is the AnimateCircle method unused code just to show what I tried and means to do:

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;
                }
            }
        }
    }*/

For example the game start when the enum default state is Center in the Start. And if I call AnimateStart(Top, Bottom); or AnimateStart(Bottom, Top);

Then inside AnimateCircle I want to move the circle from the Center to the Top or Bottom depending on how I'm calling it. So From can be Top or Bottom.

After the circle moved from the Center once to the Top or Bottom then start a ping pong nonstop between Top and Bottom (Or bottom top).

And if the game start with the enum default state as Bottom or Top then just start a ping pong between the top and Bottom without the Center.

EDIT:

This is the code for the AnimateCircle I'm using now:

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

The CreatePoints didn't change:

    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);
        }
    }

For the move first to the Top I'm calling the AnimateCircle like this:

AnimateCircle(Top, Bottom);

And inside the AnimateCircle also Top, Bottom like this:

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

In the switch case part t = 0.5f and tGoal = 2f

But instead moving first to the Top it's moving to the Bottom fast then from Bottom to Top.

But if I change t = 1.5f and tGoal = 3f; Then it will move first to the Top then from top to Bottom and that is fine. But 0.5 and 2 not moving it first up.

And if t = 1.5f and tGoal = 2f; it will move up to the Top and stop there.

But I can't find how to make the Bottom part so it will move to the Bottom first and stop or move first to the Bottom and move to Top.

Upvotes: 1

Views: 105

Answers (1)

Ruzihm
Ruzihm

Reputation: 20259

Add a float field called tGoal:

private float tGoal;

Set t depending on where you want it to start and tGoal on where you want it to stop animating. If you want it to start at Center, you have to determine the appropriate lerp value to start with:

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

Then use Mathf.PingPong to turn t into a lerp value that ping pongs. Stop when t equals tGoal, making sure tGoal never can exceed it:

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;

    }
}

Upvotes: 3

Related Questions