Godot: GDScript variable chained assignment fails when an intermediate variable is readonly.

Created on 17 Aug 2020  路  4Comments  路  Source: godotengine/godot

Godot version: 3.2.2

OS/device including version: Windows 10

Issue description:

if you run move_and_collide on a KinematicBody and it collides with something, you can't set a value on the collider you hit, it throws the error:
"invalid set index 'collider' (on base: 'KinematicCollision2D) with value of type 'KinematicBody2D"
the example shown here: https://docs.godotengine.org/en/stable/tutorials/physics/using_kinematic_body_2d.html
does not work

Steps to reproduce:
Have to kinematic bodies next to each other, one has this code:

extends KinematicBody2D

func _physics_process(delta):
    var coll = move_and_collide(Vector2.LEFT * 50)
    if coll and "value_to_set" in coll.collider:
        coll.collider.value_to_set = true

the other has this:

extends KinematicBody2D

var value_to_set = false

Minimal reproduction project:

SetIndexBugKinematic2dColl.zip

bug confirmed gdscript

All 4 comments

"invalid set index 'collider' (on base: 'KinematicCollision2D) with value of type 'KinematicBody2D"

Edit: This works if you create and use a local reference to your collider.

code

extends KinematicBody2D

func _physics_process(_delta):
    var coll: KinematicCollision2D = move_and_collide(Vector2.LEFT * 50)
    if coll != null:
        var c: KinematicBody2D = coll.collider
        #print(c.name)
        if c.name == "Stationary":
            c.value_to_set = true
        if "value_to_set" in c:
            c.value_to_set2 = true

extends KinematicBody2D

var value_to_set := false
var value_to_set2 := false

var once := true
var once2 := true
func _process(_delta):
    if value_to_set and once:
        print("value_to_set:", value_to_set)
        once = false
    if value_to_set2 and once2:
        print("value_to_set2:", value_to_set2)
        once2 = false

Interestingly, value_to_set is set to true, the failure occurs afterwards when GDScript then tries to assign the KinematicBody2D to the collider variable and fails, because collider doesn't have a setter. Hence the error message:

Invalid set index 'collider' (on base: 'KinematicCollision2D') with value of type 'KinematicBody2D (Stationary.gd)'.

As @capnm suggested the workaround is to set the value in two lines:

func _physics_process(delta):
    var coll = move_and_collide(Vector2.LEFT * 50)
    if coll and "value_to_set" in coll.collider:
        var c = coll.collider
        c.value_to_set = true

Isn't there any other report about this? This is known for a while but we couldn't yet think of a good solution.

@vnen I think I've stumbled upon exact same issue as described here, I've implemented a LinkedList implementation in goostengine/goost#12 in C++, the LinkedList.front is exposed as a read-only properly (no setter), and to workaround this issue I have to either create intermediate references to front node (or back), or use LinkedList.find().value = "Godot", or by actually calling getter property get_front().value instead.

See detailed bug report at goostengine/goost#17 for more information.

Was this page helpful?
0 / 5 - 0 ratings