Change direction of rocket projectile on creation

Godot Version

4.6

Question

I have the problem that when spawning a new rocket, it does not rotate the rocket to the correct orientation (see clip below)

My weapon has a nozzle marker and further ahead a shooting direction marker to calculate the current direction where the rocket is supposed to fly to.

My rocket init() looks is this:

func init(root_node, weapon):
	self.targetNode = targetNode
	
	self.muzzlePos = root_node.get_children()[0].global_position
	position = muzzlePos
	self.muzzleExitPos = root_node.get_children()[1].global_position
	directionVector = (muzzlePos - muzzleExitPos) * -1
	directionVector = directionVector.normalized()

and _process:

func _process(delta: float) -> void:
	translate(Vector3(delta * speed * directionVector.x, delta * speed * directionVector.y, delta * speed * directionVector.z))
	lifetime -= delta

What am I missing here to make sure that the rocket is always pointing in the direction where I am shooting at?

Just as an extra note, right now the rocket is fire-and-forget but at a later stage I also want to enable it to home in on a target, just in case if that makes any difference to the solution.

Use look_at() to properly orient rocket’s basis.

But look at what? For my fire-and-forget there is no target to look at. And if I try to look at an enemy with

self.look_at(enemy.global_position)
	translate(Vector3(delta * speed * directionVector.x, delta * speed * directionVector.y, delta * speed * directionVector.z))

then it starts spiralling in wide circles but does not really change the direction.

If there is no scaling on the rocked you can just copy nozzle marker’s global basis. You need to do it only once when the rocket is initialized.

Ok, with that change the direction is now correct but everything else is broken :smiley:

It spawns at a completely different position and also the trajectory is wrong:

Post the spawn and movement code.

Use global version of things for everything. So global_translate, global_basis, global_position.

Sure!

Spawning:

func addAmmoScene(root_node, weapon: Weapon, ammo: Ammo):
	var root = get_node("/root/Main")
	var ammoScene
	
	match ammo.ammoClass:
		Ammo.AMMO_CLASS.BULLET:
			ammoScene = bullet_scene.instantiate()
		Ammo.AMMO_CLASS.GRENADE:
			ammoScene = grenade_scene.instantiate()
		Ammo.AMMO_CLASS.ROCKET:
			ammoScene = rpg_scene.instantiate() 
	
	if ammoScene:		
		ammoScene.init(root_node, weapon)
		ammoScene.ammo = ammo		
		root.add_child(ammoScene)	

Init()

func init(root_node, weapon):
	self.targetNode = targetNode
	
	self.muzzlePos = root_node.get_children()[0].global_position
	position = muzzlePos
	self.muzzleExitPos = root_node.get_children()[1].global_position
	directionVector = (muzzlePos - muzzleExitPos)
	directionVector = directionVector.normalized()
	
	print(directionVector)
	
	self.global_basis = root_node.get_children()[0].global_basis
func _process(delta: float) -> void:
	var enemies = get_tree().get_nodes_in_group("enemy")
	var enemy = enemies.front()
	
	global_translate(Vector3(delta * speed * directionVector.x, delta * speed * directionVector.y, delta * speed * directionVector.z))
	lifetime -= delta
	
	var targetVector = self.global_position + (directionVector)
	DebugDraw3D.draw_arrow(self.global_position, targetVector)
	
	if lifetime <= 0:
		self.queue_free()
global_position = muzzlePos

Comment out all movement code and first make the spawn work properly so that the rocket shows at the correct position with correct orientation.

ok, done that and now its spawning at the correct location but wrong orientation

Let’s see the last version of spawning code. You’d want to call init() after add_child().

I have to call init() AFTER add_child()?! sh(&&(#&#&$ - just fixed that and now it works …

func addAmmoScene(root_node, weapon: Weapon, ammo: Ammo):
	var root = get_node("/root/Main")
	var ammoScene
	
	match ammo.ammoClass:
		Ammo.AMMO_CLASS.BULLET:
			ammoScene = bullet_scene.instantiate()
		Ammo.AMMO_CLASS.GRENADE:
			ammoScene = grenade_scene.instantiate()
		Ammo.AMMO_CLASS.ROCKET:
			ammoScene = rpg_scene.instantiate() 
	
	if ammoScene:		
		root.add_child(ammoScene)	
		ammoScene.init(root_node, weapon)
		ammoScene.ammo = ammo	

func init(root_node, weapon):
	self.targetNode = targetNode
	
	self.muzzlePos = root_node.get_children()[0].global_position
	self.muzzleExitPos = root_node.get_children()[1].global_position
	
	global_position = self.muzzlePos
	
	directionVector = (muzzleExitPos - muzzlePos)
	directionVector = directionVector.normalized()

	self.global_basis = root_node.get_children()[0].global_basis


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	var enemies = get_tree().get_nodes_in_group("enemy")
	var enemy = enemies.front() as Node3D
	
	global_translate(Vector3(delta * speed * directionVector.x, delta * speed * directionVector.y, delta * speed * directionVector.z))
	lifetime -= delta
	
	var targetVector = self.global_position + (directionVector)
	DebugDraw3D.draw_arrow(self.global_position, targetVector)
	
	if lifetime <= 0:
		self.queue_free()

Just wondering: what do I need to change in _process() to make it fly towards an enemy?

Yes because global transforms only make sense and work if there is a global space of the scene tree.

Do you want it to fly forward or home the enemy?

In any case you need to set the global directionVector properly. Btw no need to split it into components. Simply do global_translate(directionVector * speed * delta)

If you oriented it by copying the marker basis then just copy the forward global basis vector which is presumably basis z.

self.global_basis = root_node.get_children()[0].global_basis
directionVector = self.global_basis.z

Do you want it to fly forward or home the enemy?

Since the fly forward part is working now, it would be interesting to see the homing part :slight_smile:

Each frame calculate the direction vector from the projectile to the enemy. Construct a basis using that vector and global up and rotate the projectile basis for a small amount towards the constructed basis.

ok, I’ll try that - thanks for all your help, really appreciate it!

1 Like