0
votes

In relation to the question asked here (How to place spheres in a half circle shape between 2 points) that generates spheres between two points A and B. How do I create just one sphere that moves from Point A to Point B and then back from Point B to Point A in a loop cycle? How do I use Lerp in this context?

I have tried making the sphere move in the angle (half circle) described in the below code but it always moves in a straight line.

The below code generates spheres between two points.

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

public class GetCurves : MonoBehaviour
{

    public GameObject A;
    public GameObject B;

    public int amount;

    [ContextMenu("PlaceSpheres()")]
    public void Start()
    {
        PlaceSpheres(A.transform.position, B.transform.position, amount);
    }

    public void PlaceSpheres(Vector3 posA, Vector3 posB, int numberOfObjects)
    {
        // get circle center and radius
        var radius = Vector3.Distance(posA, posB) / 2f;
        var centerPos = (posA + posB) / 2f;

        // get a rotation that looks in the direction
        // posA -> posB
        var centerDirection = Quaternion.LookRotation((posB - posA).normalized);

        for (var i = 0; i < numberOfObjects; i++)
        {

            var angle = Mathf.PI * (i+1) / (numberOfObjects + 1); //180 degrees
            var x = Mathf.Sin(angle) * radius;
            var z = Mathf.Cos(angle) * radius;
            var pos = new Vector3(x, 0, z);
            // Rotate the pos vector according to the centerDirection
            pos = centerDirection * pos;

            var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.position = centerPos + pos;
            sphere.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
        }
    }
}

The below script I had created that makes an object move between two points in a loop but only in a straight line. How do I make it move in a curve (180 degrees)?

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

public class RunInLoop : MonoBehaviour
{

    public float speed = 0.25f;
    public Transform PointA;
    public Transform PointB;
    private Vector3 origin;
    private bool backToOrigin;

    void Start()
    {
        transform.position = PointA.transform.position;
        origin = transform.position;
    }

    void Update()
    {

            transform.position = Vector3.MoveTowards(transform.position, backToOrigin ? origin : PointB.transform.position, speed * Time.deltaTime);

            // if one of the two positions is reached invert the flag
            if (transform.position == PointB.transform.position || transform.position == origin)
            {
                backToOrigin = !backToOrigin;
            }

    }
}
1
Your code only runs once and places items in a sphere. it does not do any moving.. Is this some form of school homework? There seem to be a lot of questions this week about placing things and moving them in an arcBugFinder
Yeah this code just places number of spheres between two points. I have tried putting just one sphere to move between the two points but it does not follow the path I am creating. No definitely not school homework, I am trying to do new things on Unity and this is where I am stuck at.user11458208
You'd need to show how you were trying to move it. The problem really isnt unity but the logic of how to move along the pathBugFinder
I have updated the post with the new script that makes object move from Point A to B and back in a loop. (in a straight line)user11458208
correct it will move in a straight line because thats what you told it to do. You need to find the point on the arc and move to that, not just between a->bBugFinder

1 Answers

1
votes

Solution using your code

As I told you in my last answer that provided your first code you should store them in a list and then make the object move between them:

public class GetCurves : MonoBehaviour
{
    public GameObject A;
    public GameObject B;

    public int amount;
    public float moveSpeed;

    private List<Vector3> positions = new List<Vector3>();
    private Transform sphere;
    private int currentIndex = 0;
    private bool movingForward = true;

    private void Start()
    {
        sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
        sphere.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);

        GeneratePositions(A.transform.position, B.transform.position, amount);

        sphere.position = positions[0];
    }

    private void GeneratePositions(Vector3 posA, Vector3 posB, int numberOfObjects)
    {
        // get circle center and radius
        var radius = Vector3.Distance(posA, posB) / 2f;
        var centerPos = (posA + posB) / 2f;

        // get a rotation that looks in the direction
        // posA -> posB
        var centerDirection = Quaternion.LookRotation((posB - posA).normalized);

        for (var i = 0; i < numberOfObjects; i++)
        {

            var angle = Mathf.PI * (i + 1) / (numberOfObjects + 1); //180 degrees
            var x = Mathf.Sin(angle) * radius;
            var z = Mathf.Cos(angle) * radius;
            var pos = new Vector3(x, 0, z);
            // Rotate the pos vector according to the centerDirection
            pos = centerDirection * pos;

            // store them in a list this time
            positions.Add(centerPos + pos);
        }
    }

    private void Update()
    {
        if (positions == null || positions.Count == 0) return;

        // == for Vectors works with precision of 0.00001
        // if you need a better precision instead use
        //if(!Mathf.Approximately(Vector3.Distance(sphere.position, positions[currentIndex]), 0f))
        if (sphere.position != positions[currentIndex])
        {
            sphere.position = Vector3.MoveTowards(sphere.transform.position, positions[currentIndex], moveSpeed * Time.deltaTime);

            return;
        }

        // once the position is reached select the next index
        if (movingForward)
        {
            if (currentIndex + 1 < positions.Count)
            {
                currentIndex++;
            }
            else if (currentIndex + 1 >= positions.Count)
            {
                currentIndex--;
                movingForward = false;
            }
        }
        else
        {
            if (currentIndex - 1 >= 0)
            {
                currentIndex--;
            }
            else
            {
                currentIndex++;
                movingForward = true;
            }
        }
    }
}

