Door: Thijs Zumbrink
For my latest game Build a Thing (link) I tried out multiple methods of item placement. After some experimentation I settled on the current solution, which feels really solid and intuitive. This post explains the implementation details.
The game is a simple item stacker game, implemented in Unity. The player takes the next item and places it somewhere on the pile. A higher reached altitude results in a higher score. Unsurprisingly. the core mechanic of the game is item placement. It has the following characteristics:
Items in the pile respect physics
The currently dragged item can only be placed where it is not intersecting another object
Items in the pile interact with the currently dragged item
The currently dragged item does not influence the pile, until dropped
Those last two items sum up to a sort of "one-way physics", where two items interact but only one of the is affected.
For a visual demonstration, watch this short video:
Adding physics simulation for pile items
The approach of adding physics is pretty simple: each item has a Rigidbody2D, a sprite, an underlying shape and a certain material. The shape, using a Collider2D, is modeled to form relatively straight edges so stacking items becomes a bit easier. The material provides sliding and bouncing properties.
Restricting placement inside other objects
An issue pops up however when we add straightforward dragging behavior to the items. If we set the object position to the cursor position each frame, we bump into items in the pile. Worse, we can squish them into the ground or place our dragged item into the ground, since the ground is kinematic.
To solve both issues, I applied a spring/damper system. When the player drags the cursor, the item is pulled toward it using a spring force. A damper force is used to avoid endless oscillation. Both these forces are set to pretty high values, so movement is responsive. But this raises another issue: if we try drag an item into the ground, it bounces wildly since the applied forces are so big.
To remedy this, I implemented the Gentle Touch™ technique. After the spring force is calculated, I sweep the object in that direction to see if it is near anything that it could collide with. If so, the spring force gets reduced according to the relative distance. This completely eliminates any erratic behavior.
One-way interaction between dragged item and pile
So far the implementation allows for dragging items in a way that feels nice. However, one inconvenience for this game is that we can now knock over the pile while dragging! It would be nicer to follow the contours of the pile without being able to influence it.
To do this, a trick can be used involving kinematic RigidBodies and the collision matrix. Every item that is part of the pile gets an invisible counterpart. Its renderer is removed, its RigidBody is set to kinematic, and it follows the original position and orientation. These "ghost items" are in a special layer, the "dragging layer", that does not collide with the real pile items. Since they are in the dragging layer, they do interact with the item that the player is currently dragging, but since they are kinematic, the dragged items do not influence them. And since the original items are not kinematic, they still follow the normal physics rules.
Ghost item counterpart