Мой сборный игрок прекрасно двигается вперед, пока не достигнет объекта, что происходит? - PullRequest
0 голосов
/ 18 марта 2020

Я делаю игру для единства, основанную на TierZoo, и во время тестирования сценария движения я врезалась в одно из деревьев твердого тела для забавы ... и это заставило сборного игрока перестать двигаться вперед, и он начал двигаться в странные указания Вот мой код:

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

public class NewPlayerController : MonoBehaviour
{
    private Rigidbody rb;
    public GameObject player;
    public float thrust = 1.0f;
    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            rb.AddRelativeForce(player.transform.right * thrust * 2.5f);
        }
        if (Input.GetKey(KeyCode.A)) { player.transform.Rotate(0, -1, 0); }
        if (Input.GetKey(KeyCode.D)) { player.transform.Rotate(0, 1, 0); }
        if (Input.GetKey(KeyCode.S))
        {
            rb.AddRelativeForce(player.transform.right * thrust * -2.5f);
        }
    }
}

Если вы можете найти способ исправить это, дайте мне знать.

1 Ответ

0 голосов
/ 18 марта 2020

Вы также можете зафиксировать вращение в направлении Y, отслеживая его и устанавливая жестко в FixedUpdate.

В общем, как сказано в комментариях:

Всякий раз, когда Rigidbody задействован, вы должны не

  • делать движения через transform компонент
  • выполняет движения в Update

, оба ломают физический движок, и вы можете получить странные и неожиданные движения или просто не работать при столкновении и т. Д. c.

Скорее выполните - go через Rigidbody компонент, например, используя MovePosition и MoveRotation - сделайте это в FixedUpdate

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

Тогда для вращения у вас есть зависящие от частоты кадров значения Rotate(0, -1, 0)! Вы скорее хотите использовать Time.deltaTime, чтобы получить плавную независимую от частоты кадров скорость вращения - не в 1 градус за кадр, а, например, 45 градусов в секунду.

Ваш скрипт может выглядеть как

public class NewPlayerController : MonoBehaviour
{
    // already reference this via the Inspector
    [SerializeField] private Rigidbody rb;
    public GameObject player;
    public float thrust = 1.0f;

    private void Awake()
    {
        // as fallback get it on runtime
        if(!rb) rb = GetComponent<Rigidbody>();
    }

    bool moveLeft;
    bool moveRight;
    bool rotateLeft;
    bool rotateRight;

    private float angle;

    void Update()
    {
        // Get User input here 
        // (in your case it would be also fine to do it in FixedUpdate.
        //  What doesn't work in FixedUpdate are mainly the one-time events like GetKeyDown)
        moveRight = Input.GetKey(KeyCode.W);
        rotateLeft = Input.GetKey(KeyCode.A);
        rotateRight = Input.GetKey(KeyCode.D);
        moveLeft = Input.GetKey(KeyCode.S); 
    }

    private void FixedUpdate()
    {
        if(moveRight) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * 2.5f);
        if(moveLeft) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * -2.5f);

        // Now for the rotations keep track of what you rotated already
        // and overwrite the rotation with the fix value:
        if(rotateLeft)
        {
            // e.g. for rotating 45°/second
            angle -= -45 * Time.deltaTime; 
            rb.MoveRotation(Quaternion.Euler(0, angle, 0));
        }
        if(rotateRight)
        {
            angle += 45 * Time.deltaTime; 
            rb.MoveRotation(Quaternion.Euler(0, angle, 0));
        }
    }
}
...