I'm developing a 2D game in Unity and have been tasked with building a particular feature I'm not sure how to accomplish with Unity's physics engine. To simplify, a bunch of objects of type X and O are filled into a pit:
XXXXXXXXXXXX
XXXXXXXXXXXX
XXXXXXXXXXXX
XXoXXXoXXXoX
Both objects have Rigidbody2Ds and colliders. Objects of type X have normal gravity and should settle into place. Objects of type O have inverse gravity and should float.
However, O should not be able to push X, and X should not be able to push O. Another way of looking at it is that O should only be able to move upward, and X should only be able to move downward. If we remove some of the Xs directly above an O, the O should float upwards as the Xs fall downwards until the Xs settle on top of the O and everything stops moving:
XXXXXXXXXXXX XX XXXXXXXXX
XX XXXXXXXXX --> XXXXXXXXXXXX
XX XXXXXXXXX --> XXoXXXXXXXXX
XXoXXXoXXXoX XX XXXoXXXoX
(In the actual game Xs and Os can be different sizes; their movement is continuous and they are not constrained into rows or columns).
The Os should be able to support the weight of any arbitrary number of Xs without sinking.
XXXXXXXXXXXX
XXXXXXXXXXXX
XooooooooooX
X X
Lastly, the Os should be able to float diagonally if there is a space available:
XXXX XXXXXXX XXX XX
XXXXX XX --> XXXXX XXXX
XXXX XXXX --> XXXXoXXXXXXX
XXXo XXXXXXX XXXX XXXXXXX
I can't solve this problem simply by adjusting the mass of the Xs or Os since the number of Xs on top of an O may vary. I can't use the built-in RigidBody constraints since they don't allow you to disable only one direction along an axis (e.g. saying an object can move upward but not downward).
What's the proper way to handle this? I could do something like this:
void FixedUpdate() {
if (movementDirection == Direction.UP) {
if (transform.position.y < lastYCoordinate) {
Vector3 position = transform.position;
position.y = lastYCoordinate;
transform.position = position;
}
}
lastYCoordinate = transform.position.y;
}
but that feels hacky to me and I suspect it will keep the objects from sleeping. Are there better solutions here?