Мне нужна помощь в этом вопросе.Я пытаюсь сделать платформер - PullRequest
0 голосов
/ 19 сентября 2019

(Как только он достигает точки B, он плавно и упорядоченно переходит в точку A и обратно в точку B).По какой-то причине платформа отказывается двигаться и остается на месте.Я пробовал много вещей, таких как vector3.movetowards и многое другое, но ничто не заставляет его двигаться.

Вот код.(Точка A и точка B - пустые игровые объекты, которые не связаны с платформой)

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

public class MoveTwoTransforms : MonoBehaviour
{

    public Transform pointA;
    public Transform pointB;
    bool HeadingtowardsB;
    bool HeadingtowardsA;
    public float speed = 10;

    // Start is called before the first frame update
    void Start()
    {
        transform.position = pointA.position;
        HeadingtowardsB = true;
        HeadingtowardsA = false;
        GlideAround();

    }

    // Update is called once per frame
    void Update()
    {

    }

    public IEnumerator GlideAround()
    {
        while (true)
        {
            while ((Mathf.Abs((pointB.position.x - transform.position.x) + (pointB.position.y - transform.position.y)) > 0.05f) && HeadingtowardsB == true && HeadingtowardsA==false )
            {
                yield return new WaitForEndOfFrame();
                transform.position = Vector2.Lerp(transform.position, pointB.position, speed * Time.deltaTime);

                if(Mathf.Abs((pointB.position.x - transform.position.x) + (pointB.position.y - transform.position.y)) > 0.05f)
                {

                    HeadingtowardsB = false;
                    HeadingtowardsA = true;
                }

            }
            HeadingtowardsB = false;
            HeadingtowardsA = true;


            while (Mathf.Abs((pointA.position.x - transform.position.x) + (pointA.position.y - transform.position.y)) > 0.05f && HeadingtowardsA==true && HeadingtowardsB==false)
            {
                yield return new WaitForEndOfFrame();
                transform.position=transform.position=Vector3.Lerp(transform.position, pointA.position, speed*Time.deltaTime);
            }
        }
    }
}

Нет сообщений об ошибках, платформа не будет двигаться.Платформа все еще сталкивается и, похоже, ведет себя как нормальная платформа.

Ответы [ 4 ]

1 голос
/ 19 сентября 2019

GlideAround() является IEnumerator и не может быть вызван как метод.Вы должны запустить его, используя StartCoroutine

StartCoroutine(GlideAround());

Также обратите внимание, что speed * Time.deltaTime не имеет смысла для использования в Lerp.В вашем случае обычно требуется постоянное значение от 0 до 1 (поскольку вы повторно используете текущую позицию в качестве первого параметра).

Например, значение 0,5 означает: каждый кадр устанавливает новую позицию в центрмежду текущей и целевой позициями.

Так как вы ловите его с помощью предельного значения 0.05f, это должно быть хорошо, но в целом я бы не стал использовать Lerp как этот ... с очень маленькими значениями, которые выможет никогда не достичь целевой позиции.


Поэтому я предпочел бы либо контролировать постоянную скорость и использовать

bool isHeadingA = true;

while(true)
{
    // if it was intended you can ofourse also again use
    // Vector2.Distance(transform.position, isHeadingA  ? pointA.position : pointB.position) <= 0.05f)
    while (transform.position != (isHeadingA  ? pointA.position : pointB.position))
    {
        yield return new WaitForEndOfFrame();

        transform.position = Vector2.MoveTowards(transform.position, isHeadingA  ? pointA.position : pointB.position, speed * Time.deltaTime);
    }

    // flip the direction
    isHeadingA = !isHeadingA;
}

!= с точностью0.00001, и здесь все в порядке, поскольку MoveTowards избегает перерегулирования, поэтому в определенный момент он обязательно достигнет позиции, если speed != 0.


Или, альтернативно, вы можете использовать Lerpесли вы хотите контролировать продолжительность движения с сглаженной скоростью входа и выхода , используя, например, Mathf.PingPong в качестве фактора и Mathf.SmoothStep для облегчения входа и выхода, как

while(true)
{
    yield return new WaitForEndOfFrame();

    // linear pingpong between 0 and 1
    var factor = Mathf.PingPong(Time.time, 1);

    // add easing at the ends
    factor = Mathf.SmoothStep(0, 1, factor);
    // optionally add even more easing ;)
    //factor = Mathf.SmoothStep(0, 1, factor);

    transform.position = Vector2.Lerp(pointA.position, pointB.position, factor);
}
0 голосов
/ 20 сентября 2019

