You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am working on a 2D physics-based shmup, in the vein of Luftrausers, Jet Lancer, or Hyperspace Dogfights. I have decided to use rigid bodies for pretty much all entities in the game (players, enemies, bullets, etc), to take advantage of nice features like multiple gravity fields, mass, inertia, etc. However, there is a problem.
I often want these bodies to be able to detect collisions between one another. However, I do not want the bodies to behave like solid objects and bounce off each other in all collisions, only some collisions.
(For example: some bullets should be able to pierce enemies. If the player collides with an enemy, both should take damage, but neither should bounce off the other. However, players, enemies, and bullets _should_ bounce off of the ground.)
Workarounds
There are a few workarounds. Some of them are more suitable than others.
A. Place bodies on different collision layers/masks.
This prevents collision response, but it also prevents collision detection altogether, and is not suitable for my use case as a result.
B. Use Area2Ds for bullets.
This is the commonly proposed solution to this issue, and it does allow collision detection without solid objects, but it has some issues.
As far as I am aware, Area2Ds do not support continuous collision detection. If objects are moving fast enough, that can be an issue.
More importantly, using an Area2D means I lose out on nice physics behavior like mass, inertia, damping, gravity etc. and have to reimplement many of those things manually. While doable, this is not ideal.
While bullets don't need much physics behavior, the player and enemies do, and they need to be able to share this same collision behavior.
C. A combination of A and B
This is what I've settled on so far in my game. Each RigidBody2D also has an Area2D child with the same collision shape, but the masks are configured so that the Area2D detects collisions with things the RigidBody2D does not. This allows for a good amount of control over what interacts with what and how, but it is tedious (and rather error-prone) to set up, and it still potentially has the same tunneling issue as B. It works, but it isn't ideal.
The A Solution
A relatively simple1 way to do this without breaking backwards compatibility would be to add a solid boolean property to the RigidBody2D class, that defaults to true (or field with the opposite meaning that defaults to false, if that's more practical).
If two bodies would normally collide, and both have solid set to true, respond to the collision the same way as they do currently.
If two bodies would normally collide, and only one is solid, the behavior is the same. Maybe this should be configurable somehow, but I don't know. This seems like a reasonable default which sort of mirrors the way the layer/mask system already works, vibe-wise.
If two bodies would normally collide, but neither body is solid, they do not physically respond to the collision. However, if they have contact reporting enabled, the contact is still reported, so that users may respond to the collision however they desire in code.
(A less simple solution would be to implement something parallel to the existing collision masks to define which body combinations would experience "non-solid" collisions, but I have no thoughts on how that would work beyond an expectation that the usability would be quite poor.)
I have no idea how performant this would be, but it would be a great help and as far as I can tell is currently impossible to implement in GDScript or C#.
Footnotes
I have absolutely no idea how simple this would actually be. Probably less simple than I think. ↩
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
The Problem
I am working on a 2D physics-based shmup, in the vein of Luftrausers, Jet Lancer, or Hyperspace Dogfights. I have decided to use rigid bodies for pretty much all entities in the game (players, enemies, bullets, etc), to take advantage of nice features like multiple gravity fields, mass, inertia, etc. However, there is a problem.
I often want these bodies to be able to detect collisions between one another. However, I do not want the bodies to behave like solid objects and bounce off each other in all collisions, only some collisions.
(For example: some bullets should be able to pierce enemies. If the player collides with an enemy, both should take damage, but neither should bounce off the other. However, players, enemies, and bullets _should_ bounce off of the ground.)Workarounds
There are a few workarounds. Some of them are more suitable than others.
A. Place bodies on different collision layers/masks.
This prevents collision response, but it also prevents collision detection altogether, and is not suitable for my use case as a result.
B. Use
Area2D
s for bullets.This is the commonly proposed solution to this issue, and it does allow collision detection without solid objects, but it has some issues.
Area2D
s do not support continuous collision detection. If objects are moving fast enough, that can be an issue.Area2D
means I lose out on nice physics behavior like mass, inertia, damping, gravity etc. and have to reimplement many of those things manually. While doable, this is not ideal.C. A combination of A and B
This is what I've settled on so far in my game. Each
RigidBody2D
also has anArea2D
child with the same collision shape, but the masks are configured so that theArea2D
detects collisions with things theRigidBody2D
does not. This allows for a good amount of control over what interacts with what and how, but it is tedious (and rather error-prone) to set up, and it still potentially has the same tunneling issue as B. It works, but it isn't ideal.TheA SolutionA relatively simple1 way to do this without breaking backwards compatibility would be to add a
solid
boolean property to theRigidBody2D
class, that defaults to true (or field with the opposite meaning that defaults to false, if that's more practical).solid
set to true, respond to the collision the same way as they do currently.solid
, the behavior is the same. Maybe this should be configurable somehow, but I don't know. This seems like a reasonable default which sort of mirrors the way the layer/mask system already works, vibe-wise.solid
, they do not physically respond to the collision. However, if they have contact reporting enabled, the contact is still reported, so that users may respond to the collision however they desire in code.I have no idea how performant this would be, but it would be a great help and as far as I can tell is currently impossible to implement in GDScript or C#.
Footnotes
I have absolutely no idea how simple this would actually be. Probably less simple than I think. ↩
Beta Was this translation helpful? Give feedback.
All reactions