Godot Version
` godot 4.2.2
I want to make a bullet that always homing toward an enemy but when the enemy died, it crash. how to make the bullet always move toward the closest enemy and switch to new enemy when it dies
` godot 4.2.2
I want to make a bullet that always homing toward an enemy but when the enemy died, it crash. how to make the bullet always move toward the closest enemy and switch to new enemy when it dies
This guide might help you to build a nice homing bullet.
In your case, the game is probably crashing because the enemy has been freed (when it died).
You can use is_instance_valid() to ensure the enemy is valid before trying to access its position.
Here is some pseudo code :
if enemy_target.is_instance_valid():
#code to follow the enemy_target
...
else:
#code to find the closest enemy
...
I copied the code and used a dummy target to test it but for some reason the bullets moved to 0,0. Then I still haven’t found a way to switch to another nearby enemy. Sorry, I’m still a beginner.
Can you share the code you have so far ?
You can paste it in the forum here, surrounding it with this :
```gdscript
your code goes here
```
extends Sprite2D
@export var speed = 300
@export var drag = 10
var acceleration = Vector2.ZERO
var velocity = Vector2.ZERO
var target = null
var enemy_in = []
func _on_visible_on_screen_enabler_2d_screen_exited():
queue_free()
func _on_aim_area_area_entered(area):
if area.is_in_group("enemy"):
target = area
func _on_aim_area_area_exited(area):
target = null
func seek():
var steer = Vector2.ZERO
if target != null:
var desired = (target.position - position).normalized() * speed
steer = (desired - velocity).normalized() * drag
return steer
func _physics_process(delta):
acceleration += seek()
velocity += acceleration * delta
velocity = velocity.limit_length(speed)
rotation = velocity.angle()
position += velocity * delta
func start(_transform, _target):
global_transform = _transform
rotation += randf_range(0.09,-0.09)
velocity = transform.x * speed
target = _target
the bullet still move to 0,0 even if the enemy haven’t died yet
You should use if is_instance_valid(target):
rather than if target != null:
That will catch cases where target
has been deleted but not nulled.
Do target
and this object have the same parent? If not, you may need to use global_position
.
I’m not sure I understand the logic for the movement. seek()
, for example, is getting a normalized vector from the seeker towards the target, then multiplying that by speed
, then subtracting velocity
and normalizing it again? Then multiplying by drag
, adding that to acceleration
and multiplying by delta
before adding it to velocity
.
That seems… convoluted.
How do you want this to behave, ideally?
nope, target
have different parent
well, i just copypast the code from tutorial I’m not really understand it either. I want the bullet (this object) to move towards the enemy (target) while slowly rotating towards the enemy. Drag is to slowdown the bullet’s rotation. I also want the bullet to search for new enemy if the bullet is still exist.
It’s hard to be sure what is causing the issue in your case. It might be because of the aim_area.
func _on_aim_area_area_entered(area): if area.is_in_group("enemy"): target = area
This function is being called whenever an area enters the aim_area of your missile. Its checking if the area itself is in an group called “enemy”.
Could it be that its the owner of the area that is in the “enemy” group, and not the area itself ?
If so, this may fix your issue:
func _on_aim_area_area_entered(area):
if area.owner.is_in_group("enemy"):
target = area.owner
Notice that the target is also the area.owner in this version, and not the area itself. If you want to target the area itself, then you will need to do like @hexgrid said, and use the target.global_position
instead of the target.position
To make sure the tutorial’s code is working (even if its a bit convoluted like @hexgrid pointed out), I tested it myself. I did have to modify 1-2 lines.
(the movement is smooth in the game, its just the gif that makes it looks slow)
extends Area2D
@export var speed = 350
@export var steer_force = 50.0
var velocity = Vector2.ZERO
var acceleration = Vector2.ZERO
var target:Node2D
func start(_transform, _target):
global_transform = _transform
rotation += randf_range(-0.09, 0.09)
velocity = transform.x * speed
target = _target
func seek():
var steer = Vector2.ZERO
# The target has been freed or is null
if ! is_instance_valid(target):
# Get the nodes in the group "enemies"
var other_targets = get_tree().get_nodes_in_group("enemies")
# If there are enemies, pick a random one
if not other_targets.is_empty():
target = other_targets.pick_random()
if target:
var desired = (target.position - position).normalized() * speed
steer = (desired - velocity).normalized() * steer_force * 2
return steer
func _physics_process(delta):
acceleration += seek()
velocity += acceleration * delta
velocity = velocity.limit_length(speed)
rotation = velocity.angle()
position += velocity * delta