Opening a door with a mouse click (c#) (3D)

Hi.

I’ve been looking all day for an easy way to have a door open by just clicking it, but I haven’t come up with anything that works.
I am a student and I still get quite confused when it comes to C# code, but especially when it comes to Unity itself, I tend to completely lose track of how I’m supposed to do things.


I’ve seen there are numerous ways of doing this:

  • Using an animation: I’ve watched this video tutorial, but I can’t get the door out of automatically starting its animation.
  • Using normal clicks to simply destroy the door: I got this to work, however it’s not the result I really want, and you’d also have to click the door with your actual mouse, not with the center point of the camera.
  • Using Raycasts: this is most likely the way I want it to be done in the end, but the problem is, I don’t understand Raycast, Vector3, Quaternion and those things at all.

Another problem I’ve run into using each one of those methods: I can’t seem to scale the box collider without scaling the entire door. What I’ve done is created the actual body of the door, then created a cube, ticked off the Mesh Renderer component and placed it to the right side of it, where the actual hinges would be. I then made the body a child of this pivot point:

alt text

The rotation works the way I want it to, but apparently it’s necessary to scale this cube to cover the entire door, otherwise clicking the door itself won’t work to open it.

So, to sum up:

I’m looking for someone who’d have the time to explain to me how I would have to use Raycasting in order to get a door to rotate -90 degrees on the Y axis, and if it’s necessary, how to scale a cube that’s parent of a door, so that it actually covers said door entirely.

I hope my explanation is clear enough, it’s my first time on this forum, and I’m Belgian, so that should explain any grammatical or spelling errors.

Thanks in advance!

Raycast works by taking a vector from a position and checking if there’s a collider in the path of that vector, basically like a bullet. You can then use the data in the raycasthit variable type to do different operations with the knowledge that you hit something, in our bullet analogy: apply particle effect, hit sound and a decal for bullet hole.


Simple example

I have this script attached to an empty game object at 0,0,0 in my scene:

using UnityEngine;
using System.Collections;

public class ray_test : MonoBehaviour {
	void Update() {
		Vector3 fwd = transform.TransformDirection(Vector3.forward);
		if (Physics.Raycast(transform.position, fwd, 10)){
			Debug.DrawRay(transform.position, transform.forward*10f, Color.red);
			print("There is something in front of the object!");
		}else{
			Debug.DrawRay(transform.position, transform.forward*10f, Color.green);
			print("There is nothing in front of the object.");
		}
	}
}

What it does is cast a ray forwards, it then notifies if a collider is or isn’t caught in the ray; see pictures below. I used Debug.DrawRay to visualize the ray itself to you.

From a raycast hit TYPE you can detect what was hit.

alt text

alt text

Here’s an alternative script that will tell you what you hit:

using UnityEngine;
using System.Collections;

public class ray_test : MonoBehaviour {
	RaycastHit rayhit;
	void Update() {
		Vector3 fwd = transform.TransformDirection(Vector3.forward);
		if (Physics.Raycast(transform.position, fwd, out rayhit)){
			Debug.DrawRay(transform.position, transform.forward*10f, Color.red);
			print("The ray hit: " + rayhit.transform.gameObject.name);
		}else{
			Debug.DrawRay(transform.position, transform.forward*10f, Color.green);
			print("There is nothing in front of the object.");
		}
	}
}

alt text

Continued

Remember to set pivot mode to pivot, instead of center… nearly confused myself there.

So one last script, this allows us to open a door when it intersects the ray, our door is an empty gameobject with a a parented cube collider shaped into a door:

door.cs:

using UnityEngine;
using System.Collections;

public class door : MonoBehaviour {
	public bool 	Open 		= false;
	public float 	angle 		= 90f;
	public float	speed		= 500f;
	private float	zero;
	
	void Awake(){
		zero = transform.localEulerAngles.y;
	}
	void Update(){
		if(Open && (transform.localEulerAngles.y < (zero + angle))){
			transform.Rotate(transform.up * Time.deltaTime * speed);
		}
		if(!(Open) && (transform.localEulerAngles.y > zero)){
			transform.Rotate(-transform.up* Time.deltaTime * speed);
		}
	}
}

ray_test.cs:

using UnityEngine;
using System.Collections;

public class ray_test : MonoBehaviour {
	RaycastHit rayhit;
	float timer = 1f;
	private door d;
	void Update() {
		timer -= Time.deltaTime;
		Vector3 fwd = transform.TransformDirection(Vector3.forward);
		if (Physics.Raycast(transform.position, fwd, out rayhit)){
			Debug.DrawRay(transform.position, transform.forward*10f, Color.red);
			// New stuff here
			d = rayhit.transform.root.GetComponent<door>();
			Debug.Log(d);
			if(Input.GetKeyDown(KeyCode.Space)&&(timer < 0f)){
				if(d.Open){
					Debug.Log("User closed door");
				}else{
					Debug.Log("User opened door");
				}
				d.Open = !(d.Open);
				timer = 1f;
			}
			
			print("The ray hit: " + rayhit.transform.gameObject.name);
		}else{
			Debug.DrawRay(transform.position, transform.forward*10f, Color.green);
			print("There is nothing in front of the object.");
		}
	}
}

If you were having trouble resizing the collider then either you’re not setting the collider size in the collider inspector or you have the objects parented the wrong way around is my guess.

alt text
alt text

OK this is what I just tested. created a simple scene with 3 cubes expanded so I had 2 walls and a door (looks rubbish but you never asked for pretty!)

Opened the animation window and set the position and rotation as Curves. Set the door as closed in the first frame and set a new frame at 1 second and moved the door to an open position/rotation:

40955-dooropen.png

I duplicated that animation and called it CloseDoor then swapped the frames over so the first frame becomes the last frame and the last becomes the first.

I then added the animations to the “door” Cube and added this script to it.

using UnityEngine;
using System.Collections;

public class ClickMe : MonoBehaviour {

	private bool doorOpen = false;
	private float animationFinished = 0;

	public void OnMouseUp()
	{
		Debug.Log ("Ive been clicked");

		if(Time.time > animationFinished)
		{
			if(doorOpen)
			{
				animation.Play("CloseDoor");
			}
			else
			{
				animation.Play("OpenDoor");
			}

			animationFinished = Time.time + 1;
			doorOpen = !doorOpen;
		}
	}
}

Dragged that script onto my Cube/Door and …

When I click on the door it opens and once the animation time finishes I can click it again to close it.

Hope that helps.