Mobs are following the start position of the player, but not the player's relocated position after moving?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Pluto1

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():
	rng.randomize()
	$AnimatedSprite.play()

func _process(delta):
	pass
	
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?

:bust_in_silhouette: Reply From: AndyCampbell

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_body

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

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.

Pluto1 | 2020-11-12 04:34

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)

AndyCampbell | 2020-11-12 13:52

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.

Pluto1 | 2020-11-13 17:37

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.

AndyCampbell | 2020-11-13 23:23