I am currently trying to code an enemy that fires at the player
The enemy works with a node for the launcher and the bullet.
Both nodes have a raycast
But for some reason the bullet raycast always faces down with my code not even insinuating to do this and the transform not even being set down, so the bullet clips to the floor instead of firing at the player
I cannot work out why on earth this is happening because frankly it makes no sense
Launcher code:
extends Node3D
const bullet = preload("res://bullet.tscn")
@onready var soldier = $".."
@onready var timer: Timer = $Timer
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
if soldier in get_tree().get_nodes_in_group("canShoot"):
timer.start(0.1)
var fire = bullet.instantiate()
add_child(fire)
fire.global_transform = global_transform
if Input.is_action_just_pressed("check"):
print(global_rotation)
Bullet code:
extends RayCast3D
@export var Speed : float = 50.0
var debug = 0
@onready var timer = $Timer
@onready var despawn = $Timer2
func _ready() -> void:
timer.start(0.1)
func _physics_process(delta: float) -> void:
#print("Fire")
if not is_colliding():
position += global_basis * Vector3.FORWARD * Speed * delta
#target_position = Vector3.FORWARD * Speed * delta
target_position = Vector3.FORWARD * Speed * delta
force_raycast_update()
var collider = get_collider()
if is_colliding():
if is_colliding():
global_position = get_collision_point()
#cleanup()
set_physics_process(false)
It looks like the target position is only changed if the raycast isn’t already colliding with something. Is it possible it’s colliding with something when it’s added, so the code to change the target position never runs?
Your bullet is being made a child of the launcher instead of the scene. That means that when it is created, it is going to be attached to the launcher, and affected by its movement. It needs to be added to the level scene. (I think you haven’t encountered this problem yet.)
You are relying on the parent of the bullet, the launcher, to determine global position when you create it. However, you are creating it in its default rotation and scale. You are then attempting to change position, rotation and scale after it has already been added to the scene. Which means its _physics_process() function may have already run and moved the bullet before you update it. Which means that it’s going to test everything based on it original position, scale and rotation, before it’s actually turned to face the direction you want. Try moving the transform assignment to before you add it to the tree.
You are assuming that your gun is rotating so that the barrel is facing towards -z at all times. This may be true, but it may not be true, depending on how you are applying rotation and/or transforms to the player when you move it.
I would recommend adding a Marker3D to the end of the barrel in line with center point of the gun model, so that drawing a vector from the launcher to the Marker3D creates a vector that points in the direction you want to point the bullet. Then rotate the bullet to face that vector before adding it to the level scene.
you start the timer but don’t do anything with it. usually we check if the timer has stopped before firing the next bullet to make the delay (called rate of fire).
another thing to do is await for timeout:
timer.start(0.1)
await timer.timeout
this halts execution of the code until the timer finishes.
you can put this in _input since it’s for debugging. _process is tied to the current frame.
you can just set your timer to autostart on the node.
I hope you copied the indentations wrong, because this code doesn’t have an alternative execution path (else/elif), so it’s not going to do anything if it does collide.
there is no collision, this should go under is_colliding(), not not is_colliding()
you are calling the same method twice.
as pointed out, bullet is a child of the emiter.
either:
1 - make bullet top_level and assign rotation, which you are already doing when assigning global_transform. just go to the node and enable top_level under Node3D.
2 - add the bullet somewhere else. you can use add_sibling() to add it parallel to the emiter so it doesn’t copy the transforms, or get_tree() to add it globaly, or store a reference to a node containing all projectiles.
erase the node once it’s not used anymore, you are going to accumulate a trillion nodes that do nothing.
to delete a node, call queue_free() on the node script.
Maybe because you are running it on _process, so the signal is sent at a frame that is skipped by _process.
I’ve used await on one time things inside a for loop, that way code can be run multiple times at an interval.
for your case, maybe your shooting code should be tied to the timeout signal instead:
this connects the timeout of your timer to the fire function, the fire function spawns the bullet.
everytime the timer ends it fires. all you would have to do then is set the timer to 0.1 in the inspector.
Maybe it instantly collides with something (e. g. the enemy that spawned it)? You could try to print the collider, to see when and with what it collides.