If you want to stick to Single-Responsibility-Principles you could also seperate the movement from the list generation like e.g.

public class GetCurves : MonoBehaviour
{
    public GameObject A;
    public GameObject B;

    public int amount;
    public float moveSpeed;

    private void Start()
    {
        GeneratePositions(A.transform.position, B.transform.position, amount);
    }

    private void GeneratePositions(Vector3 posA, Vector3 posB, int numberOfObjects)
    {
        // get circle center and radius
        var radius = Vector3.Distance(posA, posB) / 2f;
        var centerPos = (posA + posB) / 2f;

        // get a rotation that looks in the direction
        // posA -> posB
        var centerDirection = Quaternion.LookRotation((posB - posA).normalized);

        List<Vector3> positions = new List<Vector3>();    

        for (var i = 0; i < numberOfObjects; i++)
        {

            var angle = Mathf.PI * (i + 1) / (numberOfObjects + 1); //180 degrees
            var x = Mathf.Sin(angle) * radius;
            var z = Mathf.Cos(angle) * radius;
            var pos = new Vector3(x, 0, z);
            // Rotate the pos vector according to the centerDirection
            pos = centerDirection * pos;

            // store them in a list this time
            positions.Add(centerPos + pos);
        }

        var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);

        var movement = sphere.AddComponent<MoveBetweenPoints>();
        movement.positions = positions;
        movement.moveSpeed = moveSpeed;
    }

and in a seperate script

public class MoveBetweenPoints : MonoBehaviour
{
    public List<Vector3> positions = new List<Vector3>();
    public float moveSpeed;

    privtae bool movingForward = true;
    private int currentIndex = 0;

    private void Update()
    {
        if (positions == null || positions.Count == 0) return;

        // == for Vectors works with precision of 0.00001
        // if you need a better precision instead use
        //if(!Mathf.Approximately(Vector3.Distance(sphere.position, positions[currentIndex]), 0f))
        if (sphere.position != positions[currentIndex])
        {
            transform.position = Vector3.MoveTowards(transform.position, positions[currentIndex], moveSpeed * Time.deltaTime);

            return;
        }

        // once the position is reached select the next index
        if (movingForward)
        {
            if (currentIndex + 1 < positions.Count)
            {
                currentIndex++;
            }
            else if (currentIndex + 1 >= positions.Count)
            {
                currentIndex--;
                movingForward = false;
            }
        }
        else
        {
            if (currentIndex - 1 >= 0)
            {
                currentIndex--;
            }
            else
            {
                currentIndex++;
                movingForward = true;
            }
        }
    }
}

enter image description here


Actual Solution

However, if you want a smooth movement on a circle curve ... why even reduce that circle curcve to a certain amount of positions? You could directly moove according to the angle between and 180° like this:

public class GetCurves : MonoBehaviour
{
    public GameObject A;
    public GameObject B;
    // now in Angles per second
    public float moveSpeed;

    private Transform sphere;
    private bool movingForward = true;
    private float angle;

    private void Start()
    {
        sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
        sphere.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
    }

    private void Update()
    {
        if (movingForward)
        {
            angle += moveSpeed * Time.deltaTime;
        }
        else
        {
            angle -= moveSpeed * Time.deltaTime;
        }

        if (angle < 0)
        {
            angle = 0;
            movingForward = true;
        }
        else if (angle > 180)
        {
            angle = 180;
            movingForward = false;
        }

        // get circle center and radius
        var radius = Vector3.Distance(A.transform.position, B.transform.position) / 2f;
        var centerPos = (A.transform.position + B.transform.position) / 2f;

        // get a rotation that looks in the direction
        // posA -> posB
        var centerDirection = Quaternion.LookRotation((B.transform.position - A.transform.position).normalized);

        var x = Mathf.Sin(angle * Mathf.Deg2Rad) * radius;
        var z = Mathf.Cos(angle * Mathf.Deg2Rad) * radius;
        var pos = new Vector3(x, 0, z);
        // Rotate the pos vector according to the centerDirection
        pos = centerDirection * pos;

        sphere.position = centerPos + pos;
    }
}