Как перейти к точке с помощью CharacterController?

#c# #unity3d

#c# #unity3d

Вопрос:

У меня есть скрипт для перехода, но он переходит в зависимости от значения константы JumpFactor. Я бы хотел, чтобы переход произошел с использованием метода JumpToPositionX (float target). Я думаю, мне нужно как-то вычислить JumpFactor в зависимости от значения цели в методе JumpToPositionX. Я нашел статью в Википедии, но я даже не знаю, с чего начать. Я не нашел примеров того, как это сделать с помощью CharacterController.

 public class ExampleClass : MonoBehaviour
{
    const float Speed = 6f;
    const float JumpFactor = 14f;
    const float Gravity = 20f;
    
    private Vector3 moveDirection = Vector3.zero;

    CharacterController controller;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        if (controller.isGrounded)
        {
            moveDirection = new Vector3(1f, 0f, 0f); // Move X Direction
            moveDirection *= Speed;
            if (Input.GetButton("Jump"))
                moveDirection.y = JumpFactor;

        }
        moveDirection.y -= Gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
    }

    // Method for jump, calling from other script.
    void JumpToPositionX(float target)
    {
    }
}
  

Ответ №1:

Теория

Я предполагаю, что вы хотите использовать баллистическую физику.

Давайте посмотрим, какую формулу мы можем использовать

speedFormula

positionFormula

Где :

  • V: Скорость
  • a: Ускорение
  • P: Позиция
  • t: время с момента запуска
  • 0: Начальный

известно, что это (0f,-9.81f) или (0f, Gravity) в вашем случае.

также известно, что это ваша начальная позиция перед переходом.

это конечная целевая позиция.

Разрешение

Вы должны найти время окончания и начальную скорость. Итак, вот уравнение положения:

Мы можем упростить процесс, просматривая только ось x, потому что ускорения нет.

упрощается до :

Давайте вычленим из формулы позиции x :

Теперь у вас есть общее время перехода. Вам просто нужно найти начальную скорость y, используя формулу положения y :

Изолировать Vyo :

Итак, теперь у вас есть вся информация для вычисления перехода: начальная и конечная позиция, общее время, начальная скорость и ускорение.

Реализация

Вот пример моноповедения, которое вы можете создать :

 public class JumpBehaviour : MonoBehaviour
{

    public CharacterController CharacterController;

    public Transform TargetPosition;

    private bool jumpStarted = false;
    private float totalTime = 0f;
    private float t = 0f;
    private Vector2 V0;

    private Vector2 initialPosition;

    private bool jumpKeyDown;

    private const float xSpeed = 6f;
    private const float gravity = -9.81f;

    void Update()
    {
        jumpKeyDown = Input.GetKeyDown(KeyCode.Space);
    }

    void FixedUpdate()
    {
        if (jumpStarted)
        {
            UpdateJumpPosition(Time.fixedDeltaTime);
        }
        else if (jumpKeyDown )
        {
            StartJump();
        }
    }

    private void UpdateJumpPosition(float deltaTime)
    {
        t  = deltaTime;

        if(t > totalTime)
        {
            //End of jump
            transform.position = TargetPosition.position;
            jumpStarted = false;
            return;
        }

        Vector2 newPosition = new Vector2(0f, gravity) * t * t   V0 * t   initialPosition;

        CharacterController.Move(newPosition);
    }

    private void StartJump()
    {
        jumpStarted = true;

        initialPosition = transform.position;

        // Absolute because xSpeed could be positive or negative. We dont want negative time
        float delta = TargetPosition.position.x - transform.position.x;
        totalTime = Mathf.Abs(delta / xSpeed);
        t = 0f;

        float yInitialSpeed = (TargetPosition.position.y - transform.position.y - gravity * totalTime * totalTime) / totalTime;

        // Using Sign to set the direction of horizontal movement
        V0 = new Vector2(xSpeed * Mathf.Sign(delta), yInitialSpeed);
    }
}
  

И это результат
результат unity

Заключение

Это всего лишь краткий пример, позволяющий понять, как вычислить начальное значение перехода и перемещения в 2D. Как сказал дерХуго в комментарии, вы не должны использовать transform.position прямую атрибуцию с помощью Physic.

Для 3D это та же идея, но вы должны вычислить скорость x, z из целевого направления и величины скорости.

 Vector3 delta = TargetPosition - transform.position;
delta.y = 0f;
float direction = delta.normalized;
Vector3 initialSpeed = direction * movementSpeed;
  

Комментарии:

1. Это хорошо и прекрасно.. НО всякий раз, когда в Unity задействована какая-либо Rigidbody (физика), вы НЕ должны изменять или получать доступ к каким-либо значениям через Transform компонент (в котором вы это делаете transform.position = newPosition; ). Это нарушает физику и все обнаружение столкновений и, следовательно, всю цель CharacterController 😉 То, что вы хотите сделать, это скорее пройти через controller.Move метод

2. ДА. Это всего лишь простой пример, если не требуется никаких физических действий. В противном случае он / она должен адаптировать способ перемещения GameObject, но, по крайней мере, у него / нее есть формула для вычисления положения сверхурочно и начальной скорости.

3. @derHugo Я отредактировал, чтобы добавить больше информации. Как вы думаете, это лучше?

4. Вы правы. Возможно, я добавлю пример с CharacterController.

5. @D.B обратите внимание, что вы все равно должны получать пользовательский ввод ( GetKeyDown ) только в Update , поскольку нельзя гарантировать, что он все еще действителен в FixedUpdate вызове 😉 Кроме того, я бы все равно получил позицию через var xyz = GetComponent<Rigidbody>().position и установил ее через GetComponent<Rigidbody>().MovePosition(xyz); , чтобы не нарушать физику 😉 .. конечно, вы кэшируете Rigidbody ссылку, как обычно