Open crazychenz opened 5 years ago
I have the same issue, however the code proposed here doesn't work for me : (
If I don't re-enable collision the map switching issue doesn't happen (but then the player has no collision lol).
Running in editor on: Godot 3.2.stable (steam version) MacOS Catalina 10.15.3
@LeTristanB, Sounds about right. I was shooting from the hip with that stuff. I ended up replacing all the gdquest code from my project, but I did still run into the issue where the collision event seems to be passed to a newly loaded scene. I'll have to look at the referenced code base again to see if I could actually patch it correctly for Godot 3.2. For now, the following is my new handler ... not sure if this pattern would work? (Just guessing for the time being.)
func _on_body_entered(body : Object, signame : String, tgtname : String, run_data : Dictionary = {}, park_data : Dictionary = {}):
if body is Player:
if park_data.has('doorexit'):
body.set_global_position(park_data.doorexit.get_global_position())
yield(get_tree(), "idle_frame")
g.call_deferred(signame, tgtname, run_data, park_data)
The extra arguments (i.e. tgtname, run_data, and park_data) just have to do with managing state. You can ignore that. signame is the function that gets called in response to triggering the signal handler. (It actually ends up calling a function called "change_client_scene" which does a load() -> remove_child(old_scene) -> add_child(new_scene)). I think the net effect of what I am doing is performing a double yield. First yielding for a frame and then doing a deferred call to the actual signal handler. This double yielding seems to have done the trick in my subsequent projects. Still doesn't feel quite right from a design pattern though.
Thanks for the report.
If I get it right, if you have doors in two different levels but that overlap with the player's location, and you spawn the player on that door, it triggers the two doors at once? From the way the game is coded, that's to be expected.
This project would need some serious code refactoring if we were to make it so you can use it as a template or something.
What I'd do is ensure the player doesn't spawn on a door, i.e. if it does, move it away from the door. Or have doors teleport to another location. See how we did this in the 2D platformer:
It's simple but it works well, we can teleport the player to any portal on any map
if you have doors in two different levels but that overlap with the player's location, and you spawn the player on that door, it triggers the two doors at once?
Not quite. I think when a player is added (add_child) to a new map, if on the new map there is a door at the position where the player was in the previous map, the door on the new map will detect a collision, despite if the player not spawning at that door's location. The bug looks like it's in the engine, not the project logic per se.
Here's a video of the unwanted teleport in action (the player should not spawn back to grassland because the player never touches the cave door to grassland): https://media.giphy.com/media/LmNqxjAFJlbfwWFWHf/source.mov
Here's how to set it up the maps to reproduce:
Using Godot 3.1.1 Stable, Windows 10, Building with GLES3 for Windows Desktop (debug builds only)
Steps To Reproduce
Work Around Overview
I still haven't pin pointed the actual bug, but I have a workaround that is acceptable for the moment.
Fundamentally, you need to disable the Player's collisions after the first door collision. This will prevent any other potential collisions from happening. Something like the following in Door.gd's _on_body_entered() call:
Now you need to re-enabled the collisions after any other signals may occur, but before the player starts playing again. This can be done in LevelLoader.gd's change_level() call:
And finally, it seemed like pausing the tree in Game.gd's change_level() call outside of the yield(transition) calls was causing some weird conditions, so I only pause the tree around the actual level transition:
And the enable_collisions() and disable_collisions() implementations in PlayerController.gd are:
Sorry for the code snippets. I would have done a fork and PR but I'm not convinced this fix is complete, its just a good enough work around for now.