Make the Position2D node follow the player in Godot.

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

In my project there a enemy(position2D) node which instances obstacles.But as the player moves the enemy node is struck where it originally was. I tried making the enemy node child of player but I am getting error. Can anyone tell me how can i move the enemy(Position 2D) move ahead of the player such that as the player moves the enemy node is instanced creating obstacles as the player moves forward ?
Here is the Project

:bust_in_silhouette: Reply From: whiteshampoo

You can check the position of the player, and add an offset to the y-value,
Add this to your enemy-script:

export var offset : float = -800
	
func _process(delta: float) -> void:
	var Player : KinematicBody2D = get_parent().get_node(("Player"))
	position.y = Player.position.y + offset

You should probably save a reference to the player-node in _ready and use that instead, so you dont have to check every _process-call.

I hope i could help you with that.

Thanks so much for your assistance.
But when running two obstacles are instancing in the same space. How can i randomize their position such that no 2 obstacles are instanced in the same space ?
Obstacles

Yasin | 2020-05-08 06:52

Unfortunatly your Link does not work :confused: (You can use https://imgur.com as an example)
I’m not sure what you mean…
A simple approach to make sure, that an obstacle does not collide with another obstacle is:

1. Create obstacle 1
2. Create obstalce 2 <----------------------------+
3. Check if they collide/overlap                  |
4. If Overlapping: Delete obstacle 2 and goto ----+

Please send pictures or code which describes your problem better.

whiteshampoo | 2020-05-08 13:05

Sorry about that. Here is the image
Error image

I have rounded the overlapping obstacles.

Yasin | 2020-05-08 18:48

Tell your script to remeber the last placement (y-coordinate should be enough) and calculate the distance to the next placement. Only place the obstacle if it is [your_choice]-Pixels away. Else: Choose another place.

whiteshampoo | 2020-05-08 19:01

Can you please show me how to remeber the last placement in code ? It would be of great help. I don’t have much experience in python.

Yasin | 2020-05-08 19:41

Have you tried it yourself?
You’ll learn much more if you try this for yourself.
It’s very easy, just save the position in a variable while instancing the new obstacle.

If you fail, or have questions, please send the code you struggle with. :slight_smile:

whiteshampoo | 2020-05-08 20:06

I have uploaded a project. In it I have created a ProgressionTester.tscn for testing how the obstacles are instanced . By running it the obstacles are instancing correctly. There is no problem with the y-axis but on the x-axis the obstacles are not spaced correctly. Can you please run and see if I have done anything wrong ?
Project - 2

Yasin | 2020-05-09 15:04

At first, this runs MUCH too fast on my PC.
You get a variable “delta” in _process. Thats the time since the last call. So this gets bigger on slower PCs. You need to multiply this with your movement:

	if Input.is_action_pressed("ui_up"):
	position.y -= 15 * delta

BUT you try to “move_and_collide” your player, but that does not work, if you manually change the position.
You should use “move_and_slide” for your game.
If you use “move_and_slide”, don’t multiply the delta. It does it by itself, as you can read here: https://docs.godotengine.org/en/latest/classes/class_kinematicbody2d.html?highlight=kinematicbody2d#class-kinematicbody2d-method-move-and-slide

Please try this as you Player.gd:

extends KinematicBody2D

# Please have a look at your Node-Inspektor (right) to understand this
export (float, 200.0, 500.0, 10.0) var progression_speed : float = 250.0
export (float, 10.0, 50.0, 1.0) var movement_speed : float = 150.0
var velocity : Vector2 = Vector2.ZERO

func get_input() -> void:
	# Here you can learn something very elegant.
	# This will make your game instantly work with gamecontroller
	# and analog-input :D
	velocity = Vector2(Input.get_action_strength("ui_right") -
						Input.get_action_strength("ui_left"),
						Input.get_action_strength("ui_down") -
						Input.get_action_strength("ui_up"))

	# Very good!
	velocity = velocity.normalized() * movement_speed
	velocity.y -= progression_speed


func _physics_process(delta : float) -> void:
	get_input()
	# No delta for move_and_slide!
	move_and_slide(velocity)

Please take some time to understand that. This will help you a lot in the future! (I wish i had learned that sooner…)
Whenever possible, use typing! Optional typing in GDScript

Ok, lets talk about enemy.gd:

You don’t need to do it like this:

export (PackedScene) var spawnScene1
onready var spawnReference = load(spawnScene1.get_path())

You can Use the PackedScene as it is:

export (PackedScene) var spawnReference

btw.: for an obstacle you should use StaticBody2D, not KinematicBody2D. Because your obstacles are VERY static :wink: (they dont move)

For your game you should not set the minWaitTime to zero. Increase it a little bit.

Where do you choose the x-coordinate for your obstacle. can’t find it :confused:

whiteshampoo | 2020-05-10 08:23

Thanks very much for your reply.
I created a different method to instance the obstacles. The scene is named as ProgressionTester.tscn. In its script you can vary the x and y axis of the obstacles generated. But I can’t randomize the x-axis ; y-axis works perfectly fine.
Here is the image of the scene Image
Here is the Project -3
Can you please check and tell if I have done anything wrong ?

Yasin | 2020-05-13 10:18

Your code works fine. But maybe it’s not what you want.
Can you show me what you get (screenshot) and draw what you want to get?

(Sorry for late response…)

whiteshampoo | 2020-05-13 12:06

It’s ok. You have helped me somuch.
You are right. You had told me

    Tell your script to remeber the last placement (y-coordinate should be enough) and calculate the distance to the next placement. Only place the obstacle if it is [your_choice]-Pixels away. Else: Choose another place.

So I tried it using the ProgressionTester.tscn. I will stick on with the previous one.
One last question; I am trying to add more than one PackedScene in the Enemy.gd. So it can spawn different type of obstacle. Is it possible to instance two or three scenes at the same time ?

Yasin | 2020-05-14 06:42

You can instance as many scenes as you want in one go.
But be careful, if you instance MANY complex nodes at one time, your game may hang for a short time. (Your scenes are not complex yet, so dont worry. Thats just for the future)

whiteshampoo | 2020-05-14 07:12

How can i add the scenes in the Enemy.gd. Can you please show it ?

Yasin | 2020-05-14 07:36

Have you tried it yourself?

whiteshampoo | 2020-05-14 08:43

In Enemy.gd you can add the path of first obstacle scene using a variable and instance it. But I didn’t know where to add the path of second and third obstacle scene in the script ?

Yasin | 2020-05-14 10:17

Easyiest way is with export:

export (PackedScene) var obstacle_type_1
export (PackedScene) var obstacle_type_2
export (PackedScene) var obstacle_type_3

Then you can just drag&drop your different obstacle-scenes into the properties (right sidebar) of your scene.

BUT, it’s much better if you use an Array with different PackedScenes (your obstacles),
if you use random obstacles, you dont have to rewrite your code to make more obstacles possible, because it will scale with the amount in the array:

extends Node2D

# ...

export (Array, PackedScene) var obstacles

# ...

func _ready():
	assert(len(scenes))
	# no obstacles would be bad
	# ...
	
func add_random_obstacle(pos : Vector2) -> Node2D:
	return add_obstacle(floor(rand_range(0, len(obstacles))), pos)
	
func add_obstacle(type : int, pos : Vector2) -> Node2D:
	assert(type >= 0 and type < len(obstacles))
	# check if type is ok
	
	var new_obstacle : Node2D = obstacles[type].instance()
	new_obstacle.position = pos
	add_child(new_obstacle)
	return new_obstacle

(<- Untested code!)

Hope you understand what i mean and can learn something from it…
The return is, if you want to tweak some properties of the instanced obstacle afterwards.

whiteshampoo | 2020-05-14 11:08

Thanks for the reply.
I created a new scene and added this script ; But I am getting an error when executing at

 func _ready():
      assert(len(scenes))

as Parser Error: Identifier not found: scenes.
Where should I add this code ; should I create a separate scene and add this code or should I add it in the Enemy.gd.

Yasin | 2020-05-16 13:59

Oh, i mistyped…
But i’m VERY sure you can figure this out yourself.

whiteshampoo | 2020-05-16 14:01

So in place of scenes I should write obstacles.

Yasin | 2020-05-16 14:03

Very correct

whiteshampoo | 2020-05-16 15:21

On running the code I am getting a blank screen. But no errors are shown in the inspector tab. Here is the Image .

Yasin | 2020-05-18 19:20

Please start a new topic, if you have still problems.

whiteshampoo | 2020-05-25 11:20

Can u check if this code is correct ; I made a few change at var pos and added add_random_obstacle(pos) .
On executing I am getting an error W 0:00:00:0382 The function ‘add_random_obstacle()’ returns a value, but this value is never used.

  extends Node2D
  export (Array, PackedScene) var obstacles

  var pos : Vector2 = Vector2()

  func _ready():
      assert(len(scenes))
      add_random_obstacle(pos)

  func add_random_obstacle(pos : Vector2) -> Node2D:
      return add_obstacle(floor(rand_range(0, len(obstacles))), pos)

  func add_obstacle(type : int, pos : Vector2) -> Node2D:
      assert(type >= 0 and type < len(obstacles))
      var new_obstacle : Node2D = obstacles[type].instance()
      new_obstacle.position = pos
      add_child(new_obstacle)
      return new_obstacle

Yasin | 2020-05-25 14:08

Thats a warning, not an error. Ignore it, or add

#warning-ignore:unused_variable

in the line before it.

whiteshampoo | 2020-05-25 14:46

I created a ProgressionTester.tscn which is a Node2D node and added the code. It works perfectly fine. Random obstacles are being instanced. But I tried adding the same code in Enemy.tscn which is a Position2D node ; But I am getting assertion error and the obstacles are not being instanced. Can you please take a look in the project below ?

[ I have added the ProgressionTester.tscn in Tests folder and Enemy.tscn in the Enemy folder. ]
Here is the Project

Yasin | 2020-05-26 14:03

Please start a new question. This has nothing todo anymore with the topic.
Have in mind, that someone who has a similar problem might find your post and gets an answer without asking :wink:
But if we continue in the comments, this is getting very confusing for any future reader.
Maybe its better if you post your problem in the forum

whiteshampoo | 2020-05-27 07:36

Sorry about that; I have posted the question as a new topic.
Here is the Question.

Yasin | 2020-05-27 08:02