JSands
JSands

Reputation: 153

Moving an instanced player with move_and_slide

I am probably overthinking this or going about it the completely wrong way. Basically I want to use move_and_slide on the instanced player (aPlayer) where I've commented, #MOVE. This script is attatched to my Tilemap on an instanced Scene Level_Test.

Code in screenshot pared down for this post because it is not relevant and nonfunctional at this time.

extends TileMap

onready var aPlayer = preload("res://Scenes/Player.tscn").instance()

var cSpawn1 = Vector2.ZERO

func _ready() -> void:
    aPlayer.position = cSpawn1
    add_child(aPlayer)

func _physics_process(delta) -> void:
    if Input.is_action_just_released("iPlayerInteract"):
        _Interact()
    else:
        var vInputDirection = Vector2(Input.get_action_strength("iPlayerRight") - Input.get_action_strength("iPlayerLeft"), Input.get_action_strength("iPlayerDown") - Input.get_action_strength("iPlayerUp"))
        if vInputDirection != Vector2.ZERO:
            _Move(aPlayer, vInputDirection)

func _Interact():
    pass

func _Move(vSelf, vDirection):
    #MOVE
    pass

Screenshot

Player Scene

Upvotes: 1

Views: 983

Answers (1)

Theraot
Theraot

Reputation: 40285

The player.tscn scene as depicted in the screenshot is structured as follows:

Player (Node2d)
└ Body (KinematicBody2D)
  ├ Camera (Camera2D)
  ├ Collision (CollisionShape2D)
  └ Sprite (Sprite)

This is what gets instanced here:

onready var aPlayer = preload("res://Scenes/Player.tscn").instance()

That sets aPlayer to the root node of the instanced scene, which is a Node2D.

And thus what you pass into _Move (_Move(aPlayer, vInputDirection)) is a Node2D, which do not have move_and_slide, and thus calling move_and_slide on it results in error.

Instead move_and_slide exists in KinematicBody(3D) and KinematicBody2D.

The simple and elegant solution is make the KinematicBoyd2D (Body) the root of the scene. There is a "Make Scene Root" in the contextual menu you get on secondary click on the Scene panel, which will do that.

Alternatively you could also reach into the scene with get_node, for example:

vSelf.get_node("Body").move_and_slide(...)

Or for example:

onready var aPlayer = preload("res://Scenes/Player.tscn").instance().get_node("Body")

Addendum: There is another way if you think about it. You can add a script to the root node (Player) and declare whatever functions you want there, including but not limited to a move_and_slide that delegates to the KinematicBody2D (Body).

I should also point out that move_and_slide will move the KinematicBody2D, but not its parent. So the position property on the Player node will no longer be the position of the KinematicBody2D. And, well, you avoid all the trouble if you make the KinematicBody2D the root.

Upvotes: 1

Related Questions