Prevent overlapping of user placed objects (GameObject.Instantiate)

Beginner Unity developer here, though have moderate background experience in C based languages (Arduino, etc). I’ve set up a basic HTC Vive Virtual Reality demo in which the player can use their controllers to select and place objects - I’m placing objects via a Raycast from one of the controllers, Instantiating it if it intersects with a place which is valid at the point of intersection (RaycastHit.point). This creates objects who’s center is on the ground, or surface where it’ll be placed, so it’s sunken into the ground. Is there anyway to make it so that it will shift up to let the object sit on the ground, or rest with it’s back against the wall? Here is my code.

using UnityEngine;
using System.Collections;

public class Pointer : MonoBehaviour {
	/*
	//Vive button setup
	private Valve.VR.EVRButtonId gripButton = Valve.VR.EVRButtonId.k_EButton_Grip;
	private Valve.VR.EVRButtonId triggerButton = Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger;
	private Valve.VR.EVRButtonId touchpad = Valve.VR.EVRButtonId.k_EButton_SteamVR_Touchpad;
	SteamVR_TrackedObject controller;
	*/
	public GameObject placedObj;

	public float rotationSpeed = 1.0f;

	public float laserWidth = 0.01F;
	public Material LaserEffect;

	GameObject manipObj;
	GameObject[] existObj;

	public bool alreadyInst = false;

	LineRenderer myLine;
	RaycastHit hitPos;



	void Start () {

		//controller = GetComponent<SteamVR_TrackedObject> ();
		myLine = gameObject.AddComponent<LineRenderer> ();
		myLine.SetWidth (laserWidth, laserWidth);
		myLine.enabled = false;
		myLine.material = LaserEffect;


	}

	void Update () {
		//steamVR Controller setup
		//SteamVR_Controller.Device device = SteamVR_Controller.Input((int)controller.index);

		Ray pointerRay = new Ray (this.transform.position, this.transform.forward);
		bool hit = Physics.Raycast (pointerRay, out hitPos, 100);
		if (hit) {
			if (hitPos.collider.tag == "environment") {
				myLine.enabled = true;
				myLine.SetPosition (0, transform.position);
				myLine.SetPosition (1, hitPos.point);
			} else {
				myLine.enabled = false;
			}
		} else {
			myLine.enabled = false;
		}

		//if there's a object selected, it's not been instantiated, raycast hits something, and what it's hitting is environment
		if (placedObj) {
			if (alreadyInst == false) {
				if (hit) {
					if (hitPos.collider.tag == "environment" || hitPos.collider.tag == "object") {
						manipObj = (GameObject)Instantiate (placedObj, hitPos.point, Quaternion.identity);
						manipObj.tag = "manip";
						alreadyInst = true;
					}
				}
			} else if (!hit) {//if it's not hitting anything, destroy it and reinstantiate it when it hits something again
				Destroy (manipObj);
				alreadyInst = false;
			} else {//repositioning
				reposition (hitPos);

				//rotate keyboard
				if (Input.GetKey(KeyCode.Q)) {
					manipObj.transform.Rotate (Vector3.up * rotationSpeed, Space.Self);
				}
				if (Input.GetKey (KeyCode.E)) {
					manipObj.transform.Rotate (Vector3.down * rotationSpeed, Space.Self);
				}
				/*
				//rotate vive (TO BE TESTED)
				Vector2 touchPos = device.GetAxis();
				if (touchPos.x > 0.5 && device.GetPress (touchpad)) {
					manipObj.transform.Rotate (Vector3.down * rotationSpeed, Space.Self);
				}
				if (touchPos.x < -0.5 && device.GetPress (touchpad)) {
					manipObj.transform.Rotate (Vector3.up * rotationSpeed, Space.Self);
				}

				//Place the object! Vive
				if (device.GetPressDown (triggerButton)) {
					placedObj = null;
					alreadyInst = false;
				}
				*/
				//Place the object! Keyboard
				if (Input.GetKeyDown (KeyCode.P)) {
					manipObj.tag = "object";
					placedObj = null;
					manipObj = null;
					alreadyInst = false;
				}
			}
				
		}
		/*
		//delete the objects
		if (device.GetPressDown (gripButton)){
			deleteObjs ();
		}
		*/
		if (Input.GetKeyDown (KeyCode.D)) {
			deleteObjs ();
		}

	}


	void reposition (RaycastHit pos){
		manipObj.transform.position = pos.point;
	}

	void deleteObjs(){
		existObj = GameObject.FindGameObjectsWithTag ("object");
		for (int i = 0; i < existObj.Length; i++) {
			Destroy (existObj *);*
  •  }*
    
  • }*
    }
    placedObj is the object to be placed, I’m passing it in via another script.
    Note that a lot of code is commented out, I currently don’t have access to a Vive however I can test it just as well with two cubes and the keyboard.

1 Answer

1

You could rotate the placed object to have the same rotation as the plane . Then you could get the bounds of the placed object and move it in the direction the plane is facing (transform.forward) by half of the bounds extents in the forward direction of the object. You probably have to get the bounds before rotating the object, because the bounds are axis-aligned, which could lead to problems (if your planes only face the direction of a global axis this should not be a problem).

Thank you for the reply! This helped a lot - however from further searching I used [RaycastHit.Normal][1] to find the angle of the surface I hit, therefore the direction I should shift the object in (for now it's rounded to one of the world axes) [1]: http://docs.unity3d.com/ScriptReference/RaycastHit-normal.html