Reputation: 45
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.
Upvotes: 0
Views: 177
Reputation: 90590
Whenever dealing with Rigidbody
or Rigidbody2D
there are two main rules
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.
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
Upvotes: 1