简体   繁体   中英

Clamp rigidbody2D Controller

I have a class that deals with the control of a ship, and I want to clamp the position on the y axis.

 public class ControlledRigidbody2D : MonoBehaviour
{
public float verticalInputAcceleration = 1;
public float horizontalInputAcceleration = 20;
public float maxSpeed = 10;
public float velocityDrag = 1;
private Vector3 velocity;
private void Update()
{
    Vector3 acceleration = Input.GetAxis("Vertical") * verticalInputAcceleration * transform.up;
    velocity.y += acceleration.y * Time.deltaTime;
    Vector3 accelerationRight = Input.GetAxis("Horizontal") * horizontalInputAcceleration * transform.right;
    velocity.x += accelerationRight.x * Time.deltaTime; ;
    velocity = velocity * (1 - Time.deltaTime * velocityDrag);
    velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
    transform.position += velocity * Time.deltaTime;
}
}

Thank you very much in advance.

Whenever dealing with Rigidbody or Rigidbody2D there are two main rules

  1. Do not do things in Update but rather in FixedUpdate which is used for all Physics and Physics2D engine related calculation.

    Moving the object in Update would cause some jitter and braking the Physics reactions like collisions etc.

  2. Do not go directly through the Transform component but use properties and methods of the Rigidbody or Rigidbody2D instead!

    Like in your case Rigidbody2D.MovePosition or Rigidbody2D.velocity

    Again moving the object via the Transform component breaks the Physics

so your code should be like

// already reference the component via the Inspector
[SerializeField] Rigidbody2D rb;

Vector3 acceleration;
Vector3 accelerationRight;

privtae void Awake()
{
    if(!rb) rb = GetComponent<Rigidbody2D>();
}

// Get user input within Update
private void Update()
{
    acceleration = Input.GetAxis("Vertical") * verticalInputAcceleration * transform.up;
    accelerationRight = Input.GetAxis("Horizontal") * horizontalInputAcceleration * transform.right;
}

// update the Rigidbody in FixedUpdate
private void FixedUpdate()
{
    velocity = rb.velocity;

    // do these here so Time.deltaTime uses the correct value
    velocity += acceleration * Time.deltaTime;
    velocity += accelerationRight * Time.deltaTime;
    velocity = velocity * (1 - Time.deltaTime * velocityDrag);
    velocity = Vector3.ClampMagnitude(velocity, maxSpeed);

    // Problem: MovePosition expects a value in global world space
    // so if your velocity is in local space 
    // - which seems to be the case  - you will have to convert 
    // it into a global position first
    var newPosition = rb.position + transform.TransformDirection(velocity  * Time.deltaTime);
    rb.MovePosition(newPosition);
}

or alternatively you could also simply directly assign this new velocity to the rigidbody

// update the Rigidbody in FixedUpdate
private void FixedUpdate()
{
    velocity = rb.velocity;

    // do these here so Time.deltaTime uses the correct value
    velocity += acceleration * Time.deltaTime;
    velocity += accelerationRight * Time.deltaTime;
    velocity = velocity * (1 - Time.deltaTime * velocityDrag);
    velocity = Vector3.ClampMagnitude(velocity, maxSpeed);

    rb.velocity = velocity;
}

Typed on smartphone but I hope the idea gets clear

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM