Many games make use of spawn points and waypoints. This recipe demonstrates two very common examples of spawning—the choosing of either a random spawn point, or the nearest one to an object of interest (such as the Player's character), and then the instantiation of an object at that chosen point.
This recipe builds upon the previous recipe. So, make a copy of this project, open it, and then follow the next steps.
To find a random spawn point, follow these steps:
m_red
Material.Prefab-ball
, and drag your Sphere into it (and then delete the Sphere from the Hierarchy panel).Capsule-spawnPoint
at (3, 0.5, 3), give it the tag as Respawn
(this is one of the default tags that Unity provides).SpawnBall
to the Cube-the player GameObject:using UnityEngine; using System.Collections; public class SpawnBall : MonoBehaviour { public GameObject prefabBall; private SpawnPointManager spawnPointManager; private float destroyAfterDelay = 1; private float testFireKeyDelay = 0; void Start (){ spawnPointManager = GetComponent<SpawnPointManager> (); StartCoroutine("CheckFireKeyAfterShortDelay"); } IEnumerator CheckFireKeyAfterShortDelay () { while(true){ yield return new WaitForSeconds(testFireKeyDelay); // having waited, now we check every frame testFireKeyDelay = 0; CheckFireKey(); } } private void CheckFireKey() { if(Input.GetButton("Fire1")){ CreateSphere(); // wait half-second before alling next spawn testFireKeyDelay = 0.5f; } } private void CreateSphere(){ GameObject spawnPoint = spawnPointManager.RandomSpawnPoint (); GameObject newBall = (GameObject)Instantiate (prefabBall, spawnPoint.transform.position, Quaternion.identity); Destroy(newBall, destroyAfterDelay); } }
SpawnPointManager
to the Cube-player
GameObject:using UnityEngine; using System.Collections; public class SpawnPointManager : MonoBehaviour { private GameObject[] spawnPoints; void Start() { spawnPoints = GameObject.FindGameObjectsWithTag("Respawn"); } public GameObject RandomSpawnPoint (){ int r = Random.Range(0, spawnPoints.Length); return spawnPoints[r]; } }
SpawnBall
scripted component. Then, drag Prefab-ball over the public variable projectile called Prefab Ball.The Capsule-spawnPoint objects represent candidate locations, where we might wish to create an instance of our ball Prefab. When our SpawnPointManager
object, inside the Cube-player GameObject, receives the Start()
message, the respawns GameObject array is set to the array, which is returned from the call to FindGameObjectsWithTag("Respawn")
. This creates an array of all the objects in the scene with the tag called Respawn
— that is, all our Capsule-spawnPoint objects.
When our SpawnBall
object GameObject Cube-player receives the Start()
message, it sets the spawnPointManager
variable to be a reference to its sibling SpawnPointManager
script component. Next, we start the coroutine method called
CheckFireKeyAfterShortDelay()
.
The CheckFireKeyAfterShortDelay()
method uses a typical Unity coroutine technique that goes into an infinite loop using a delay controlled by the value of the testFireKeyDelay
variable. The delay is to make Unity wait before calling CheckFireKey()
to test if the user wants a new sphere to be spawned.
Coroutines are an advanced technique, where execution inside the method can be paused, and resumed from the same point. The Yield
command temporarily halts the execution of code in the method, allowing Unity to go off and execute code in the other GameObjects and undertake physics and rendering work and more. They are perfect for situations where, at regular intervals, we wish to check whether something has happened (such as testing for the Fire key, or whether a response message has been received from an Internet request and so on).
Learn more about the Unity coroutines at http://docs.unity3d.com/Manual/Coroutines.html.
The SpawnBall
method CheckFireKey()
tests whether, at that instant, the user is pressing the Fire button. If the Fire button is pressed, then the CreateSphere()
method is called. Also, the testFireKeyDelay
variable is set to 0.5. This ensures that we won't test the Fire button again for half a second.
The SpawnBall
method CreateSphere()
assigns variable spawnPoint
to the GameObject
returned by a call to the RandomSpawnpoint(…)
method of our spawnPointManager
. Then it creates a new instance of prefab_Ball
(via the public variable) at the same position as the spawnPoint
GameObject.
There are some details that you don't want to miss.
Rather than just choosing a random spawn point, let's search through array spawnpoints, and choose the closest one to our player.
To find the nearest spawn point, we need to do the following:
SpawnPointManager
:public GameObject NearestSpawnpoint (Vector3 source){ GameObject nearestSpawnPoint = spawnPoints[0]; Vector3 spawnPointPos = spawnPoints[0].transform.position; float shortestDistance = Vector3.Distance(source, spawnPointPos); for (int i = 1; i < spawnPoints.Length; i++){ spawnPointPos = spawnPoints[i].transform.position; float newDist = Vector3.Distance(source, spawnPointPos); if (newDist < shortestDistance){ shortestDistance = newDist; nearestSpawnPoint = spawnPoints[i]; } } return nearestSpawnPoint; }
SpawnBall
so that the spawnPoint
variable is set by a call to our new method called NearestSpawnpoint(…)
:private void CreateSphere(){ GameObject spawnPoint = spawnPointManager.NearestSpawnpoint(transform.position); GameObject newBall = (GameObject)Instantiate (prefabBall, spawnPoint.transform.position, Quaternion.identity); Destroy(newBall, lifeDuration); }
In the NearestSpawnpoint(…)
method, we set nearestSpawnpoint
to the first (array index 0) GameObject in the array as our default. We then loop through the rest of the array (array index 1 up to spawnPoints.Length
). For each GameObject in the array, we test to see if its distance is less than the shortest distance so far, and if it is, then we update the shortest distance, and also set nearestSpawnpoint
to the current element. When the array has been searched, we return the GameObject that the nearestSpawnpoint
variable refers to.
Let's make our code a little more robust, so that it can cope with the issue of an empty spawnPoints
array—that is, when there are no objects tagged Respawn in the scene.
To cope with the no objects tagged Respawn we need to do the following:
Start()
method in the C# script class called SpawnPointManager
, so that an ERROR is logged if the array of objects tagged Respawn is empty:public GameObject NearestSpawnpoint (Vector3 source){ void Start() { spawnPoints = GameObject.FindGameObjectsWithTag("Respawn"); // logError if array empty if(spawnPoints.Length < 1) Debug.LogError ("SpawnPointManagaer - cannot find any objects tagged 'Respawn'!"); }
RandomSpawnPoint()
and NearestSpawnpoint()
methods in the C# script class called SpawnPointManager
, so that they still return a GameObject even if the array is empty:public GameObject RandomSpawnPoint (){ // return current GameObject if array empty if(spawnPoints.Length < 1) return null; // the rest as before ...
CreateSphere()
method in the C# class called SpawnBall
, so that we only attempt to instantiate a new GameObject if the RandomSpawnPoint()
and NearestSpawnpoint()
methods have returned a non-null object reference:private void CreateSphere(){ GameObject spawnPoint = spawnPointManager.RandomSpawnPoint (); if(spawnPoint){ GameObject newBall = (GameObject)Instantiate (prefabBall, spawnPoint.transform.position, Quaternion.identity); Destroy(newBall, destroyAfterDelay); } }
3.147.79.11