Game Over and Key/Door Relationship

Hey guys

So i’m struggling to find an example for a game over and reset on here. It might be under “death”. I have a trigger collision zone that is obviously invisible. It’s very similar to How to make game objects detect when you cross their vision? (SOLVED) in this one, police officers are searching for you (the robber) and if you get in their line of sight (I added a trigger collision zone) you die and restart from the start. Any clues on how I can do this?
— To recap: how to tell the game that the game is over once I cross the trigger zone

Another thing is that I can’t find a key/door relationship. You need to grab the key and unlock the door to move. The game objects are key.go and door.go, how would I go about doing that?

I appreciate any help.
Thanks

There are a number of ways to game restarts this depending on how you game is setup. The easiest way would be to reload the game collection. If you are using collection proxies to load the game collection then you can just unload and reload the game. I assume you’re not building your game world dynamically so this is your main option but if you change your game to build its level layouts based on some meta data then there are other ways to go about it.

The runner example shows another way to restart a game which is to reinitialize everything manually https://www.defold.com/tutorials/runner/

For key/door relationship you can put a property on each key/door with a numeric value to show association. So if key.go and door.go each has a script add go.property("key", 0) to each and then in the editor you can set this property so that they have an association. Then when player collides with a key value add that key value to a table in the player’s key data and let the player open any door with a key value they have.

so for the Key/Door relationship, I have to set a collision script for both Key.go and door.go? If I want each key to have an exclusive relationship to its own door, then would I be better of creating key1.go, key2.go etc. or just creating a table that stores the data separately?

What’s better is ultimately up to your design. Right now it’s okay to test different ideas and see what works best until you figure out the best design. You absolutely do not want for example a ton of different unique scripts for each key with hard coded data. That’s what the script properties are for so you can have a generic script and then define variables in the properties. So you would still have a single key.go and a single door.go but duplicate them in a collection and define different script properties to tie them to different key sets. I’ll make a small example and post it soon.

1 Like

And here’s an example. I modified my FOV example to add keys/doors.

So there is only one key.go and one door.go and only one key.script and one door.script. Both key.script and door.script have keyset properties, which in the collection they are placed in have different values set. Both scripts watch player_data to compared their position to the player position to know if there is a collision or not. If keys get collision then they are added to the player’s key inventory. When the player collides with a door the door checks to see if the player has the door’s keyset key yet or not.

door_keyset_example.zip (290.1 KB)

4 Likes

Thank you.
Im also having trouble with the death script I got from https://www.defold.com/examples/physics/trigger/

I established a trigger zone with the proper groups and masks and wrote the following script

> function on_message(self, message_id, message, sender)
>     if message_id == hash("trigger_response") then 
>         if message.enter then 
>             msg.post("#player", "reset") 
>         end
>     end
> end

but it’s not doing anything. Isn’t this right? the #player (player.go) should reset if I go through the zone. I don’t want the level to reset, just the player. I feel like that’s a lot easier because as of right now I only have one level.

EDIT: This also removes all static collision relationships I have :frowning:

You have to add something to your player script to watch for the “reset” message and place it back at its original position. On the player script’s init you can save the initial values to for example self.start_position so that it’s easier to reset the player.

Publish your project to github or here as a zip and we can offer better advice for what is wrong.

So in natural fashion… it says there is an error so it wont zip it so here is my entire code. (I changed the format of the game to a goat trying to escape and I haven’t done the keys yet because the trigger zones are not working)

> function init(self) 
>     msg.post(".", "acquire_input_focus") 
>     self.start_position = go.get_position()
> 
>     self.moving = false     
>     self.input = vmath.vector3() 
>     self.dir = vmath.vector3(0, 1, 0) 
>     self.speed = 300
> end
> 
> function final(self) 
>     msg.post(".", "release_input_focus") 
> end
> 
> function update(self, dt) 
>     if self.moving then
>         local pos = go.get_position() 
>         pos = pos + self.dir * self.speed * dt 
>         go.set_position(pos) 
>     end
>     
>     self.input.x = 0 
>     self.input.y = 0
>     self.moving = false
> end
> 
> function on_input(self, action_id, action) 
>     if action_id == hash("up") then
>         self.input.y = 1  
>     elseif action_id == hash("down") then
>         self.input.y = -1
>     elseif action_id == hash("left") then
>         self.input.x = -1
>     elseif action_id == hash("right") then
>         self.input.x = 1
>     end
>         
>     if vmath.length(self.input) > 0 then
>         self.moving = true 
>         self.dir = vmath.normalize(self.input) 
>     end
> end
> 
> function on_message(self, message_id, message, sender)
>   -- Handle collision
>   if message_id == hash("contact_point_response") then
>     local newpos = go.get_position() + message.normal * message.distance
>     go.set_position(newpos)
>   end
> end
> 
> function on_message(self, message_id, message, sender)
>     if message_id == hash("trigger_response") then 
>         if message.enter == hash("danger") then
>        		msg.post("#playerCS", "disable")
>             msg.post("#playerCS", "reset") 
>         end
>     end
> end

