1
votes

Im making a platformer in godot and in the physics process im getting the players location so I can move the enemy to it(its in the enemy's script but I can not figure out how to move it there im using get_node("/root/World/Player").get_position() to get the location but when I move and slide towards the player it gives me an error.(btw it is a platformer so it would be nice if the method added gravity)

Invalid type function 'move_and_slide' in base 'KinematicBody2D (enemy.gd)'. Cannot convert argument 2 from float to Vector2.

(It would be nice if the way it

1

1 Answers

0
votes

Let us start by looking at the documentation of move_and_slide. This is the signature of the function:

Vector2 move_and_slide ( Vector2 linear_velocity, Vector2 up_direction=Vector2( 0, 0 ), bool stop_on_slope=false, int max_slides=4, float floor_max_angle=0.785398, bool infinite_inertia=true )

Notice:

  • The first parameter is a velocity vector.
  • The second parameter is an up vector.

Thus, this function does not work with a position.

And the error you are getting is because you are passing a float on the up parameter.


Why does move_and_slide take an up vector? It is because move_and_slide updates the values you get from is_on_ceiling, is_on_floor and is_on_wall. And how does it know what is a ceiling, a floor or a wall? That's right, it needs to know what way it up. If you let the up vector at ZERO (or just not pass it, since that's the default value), they are all considered walls (and this is OK for a top down game).


Now, you want to do a platformer game, presumably a side scroller. Most likely you want to pass Vector2.UP as second parameter. And that should fix the error.


However, you are sneaking another question in there. One more suited for gamedev.stackexchange.com. You can ask question there (and it does not have to be that you are getting an error).

So, you want to implement a kinematic body with gravity that chases the player. Let us start with the gravity…

The run of the mill code for a kinematic body with gravity looks like this:

extends KinematicBody2D

export(Vector2) var velocity:Vector2
export(float) var gravity:float = 100

func _physics_process(delta:float) -> void:
    velocity.y += gravity * delta
    velocity = move_and_slide(velocity, Vector2.UP)

Ok, gravity is probably not 100. But that is the basic structure of the code. Note the distance units - being a 2D game - are in pixels, and delta is in seconds. Thus, gravity is in pixels per second squared.


And you want to chase the player avatar. In order to implement that I'll do the following changes:

  • Have a reference to the player avatar.
  • Split velocity into vertical and horizontal components.
  • Have an horizontal speed.
extends KinematicBody2D

export(NodePath) var player_path:NodePath = @"/root/World/Player"
export(float) var horizontal_speed:float = 100
export(float) var gravity:float = 100

onready var player:Node2D = get_node(player_path)
var _velocity:float = 0

func _physics_process(delta:float) -> void:
    _velocity.y += gravity * delta
    _velocity = move_and_slide(_velocity, Vector2.UP)
    var direction_to_player = transform.origin.direction_to(player.transform.origin)
    _velocity.x = direction_to_player.x * horizontal_speed

This code uses a NodePath to find the player avatar. Which it queries on ready, and uses that reference from there on. Assuming the player is always there, that is no problem.

The horizontal_speed specifies how fast it moves horizontally towards the player. In pixels per second.

If you don't want it to change velocity while it is in the air, we can do that too:

extends KinematicBody2D

export(NodePath) var player_path:NodePath = @"/root/World/Player"
export(float) var horizontal_speed:float = 100
export(float) var gravity:float = 100

onready var player:Node2D = get_node(player_path)
var _velocity:Vector2 = Vector2.ZERO

func _physics_process(delta:float) -> void:
    _velocity.y += gravity * delta
    _velocity = move_and_slide(_velocity, Vector2.UP)
    if is_on_floor():
        var direction_to_player = global_transform.origin.direction_to(player.global_transform.origin)
        _velocity.x = direction_to_player.x * horizontal_speed

Notice I'm using global_transform.origin. You could also use global_position. Don't use transform.origin nor position, because they are relative to the parent node. And if the parent is not the same, you are going to get a wrong direction. *I bias towards using transform because

Notice also I'm using is_on_floor after move_and_slide, so I get the updated value. I strongly encourage this pattern: gravity, move_and_slide, decisions.

This is not going to jump or climb ladders or anything like that. It will also get stuck on walls. It has nothing resembling path finding or obstacle avoidance. So, as you can imagine, it can get quite complex depending on what you want to do. However, it grows from there. I know little of the behavior you want to give these kinematic bodies, beyond that you want them to go to the player, using mode_and_slide and with gravity, I have no idea. Thus, I cannot help you further.