- Home /
open and close a door with a keypress
Hi
I have a door with a close and open animation. I want to open it and close it with a single key press code so far below
function Update(){ print(doorIsOpen); var hit : RaycastHit ; var door:GameObject = GameObject.Find("Locker2") ; if (Physics.Raycast (transform.position,transform.forward, hit, 2)){ if(hit.collider.gameObject.tag =="lockerx" ) { if (Input.GetButtonDown("Fire1") ) { door.animation.Play("open"); doorIsOpen = false;
} if (Input.GetButtonUp("Fire1") && doorIsOpen == false) { door.animation.Play("close"); doorIsOpen = true;
} } } }
Answer by straydogstrut · Apr 03, 2010 at 06:07 PM
You haven't said what the problem is and nothing jumps out at me immediately, although it looks like you're checking to see if the collider hit by your raycast has a tag of "lockerx", yet you play the animation of the door "Locker2" every time. In my experience if you have a few objects called the same, you'll only get back one of them or not at all.
Here is the code i'm using to open any door with a collider that has a tag "door". Also included is a timer to close the door after a specified time and sounds to play. This was modified from the Unity Game Development Essentials book which i'd highly recommend.
// Three private variables to store the state of the door, // a timer, and the current door collided with private var doorIsOpen : boolean = false; private var doorTimer : float = 0.0; private var currentDoor : GameObject;
// Three public variables to allow us to set the length // of time the door will stay open and the sounds used var doorOpenTime : float = 3.0; var doorOpenSound : AudioClip; var doorCloseSound : AudioClip;
function Update () {
// if the Ctrl button is pressed
if (Input.GetButtonDown("Fire1") ) {
// Declare a private variable of type RaycastHit for our ray
var hit : RaycastHit;
// Cast a ray 1 game unit (metre) forward from our position
if(Physics.Raycast (transform.position, transform.forward, hit, 1)){
// if it hits a collider tagged "door" and the door is not open
if(hit.collider.gameObject.tag == "door" && doorIsOpen == false){
// store the gameObject of the collider hit
currentDoor = hit.collider.gameObject;
// Call the Door() function with parameters for:
// sound to play, doorIsOpen, animation, currentDoor gameobject
Door(doorOpenSound, true, "dooropen", currentDoor);
}
}
}
// timer to close the door after the specified time
if(doorIsOpen){
doorTimer += Time.deltaTime;
if(doorTimer > doorOpenTime){
// Call the door function again with parameters to close the door
Door(doorCloseSound, false, "doorclose", currentDoor);
// reset the timer
doorTimer = 0.0;
}
}
}
// The Open and Close Door function
function Door(aClip : AudioClip, openCheck : boolean, animName : String, thisDoor : GameObject){
// Play the sound assigned to the doorOpenSound/doorCloseSound variable
audio.PlayOneShot(aClip);
// Set the doorIsOpen variable to true or false
doorIsOpen = openCheck;
// Play the animation clip (animName) for this door
thisDoor.animation.Play(animName);
}
Thanks for the reply If i run the game the door just closes does not open. I want the player to open & close the door without timer thanks
the lockerx is a object tag attached to two models which make up the locker
Are you sure you've unchecked 'play automatically'? And when you say two models, are they two doors that open or do you mean a locker and its door? The tag would have to be on whichever object has the animation (usually the parent but double check)
Thanks very much for the second answer.I was having trouble with the if else. One last thing if I have multiple doors the open/ close goes weird I am duplicating the door then adding the script any ideas
Answer by straydogstrut · Apr 03, 2010 at 09:49 PM
Here is my script without the timer and closing the door by pressing Ctrl again (you'll have to be facing the door itself). Also, in this version i'm referencing a parent object in case that's where your animation is. Ignore my last comment re. the tag: if the animation is on the parent object, you'll want to put the tags on the child objects (the doors). You can check which object the ray is hitting by putting Debug.Log(hit.collider.gameObject.name);
after the raycast like I have below. The objects hit will need the tags put on them.
private var doorIsOpen : boolean = false; private var currentDoor : GameObject;
var doorOpenSound : AudioClip; var doorCloseSound : AudioClip;
function Update () {
if (Input.GetButtonDown("Fire1") ) {
var hit : RaycastHit;
if(Physics.Raycast (transform.position, transform.forward, hit, 2)){
Debug.Log(hit.collider.gameObject.name);
if(hit.collider.gameObject.tag == "door" && doorIsOpen == false){
currentDoor = hit.collider.gameObject;
Door(doorOpenSound, true, "dooropen", currentDoor);
}else if(doorIsOpen == true){
currentDoor = hit.collider.gameObject;
Door(doorOpenSound, false, "doorclose", currentDoor);
}
}
}
}
function Door(aClip : AudioClip, openCheck : boolean, animName : String, thisDoor : GameObject){
audio.PlayOneShot(aClip);
doorIsOpen = openCheck;
// Here we are addressing the parent instead
thisDoor.transform.parent.animation.Play(animName);
}
@script RequireComponent(AudioSource)
thanks this works great I was having trouble with multiple doors as well
Are you still having trouble? What problem are you getting? Since the raycast returns the specific collider of the door it hits, it should only act on that door. It works for me both when I duplicate the door object (I have a parent object with two child doors tagged 'door') and also when I put the door in a prefab and drag copies into the scene. Have you tried attaching the script, then duplicating the door?
Actually, ignore my last, the script should be on the First Person Controller (or whatever is your playable character that you want to cast the ray from), not the door. Is that what you're doing?
I am looking at the door problem at the moment ,I think it might be current door
Yes I have made prefab of locker comprising of 2 meshes I have tag of door on one of meshes. works fine with one door when duplicate I open both doors then when I try to shut them the second door goes it seems to be the doorIsOpen boolean conflict when I open one door it thinks door 2 is open
Answer by straydogstrut · Apr 18, 2010 at 03:17 PM
One of the problems I discovered with my previous answer is that only one door can be opened at a time. This is because the script is on the First Person Controller so only one 'doorIsOpen" variable is being dealt with.
Since my own script was getting a bit unwieldy, sandwiched in amongst the other player interaction stuff, i've completely rewritten it and moved it to a seperate script. The following script should be placed on your door object, bearing in mind you may need to make amendments if your animation is not on the same object (it may be on a child).
// Two private variables to store the state of the door and a timer private var doorIsOpen : boolean = false; private var doorTimer : float = 0.0;
// Three public variables for time the door will stay open and sounds used var doorOpenTime : float = 3.0; var doorOpenSound : AudioClip; var doorCloseSound : AudioClip;
function Start(){
doorIsOpen = false;
}
function Update () {
// a timer to call the Door() function to close the door after
// the specified time
if(doorIsOpen){
doorTimer += Time.deltaTime;
if(doorTimer > doorOpenTime){
Door();
doorTimer = 0.0;
}
}
}
// the function to open and close the door function Door(){
if(doorIsOpen == false){
audio.PlayOneShot(doorOpenSound);
doorIsOpen = true;
animation.Play("dooropen");
} else {
audio.PlayOneShot(doorCloseSound);
doorIsOpen = false;
animation.Play("doorclose");
}
}
@script RequireComponent(AudioSource)
Since the door's open state is initially set to false, the door will not open automatically (unless you have your animation set to 'Play automatically'!). Instead, i'm calling the door to open from other scripts, such as when the player walks up to the door and presses the spacebar:
function Update () {
if (Input.GetButtonDown("Jump") ) {
var hit : RaycastHit;
if(Physics.Raycast (transform.position, transform.forward, hit, 1)){
// if we've hit one of the objects tagged "door"
if(hit.collider.gameObject.tag == "door"){
// store the gameObject of the collider
// and use this to call the Door() function
currentDoor = hit.collider.gameObject;
currentDoor.GetComponent(doorControl).Door();
}
}
}
Answer by Michael 12 · Feb 21, 2011 at 01:47 AM
I have a question about this, I'm new to the whole code and game creation thing in general so hopefully you'll explain it simply for me. This sounds like what I need but I've no idea how to implement it.
I have a structure that has and animated door, the door is two parts that slide open in oposit directions from each other, my animation I made in Unity with the built in animation editor as it just a simple slide open animation. My animation is also the child of my main structure, how do I get this to work with that sort of set up?
My animation is named "PwrStationDoorsOpen" and is on my main structure, the doors are a child of that structure.
My Doors are named: "PowerStationDoor01" and "PowerStationDoor02"
The animation is just a loop of something like this:
-><- Doors Closed
-> <- Doors Open
I hope that crude example is illustrative enough lol
How do I code that and where do I put the scripts?
Answer by mutantsproducer · Feb 22, 2011 at 12:04 AM
Hi. I figured it out i think. Do on trigger enter and inside the function say to play the animation. here is an example:
function OnTriggerEnter () { Animation.Play(NameOfAnimation); }
But to make it work, make the player and floor a trigger,put the door on top of a cube that's on top of the ground. that is for collision doors, and for click-to-open doors just type it the same and add an if statement like this: if(GetButtonDown("Fire1") and put the Animation.Play crap in curly braces after the If statement. If this does not work then upgrade unity to 3.1 or your screwed if i'm last one on this thread other then you.