Создать только одну сферу, которая перемещается между двумя точками в петле внутри полукруга? - PullRequest
0 голосов
/ 25 июня 2019

Относительно вопроса, заданного здесь ( Как поместить сферы в форме полукруга между 2 точками ), которые генерируют сферы между двумя точками A и B. Как создать только одну сферу, которая перемещается из точки A в точку B, а затем обратно из точки B в точку A в цикле цикла? Как мне использовать Lerp в этом контексте?

Я пытался заставить сферу двигаться под углом (полукругом), описанным в приведенном ниже коде, но она всегда движется по прямой линии.

Приведенный ниже код создает сферы между двумя точками.

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

Приведенный ниже скрипт, который заставляет объект перемещаться между двумя точками в цикле, но только по прямой линии. Как заставить его двигаться по кривой (180 градусов)?

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 Ответ

2 голосов
/ 25 июня 2019

Решение с использованием вашего кода

Как я уже говорил вам в моем последнем ответе , который предоставил ваш первый код, вы должны сохранить их в списке, а затем заставить объект перемещаться между ними:

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

Если вы хотите придерживаться Принципов единой ответственности, вы также можете отделить движение от генерации списка, например,

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

и в отдельном сценарии

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


Фактическое решение

Однако, если вам нужно плавное движение по кривой круга ... зачем даже уменьшатьэтот круг изогнут до определенного количества позиций?Вы можете прямо передвигаться в зависимости от угла между и 180° следующим образом:

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...