Search Unity

Opening Door with Key

Discussion in 'Scripting' started by heyramb89, Jan 14, 2019.

  1. heyramb89

    heyramb89

    Joined:
    Dec 29, 2018
    Posts:
    29
    Hi,

    I am a newbie in Unity & C#.
    I am working on a 2D game & want a script which will open the door,
    Initially if clicked on the 2d sprite(Door) the dialogue appears saying, "It's locked."
    But if I use a correct key/ item it should go to the next scene.
    I have done dialogue & next scene stuff.
    But I don't understand how I should match the key item(prefab) which I have collected on the door.
    I tried using tag but don't know how to implement it.

    The current structure is:
    • The item(key) is gameObject on the scene which when player collects a prefab of key gets loaded in the inventory.
    • I have DragHandler attached on the same item (key) prefab.
    • Now I want this prefab when dragged on the door should load active next scene and destroy(remove) this prefab from the inventory.
    • Box Collider2D attached to the door.
    • UseItem script attached to the door.
    Do I also need to add bool for OpenDoor.
    The attached script taking(activating) me to the next scene but with any object which has been dragged on the door.
     

    Attached Files:

  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    Based on your script, you're only checking that something was dropped on the door. You need to do a check for what was dropped on the door. Either by checking what entered the collider or by checking it when it was dropped.
     
  3. romatallinn

    romatallinn

    Joined:
    Dec 26, 2015
    Posts:
    161
    So, let's think...

    The first question I have is whether or not there can be multiple doors and keys? So, for example, one key opens this specific door, and the other one opens another door. According to what I can see, you have only one door and one key, right?

    You indeed can use tagging. There are some other options as well; for example, using dedicated classes for both the key and the door. But let's do it with the tags.

    I would add a tag for the door, and not for the key. So, click on the door object (the part that has collider in it), click at the Tag menu -> Add tag. Click "+" in the following window and add "Door" as a new tag. Choose it for the corresponding prefab/object of the door.

    If I am not mistaken, then in the given code the key will just always disappear whenever you drop it on something. That is probably you don't really want to have, right? You want first check if this object is useable with the object under the mouse, and only then disable/remove it.

    I would change UseItem a little bit:


    Code (CSharp):
    1. public class UseItem: MonoBehaviour, IDragHandler
    2. {
    3.  
    4. // All variables ....
    5. // ....
    6.  
    7. public String useableWith = "Door"; // Tag that is usable with this object
    8.  
    9. public void OnDrop(PointerEvent data)
    10. {
    11.      if (data.pointerDrag != null) {
    12.           RaycastHit2D hit: RaycastHit;
    13.           Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    14.    
    15.           if (Physics2D.Raycast(ray, hit)) {
    16.                    if (hit.gameObject == useableWith)
    17.                     {
    18.                           ItemUsed();
    19.                     }
    20.            }
    21.      }
    22.  
    23. }
    24.  
    25. void ItemUsed()
    26. {
    27.      // Disable/remove object from the inventory
    28.      // etc
    29.      // Load new scene
    30. }
    31.  
    32. }
    33.  
    34.  
    It is not the best option ever. It all depends on your specific use case. For example, in this code I wrote key specific logic in the class named UseItem. But do other objects can be also usable, so they extend from this class? Then it's probably better to extend upon this class creating the Key class.

    Code (CSharp):
    1. public class KeyItem: UseItem
    And it is not that difficult to do. So, try the code and if it works fine, hit me up I'll help you to make it better, so there can be multiple usable/draggable objects with different outcome logic.

    The code is not checked, so let me know if any errors appear.
     
    Last edited: Jan 14, 2019
  4. heyramb89

    heyramb89

    Joined:
    Dec 29, 2018
    Posts:
    29
    Thanks for such an elaborated explanation.

    Yes, there are multiple doors with different keys to use.
    The code is throwing an error. Please check below:
    (20,19): error CS1525: Unexpected symbol `:', expecting `,', `;', or `='

    So, I changed " : " to " = ", but now it's throwing this error:
    (8,9): error CS0246: The type or namespace name `String' could not be found. Are you missing `System' using directive?

    I don't know which directive to use to solve this.
    Also I want to remove/deactivate the prefab (as key here) from inventory.
    Please check the attached screenshots for UseItem & PickUp Script.

    Thanks once again.


     

    Attached Files:

  5. heyramb89

    heyramb89

    Joined:
    Dec 29, 2018
    Posts:
    29
    Is this gonna do the trick for destroying prefab of key from the inventory?
     

    Attached Files:

  6. romatallinn

    romatallinn

    Joined:
    Dec 26, 2015
    Posts:
    161
    Then I would do it differently. Unfortunately, I won't be able to implement the entire system right here, but I'll try to give you a hint on how to approach it.

    Implement two classes: the key and the door. Both of them should have "the key property" as integer. So for a single cluster of doors/keys you assign the same number. In other words, the keys that have this property as "1", for example, will open only doors with the equivalent key.

    The door class would have a public method that accepts this key id. The passed key id would be then verified with its own key. If they are the same, then activate some desired logic (e.g., load new scene). Probably a good idea to return true/false, I'll explain it later.

    The key class ideally should inherit from UsedItem. I understand that you are a newbie. I cannot explain it easily, but it would really benefit. You should override ItemUsed method inside, so it would call out that OpenDoor method from the door class.

    So, simply stating, the core system would look like that:
    1. The key when it's dropped tries to access the door class on the object that was under it.
    2. The key could be dropped on something random. So in this case this door class will be absence. Just ignore it.
    3. If the object that was used with the key has indeed the door class, then call out the method that will verify whether or not this is a correct key by comparing the assigned properties.
    4. If the properties match, activate the desired logic (e.g., load new scene)
    5. In the key class you then need to check the return value (true/false). If it's true (the door was opened), you can delete the key from the inventory, etc. Otherwise, just ignore it or put the key back to the inventory.
    Hopefully it will give you an idea on how to implement the system you want...
     
    Last edited: Jan 16, 2019
  7. romatallinn

    romatallinn

    Joined:
    Dec 26, 2015
    Posts:
    161
    My bad... You have found the first typo, the second one is located at

    public String useableWith = "Door";


    but needs to be

    public string useableWith = "Door";
     
  8. romatallinn

    romatallinn

    Joined:
    Dec 26, 2015
    Posts:
    161
    It is a really difficult question. It depends on how your inventory works... And what does BasementKey(clone) return.

    But as far as I can see in your Pickup class,

    Destroy(gameObject);


    Should be enough.
     
  9. heyramb89

    heyramb89

    Joined:
    Dec 29, 2018
    Posts:
    29
    @romatallinn
    I was working on the easiest parts of the game. This is why it took me some time to reply.
    I tried to do as you said but still somethings are not clear to me.
    Please check the code below.

    Doors---

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Doors : MonoBehaviour
    6. {
    7.     public int doorNumber;
    8.     public bool isOpen;
    9.    
    10. }
    Keys---

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class KeyItem : DropHandler
    {
    private Doors doors;
    public int keyNumber;
    public bool isUsed;

    public override void ItemUsed()
    {
    if (keyNumber == doors.doorNumber)
    {
    doors.isOpen = true;
    isUsed = true;
    }
    }
    }

    DropHandler (changed name from UseItem)---

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using System.Linq;

    public class DropHandler : MonoBehaviour, IDropHandler
    {
    //public KeyItem keyItem;
    //public Doors doors;

    public GameObject item;

    public GameObject myCurrentScreen;
    public GameObject myNextScreen;

    public GameObject dialogues;
    public GameObject nextButton;

    public void OnDrop(PointerEventData data)
    {
    if (data.pointerDrag != null)
    {
    RaycastHit hit;
    var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

    if (Physics.Raycast(ray, out hit))
    {
    if (hit.collider != null)
    {
    Destroy(gameObject);
    ItemUsed();
    }
    }
    }
    }

    public virtual void ItemUsed()
    {
    myNextScreen.SetActive(true);
    myCurrentScreen.SetActive(false);
    dialogues.SetActive(false);
    nextButton.SetActive(false);
    }

    }

    I also didn't understood how to accept & verify keyIDs.