# BGE: Basic Door & Key Logic

I’m trying to create a door & key system in the BGE, but I’m struggling with the game logic.

I followed a video tutorial to understand the basics, but I found that method doesn’t scale very well since it doesn’t take into account (1)different keys being required for different doors, (2)some doors not requiring keys, or (3)the ability of non-player characters to open doors (planning to add this later).

The approach I’ve come up with is as follows.

Each door sensor listens for 3 conditions:

• a player collision
• an attempt by the player to open (interact) with the door.
• a specific key (if required).

The door sensor is basically working. If its conditions are met it will cause the door to open. The key is able to be picked up, and send some message (“got_key_a”).

What isn’t working is that the door sensor collision can’t seem to be set to evaluate whether property “has_key_a” is True. Instead it simply sees that the property exists on the colliding object (Player), and lets them open the door regardless of whether they’ve acquired Key A.

Another approach I tried was sending a Message rather than using a property. The problem there seemed to be the timing of when the message was sent. I guess that the message being sent once doesn’t satisfy the condition… rather the message must be sent at the same time the other conditions are checked for. Since it is never the case that a a key is acquired at the same moment the corresponding door is tried, this approach does not work.

Screenshot just in case it helps:

I am open to Python-based solutions too, as long as the code is thoroughly commented so that it can be easily understood.

Any help appreciated.

## Update

I think my problem lies here. Instead of sending a signal only when has_key_a is True, it sends a signal if the property has_key_a exists.

I want has_key_a to be evaluated, but inserting expressions in the Collision Sensor is not allowed. What can I do instead?

If I use an Expression here I am unable to get it into the And controller. I must choose one or the other, but what I need is to combine them.

The door must be able to detect a collision with player who has_key_a==True and tries to interact at the same time.

• I have a video tutorial here, it's not in english, but you may reproduce the door mechanics I made in it (using a rigid body door, locking the transforms in some axis and using logic bricks and a property to set it to locked and opened): youtu.be/6GAqpdIsfW0 – Joel Gomes Feb 18 '19 at 9:51
• @JoelGomesdaSilva Okay, thank you for sharing. I look forward to watching it after I get home. – Mentalist Feb 18 '19 at 10:43
• @JoelGomesdaSilva Hey, great tutorial! I didn't know it was possible to make such a naturally swinging door in the BGE! Even though I didn't understand the words, I definitely learned some new techniques. – Mentalist Feb 18 '19 at 13:09
• @JoelGomesdaSilva A couple of questions... 1. What did you do with Collisions Groups in the beginning? 2. What did you do with State changes and your door lock Property Toggle? In mine I tried using the expression to check if the property is True, but for some reason it's registering as True before I even pick up the key. – Mentalist Feb 18 '19 at 13:45
• I've solved this and plan to post my solution soon. – Mentalist Mar 8 '19 at 17:51

A door key question deserves a dorky answer, so here goes...

I set up a Player and a Non-Player Character (NPC) which could just as easily serve as Player 2 in a 2-player game. Here I used it just for testing, although in a game it could serve as a scripted enemy or ally, or whatever. The point is that it can acquire keys just like the Player can.

Character Properties

These Boolean values go from 0 to 1 (False to True) when a key is acquired by the character.

(NPC has the same Properties as Player, except that it has the Property npc instead of player.)

Each character has its movement controls and an interaction control which can be used to (among other things) open doors when it is near them, and has the required key. Interaction from each character sends a unique message (either player_interact or npc_interact).

In order to add multi-key support, each character has a Sensor for each key, which all get fed into a Python Script Controller (keys.py).

keys.py

import bge
cont = bge.logic.getCurrentController()
own = cont.owner

key_alpha_status = cont.sensors["GetKeyAlpha"]
if key_alpha_status.positive:
own['has_key_alpha'] = True
print("Alpha Key acquired!")

key_beta_status = cont.sensors["GetKeyBeta"]
if key_beta_status.positive:
own['has_key_beta'] = True
print("Beta Key acquired!")

key_gamma_status = cont.sensors["GetKeyGamma"]
if key_gamma_status.positive:
own['has_key_gamma'] = True
print("Gamma Key acquired!")

key_delta_status = cont.sensors["GetKeyDelta"]
if key_delta_status.positive:
own['has_key_delta'] = True
print("Delta Key acquired!")

key_epsilon_status = cont.sensors["GetKeyEpsilon"]
if key_epsilon_status.positive:
own['has_key_epsilon'] = True
print("Epsilon Key acquired!")