Вот код, который работал.

общедоступный IEnumerator GlideAround () {

    while (true)
    {
        while (HasReachedA == false)
        {
            yield return new WaitForEndOfFrame();



            transform.position = Vector2.Lerp(transform.position, pointA.position, 0.01f);
            if ((Mathf.Abs(Vector2.Distance(pointA.position, transform.position)) < 0.01f))
            {
                HasReacedB = false;
                HasReachedA = true;
            }
        }

        while (HasReacedB == false)
        {
            yield return new WaitForEndOfFrame();
            transform.position = Vector2.Lerp(transform.position, pointB.position, 0.01f);


            if ((Mathf.Abs(Vector2.Distance(pointB.position, transform.position)) < 0.01f))
            {
                HasReacedB = true;
                HasReachedA = false;
            }




        }
    }
}
0 голосов
/ 19 сентября 2019

Основная проблема в том, что вы не используете сопрограммы должным образом, как указано в ответе derHugo .


Однако я предоставлю свой собственный ответ, увидев, что высовершаем ошибку новичка в том, что way переборщили эту проблему.

Я думаю, что преподавание на примере может быть наиболее подходящим в этом случае, поэтому вот оно:

Если точки, определяющие движение платформы, статичны, вы должны сделать это с анимацией.Я не буду объяснять это здесь.Учебные пособия как этот можно легко найти во всех учебных пособиях по единству, форумах по единству, других вопросах и ответах StackOverflow и на YouTube.


Если ваши очки являются динамическими, этого более чем достаточно:

public class MoveTwoTransforms : MonoBehaviour {
    public Transform pointA;
    public Transform pointB;
    public float speed = 10;

    void Start() {
        transform.position = pointA.position;
        StartCoroutine(GlideAround());
    }

    private IEnumerator MoveTowards(Vector3 targetPosition) {
        while (transform.position != targetPosition) {
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
            yield return null;
        }
    }

    private IEnumerator GlideAround() {
        while(true) {
            yield return StartCoroutine(MoveTowards(pointA));
            yield return StartCoroutine(MoveTowards(pointB));
        }
    }
}

Просто последнее замечание: если на платформе должна быть физика или коллайдер, предпочтительно добавить Rigidbody, установить его равным kinematic и к движениюустановив Rigidbody.position вместо преобразования.Это связано с тем, что он обновляется в физическом цикле (FixedUpdate), а не в цикле кадров (Update), и позволяет избежать некоторых ошибок, связанных с асинхронностью между физической системой и движущимися объектами через позицию преобразования.

rigidbody.position = Vector3.MoveTowards(rigidbody.position, //...
0 голосов
/ 19 сентября 2019

Попробуйте это:

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

public class MoveTwoTransforms : MonoBehaviour
{

    public Transform pointA;
    public Transform pointB;
    bool HeadingtowardsB;
    bool HeadingtowardsA;
    public float speed = 10;

    // Start is called before the first frame update
    void Start()
    {
        transform.position = pointA.position;
        HeadingtowardsB = true;
        HeadingtowardsA = false;
        StartCoroutine(GlideAround());

    }

    // Update is called once per frame
    void Update()
    {

    }

    public IEnumerator GlideAround()
    {
        //Because we want a specific speed, the % between the two points 
        //that we should be at will be equal to (time * speed) / distance
        //with an adjustment for going backwards. 
        float distance = Vector3.Distance(pointA, pointB) * 2;
        float lapTime = distance / speed;
        float startTime = Time.time; 
        Debug.Log("The platform speed is: "  + speed.ToString());
        Debug.Log("The distance for one full lap is: "  + distance.ToString());
        Debug.Log("One lap will take: "  + lapTime.ToString() + " seconds");


        while (true)
        {
            yield return new WaitForEndOfFrame();
            float elapsedTime = (Time.time - startTime) % lapTime;
            float progress = elapsedTime / (lapTime / 2);
            if (progress > 1){
                progress = 2 - progress;
            }
            Debug.Log("The platform speed is currently: "  + progress.ToString() + "% between pointA and pointB");
            transform.position = Vector2.Lerp(pointA.position, pointB.position, progress);
    }
}

Как я уже упоминал в комментариях, ваш Lerp использует процент между двумя точками в качестве возвращаемого значения.Вам нужно указать процент, а не скорость.

Вот реализация, которая использует скорость, как вы и хотели, но ответ @ derHugo с PingPong намного проще!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...