- Home /
Problem is not reproducible or outdated
Unity 2d Physics Collision Jumping / Glitching
I'm having trouble with a rotating canister object colliding with static box collider objects. Basically, I'm trying to replicate in 2D those explosive gas canisters from Half-Life 2 that push themselves around via escaping gas resulting in much hilarity and hi-jinx.
The canister is a 2d box collider with continuous collision detection enabled and a 2d rigid body and the background objects are static 2d box colliders. I'm using body.AddForceAtPosition(-gasEscapePosition * gasLeakForce, gasEscapePosition) to move the object around in FixedUpdate.
When the canister collides with any walls, its causing the object to jump for a frame and looks terrible. This has only been a problem since I started using AddForceAtPosition instead of AddForce.
Here is a gif of it jumping around: image link
Also, here is the movement code:
using UnityEngine;
public class CanisterHealth : Health
{
public override float maxHealth { get { return 30.0f; } set { } }
public override float drain { get { return 0.0f; } }
// Canister Variables
public bool gasLeak = false;
public float gasLeakForce;
public float explosionDelay;
public float timeToDie;
public Vector2 gasEscapePosition;
public float gasEscapeOffSet;
// Vacuum variables
public GameObject gasLeakParticles;
/* Cached components */
[HideInInspector] public Rigidbody2D body;
public void Start()
{
// Cache component lookups
body = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (gasLeak && Time.time > timeToDie) Explode();
}
private void FixedUpdate()
{
if (gasLeak) GasLeak();
}
// Decrement the props's health by amount and set color
public override void Damage(float amount, ContactPoint2D contactPoint)
{
// Flash body if damaged to give feedback
if (health > 0)
{
if (!flashing) StartCoroutine(Flash());
health -= amount;
}
// Flash body and reduce time to die if already leaking
else if (gasLeak)
{
if (!flashing) StartCoroutine(Flash());
timeToDie -= amount * 0.1f;
}
// Start gas leak
else if (health <= 0 && !gasLeak && canDie)
{
Dying(contactPoint);
}
}
public void Dying(ContactPoint2D contactPoint)
{
if (gasLeakParticles)
{
// Create gas escape position and direction
gasEscapePosition = contactPoint.normal;
float targetAngle = (Mathf.Atan2(gasEscapePosition.y, gasEscapePosition.x) * Mathf.Rad2Deg) + gasEscapeOffSet;
Quaternion rotation = Quaternion.AngleAxis(targetAngle, Vector3.forward);
// Create gas VFX and add as child of canister object so they remain attached
GameObject vfx = Instantiate(gasLeakParticles, contactPoint.point, rotation) as GameObject;
vfx.transform.parent = tr;
}
gasLeak = true;
timeToDie = Time.time + explosionDelay;
}
private void Explode()
{
// Create delayed explosion and vacuum if an outside wall
if (explosion != null) Instantiate(explosion, tr.position, Quaternion.identity);
// Kill the poor object - :(
Destroy(this.gameObject);
}
private void GasLeak()
{
// Add blow force from escape point
body.AddForceAtPosition(-gasEscapePosition * gasLeakForce, gasEscapePosition);
}
}
Any ideas as to why?
Rigidbody2D.AddForceAtPosition uses world-space as the position. Your usage seems very odd in that you're using some world-space position * gasLeakForce as the force. Are you mixing-up world/local-spaces?
You can convert between global and local-spaces using Rigidbody2D.GetRelativePoint and Rigidbody2D.GetPoint.
Already solved this while I was waiting for it to be approved. It was a world and local space mix-up, yeah.
Thanks anyway $$anonymous$$elv.