#Setting Up Homing Missile Target
36 messages · Page 1 of 1 (latest)
@export var target: Node2D = null
func _ready():
call_deferred("seeker_setup")
func seeker_setup():
await get_tree().physics_frame
if target:
navigation_agent_2D.target_position = target.global_position
func movement(delta):
var current_agent_position = global_position
var next_path_position = navigation_agent_2D.get_next_path_position()
if target:
navigation_agent_2D.target_position = target.global_position
if navigation_agent_2D.is_navigation_finished():
return
velocity = current_agent_position.direction_to(next_path_position) * turn_speed * delta```
It works as it should in the scene because I can link it directly in the level scene
I also want it to only track on the x axis, but I would need to solve this issue first
Thanks in advance
The approach I took in my last game was to start by setting the projectile's velocity so it is moving towards the target's current position. I then turned the projectile to track the target in the _physics_process with code like this:
var offset_angle := velocity.angle_to(target_node.global_position - global_position)
if abs(offset_angle) < MAX_OFFSET_ANGLE:
velocity = velocity.rotated(offset_angle)
MAX_OFFSET_ANGLE is the maximum angular deviation from the protectile's current trajectory to the target that will cause the projectile to turn towards the projectile. I didn't want the homing to be too good or it makes it impossible for the player to evade! I was using a value of 0.05.
Another way to turn the projectile would be to use move_toward which I think would be something like this, although I haven't actually tried it:
velocity = velocity.move_toward(target_node.global_position - global_position, TURN_SPEED * delta)
How did you set up which node is being tracked?
In my game only the enemies fired homing missiles so they were always tracking the player.
However it should be easy to pass a reference to the object that is to be tracked to the instantiated projectile. Take out the @export from the target variable declairation and then in the code where you instantiate the projectile, after instantiating it but before you add it to the scene tree, directly set the target variable to be a reference to the target object.
So, I have a node that instantiates the missiles at the top of the screen that looks like this
var e = enemies.pick_random().instantiate()
e.global_position = Vector2(randf_range(50, 490), -50)
enemy_container.add_child(e)```
I would set the target here?
I'm confused how I would set the missile's target from this node
You would have the missile pick the target when the missile is instantiated. Perhaps by calculating the closest enemy and choosing that one.
Or are you wondering how to make this connection in the first place?
yeah, I don't know how to go about doing this process
I have an area 2D set up in front of the missile to detect the player, but that's about it
So your missile would have a var target: Entity.
Every frame the missile moves toward the target. So far so good.
There's a few ways for the missile to get the reference to the target. I'm not a fan of Autoloads but that's the easiest way to do it (It's also not a terribly egregious use of one in this case). If your world has an enemies node, and all your enemies are children of that node, you can go though that list and select the one you want. You can do it with signals as well but I don't think there's much advantage to that method.
After instantiating the missile you can set the target directly with something like:
e.target = get_node("/root/Player")
Replacing the path with the correct path to reach your player object. It would be most efficient to store the reference to the player object in a variable in an autoload and then reference it from there instead of searching for the player node each time though.
Oh, my bad. I thought it was suppose to home to an enemy
Actually, instead of using an autoload you could just put a target variable in the script that spawns the missiles, set it to the player in that script's _ready function and then use that when setting the target for each missile.
how would I signal to the missile script that the target has been set from there?
You don't need to send a signal. You would be setting the missile's target directly with:
e.target = get_node("/root/Player")
it still comes back as a null_instance
I tried it moving the @export var target: Node2D = null into this node as well and tried it that way, but with the same result
the missile is preloaded in this script as well
this is what the entire script looks like ```extends Node2D
@export var enemies: Array[PackedScene] = []
@onready var enemy_container: Node2D = $EnemyContainer
@onready var player: CharacterBody2D = $Player
@onready var spawn: Marker2D = $Spawn
var missile = preload("res://Level/Scenes/Missile.tscn")
#@export var target: Node2D = null
Called when the node enters the scene tree for the first time.
func _ready():
player.position = spawn.global_position
Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
func _on_enemy_spawn_timer_timeout():
var e = enemies.pick_random().instantiate()
missile.target = get_node("res://Player/Scenes/Player.tscn")
e.global_position = Vector2(randf_range(50, 490), -50)
enemy_container.add_child(e)```
Take out missile.target = get_node("res://Player/Scenes/Player.tscn") and replace with e.target = player
That worked, thank you.
I have to make a separate spawner just for the missiles since the other enemies do not have targeting
but also track on the y axis which I do not want
idk if you know how to do that
You could add a target variable to the other enemies scripts but just not do anything with it.
No problem, good luck with your game!
you too