Unity2D: Apply gravity to some items, when everything else is gravity-free?

Sorry for the incredibly vague title: Let's say you have an NPC, and when he dies he'll spawn items, coins for example. Instead of just pushing the coins in random directions it would look a lot neater if they coins arced to the ground (see picture below)

The red circle represents a dead npc, the black lines represents gold coins.

Every entity in my game has a RigidBody2D with gravity set to 0, otherwise they'd fall to the bottom of the gray box.

Is it possible to 'pretend' that the ground around the dead npc has collision?

I thought about maybe adding a collision-box below the coins which follow the coins in the X-dimension only, but I'm not sure how to set the coins to only collide with these boxes (and perhaps left and right walls)

3 Answers

The answer is to not have a collide-box on the item/coin itself, but it still needs a rigidbody2D to simulate gravity.

We start by finding the objects startposition upon construction. We add a force to it, to push it upwards, to simulate that the item/coin is being 'thrown' out of the dead NPC:

startPosY = gameObject.rigidbody2D.transform.position.y;
startForce.x = 75;
startForce.y = 400;
rigidbody2D.AddForce(startForce);


Now we want to simulate 'bouncing', as if it was bouncing across the floor. We do so by checking if it's intercepting the 'startPosY' we stated in the beginning. If it's intercepting, stop it (enabling its kinematic-boolean and disabling it) and apply a smaller force to it:

if(rigidbody2D.transform.position.y <= startPosY && startForce.y > 0.05)
{
rigidbody2D.isKinematic = true;
rigidbody2D.isKinematic = false;
startForce.x *= 0.7f;
startForce.y *= 0.7f;
rigidbody2D.AddForce(startForce);
}


At some point we would like to stop the bouncing. Since we don't want the item to slide down to the bottom of the level, we disable its gravity:

else if(startForce.y < 0.05)
{
rigidbody2D.isKinematic = true;
rigidbody2D.isKinematic = false;
rigidbody2D.gravityScale = 0;
}


I still have to play around with perhaps modifying the 'startPosY' so all coins don't stack up on one X-axis. Also it sometimes keeps going into the statement

if(rigidbody2D.transform.position.y <= startPosY && startForce.y > 0.05)


because the position so happens to be under startPosY for consecutive frames.

You can probably use layers to apply collisions on certain objects with designated layers.

The basic idea is to define a layer for the collision ground and the coins so that coins will only collide with the ground (or the objects in the same layer) and not other objects. Upon collision, you will want to check the layer of the other collision:

function OnCollisionEnter2D(coll: Collision2D) {
{
if (coll.gameObject.layer == LayerMask.NameToLayer("LAYER_NAME"))
{
Debug.Log("Collision occurred in LAYER_NAME");
}
}

• But this wouldn't work, as all the space around the red circle in the image above is a floor tile. If you checked for a 'Floor'-layer it would collide with the layer instantly. i.imgur.com/VsJiIxZ.png All the green squares represent floor-tiles. Jan 10, 2015 at 23:35

You can assign object/prefabs a Tag. by checking specific tag (e.g. 'Coin') to collide with floor and allow only this to be bounced. Quoting Varaquilex above

function OnCollisionEnter2D(coll: Collision2D) {
{
if (coll.gameObject.tag == "Coin")
{
Debug.Log("Collision occurred for Coin");
}
}


Of course you may want to tag and check the floor as well.

• I'm not sure if this would work. You'd have to assign and unassign the coin prefab the tag, otherwise it would collide with the floor instantly, like Varaquilex' suggestion. I think this is the whole problem, you can't really use the floor itself for collision, you have to initialize some trigger-box dynamically along with the coin or something like that. Jan 11, 2015 at 10:02