- Home /
How to make script affect only one this game object
Hello everyone. I am 3D modeller more than a programmer. But now I need several doors in my scene to be opened and closed.
What I have. Two doors. One animator controller attached to these doors. A couple of clips placed in this animator controller, that is for opening rotation and closing rotation. And DoorController script.
First I had an issue in which all of my doors were opened in one moment when I have triggered an OpenDoor animation. I resolve this problem by using a call to a certain object that Raycast hitting with, instead of just getting a local Animator object. But what problem I have now is: When I open one of the doors, my program assign a string value "Opened" to doorState parameter of ALL OF THE DOORS IN THE SCENE. This makes rest of the doors playing the wrong animation after all (because they still closed in real).
The question is: How can I use my script with only one instance of a door and store unique parameter's values for this only one instance. How can I send command in this script to only this one certain door, not to everyone that have this script attached? How can I call to Animator component of this only one instance of a door? Not to everyone that have this script attached.
public class DoorController : MonoBehaviour {
//Animator m_animator;
public Camera m_camera;
public float maxDistance = 2;
private string doorState;
RaycastHit hit;
// Use this for initialization
void Start () {
//m_animator = gameObject.GetComponent<Animator>();
doorState = "Closed";
}
// Update is called once per frame
void Update () {
if (Physics.Raycast(m_camera.transform.position, m_camera.transform.forward, out hit, maxDistance))
{
if (hit.transform.tag == "Door")
{
if (Input.GetButtonDown("Use"))
{
OpenDoor();
}
}
}
}
void OpenDoor()
{
if (doorState == "Closed")
{
// Open a door
//m_animator.SetTrigger("OpenDoor");
hit.transform.GetComponent<Animator>().SetTrigger("OpenDoor");
doorState = "Opened";
}
else
{
// Close a door
//m_animator.SetTrigger("CloseDoor");
hit.transform.GetComponent<Animator>().SetTrigger("CloseDoor");
doorState = "Closed";
}
}
}
Can you post a screen shot of how you have the doors set up in the editor?
Of course...
Door_Room_800 is just a parent object. Door_Room_800_low is a Door, moving part. Door_Room_Frame_800 is a frame around a door, not moving part.
Yes, please post a screenshot of the hierarchy and the inspector of them. It is difficult to decide from this code alone why this problem happens.
BTW, a suggestion: change the order of the raycast and check for button down: a raycast is much more costly than input query, so you would only want to do it if the player has activated the "Use" key.
Please concentrate on 'Why my doorState variable has changed for every door game object, not for one.'
On my $$anonymous$$d something like: Instance of a DoorController class, unique variable for this instance of this script.
I was thinking if I call some component of gameobject in script that attached to this gameobject, this will affect only this certain gameobject and no more else. I need something like separate instance with itself parameters.
Unless you mark a member variable static, it will be a separate variable for each instance for the class, just as you want. That is, the behaviour that you are experiencing is as if you had a static variable somewhere, but you don't.
The other possibility is that you are somehow controlling the same component, for example the GetComponent<Animator>()
call somehow gets the same Animator
, but this is only possible if the doors have a common parent somewhere and you call GetComponent()
on that parent.
So because your code (correctly) doesn't have static variables and seems fine, the only other possibility at first glance is that the components are mixed up, so that is why we asked for the setup of the game objects.
Answer by Shemamforash · Jul 25, 2018 at 11:43 AM
Hey there! The issue here is that the raycast is being performed in every Update() on every door. This means that if your main camera hits any door in the scene, each raycast from each door is going to register as having hit a door. This will, in turn, set the state of every door to "Opened". You could either check that hit.gameObject == this, to ensure that only the door that is actually hit by the raycast is marked as "Opened", or do as @Zodiarc says and use a collider to check whether the player is within door opening range.
Personally, I would go down the collider route as it's simpler and doesn't involve casting rays every frame for every door.
As a side note, it would probably be better to perform the input check in the player script rather than the door script in order to centralise your input logic. You might also like to use an enum to indicate Open and Closed states for your door rather than strings. If you haven't used enums before it's definitely worth learning and can make your code a bit clearer.
You are right, nice catch!
The separate raycasts detect any door, but activate the door on which the script is.
Answer by Zodiarc · Jul 25, 2018 at 07:55 AM
That's how I would do it:
Add a collider to the player and check the isTrigger (or similar) checkmark. Then write something similar to that:
class DoorController: MonoBehaviour {
private Animator animator;
public bool open = false;
public void Start() {
this.animator = GetComponent<Animator>();
}
public void OnTriggerStay(Collider other) {
if(Input.GetButtonDown("Use")) {
open = !open;
animator.SetBool("Open", open);
}
}
}
OnTriggerStay will only be called when the collider of the door is within a trigger collider, so only one door should be affected. Note: I didn't check if it actually works. To improve it further you can also check if the other collider is the player
$$anonymous$$ade it. Now doors just shaking. Close-Close-Close-Close-Close repeat... Tin-tin-tin-tin-tin....
After all, a script is work. The door opens and closes. But the last animation is repeating.
Everything is good. Just use Trigger ins$$anonymous$$d of a Bool in Animator.
Thank you.
public void OnTriggerStay(Collider other)
{
if (Input.GetButtonDown("Use") && other.tag == "Player")
{
if (open == false)
{
m_animator.SetTrigger("OpenDoor");
}
else
{
m_animator.SetTrigger("CloseDoor");
}
open = !open;
}
}
ADDITION: Animation playing all the time if you use Bool in Animator. It's playing once if you use Trigger.
Hello there. In continuous of this idea...
Now I have this code:
public void OnTriggerStay(Collider other)
{
if (Input.GetButtonDown("Use") && other.tag == "Player")
{
if (open == false)
{
switch (gameObject.tag)
{
case "Door95":
m_animator.SetTrigger("OpenDoor95");
break;
case "Door105":
m_animator.SetTrigger("OpenDoor105");
break;
case "Door120":
m_animator.SetTrigger("OpenDoor120");
break;
default:
break;
}
Debug.Log("OPEN DOOR");
}
else
{
switch (gameObject.tag)
{
case "Door95":
m_animator.SetTrigger("CloseDoor95");
break;
case "Door105":
m_animator.SetTrigger("CloseDoor105");
break;
case "Door120":
m_animator.SetTrigger("CloseDoor120");
break;
default:
break;
}
Debug.Log("CLOSE DOOR");
}
open = !open;
Debug.Log("CHANGE OPEN");
}
}
But sometimes my door open and close with one button pressing (and sometimes - not). What could it be?
$$anonymous$$y keyboard is alright.
Pay attention to time keys.
Your answer
Follow this Question
Related Questions
PARTICLE SYSTEM NEITHER EMITTING NOR PLAYING (BY SCRIPT) 3 Answers
LayoutKind.Explicit FieldOffset structs getting wrecked at Instantiate() 1 Answer
Gamecontroller "Awake" instantiates other objects - Event order question 2 Answers
Making the collider change after being instantiate 2 Answers
Tiny instantiated GameObject 2 Answers