Help with 2d colliding jittering

Hi, I just started making a game, it is in 2d and relies on physics, and my objects always have crazy jitter when colliding and I dont know what to do

here are my settings for the objects

the jittering only happens when i move the spaceship, when it doesnt move its fine

here is the code for the asteroids and the spaceship

spaceship:
using UnityEngine;

public class PlayerController : MonoBehaviour
{
public float moveSpeed = 5f;
private float screenHeight;
private float screenWidth;
private float objectHeight;
private float objectWidth;
private SpriteRenderer spriteRenderer;
void Start()
{
Camera camera = Camera.main;
spriteRenderer = GetComponent();

    screenHeight = camera.orthographicSize;
    screenWidth = screenHeight * camera.aspect;

    objectHeight = spriteRenderer.bounds.size.y / 2;
    objectWidth = spriteRenderer.bounds.size.x / 2;

}

void Update()
{
    float horizontalInput = Input.GetAxis("Horizontal");
    float verticalInput = Input.GetAxis("Vertical");

    Vector3 movement = new Vector3(horizontalInput, verticalInput, 0) * moveSpeed * Time.deltaTime;
    Vector3 newPosition = transform.position + movement;

    newPosition.x = Mathf.Clamp(newPosition.x, -screenWidth + objectWidth, screenWidth - objectWidth);
    newPosition.y = Mathf.Clamp(newPosition.y, -screenHeight + objectHeight, screenHeight - objectHeight);

    transform.position = newPosition;
}

}

asteroids:
using UnityEngine;
using System.Collections;

public class RandomPassThroughSpawner : MonoBehaviour
{
public GameObject objectPrefab;
public float maxSpeed = 15f;
public float minSpeed = 100f;
public float spawnDelay = 0.3f;
public float minSize = 1f;
public float maxSize = 5f;
private float screenWidth;
private float screenHeight;
private float offScreenMargin = 1.5f;

void Start()
{
    Camera camera = Camera.main;
    screenHeight = camera.orthographicSize;
    screenWidth = screenHeight * camera.aspect;

    // Start the spawning coroutine
    StartCoroutine(SpawnObject());
}

IEnumerator SpawnObject()
{
    while (true)
    {
        GameObject newObject = Instantiate(objectPrefab);

        int spawnSide = Random.Range(0, 4);
        Vector3 spawnPosition = Vector3.zero;

        switch (spawnSide)
        {
            case 0: // Top
                spawnPosition = new Vector3(Random.Range(-screenWidth, screenWidth), screenHeight * offScreenMargin, -3);
                break;
            case 1: // Bottom
                spawnPosition = new Vector3(Random.Range(-screenWidth, screenWidth), -screenHeight * offScreenMargin, -3);
                break;
            case 2: // Left
                spawnPosition = new Vector3(-screenWidth * offScreenMargin, Random.Range(-screenHeight, screenHeight), -3);
                break;
            case 3: // Right
                spawnPosition = new Vector3(screenWidth * offScreenMargin, Random.Range(-screenHeight, screenHeight), -3);
                break;
        }

        float objectSize = Random.Range(minSize, maxSize);
        newObject.transform.localScale = new Vector3(objectSize, objectSize, objectSize);

        newObject.transform.position = spawnPosition;

        float randomAngle = Random.Range(0f, 360f); // Angle in degrees
        Vector3 randomDirection = new Vector3(Mathf.Cos(randomAngle * Mathf.Deg2Rad), Mathf.Sin(randomAngle * Mathf.Deg2Rad), 0);

        float randomSpeed = Random.Range(minSpeed, maxSpeed);

        Rigidbody2D objectRb = newObject.GetComponent<Rigidbody2D>();
        objectRb.linearVelocity = randomSpeed * randomDirection;

        yield return new WaitForSeconds(spawnDelay);
    }
}

}

pls help

Show the rest of the Rigidbody2D. Use Continuous mode on important objects, like the Player.

You’re both modifying the transform.position AND using a dynamic rigidbody.

You have a choice to physically move the object (apply forces to it)

or use a Kinematic object

Read this: Unity - Manual: Introduction to Rigidbody 2D

2 Likes

Exactly, and to clarify: objects with non-kinematic rigidbodies must only be moved by adding forces otherwise collisions will not function correctly becausea direct transform manipulation allows you to position objects inside collisions, which the physics simulation then tries to correct by moving the objects apart and thus you get the jittering during collisions.

1 Like

A Rigidbody2D is NOT a renderer where you set the Transform and this is where it renders when rendering is done (per-frame obviously).

You should never set the Transform, use the Rigidbody2D API to cause movement no matter what the body type. Changing the Transform ONLY changes the Transform, it doesn’t immediately change anything else in Unity and certainly not the components such as Rigidbody2D. You can see this by setting the Transform.position then reading the Rigidbody2D.position.

When setting the Transform, it means the Rigidbody2D will be teleported (not moved through space) to the new position when the simulation runs next (during the FixedUpdate) as physics doesn’t run per-frame (by default) so doing this per-frame is even worse. Interpolation won’t be supported when you’r doing this to the Transform.

