Techshop

Unity Tutorial 26 - Refining the game part 3

Now the fun thing…

There are no coins on the game at the start

We need to spawn a load of coins at the beginning of the game.

I'm going to try and make this easy, by using a cube to define the volume in which to spawn the cubes, and a script to spawn them.

Starting from the initial view

Building a cube

And manipulating it to fill the rough volume I want the coins to spawn into

I've named the cube 'InitialCoinSpawner'

I've added 'InitialCoinSpawner' as a script too.

I've also made the cube a child of the "spawner" to keep the spawing objects together

Once we have this we need to do the code to make it do all the calculations of where to spawn the coins.

The Unity API exposes the bounding volume of a mesh. So we can use this to calculate the extent of the cube we just added and calculate where to randomly place coins. We also need to know the size of the coins to make sure we don't place the center of the coin at the edge of the cube and therefore overflowing outside of the cube. We could decrease the size of the mesh by ½ the size of the coin, but if we ever change the coin to something else, we'd have to change this too. Might as well add it to the calculations too.

Now. There are two ways to get the bounding volume of the Mesh. Via the Mesh directly, or via the Component that renders it. Asking the mesh is a little wrong. The mesh works in its own space and can be very different to the World space. The "Renderer" component works in World space and will be the same, expected, values as we see in the Scene.

I'm going to dump the code from the "InitialCoinSpawner" and then explain it….

public class InitialCoinSpawner : MonoBehaviour {
   public GameObject spawnObject;
   public int numberToSpawn = 50;
   public Transform spawnContainer;

   private void Start() {
       gameObject.SetActive(false);

       var cubeBoundary = GetComponent().bounds;


       var temporarySpawn = Instantiate(spawnObject);
       var spawnBounds = temporarySpawn.GetComponent().bounds;
       var size = spawnBounds.size / 2.0f;

       var spawnMinimum = cubeBoundary.min + size / 2.0f;
       var spawnMaximum = cubeBoundary.max - size / 2.0f;

       Destroy(temporarySpawn);

       for (var i = 0; i < numberToSpawn; ++i) {
           var position = new Vector3(
               Random.Range(spawnMinimum.x, spawnMaximum.x),
               Random.Range(spawnMinimum.y, spawnMaximum.y),
               Random.Range(spawnMinimum.z, spawnMaximum.z)
           );

           temporarySpawn = Instantiate(spawnObject, spawnContainer);
           temporarySpawn.transform.position = position;
       }
   }
}

To start with we need 3 publicly exposed attributes that we can access in the Unity IDE.

spawnObject will be the item we are going to spawn, the coin in our case

numberToSpawn will allow use to control how many we spawn at the start, so we can fine-tune it.

spawnContainer is the Transform object that will be the container of the object, just so we can spawn them to the same place as the other coins. This is going to be the "spawn" object in the hierarchy. Essentially the immediate parent of the "InitialCoinSpawner".

Ultimately we could've made it so that this "Cube" object was an object that the script pointed to, and the script was in the "spawner" and pointed to the Object that defined the boundaries, but I went this way around instead.

The Start method is where all the magic happens.

To start with we immediately deactivate the object. We don't really need it. It's just a placeholder.

We then get the full boundary of the object, in World Space, using the Renderer.

We now need to create a temporary instance of the "spawnObject". If it doesn't have an instance it doesn't report on its boundaries, so we need to create a temporary one to find this out.

Again, using the Renderer, we discovery it's "bounds" object, but this time we use it to find the objects size.

We move in the boundary of the cube by ½ of the size of the object, this is to make sure when we create an instance of the spawned object, its edges will only go up to the edges of the cube at most.

Destroy the temporary object.

Finally, create "numberToSpawn" instances of the spawned object, positioning it randomly within the calculated extrema, making it a child of the "spawnContainer".

This looks like this

And roughly is about correct

GIT TAG 022_AddingCoinsOnStart

I've changed a few options in the game.

The odd coin was falling through the floor object. I think this was due to the multiple collisions forcing overlapped coins to not work correctly. It appears as though turning on "Interpolate" in the coin prefab "Rigidbody" has fixed that, but it was intermittent and may crop up on occasion.

The coin prefab also had all the 'Static' options removed. This was mainly the shading, but it looks better.

I put the InitialCoinSpawner in a "Hide" layer I created. This is so I can hide it in the scene view and it doesn't get in the way of viewing the coin pusher in the scene.

Unity - A simple tutorial < Unity Tutorial 25 - Refining the game part 2 Unity Tutorial 27 - More Refinements >