Unity 3D Place Objects on Mouse Click
66
Ability to spawn objects on mouse click is useful when you need to create a level editor or simply to allow players to place objects anywhere on the map.
In this tutorial I will be showing how to make a simple level editor with ability to spawn objects on mouse click.
So let's begin!
Steps
- Open Scene with your level (In my case it will be a simple Scene with a plane and a Camera which points down)
- Create new script, call it "SC_Object" and paste the code below inside it:
SC_Object.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SC_Object : MonoBehaviour
{
public Renderer[] objectRenderers; //Assign object renderers
public void ReplaceMaterials(Material material)
{
for(int i = 0; i < objectRenderers.Length; i++)
{
objectRenderers[i].sharedMaterial = material;
}
}
}
- Create new script, call it "SC_ObjectSpawner" and paste the code below inside it:
SC_ObjectSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SC_ObjectSpawner : MonoBehaviour
{
public SC_Object[] availableObjects;
public Material overdrawMaterial;
Vector2 scroll;
Transform buildTarget;
bool canPlace = false;
SC_Object selectedObject;
int selectedObjectindex = -1;
Rect areaRect = new Rect(5, 5, 150, 150);
// Start is called before the first frame update
void Start()
{
//Create build target object
GameObject tmpObj = new GameObject("BuildTarget");
buildTarget = tmpObj.transform;
}
// Update is called once per frame
void Update()
{
buildTarget.position = GetRaycastPosition();
if (canPlace && selectedObject)
{
//Place Object
if (Input.GetMouseButtonDown(0) && !areaRect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)) && !Input.GetKey(KeyCode.LeftControl))
{
Instantiate(availableObjects[selectedObjectindex], selectedObject.transform.position, selectedObject.transform.rotation);
}
//Rotate Left
if (Input.GetKey(KeyCode.A))
{
selectedObject.transform.Rotate(Vector3.up, -2, Space.World);
}
//Rotate Right
else if (Input.GetKey(KeyCode.D))
{
selectedObject.transform.Rotate(Vector3.up, 2, Space.World);
}
}
//Delete Object
if (Input.GetMouseButtonDown(0) && Input.GetKey(KeyCode.LeftControl))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(ray, out hit, 300))
{
if (hit.transform.root.GetComponent<SC_Object>())
{
Destroy(hit.transform.parent.gameObject);
}
}
}
//Clear selection
if (Input.GetKeyDown(KeyCode.LeftControl) && selectedObject)
{
Destroy(selectedObject.gameObject);
}
}
Vector3 GetRaycastPosition()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
canPlace = false;
//Do Raycast hit only against UI layer
if (Physics.Raycast(ray, out hit, 300, 1 << 5))
{
canPlace = true;
return hit.point;
}
return new Vector3(5000, 5000, 5000);
}
void OnGUI()
{
GUILayout.BeginArea(areaRect, "", "box");
GUILayout.Label("Select Object:");
scroll = GUILayout.BeginScrollView(scroll);
for(int i = 0; i < availableObjects.Length; i++)
{
if (GUILayout.Button(availableObjects[i].name))
{
//Destroy previous selected object if there any
if (selectedObject)
{
Destroy(selectedObject.gameObject);
}
//Instantiate Object
selectedObject = Instantiate(availableObjects[i], buildTarget.position, buildTarget.rotation);
selectedObject.transform.SetParent(buildTarget);
selectedObject.ReplaceMaterials(overdrawMaterial);
selectedObjectindex = i;
}
}
GUILayout.EndScrollView();
GUILayout.EndArea();
}
}
- Create new GameObject, name it "_ObjectSpawner"
- Attach SC_ObjectSpawner script to "_ObjectSpawner"
- Change the layer of a ground (In my case the Plane) to "UI"
- Create new Shader (Create -> Shader -> Unlit Shader), call it "Overdraw" and paste the code below inside it
Overdraw.shader
Shader "FX/Overdraw" {
Properties
{
_Color ("Main Color", Color) = (0,1,0.4,0.5)
}
SubShader
{
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
LOD 100
Fog { Mode Off }
ZWrite On
ZTest LEqual
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
fixed4 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return _Color;
}
ENDCG
}
}
}
- Create new Material and name it "overdraw_material" and change its Shader to "FX/Overdraw"
- Assign "overdraw_material" material to Overdraw Material variable in SC_ObjectSpawner
Now it's time to setup Objects that will be spawned on mouse click. For this tutorial I will be using 3D Models from this Asset Store package.
- Create new GameObject and place it at the bottom of a 3D model, like this:
- Move the model inside that GameObject. (Rename the Object to whatever name you want to be displayed in the list, in my case I named it "Hangar 1")
- Attach SC_Object script to the root GameObject and assign child mesh renderers to Object Renderers array:
- Save the Object to Prefab and repeat the same process for the rest of the models:
- Lastly assign the Prefabs to Available Objects array at "SC_ObjectSpawner"
- Now press Play to test it:
Select any Object from the list and place it anywhere on the map by left clicking.
Press A, D to rotate the Object.
Hold Left Ctrl + Left Click to remove the Object.