0

can you please help me, I have this script:

extends KinematicBody2D

var motion = Vector2(0, 300)

var sensitivity = 13
onready var player = get_node("../Player")
onready var enemy = get_node("../Enemy")


func _ready():
    randomize()
    reset_ball()

func _physics_process(delta):
    if not get_parent().game_started:
        return
    if is_on_wall():
        motion.x *= -1
    
    
    if is_on_floor():
        touch_someone(player)
    if is_on_ceiling():
        touch_someone(enemy)
    
    move_and_slide(motion, Vector2(0, -1))


func touch_someone(node):
    motion.y *= -1
    motion.x = (position.x - node.position.x) * sensitivity

func reset_ball():
    motion.x = rand_range(-300, 300)

nd when I run the game this error message appears invalid get index 'game_started' (on base: 'Node').

This is the error

1 Answers1

2

The error is telling you that there isn't a game_started defined in the parent node. There is a parent node, but it does not have a property game_started defined.

You probably intended it to be a property, but you forgot to define it, defined it somewhere else, or you did define it in the correct place, but instanced the node under the wrong parent. However, it is also possible you made it a method and simply forgot (). I don't know which is the case.

Regardless, in Godot, a common design pattern is to access down and signal up the scene tree. In this case, you are trying to access up the scene tree. This is problematic because the scene can't ensure where it will be instanced.

I'll give you a few approaches to solve this problem:

  • Check if game_started exists.

    The change that will have a smaller impact on your architecture is to check if the parent node has game_started before trying to read it. Which looks something like this:

    var parent = get_parent
    if !"game_started" in parent or !parent.game_started:
        return
    

    However please notice that even if this gets rid of the error, it is not fixing the source of the problem. Since game_started is not defined in the parent anyway.

    Furthermore, _physics_process is still getting called. There are ways to don't even have the call, which is better for performance. Will come back to that.

  • Let the parent access the child.

    What you want to accomplish is to enable and disable _physics_process based on the value of game_started. There is a way to enable and disable _physics_process in the engine: set_physics_process.

    Presumably there is some other code somewhere that sets game_started on the parent, in that moment it could call set_physics_process on the child to disable or enable _physics_process accordingly.

    You may even use a property (with setget) to this effect.

    For example:

    var game_started:bool setget set_game_started
    
    func set_game_started(new_value:bool) -> void:
        if game_started == new_value:
            return
    
        for child in get_children():
            child.set_physics_process(new_value)
    
        game_started = new_value
    

    With this, your script does not have to check game_started. One drawback is that the code only uses set_physics_process on the direct children. We could write a recursive version, however, we can do better!

  • Use pause.

    As you can see in pausing games, you can use get_tree().paused to get or set if the game is paused. Which will stop _physics_process (among other methods) depending on the pause_mode.

    Thus, you can have the parent update get_tree().paused...

    Assuming, you also want a pause, you may follow this pattern:

    var game_started:bool setget set_game_started
    var game_paused:bool setget set_game_paused
    
    func set_game_started(new_value:bool) -> void:
        game_started = new_value
        update_pause()
    
    func set_game_paused(new_value:bool) -> void:
        game_paused = new_value
        update_pause()
    
    func update_pause() -> void:
        get_tree().paused = !game_started or game_paused
    

    Then, for the nodes that should still work when the game is paused or not started, you can se pause_mode = PAUSE_MODE_PROCESS so they don't get _physics_process et.al. disabled. Then they can check game_started and game_paused to distinguish if the game is paused or not started.

    A drawback is that this will affect nodes everywhere… If only game_started and game_paused could be available everywhere… Well, we can do that too!

  • Use an autoload.

    Make an autoload (via project settings) of a scene with a node that has game_started et.al. So that it is available from everywhere. Then you can access it from everywhere.

    You can do this combined with the paused as explained above. Which is what I would recommend.

    Alternatively. Since you can access it from everywhere, you you could simply access it instead of the parent:

    if !autoload_name.game_started:
        return
    

    This is the exception to the access down and signal up rule. Since the autoload is available everywhere and it does not depend on where or how the scene was instanced.

    I remind you, is that paused and set_physics_process will avoid the call to _physics_process, and thus are more performant than checking this way.

Theraot
  • 31,890
  • 5
  • 57
  • 86