Been messing a lot with these 2D features, love them ! But came something I really need rigidbody2d.AddExplosionForce, it exists within the regular rigidbody but not in the rigidbody2d. Anyone have any ideas, or a away around get this to work? Really hoping they'll add it later.
Agreed. Also missing, and equally as important IMHO, is an equivalent for applying a ForceType, and also applying a rigidbody2d.rotation I hope the Rigidbody2D class gets expanded to be as full-featured as the 3D class in short order. In its current state it is useless for my game and we stick with PhysX just because of its feature-completeness. Also on the wishlist is the ability to change the axes the entire new 2D system works with. Our game is currently built on the XZ (top-down) not XY axes, which is unchangeable because this is also the only orientation of a NavMesh, AFAIK. Seems like a huge oversight to not have the 2D features compatible with their own NavMesh system.
Cool. Who did you contact at support? I'd really like to get in touch with them regarding the other missing features mentioned above, and it would be good to know they are going to a willing listener.
This is the extension script I'm currently using as a workaround. Don't know if that's of any use for you guys: Code (csharp): public static class Rigidbody2DExtension { public static void AddExplosionForce(this Rigidbody2D body, float explosionForce, Vector3 explosionPosition, float explosionRadius) { var dir = (body.transform.position - explosionPosition); float wearoff = 1 - (dir.magnitude / explosionRadius); body.AddForce(dir.normalized * explosionForce * wearoff); } public static void AddExplosionForce(this Rigidbody2D body, float explosionForce, Vector3 explosionPosition, float explosionRadius, float upliftModifier) { var dir = (body.transform.position - explosionPosition); float wearoff = 1 - (dir.magnitude / explosionRadius); Vector3 baseForce = dir.normalized * explosionForce * wearoff; body.AddForce(baseForce); float upliftWearoff = 1 - upliftModifier / explosionRadius; Vector3 upliftForce = Vector2.up * explosionForce * upliftWearoff; body.AddForce(upliftForce); } }
I have added a whole bunch of missing methods, unfortunately these didn't make it into the 4.3 release. If you are referring to ForceMode type used in the AddForce methods (etc) then this has been added since the 4.3 release. Can you not use the Rigidbody2D AddTorque method or just modify the angularVelocity property directly or were you referring to something else?
Thanks for the reply! I was referring to ForceMode; my mistake. And excellent! In 3D, rigidbody.rotation sets the rotation (Quanternion) *directly* without force or velocity. It is akin to changing the Transform values, but my understanding is that setting it in rigidbody.rotation doesn't fight the physics step. For example, in currently using the 3D physics system, my (2D) player character gets its rotation changed directly to face the user's input direction, but also generally moves and bounces around by forces and interactions in the world. I did try merely setting transform.rotation, but there is a visible "jitter" every frame where the player shakes when he also has an angular velocity from bouncing around the world etc. Rigidbody.rotation eliminates this problem and plays much more nicely with the angular velocities in play. So that's why I'd like to see this method in the 2D rigidbody as well, if possible. I'm sure the MoveRotation and MovePosition methods would be similarly useful to others, as well. Those additionally check for collisions between the two positions.
I'm not sure I appreciate the need for setting the 2D rigid-body directly so it's out of sync with the transform until the next physics update. Either way, setting the rigid-body directly is bad for physics and performance just as setting indirectly via the transform is. It seems like this is just different way of potentially encouraging bad behaviour. Unfortunately, this is not true at all. It causes contacts to (eventually) be re-evaluated and has other potential side-effects in Box2D. Here's what happens: If you change the rigid-body position or rotation (say I expose Rigidbody2D.position and rotation) then any interpolation/extrapolation until the next physic update would have to stop so smooth motion until the next update ceases and if this continually happens then you'll get jitter. If interpolation is off, you'll continue to render at the transform position but that won't match the Rigid-body position. This doesn't provide any benefit I can see. So until the next physics update the rigid-body and the transform won't match and it'll render at the current interpolated position or if interpolation is off, it'll render at the rigid-body position *before* you updated it. When the next physics update comes along, the rigid-body change will update the transform or, if interpolation is on, it'll interpolate from the rigid-body position you set to the position the physics system has updated to (assuming it's different). Don't get me wrong here though; I'm not trying to be obstructive or anything, my intention is to try to ensure we don't just copy the Physics 3D API into the 2D one blindly as there are a bunch of things that we are considering changing/deprecating later for 3D so we'd like to keep 2D as "clean" as possible. Of course this doesn't mean we should sacrifice useful functionality so If I can fully understand the use-case and it's real, it'll go in. Yes and that's coming although it really should only work for kinematic bodies. For dynamic bodies it's terrible for performance and doesn't give the correct behaviour i.e. only kinematic bodies will not be affected by collisions during the move position/rotation. With MoveRotation/MovePosition in-place and using a kinematic body you should be good to go.
Hmm, interesting. All I can do is defend my own usage of the method to which I don't think there is an appropriate way of emulating the behaviour through forces or angular velocity. When there is user input in any direction, I quickly (but smoothly) lerp the rotation value of the rigidbody to match and follow the input, so that the player character is pointing in the direction of input. When there isn't user input in a direction, then I stop setting the rigidbody.rotation. What happens at that point is a unique behvaviour and why I like to do things this way. Although the rigidbody has been directly pointing in the direction of user input for a while. as soon as I stop setting the rotation directly, there is a continuation of the momentum in angular velocity. In other words, the rigidbody will then have a bit of angular momentum in the direction of something that would have physically caused him to turn a bit a couple seconds ago (ie something hit his side and would have caused him to spin if this hadn't been overcome by rigidbody.rotation). So you see the residual effects of that previous momentum on the rigidbody as soon as direct control is released. I know this is probably an edge case, but I do really like the mix of arcade-controls and physical interaction this gives us, and I can't think of any other way it'd be possible. It gives a feeling of being bounced around the world, even though the player always has very direct control of the character. What is interesting is that although I am using Interpolation and have a fairly high difference between my physics timestep and actual graphical framerate, I'm not seeing the negative jitter effects on interpolation that you mentioned should be happening. Perhaps because I am only setting the rotation by very small (lerped) amounts each frame. On a philosophical note: You can disallow something because it is a bad idea programatically, but that doesn't mean it is a bad idea for the game. An improper usage might be the only way to achieve a great game in some circumstances!
MoveRotation is indeed very important. I have a ship that should be turned in the direction where the joystick is pushed. With 3D rigidbody it is done like this: targetAngle = Mathf.Rad2Deg * Mathf.Atan2(controlAxis2.y, controlAxis2.x) + 90f; //Move object angle towards target angle using linear interpolation currentAngle = Mathf.LerpAngle(currentAngle, targetAngle, rotationDamping/2 * Time.fixedDeltaTime); //Rotate object using physics handled MoveRotation rigidbody.MoveRotation(Quaternion.Euler(new Vector3(0f,currentAngle, 0f))); This is a top-down shooter, so it is the y-value that is rotated... But how on earth could that be done with AddTorque only?
I just logged in liked your reply and needed to say this was amazingly useful for me as I needed it for my game desperately.
Minor improvement to Swamy's excellent snippet, preventing attraction/negative explosion forces from happening, when radius is small: Code (csharp): public static class Rigidbody2DExtension { public static void AddExplosionForce(this Rigidbody2D body, float explosionForce, Vector3 explosionPosition, float explosionRadius) { var dir = (body.transform.position - explosionPosition); float wearoff = 1 - (dir.magnitude / explosionRadius); body.AddForce(dir.normalized * (wearoff <= 0f ? 0f : explosionForce) * wearoff); } public static void AddExplosionForce(this Rigidbody2D body, float explosionForce, Vector3 explosionPosition, float explosionRadius, float upliftModifier) { var dir = (body.transform.position - explosionPosition); float wearoff = 1 - (dir.magnitude / explosionRadius); Vector3 baseForce = dir.normalized * (wearoff <= 0f ? 0f : explosionForce) * wearoff; body.AddForce(baseForce); float upliftWearoff = 1 - upliftModifier / explosionRadius; Vector3 upliftForce = Vector2.up * explosionForce * upliftWearoff; body.AddForce(upliftForce); } }
I have used free asset on the asset store : https://assetstore.unity.com/packages/tools/physics/2d-explosion-force-24077 and then i found this paid asset : https://assetstore.unity.com/packages/tools/physics/explosion-force-2d-123077 I've also researched on google and the best solution for me was the paid asset. Free one works, but it's basic and simple. Paid one is well... paid. It has great features and comes with ready to use explosions.
If you just simply subtract the object's position with the explosion force, then the larger the distance the larger the force. Therefore you would need to make the distance Inversely Proportional to the force. This can be done if you know the Max Distance the bomb can effect. Furthermore, if the distance is negative switch the Max Distance into a negative. Code (CSharp): void ExplosionForce(List<Collider2D> players) { foreach (Collider2D hit in players) { Rigidbody2D rb = hit.GetComponent<Rigidbody2D>(); float x = MaxDistance - (rb.position.x - transform.position.x); float y = MaxDistance - (rb.position.y - transform.position.y); if (x > MaxDistance) { x = -MaxDistance - (rb.position.x - transform.position.x); } if (y > MaxDistance) { y = -MaxDistance - (rb.position.y - transform.position.y); } rb.AddForce(new Vector2(x,y)/2, ForceMode2D.Impulse); } }
When I try this on a large physics object, it barely pushes it when I have an absurdly high explosion force. If your explosion radius isn't big enough, it's common to see wearoff go negative and turn the whole force to 0. I used the collision's attachedRigidBody as the body to add the force to.
I can't believe this. I came here to find a 2D implementation for AddExplosionForce. I find garbage. Here is the modified AddExplosionForce script from MaDDoX, originally Swampy. The blue cube is a rigidbody at (-0.683411, 0.679397) with AddExplosionForce(10f, Vector3.zero, 5f, 1f, ForceMode.Impulse). The red square is the exact same, except that it uses a Rigidbody2D and the Rigidbody2D AddExplosionForce method. I'm sorry, but I mean, common... I wanna be a nice guy but this one would be a dev-job-deal breaker. All kidding aside, I didn't came just to S*** talk. Here's my own method: Apart from the torque, which has been a real B to figure out, the movement is 100% solid lock-and-loaded double barrels accurate. Seriously I shot Tim and Tom here at a 5000 impulse force escape velocity and 10 seconds later their positions still matched. By all means, partake. When you download the Rigidbody2DExtensions.txt, make sure to change it to a .xml and put it in the same directory as the Rigidbody2DExtensions so the methods are correctly documented. If anyone finds out how to get that rotation right, optimize it better (I did my best but it can always be better), or has any issues with more complex bodies, I haven't tested those, please let me know.
I did some more testing on that rotation and annoyingly my code is correct. In 3D, both these methods shoot a rigidbody in exactly the same way, it is 1 to 1. Code (CSharp): void UnityMethod() { rigidbody.AddExplosionForce(force, pos, 0f, upwards, mode); } void MyMethod() { // This is under the right conditions the same way force is applied in 2D. var upPos = pos + Vector3.down * upwards; var newPos = rigidbody.ClosestPointOnBounds(upPos); var dir = (newPos - upPos).normalized; rigidbody.AddForceAtPosition(dir * force, newPos, mode); } It just seems to be a difference of Rigidbody2D rotation calculations and / or inertia. I did find a hack that works every time, even if it's very impractical. If you apply AddExplosionForce to a rigidbody, then do this: Code (CSharp): var angularVelocity = rigidbody.angularVelocity.z; rigidbody2D.angularVelocity = angularVelocity * Mathf.Rad2Deg; The rotations match perfectly. This only works if the rigidbody and rigidbody2D aren't already rotating.