Skip to main content

Spawn and Despawn Objects when you Mouse Click in a Scene

There is an example of this here.

Setup a scene with varied terrain on it.

Create prefabs that can be used to spawn objects. You only need one for this example.

Set the parent of the prefab to have a tag named Player (or whatever you wish). We will use this later to check if we have clicked on an object that we should be able to destroy / despawn.

In the main scene create a UIManager GameObject.

On this add the Player Input component.

Create input actions for this.

Add in a primary and secondary action for the left and right mouse button. These will be used to spawn and despawn items.

We are going to use a C# script for the input actions.

Select the Input Actions and then check Generare C# Class and then apply.

Create a C# class and attached to a UI Manager GameObject you create. In this example the C# scripts is called PrimaryClickItemSpawner

Points 1-6 setup the variables and import the Input System package.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 1. Import InputSystem
using UnityEngine.InputSystem;

public class PrimaryClickItemSpawner : MonoBehaviour
{
// 2. Add Input actions (requires Generate C# script checked)
private MouseControlsPointAndClick _controls;
// 3. list of prefabs to be able to spawn (placeholder for later task)
public GameObject[] prefabs = new GameObject[4]; //Prefabs to spawn
// 4. List to store spawned gameobjects to be able to manage them.
public List<GameObject> spawnedItems = new List<GameObject>();

// 5. Currently selected prefab from list. Only default in this example
int selectedPrefab = 0;
// 6. Size of the raycast to draw.
int rayDistance = 300;
}

Save the file and return to Unity. Drag the prefabs onto the prefabs array.

The code below is applied to a UI Manager GameObject and utilises a set of Input Actions that have a C# class generated for it.

Work through points 7-27 as detailed in the code comments below.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 1. Import InputSystem
using UnityEngine.InputSystem;

public class PrimaryClickItemSpawner : MonoBehaviour
{
// 2. Add Input actions (requires Generate C# script checked)
private MouseControlsPointAndClick _controls;
// 3. list of prefabs to be able to spawn (placeholder for later task)
public GameObject[] prefabs = new GameObject[4]; //Prefabs to spawn
// 4. List to store spawned gameobjects to be able to manage them.
public List<GameObject> spawnedItems = new List<GameObject>();

// 5. Currently selected prefab from list. Only default in this example
int selectedPrefab = 0;
// 6. Size of the raycast to draw.
int rayDistance = 300;

// Start is called before the first frame update
void Start()
{
// 7. Create new input actions using the C# script
_controls = new MouseControlsPointAndClick();
// 8. Enable / turn on the MouseRTS action map
_controls.MouseRTS.Enable();
// 9. When the PrimaryAction binding is performed call the PrimaryPerformed function
_controls.MouseRTS.PrimaryAction.performed += PrimaryPerformed;
/* 10.
When the PrimaryAction binding is released call the PrimaryCancelled function
Not used in this example
*/
_controls.MouseRTS.PrimaryAction.performed += PrimaryCancelled;
// 11. Right mouse button pressed
_controls.MouseRTS.SecondaryAction.performed += SecondaryPerformed;
// 12. Right mouse button cancelled / released (not used)
_controls.MouseRTS.SecondaryAction.canceled += SecondaryCancelled;
}

/* 13.
Primary button pressed. When left mouse pressed do this.
Get the context of the button (what happened)
This will cast a ray from the mouse position and see what it hits.
*/
void PrimaryPerformed(InputAction.CallbackContext context) {
// 15. Store the raycast hit result
RaycastHit hit;
// 16. Create a ray from the current mouse position through the screen towards the scene
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
/* 17.
Cast the ray using the physics engine and see what it hits.
Store what it (output) hits in the hit variable created earlier
*/
if (Physics.Raycast(ray, out hit))
{
// 18. We are here because the raycast hit something

/* 19.
This is a messy check for the if statement.
There are two main checks carried out.
First we need to see if the parent of the hit object does not exist (e.g. hit null)
Or check that the object it hit was not one of the objects tagged with
player that we have spawned (otherwise we can spawn objects on top of each other)
*/
if(hit.collider.transform.parent == null || hit.collider.transform.parent.CompareTag("Player") == false) {
/* 20.
If we pass this instantiate (create) the object at the point the we hit
the terrain (or other object)
We use Quarternion.identiy to spawn it at the world space.
*/
GameObject go = Instantiate(prefabs[selectedPrefab], hit.point, Quaternion.identity);
// 21. Update the name of the prefab instance
go.name += " _instantiated";
// 22. Add it to the spawned items list.
spawnedItems.Add(go);
}
}
}

// 14. Primary button released not used in this example.
void PrimaryCancelled(InputAction.CallbackContext context) {

}

/* 23.
Now we want to despawn the item when we right click on it
*/
void SecondaryPerformed(InputAction.CallbackContext context) {
// 23. We run the same kind of checks as before but this runs when we right click
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (Physics.Raycast(ray, out hit))
{
/* 24.
Check if we hit the parent gameobject with the tag Player.
*/
if(hit.collider.transform.parent.CompareTag("Player")) {
// 25. If so remove the gameobject from the spawnedItems list
spawnedItems.Remove(hit.transform.parent.gameObject);
// 26. Then destroy the object to free up memory and remove it from the scene.
Destroy(hit.transform.parent.gameObject);
}
}
}

// 27. Not used in this example
void SecondaryCancelled(InputAction.CallbackContext context) {

}
}