#Top-down 2D RPG, Adding regions to the overworld

1 messages · Page 1 of 1 (latest)

mint token
#

Hello all! I am attempting to make my first game, which is a top-down 2D RPG in the style of Dragon Warrior/Dragon Quest. I have a basic overworld composed of a Node2D with a TileMapLayer which provides the terrain and impassible obstacles (mountains, water, etc). I have a Player scene composed of a CharacterBody2D with animations and a CollisionShape2D which I have moving around the map in a satisfactory manner. So far so good. Next I want to add different regions to the map which, upon entry, will update some settings about the frequency of random encounters and a dictionary containing which encounters are possible (along with their relative rarity).

In order to accomplish this, I created a scene called DifficultyRegion which extends Area2D. My thought process is that I could create multiple DifficultyRegion nodes in the overworld, give them each a child CollisionShape2D in the overworld (so the overworld scene controls the placement of each zone), and then use the GDScript of the DifficultyRegion to emit a signal whenever the player enters that region. My script is as follows:

class_name DifficultyRegion
extends Area2D

@export
var region_name: String
@export 
var encounter_frequency: int
@export
var encounter_types: Dictionary

signal difficulty_region_changed(region_name: String, encounter_frequency: int, encounter_types: Dictionary)

func _on_body_entered(body: Node2D) -> void:
    print("DifficultyRegion Entered by body of type " + body.get_class())
    if body.get_class() == "Player":
        difficulty_region_changed.emit(region_name, encounter_frequency,  encounter_types)

Unfortunately, in spite of hooking up the signal 'body_entered' signal of the Area2D to the to the _on_body_entered() function, it doesn't seem to be firing at all. Can anyone spot what I'm doing wrong?

steel kettleBOT
obtuse crag
#

Have you checked your collisions are on the correct layers to fire events between each other. There are two settings collision layer and collision mask. They need to be set appropriately and you should also make sure your signals are appropriate for the nodes youre using. The areas that are being monitored for may not be appropriate types.

#

Can't look at the code right now but those are the things I'd check for initially when your signals aren't firing off.

mint token
obtuse crag
#

Does your character body have a collision shape?

#

I see now that I'm looking at your node tree your character player has no collision shape. That's probably why it's not working.

#

If your player scene does have a collision shape inside the scene what does that scene look like?

agile laurel
#

Player has no CollisionShape

mint token
#

The player has a CollisionShape2D and a state machine for managing movement. The Overworld scene contains a DifficultyRegion which is working with the same layer and mask as the player. For context, here is the State Machine and the two states it currently has:

extends Node

@export
var starting_state: PlayerState

var current_state: PlayerState

func init(parent: Player) -> void:
    for child in get_children():
        child.parent = parent
    change_state(starting_state)

func change_state(new_state: PlayerState) -> void:
    if current_state:
        current_state.exit()
    current_state = new_state
    new_state.enter()

func process_physics(delta: float) -> void:
    var new_state = current_state.process_physics(delta)
    if new_state:
        change_state(new_state)

func process_input(event: InputEvent) -> void:
    var new_state = current_state.process_input(event)
    if new_state:
        change_state(new_state)

func process_frame(delta: float) -> void:
    var new_state = current_state.process_frame(delta)
    if new_state:
        change_state(new_state)

extends PlayerState

@export
var move_state: PlayerState

func enter() -> void:
    super()
    

func process_input(event: InputEvent) -> PlayerState:
    var direction: Vector2 = _get_movement_vector()
    if direction != Vector2.ZERO:
        return move_state
    return null

func process_physics(delta: float) -> PlayerState:
    return null

func process_frame(delta: float) -> PlayerState:
    return null

#

And the move state (message too long before):

steel kettleBOT
mint token
obtuse crag
#

Might be something to do with your collision shapes and your custom movement. Could be that your collision shapes aren't moving around or your signals aren't being listened for in the right place. Hard to say without seeing the app run or knowing more about how you've got everything set up. Reach out again if you want.

mint token
#

@obtuse crag I have this project in a private Github repo which I'd be happy to add you to temporarily if you'd like. Barring that, I'll see if I can record a demo like yours. Honestly I'm baffled by the situation. My character collides properly with tiles on the TileMapLayer which have collision defined, so I feel confident the player's collision shape is moving with them. More baffling still, if I handle the DifficultyRegion's body_entered from the level scene itself it works exactly as I expected it to when handling it from the inside.

obtuse crag
#

That does seem odd! I'll send you a DM to my Github account and I'd be glad to take a look.

mint token
#

I appreciate the help! I am also currently in handbrake trying to compress the screen recording I just took so it's small enough to pist here.

obtuse crag
#

Figured it out! Your difficulty_region node in your test_arena.tscn scene is not actually pointing to your difficulty region scene.
Notice how the script icon here is darkened and doesn't have the scene icon next to it. At some point in developing you added your difficulty_region node to the scene tree of test_arena.tscn in a way that didn't instantiate it from the actual file.

#

Cool game so far, good luck in your development!

mint token
#

Interesting! I added it by selecting the TestArena node and pressing command+A to add a sub node, and then selected DifficultyRegion from the new Node dialog. I've just tested again, and this does not seem to do what I expect it to do! How would you recommend adding the DifficultyRegion to the TestArena?

#

Nevermind, I tried again using the "Instantiate Child Node" button next to the "Add Child Node" button, and that seems to have done the trick!

#

@obtuse crag I appreciate your help, and will mark this thread as resolved!

obtuse crag
#

Yep! Adding as sub node is different, that's like adding a node of type DifficultyRegion to the scene instead of adding the actual scene so your connections weren't fully there. You can create custom nodes in Godot which is where sub node would be useful I think. I'm not too familiar with that feature.

If you're trying to reuse a scene always use Instantiate Child Node.