0 votes

Hey all,

I'm fairly new to Godot, but I've been programming games for a bit. I understand GDScript, but using it fully still escapes me. So i'm still learning/struggling. I moved over from python/pygame for obvious reasons.

Anyway, I'm working on a sokoban style puzzle game (grid based movement) and I want blocks that have moved next each other to 'combine' and move together. Kinda like legos. I'm currently using raycast2D to detect collision between sprites, and it has been successful, but I receive an error when the sprite being moved collides with a wall (object in tilemap).

This is the error: Invalid get index 'position' (on base: 'Node').

To track the position i'm essentially grabbing colliding sprite and saving it once in a variable. Then I match the collided sprites position to that of the one that is in 'control' or allowed to move, but again I receive the error when the control sprite reaches a collision.

The idea behind control is that i'll have multiple instances of a sprite and have the ability to shuffle control between the various sprites in a scene.

Here is the sprite script:

extends Sprite

# if the sprite is currently in control, can be rotated with space
export var Control = false

# make the raycast available to use in the player script
onready var ray = $Area2D/RayCast2D
onready var rayUP = $Area2D/rayUP
onready var rayDOWN = $Area2D/rayDOWN
onready var rayLEFT = $Area2D/rayLEFT
onready var rayRIGHT = $Area2D/rayRIGHT

# detect collision only once with these flags
var colUP = false
var colDOWN = false
var colLEFT = false
var colRIGHT = false

var UColSprite
var DColSprite
var LColSprite
var RColSprite

var speed = 600 # large speed value to determine how fast the sprite will move
var tile_size = 64 # size in pixels of the tiles on the grid

var last_position = position # last idle position to keep track of
var target_position = position # new position to be moved to
var movedir = Vector2(0, 0) # the move direction 

# init function
func _ready():
    # snap the player to a grid position if misplaced
    # and update its position trackers to the snapped vector2
    position = position.snapped(Vector2(tile_size, tile_size))
    last_position = position
    target_position = position

# set move direction based on player input
func get_movedir():
    # collect the input and store it
    var LEFT = Input.is_action_pressed("ui_left")
    var RIGHT = Input.is_action_pressed("ui_right")
    var UP = Input.is_action_pressed("ui_up")
    var DOWN = Input.is_action_pressed("ui_down")

    # process the movement based on each vector
    movedir.x = -int(LEFT) + int(RIGHT) # is negative one if moving left and vice versa, if both then zero
    movedir.y = -int(UP) + int(DOWN) # same up with y

    # prevent diagonal movement
    if movedir.x !=0 && movedir.y != 0:
        movedir = Vector2.ZERO # no value

    # set the end of the ray cast to the edge of the player sprite
    if movedir != Vector2.ZERO:
        ray.cast_to = movedir * tile_size / 2

# process movement every frame
func _process(delta):

    if Control == true:
        # idle
        if position == target_position:
            get_movedir()
            last_position = position # save the players current position
            target_position += movedir * tile_size # if movement, then calculate new target position


        # moving
        else:

            # make sure not to move the player if they will collide with a wall
            if ray.is_colliding():
                target_position = last_position # set the player back to there original location
            else:
                # update the position
                position += speed * movedir * delta

                # prevent the player from moving past the target
                var distance = (position - last_position).abs().length() # how far they moved frem the idle position

                # track the distance
                if distance > tile_size - speed * delta:
                    # subtract speed * delta so there's no break/pause in movement
                    position = target_position
    else:
        # if the sprite is not being controlled, collect a collision if the controlled sprite moved next to it6

        if rayUP.is_colliding():
            if colUP == false:
                colUP = true
                UColSprite = rayUP.get_collider().get_parent()
            position = UColSprite.position - Vector2(0, 64)


        if rayDOWN.is_colliding():
            if colDOWN == false:
                colDOWN = true
                DColSprite = rayDOWN.get_collider().get_parent()
            position = DColSprite.position + Vector2(0, 64)

        if rayLEFT.is_colliding():
            if colLEFT == false:
                colLEFT = true
                LColSprite = rayLEFT.get_collider().get_parent()
            position = LColSprite.position + Vector2(64, 0)

        if rayRIGHT.is_colliding():
            if colRIGHT == false:
                colRIGHT = true
                RColSprite = rayRIGHT.get_collider().get_parent()
            position = RColSprite.position - Vector2(64, 0)
in Engine by (19 points)

1 Answer

0 votes

You can avoid this specific error by converting the node that contains your walls to Node2D. The class "node" is too general to have a variable for "position" its only at the level of Node2D and after that the concept of space exists.
(Sprite < Node2D < CanvasItem < Node < Object)

However assuming you have walls placed in the scene to test, that parent (with the type Node) will just move the player to the same position which ever wall it collides with? Project files needed for further details.

by (911 points)

Thanks!

I figured it out based on your response.

The Tilemap within my level scene tree was reporting collision to the root of the scene, which like you said has no "position".

I just had to turn collision with bodies off within the raycast2D nodes that I have attached to my sprite to stop the error from occurring!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.