Placing Objects
Goals
- Implement a cube spawner
- Place the spawner with the tap gesture
1. Add a spawner
- Right click the scene hierarchy, choose
Empty Game Object
- Call the game object
Spawner
- Place it at
(0,0,3)
- In the
Scripts
folder of your assets, add a new script, call it:Spawn
- Add this script to your
Spawner
object - Edit the script (via
Right click
-edit script
)
Optional: It can be helpful to have a visible object here to ensure everything is working - just drag a cube or sphere under it. Be sure to disable the physics material of the mesh, or it will interact weirdly with the cubes it is spawning.
2. Write the script
Our spawner needs some inputs for sanity
- The game object to spawn copies of
- Time between spawns
- Maximum number of things to spawn
Our spawner will be resposible for the lifetime of the children.
Add the following fields. Note we've put a list in to keep track of our spawned objects.
public GameObject ThingToSpawn;
public int MaxNumberOfThings = 5;
public int NumberOfSecondsBetweenSpawns = 1;
private List<GameObject> _spawnedThings = new List<GameObject>();
We're going to use a Coroutine - which is a clever hack by Unity to manage operations that need to be performed over multiple game loop cycles, by leveraging yield
. Let's write it now:
IEnumerator DoTheSpawns()
{
if (ThingToSpawn == null)
yield break;
while (true)
{
// Pop things off if there are too many
while (_spawnedThings.Count >= MaxNumberOfThings)
{
Destroy(_spawnedThings[0]);
_spawnedThings.RemoveAt(0);
}
// Create a new thing
var newThing = Instantiate(ThingToSpawn, transform.position, Quaternion.identity, transform);
_spawnedThings.Add(newThing);
// Don't execute again until the time has passed
yield return new WaitForSeconds(NumberOfSecondsBetweenSpawns);
}
}
The Coroutine will be stopped when the Game Object is destroyed, so we need not worry about a terminating condition.
We'll start this coroutine in the Start
method:
void Start()
{
if (ThingToSpawn == null)
Debug.LogError("Spawn: No things to spawn");
if (NumberOfSecondsBetweenSpawns <= 0)
Debug.LogError("Spawn: Need to have some positive time between spawns");
StartCoroutine(DoTheSpawns());
}
3. Configure the objects
Switch back to the Unity editor to configure this script
- Select the
Cube
game object - Remove the
ThrowAtWall
script - Select the
Spawner
game object - Drag the
Cube
game object to the appropriate field - Leave the other values at their defaults.
Hit play - you should see the cubes fall.
4. Extract a prefab for the cube
We no longer need the cube to be in the initial scene - so let's make a prefab out of it
- Create a folder in your assets called
Prefabs
- Drag the cube to the folder
- Delete the cube from the scene
- Drag the cube prefab to the
Thing to Spawn
field of the spawner
Run again - it should work as before.
5. Create a script to move the spawner
As in step 1, add a script called MoveToTapPosition
, attach it to the spawner.
This is the code we'll use:
using HoloToolkit.Unity.InputModule;
using UnityEngine;
public class MoveToTapPosition : MonoBehaviour, IInputClickHandler
{
public Camera Camera;
public float OffsetFromWall = 0.5f;
public float OffsetWhenNoWall = 5;
void Start()
{
InputManager.Instance.AddGlobalListener(gameObject);
}
public void OnInputClicked(InputClickedEventData eventData)
{
var origin = Camera.transform.position;
var direction = Camera.transform.rotation * Vector3.forward;
RaycastHit hit;
var rayCastSuccessful = Physics.Raycast(origin, direction, out hit);
if (!rayCastSuccessful)
return;
var spawnPosition = hit.point + hit.normal * OffsetFromWall;
gameObject.transform.position = spawnPosition;
}
}
In this code we do a ray cast to look for an intersection with a surface - in this case, the room.
A ray cast works by starting from an origin and moving along a particular direction until it intersects with something (yes, this is a simplified explanation). When it intersects with something, some information about the RaycastHit
is calculated - such as the position and the normal.
In this case, we start the ray at the camera position and face it in the direction the camera is looking. If a hit is found, the spawn position is offset from the wall a specified amount (along the surface normal). If not, it sets the position to a specific distance along the ray.
6. Test it out
Back to Unity.
- Select the
Spawner
game object - Drag the
HoloLensCamera
to theCamera
section - Leave the rest as-is
Play!
Now whenever you tap, the spawner will move around. Hurrah!
Next: World Anchors
Prev: Interacting with world