Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Using an Array to open a Door?

Discussion in 'Scripting' started by Daakk0, Aug 10, 2023.

  1. Daakk0

    Daakk0

    Joined:
    Sep 15, 2022
    Posts:
    3
    Hello!

    I'm making a game for my school project and it requires me to include an array within my code. I decided to use an array to keep track of 3 buttons that need to be pressed for the door to open. However, the only way to press a button is by using a gameObject with the "Box" tag to be placed 'in' it (Like in the puzzles in the game Portal where the box is put on the button and must stay on it to "power" the door).

    Moreover, the teacher said it could be a good idea to use lights as a way to indicate whether a button is pressed, and which one it is.

    So far, I've got this which my coding brother to help me on.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ArrayTest : MonoBehaviour
    6. {
    7.     public GameObject[] Lights = new GameObject[3];
    8.     public GameObject[] Buttons = new GameObject[3];
    9.     public Material[] material;
    10.     Renderer rend;
    11.     public bool[] lightsOn = new bool[3];
    12.     // 1. All 3 buttons are running this script separately. So each button will each have their own copy
    13.     // of the boolean array. How can we make all the buttons look into the same array, and not make their own copies?
    14.  
    15.     // 2. We needed to create the Buttons array on every single button (populating the array 3 times) to get this to work.
    16.     // There must be a better way of doing this, ie can we define the array somewhere else so we only define it once, and the script
    17.     // can look at that array?
    18.     public GameObject door;
    19.     bool isOpened = false;
    20.  
    21.     void Start()
    22.     {
    23.         rend = GetComponent<Renderer>();
    24.         rend.enabled = true;
    25.         rend.sharedMaterial = material[0];
    26.  
    27.         lightsOn[0] = false;
    28.         lightsOn[1] = false;
    29.         lightsOn[2] = false;
    30.     }
    31.    
    32.     void OnTriggerEnter(Collider col)
    33.     {
    34.         //The buttons hit SOMETHING
    35.         if (col.gameObject.tag == "Box")
    36.         {
    37.             //The buttons (any of them) hit a Box
    38.             //"gameObject.name" = the name of the Box that was hit
    39.             //Debug.Log(gameObject.name);
    40.             if(gameObject.name == Buttons[0].name)
    41.             {  
    42.                 //this means, button 1 got hit
    43.                 Lights[0].GetComponent<Renderer>().material = material[1];
    44.                 lightsOn[0] = true;
    45.             }
    46.             else if (gameObject.name == Buttons[1].name)
    47.             {
    48.                 //this means, button 2 got hit
    49.                 Lights[1].GetComponent<Renderer>().material = material[1];
    50.                 lightsOn[1] = true;
    51.             }
    52.             else if(gameObject.name == Buttons[2].name)
    53.             {
    54.                 //this means, button 3 got hit
    55.                 Lights[2].GetComponent<Renderer>().material = material[1];
    56.                 lightsOn[2] = true;
    57.             }
    58.             //Lights[1].GetComponent<Renderer>().material = material[1];
    59.         }
    60.         else if(col.gameObject.tag != "Player")
    61.         {
    62.             //No collisions
    63.             Lights[0].GetComponent<Renderer>().material = material[0];
    64.             Lights[1].GetComponent<Renderer>().material = material[0];
    65.             Lights[2].GetComponent<Renderer>().material = material[0];
    66.         }
    67.  
    68.         Debug.Log(lightsOn[0] == true &&
    69.            lightsOn[1] == true &&
    70.            lightsOn[2] == true);
    71.  
    72.         if (lightsOn[0] == true &&
    73.            lightsOn[1] == true &&
    74.            lightsOn[2] == true && !isOpened)
    75.         {
    76.             //open door
    77.             isOpened = true;
    78.             door.transform.position += new Vector3(0, 4, 0);
    79.         }
    80.     }
    81.  
    82.     void OnTriggerExit(Collider col)
    83.     {
    84.         if (col.gameObject.tag == "Box")
    85.         {
    86.             Lights[1].GetComponent<Renderer>().material = material[0];
    87.         }
    88.     }
    89.  
    90.  
    91. }
    92.  
    Essentially, the comments at the top labeled "1." and "2." are the problems we have that we have no idea how to solve. I've brought it up to my teacher and he instead offered his solution of creating a "gameManager" to fix the problem of having multiple arrays.

    As such, I have created these 2 scripts which have the rough idea of what I want to do (excluding the lights first, I just want the buttons and door to work at least).

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GameManager : MonoBehaviour
    6. {
    7.  
    8.     Trigger trigger;
    9.     public GameObject[] Buttons = new GameObject[3];
    10.     public int[] ArrayC;
    11.  
    12.     void Awake()
    13.     {
    14.         ArrayC[0] = 1;
    15.     }
    16.  
    17.     void Counter()
    18.     {
    19.         if (ArrayC[0] == 1)
    20.         {
    21.             ArrayC[1] == 1;
    22.         }
    23.         else if (ArrayC[1] == 1)
    24.         {
    25.             ArrayC[2] == 1;
    26.         }
    27.     }
    28.  
    29.  
    30. }
    31.  
    32.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Trigger : MonoBehaviour
    6. {
    7.     GameManager gameManager;
    8.     public bool onState = false;
    9.     void OnTriggerEnter(Collider col)
    10.     {
    11.         ArrayC[0] = 1;
    12.     }
    13.  
    14.    
    15. }
    16.  
    I have looked at numerous sources regarding how to reference other scripts in my "GameManager" and how to change array indexes but none have been fruitful.

    So sorry for the long post but I have been really stumped on this for the last 4 days, and slowly getting annoyed at myself for just not getting it haha.

    Anyways, hopefully someone took the time to read through this and hopefully your solution could help.

    Thank you SO much!
     
  2. Chubzdoomer

    Chubzdoomer

    Joined:
    Sep 27, 2014
    Posts:
    106
    For a multi-button door like this, you might want to break it up into three main parts:
    • A "ButtonGroup" script that accepts an array of buttons and then performs a certain action once every button in that array is pressed (Sidenote: I don't much care for the name "ButtonGroup," but wasn't sure what else to call it)
    • A "Button" script that handles one particular button's status (pressed or not pressed)
    • A "Door" script that contains a public Open method (to be called by the ButtonGroup script once all of its buttons are pressed)

    How you actually tie this all together is up to you, and could be done in countless ways. You could use an event system for example and make it so that every Button fires off an OnPressed/OnReleased event that the ButtonGroup listens for/reacts to. To open the door, you could give the ButtonGroup script a public OnAllButtonsPressed UnityEvent, which allows you to hook up another object's (public) method via the Inspector (in this case, the Door script's public Open method).

    Here's an ultra simple event-driven example I whipped up, using free assets from Kenney.nl:
    https://www.mediafire.com/file/dorfuuzw6zyrw1w/Multi+Button+Door+Example.unitypackage/file

    Click on a button to press it, and click again to release it. The door will only open once all three are pressed, and will close the moment so much as one of them is released.
     
    Last edited: Aug 10, 2023
  3. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728


    If your teacher is anything like me, they are going to have a heart attack seeing so many "GetComponent()" calls. I would research into "caching variables". ;)

    And personally I would have the "door" as a separate script, and have all of it's buttons/lights/materials as cached variables, which I guess would all be in arrays. That way functions inside the door can be more general in a sense, and easy to add more buttons/functionality(which I think is why your teacher is hinting arrays).

    Since writing out button1 does this, button2 does that, button3 does the other thing, can be quite the task if you write them all out like that. So using Arrays or Lists can easily make one function do all, the only thing that changes is the index of which one is to be used at that time.
    doors[2].ActivateButton(3);


    Another hint I'll give you, since that's the point of having a teacher is so you can learn and understand, is it's often best to make a Array or List of the class, not the object or it's component. Because once you get the reference of the class, you can easily call:
    Code (CSharp):
    1. for (int i = 0; i < allDoors.Count; i++)
    2. {
    3.     allDoors[i].Close_ResetAllButtons();
    4. }
    But for sure, whenever you get more than 3 of typing the same thing over and over? It's probably best to put it into an Array or List. :)