gamefss

the group for the trigger lights and the static walls is named “wall” because that is, for some reason, the only relationship the engine recognizes.

As @Pkeod pointed out. The reset message is not something provided and handled by and the engine itself. You need to add an on_message handler in the player script that reacts to the reset message. You can see what I mean if you check the hero.script of the Runner tutorial.

My new code is a mix from the snake tutorial I feel like that’s easier to understand as it uses a self.alive command. I have mixed it in with the command from the runner tutorial. I’m not a programmer so sorry if I’m having trouble understanding it.

function init(self) 
    msg.post(".", "acquire_input_focus") 
    self.start_position = go.get_position()

    self.moving = false     
    self.input = vmath.vector3() 
    self.dir = vmath.vector3(0, 1, 0) 
    self.speed = 300
    self.alive = true
end

function final(self) 
    msg.post(".", "release_input_focus") 
end

function update(self, dt) 
    if self.moving then
        local pos = go.get_position() 
        pos = pos + self.dir * self.speed * dt 
        go.set_position(pos) 
    end
    
    self.input.x = 0 
    self.input.y = 0
    self.moving = false
end

function on_input(self, action_id, action) 
    if action_id == hash("up") then
        self.input.y = 1  
    elseif action_id == hash("down") then
        self.input.y = -1
    elseif action_id == hash("left") then
        self.input.x = -1
    elseif action_id == hash("right") then
        self.input.x = 1
    end
        
    if vmath.length(self.input) > 0 then
        self.moving = true 
        self.dir = vmath.normalize(self.input) 
    end
end

function on_message(self, message_id, message, sender)
  -- Handle collision
  if message_id == hash("contact_point_response") then
    local newpos = go.get_position() + message.normal * message.distance
    go.set_position(newpos)
  end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("reset") then
		self.velocity = vmath.vector3(0, 0, 0)
		self.correction = vmath.vector3()
		self.ground_contact = false
		self.anim = nil
		go.set(".", "euler.z", 0)
		go.set_position(self.position)
		msg.post("#playerCS", "enable")
	end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("trigger_response") then 
        if message.enter == hash("danger") then
        	self.alive = false
       		msg.post("#playerCS", "disable")
            msg.post("#playerCS", "reset") 
        end
    end
end

The runner tutorial is hard to apply to mine because it forces the game to spawn in objects and when you die, it forces it to despawn the objects. The only thing I want to do is just move the character back to where the character starts the level once the character crosses a trigger zone

You cannot have two on_message functions like you have in your code. What is playerCS? I assumed this was another script. Where is the script you posted above attached?

Both scripts I have showed you are part of the same player script (attached to the player object). Should I have a separate collision script for the player? PlayerCS is the name of the kinematic collision object that I assigned to the player.go character.

In the script, the first “on_message” was from the link below where you helped with the collisions for the walls (which worked by the way) but they bypassed the “group” and “mask” relationship. As in, any group not named “wall” or “player” would not get triggered.

the second on_message defines the reset function and the final one tells me to reset the player. Should I have only one on_message and have the rest in on_update?

As you posted in here Collision detection here is my entire(?) project gamefiles_goat.zip (4.6 MB)

Ok, so if it’s a single script and attached to the player object then there’s no need for any reset message. Like this:

function on_message(self, message_id, message, sender)
	-- Handle collision
	if message_id == hash("contact_point_response") then
		local newpos = go.get_position() + message.normal * message.distance
		go.set_position(newpos)
	elseif message_id == hash("trigger_response") then 
		if message.enter == hash("danger") then
			-- return player to original position
			go.set_position(self.start_position)
		end
	end
end
1 Like