When you spawn an object with a Rigidbody2D on it, calculate where you want it first then instantiate it and pass the position/rotation to the “Instantiate” call itself. Instantiating it then modifying the Transform means it’s created at the world origin (0,0,0) then until the simulation runs, it sits there in the wrong place.

Ok, so I need to fix the player movement and apply a force, and instantiate the asteroid’s position and rotation first, thanks :slight_smile:

1 Like

i fixed but now at the edge the player is jittering, verything else is working tho
using UnityEngine;

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    private float screenHeight;
    private float screenWidth;
    private float objectHeight;
    private float objectWidth;
    private SpriteRenderer spriteRenderer;
    private Rigidbody2D rb;
    void Start()
    {
        Camera camera = Camera.main;
        spriteRenderer = GetComponent<SpriteRenderer>();

        screenHeight = camera.orthographicSize;
        screenWidth = screenHeight * camera.aspect;

        objectHeight = spriteRenderer.bounds.size.y / 2;
        objectWidth = spriteRenderer.bounds.size.x / 2;

        rb = GetComponent<Rigidbody2D>();
        rb.linearDamping = 0.0f;

    }

    void FixedUpdate()
    {
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");

        Vector2 movement = new Vector2(horizontalInput, verticalInput) * moveSpeed;

        rb.linearVelocity = movement;

        Vector2 newPosition = new Vector2(
            Mathf.Clamp(rb.position.x, -screenWidth + objectWidth, screenWidth - objectWidth),
            Mathf.Clamp(rb.position.y, -screenHeight + objectHeight, screenHeight - objectHeight));

        rb.position = newPosition;
    }

}

By “jittering” I presume you mean that physics is moving your Rigidbody2D because you’re setting a velocity but then you’re stomping over that by immediately setting the position explicity.

You set the velocity then set the position. The physics solver runs and integrates velocity to give you a new position which is likely to be outside your “clamped” window. You then repeat this over and over.

You don’t want to be setting velocity that moves you outside of your region. Either that or set-up colliders surrounding that region to you don’t have to explicly set the body position. You should always avoid this.

Try this which will only move to the clamped region and no further. If you’re already at the clamped region, it’ll not move. This means it’ll quite happily slide along the clamped edges too without going into them.

Feel free to ask any questions about it:

void FixedUpdate()
{
    var horizontalInput = Input.GetAxis("Horizontal");
    var verticalInput = Input.GetAxis("Vertical");

    // Calculate the input velocity demanded.
    var velocity = new Vector2(horizontalInput, verticalInput) * moveSpeed;

    // Calculate the future body position using the velocity.
    var bodyPosition = rb.position + velocity * Time.fixedDeltaTime;

    // Clamp the future body position to our region.
    var clampedBodyPosition = new Vector2(
        Mathf.Clamp(bodyPosition.x, -screenWidth + objectWidth, screenWidth - objectWidth),
        Mathf.Clamp(bodyPosition.y, -screenHeight + objectHeight, screenHeight - objectHeight));

    // Calculate the velocity assuming any contact with our clamped region.
    var clampedNormal = (clampedBodyPosition - bodyPosition).normalized;
    velocity -= clampedNormal * Vector2.Dot(velocity, clampedNormal);
    
    // Set the (clamped) velocity.
    rb.linearVelocity = velocity;
}

Hope this helps.

thanks, I will also try setting up a wall with colliders on

1 Like

If you’re doing that then set the player Rigidbody2D to use continuous then simply use a single EdgeCollider2D with 4 vertices defining surrounding the area.

The downside to that is that if you’re running on different resolutions then you’ll need to update those vertices.

1 Like

I looked at this code, and I dont get the part with

   var clampedNormal = (clampedBodyPosition - bodyPosition).normalized;
    velocity -= clampedNormal * Vector2.Dot(velocity, clampedNormal);

That does two things:

  1. Calculate a collision normal (or attempts to)
  2. Use the normal to remove velocity

The first part uses the body position we’d like to move to (bodyPosition) and the body position we clamp to (clampedBodyPosition). If they are the same i.e. the clamping did nothing then the “clampedNormal” is (0,0) and we’re free to move without issue. With a normal of (0,0) step 2 results in no velocity being removed as it’s clampedNormal * XXX.

If we did clamp and changed either the X or Y position then the “clampedNormal” (because it’s normalised) will be a collision normal i.e. a unit-vector in the opposite direction of the movement or in other words, pointing away from the clamped region in X/Y.

If we hit the right clamp we end up with a normal of (-1,0), the top we get a normal of (0,-1) or if we hit bottom/right we get approx (-0.7, -0.7).

When we use this in the second part, we’ll end up removing the velocity in that direction.

This is only one way of doing it though. You could also add colliders around the edge and perform a Rigidbody2D.Cast query to figure out where you’d hit and move there. Or you could use the Rigidbody2D.Slide functionality.

1 Like

ok it works now thank you

1 Like