0 votes

Hi, I'm trying to make mobs follow my player. I used a tutorial, but it is not working correctly for my code. The mobs all go to where the player start position is and pile up on eachother - do I have to instance the player instead or something? - I thought the tutorial I looked at didn't do that. Here is the code for my mob (named jelly):

extends KinematicBody2D

signal jelly_dead
var backcount = 1

var player = preload("res://player.tscn").instance()
# Node references
# Random number generator
var rng = RandomNumberGenerator.new()

# Movement variables
export var speed = 50
var direction : Vector2
var last_direction = Vector2(0, 1)
var bounce_countdown = 0

func _ready():

func _process(delta):

func _physics_process(delta):
    var movement = direction * speed * delta

    var collision = move_and_collide(movement)

    if collision != null and collision.collider.name != "player":
        direction = direction.rotated(rng.randf_range(PI/4, PI/2))
        bounce_countdown = rng.randi_range(2, 5)

func _on_Timer_timeout():
    # Calculate the position of the player relative to the mob
    var player_relative_position = player.position - position
    if player_relative_position.length() <= 16:
        # If player is near, don't move but turn toward it
        direction = Vector2.ZERO
        last_direction = player_relative_position.normalized()
    elif player_relative_position.length() <= 200 and bounce_countdown == 0:
        # If player is within range, move toward it
        direction = player_relative_position.normalized()
    elif bounce_countdown == 0:
        # If player is too far, randomly decide whether to stand still or where to move
        var random_number = rng.randf()
        if random_number < 0.03:
            direction = Vector2.ZERO
        elif random_number < 0.1:
            direction = Vector2.DOWN.rotated(rng.randf() * 2 * PI)
    # Update bounce countdown
    if bounce_countdown > 0:
        bounce_countdown = bounce_countdown - 1

What could I do to fix this?

in Engine by (24 points)
edited by

1 Answer

+1 vote
Best answer

As you suggested, I think your problem is that your player variable points to the definition of the player scene not the actual instance of that scene in your world.

You need your player variable to be a reference to the player object when that has been instantiated in the world (in the scene tree).

One way to do it is to

1) at the top of your script, change your definition of the player variable to simply declare the player variable (null), not define it (because it won't be instantiated until the node tree is created in game)
var player : Object = null

2) in your ready function you can set _player (it will have been instantiated at this point)
player = $"/root/World/player" [I do not know how you have setup the player in your node tree, so change this to the path to your player kinematic

These are the docs about using nodepaths here

Hard-coding a nodepath like this is fragile since you will need to update that it if you change where you player is in the tree. So you will probably want a more reliable method to figure out where the player object is in the tree. Documentation for other approaches is here

by (541 points)
selected by

Fixed! Thank you for highlighting the issue for me. Looks like I didn't follow the tutorial correctly (I'm only using it as a reference). I'm new to this and I think my biggest issue was understanding the what and why of the "root" node. I think I understand now though, it's just root by default always for your selected scene? Ah I guess, I'll read up on it.

Hi, Yes - the top node will always be root. So, when you look at the node tree in the GUI, you are seeing what comes after root (root is hidden)

Follow up question, in case you know whats going on:

I fixed the above problem but the instanced mobs still also don't detect collisions with the player, however the mob that is not instanced (placed in the scene editor) does. Why would that be?

EDIT: Looks like it only works if I configure that layer/mask of the player both to 1, along with the mob, for some reason it doesn't work if they have a layer/mask of something different from 1 even if everything is correct.

Hi, Yes - for collision detection to work they Mobs and Player need to share a common collision layer.
Are you changing the collision layer when you add the Player or Mob in the editor? If you are, you would need to ensure that mobs instanced in your script share a collision layer.

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 Frequently asked questions and 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 [email protected] with your username.