Search code examples
godotgdscriptgodot4

A better way for nodes to communicate between a classes inside a node script


Quick explanation: I have an objective system, its goal is to run and process objectives, for example wanting the player to go to a specific location or collect an amount of items.

the issue: So I am currently storing the nodes I need for my objectives in a dictionary with the key being a string and the value being a path to the nodes I need, I feel like there is a better way of doing it, I was thinking of utilizing signals but I am not an expert on using them, I was kinda thinking of somehow have the area3D have its own script that emits a specific signal with a keycode value (export var) and have the current objective listen to that keycode, I want to do something like this to avoid having links between nodes and should make it more dynamic, how do I go about doing this or something similar, also I am 100% open for even better ideas!

extends Node


@export var hud : CanvasLayer
# Holds objective nodes so we can connect them to the objective base class
@export var objective_configurations : Dictionary = {}
# Holds the logic, its a simple state machine that checks if the objective is complete
# or not and based on the information it returns we decide what happens.
var system = Objective_System.new()

func _ready():
    # Have a setup function to config each objective
    setup()

func _process(delta):
    # does the state machine comparisions in a match statement
    system.update()

func setup():
    # Get the path for our area3D we want
    var path_1 = objective_configurations.get("Location_1")
    # get the node using the path
    var node_1 = get_node(path_1)
    # create a specific objective with name and discription attached
    var objective_1 = Objective_Location.new("Go to pink area","You must find the pink area!!!")
    # set any variables the objective might need in this case an area3D
    objective_1.set_variables(node_1)
    # and finally add it to the system so it can be processed.
    system.add_objective(objective_1)
    
    # same as the top but a different area3D
    var path_2 = objective_configurations.get("Location_2")
    var node_2 = get_node(path_2)
    var objective_2 = Objective_Location.new("Go to the green area","Find the dangerous green area!!!")
    objective_2.set_variables(node_2)
    system.add_objective(objective_2)

as you can see I currently have a setup function that lets me do all the configuring but I feel like there is a better way of handling this, I simply want to setup to be just setting names and discriptions and maybe in the future some code key word for it to listen to.

class_name Objective_Location extends Objective

var Area : Area3D
var in_area : bool = false
func set_variables(_area : Area3D):
    
    Area = _area

func start_objective():
    Area.body_entered.connect(entered)
    print(Name)
    print(Discription)

func check_objective() -> States:
    if in_area:
        return States.Completed
    else:
        return States.Running

func completed_objective():
    print("Objective " + Name + " complete!")

func entered(body):
    if body is Player and Status != States.Done:
        in_area = true

and this is the objective go to location class, the base class holds 3 functions, start, check and complete objective


Solution

  • You can make a dynamic objective system using groups instead of manually setting each one of you objectives.

    For this, add the objectives nodes to a group through the Godot Interface: Image showing the Godot group interface

    Then, in the objective system, retrieve the nodes list using get_nodes_in_group function and iterate through them, like this:

    for objective_node in get_tree().get_nodes_in_group('guards'):
       var objective = Objective_Location.new("Go to pink area","You must find the pink area!!!")
       objective.set_variables(objective_node)
       system.add_objective(objective)