key_zeta_status = cont.sensors["GetKeyZeta"]
if key_zeta_status.positive:
own['has_key_zeta'] = True
print("Zeta Key acquired!")


Character Logic

The key objects themselves don't play a very active role in the logic. If touched by something having the property player or the property npc the given key will disappear.

Key Logic

Each door object animates through various States, the important thing being that animation is initiated upon receiving a Message unique to that door (open_door01, open_door02, and so on).

Each door has a corresponding sensor object that is an Invisible physics Ghost. It's just an area within which collision can be detected, as one condition that needs to be met for a door to be opened.

Door Sensor Object - Physics Settings

We don't want it to be possible for a player to open a door from across the room - unless that door is intended to be opened by a remote switch, in which case the sensor can be moved to the location of the switch instead of surrounding the door.

Each door sensor object's game logic does two things:

(1) Checks if a character is colliding with the sensor object (using two Collision Sensors that listen for player and npc Game Properties respectively), and (2) Checks if the character is attempting interaction (by listening for either a player_interact or npc_interact Message). This input gets routed to a Python Script Controller for that specific door type (door_alpha.py, door_beta.py, and so on).

Door Sensor Object Logic

Someone with better programming skills than myself could surely find a way to eliminate the need for individual scripts for each door/key type, but at least this works. It just requires preparing one .py script of each door/key type by doing a Find/Replace in a text editor to change require_key_beta and has_key_beta to require_key_gamma and has_key_gamma... if you follow what I mean. I've only prepared Alpha and Beta types for this demo, since there are only two keys. How many key types do you realistically need? (6 should be plenty?)

door_alpha.py

import bge
cont = bge.logic.getCurrentController()
own = cont.owner

p_collision = cont.sensors["PlayerColl"]
p_interaction = cont.sensors["PlayerInteract"]

npc_collision = cont.sensors["NPCColl"]
npc_interaction = cont.sensors["NPCInteract"]

open_door = cont.actuators["OpenDoor"]

### PLAYER ###

#If this door requires a key, and player is colliding with it, and colliding player has the key, and a player interaction message is received:
if own['require_key_alpha'] == True and p_collision.positive and p_collision.hitObject['has_key_alpha'] == True and p_interaction.positive:
print("Door unlocked")
cont.activate(open_door)

#If this door requires a key, and player is colliding with it, and colliding player does NOT have the key, and a player interaction message is received:
if own['require_key_alpha'] == True and p_collision.positive and p_collision.hitObject['has_key_alpha'] == False and p_interaction.positive:
print("Can't unlock this door without a key")

### NON-PLAYER CHARACTER ###

#If this door requires a key, and non-player is colliding with it, and colliding non-player has the key, and a non-player interaction message is received:
if own['require_key_alpha'] == True and npc_collision.positive and npc_collision.hitObject['has_key_alpha'] == True and npc_interaction.positive:
print("Door unlocked")
cont.activate(open_door)

#If this door requires a key, and non-player is colliding with it, and colliding non-player does NOT have the key, and a non-player interaction message is received:
if own['require_key_alpha'] == True and npc_collision.positive and npc_collision.hitObject['has_key_alpha'] == False and npc_interaction.positive:
print("Can't unlock this door without a key")


The resulting output of the Python script (example:door_alpha.py) from the given door sensor object will activate a Message Actuator, which will send a Message with a subject such as open_door01, which I mentioned earlier.

Here are the parts of that code to pay attention to:

open_door = cont.actuators["OpenDoor"]


and within the IF statements:

cont.activate(open_door)


You know how the rest goes - corresponding door object receives the message, the animation of the door opening is triggered. Our player progresses and presumably has fun.

As for the animation of the doors, there are several ways to do it. Most will involve switching States. On my doors there are four States: Initial, Opening, Open, Closing. Closing loops back to Initial, in other words Initial is the same as Closed.

States can't be labeled directly, but labeling the State Actuator's destination makes it easier to keep track of what State should come next (In mine, the State Actuator of Initial is labeled "To Opening", for example).

Door Object Logic: Animating Through States

Door01 is basic, using Delay Sensors and Motion Actuators. For Door02 I wanted more control in animating individual parts of the door, so it makes use of Property Sensors (that evaluate if the Property frame is equal to a given frame, then change the State accordingly) and Action Actuators that play specific frame ranges of the animated Action and set the value of frame. Because Door02's animation is done using Actions, it is actually an Armature Object, with Mesh Objects parented to its animated Bones.

I think that covers everything. Enjoy playing with the .blend. If anyone has questions, comments, or ideas for improvement, I'm all ears.