How to make the direction of an object depend on the rotation of the object?

Godot Version

4.3

Question

I need to make an arrow that will fly smoothly, I made a RayCast2D that will randomly rotate to scatter the arrows and not direct their flight, as a result, if the object (bow) from which you need to shoot is turned up, then the arrow flies normally and even with a scatter, but if you turn the bow is at, say, 45 degrees, then the arrow will still fly up, and I need the rotation of both the bow and RayCast to be taken into account, but I don’t know how to do this.
Arrow code:

extends CharacterBody2D

var speed : int = 200

var dir
var spawn_pos : Vector2
var spawn_rot : float

func _ready() -> void:
	global_position = spawn_pos
	rotation_degrees = spawn_rot

func _physics_process(delta):
	dir = Vector2(0, -1).rotated(rotation)
	velocity = dir * speed
	move_and_slide()

	if is_on_wall() or is_on_ceiling() or is_on_floor():
		break_arrow()

	move_and_slide()

func _on_enemy_area_body_entered(body: Node2D) -> void:
	if body.is_in_group("Enemies"):
		body.death()
		break_arrow()
		Global.hit_stop(0.5, 0.1)
	elif body.is_in_group("Bosses"):
		body.health -= 1
		break_arrow()

func break_arrow():
	$EnemyArea.hide()
	$ArrowSprite.hide()
	$CPUParticles2D.one_shot = true
	$CPUParticles2D.emitting = true
	await get_tree().create_timer(1).timeout
	self.queue_free()

Bow code:

extends Area2D

var is_inside_area : bool = false
var spray : float = 2.5
var obj_rotation = self.rotation_degrees * -1
@onready var arrow = load("res://Scenes/Projectiles/arrow.tscn")
@onready var ray_cast: RayCast2D = $RayCast2D

func _process(delta: float) -> void:
	if Input.is_action_just_pressed("enter") and is_inside_area:
		shoot()

func _on_body_entered(body: Node2D) -> void:
	if body.name == "Player":
		is_inside_area = true

func _on_body_exited(body: Node2D) -> void:
	if body.name == "Player":
		is_inside_area = false

func shoot():
	rand_direction()
	var instance_arrow = arrow.instantiate()
	instance_arrow.spawn_pos = global_position
	instance_arrow.spawn_rot = ray_cast.rotation_degrees
	add_child(instance_arrow)

func rand_direction():
	ray_cast.rotation_degrees = 0
	var rand_dir_var = floor(randf_range(spray, -spray))
	ray_cast.rotation_degrees = rand_dir_var
	

Arrow scene :


Bow scene:

I am not sure what problem you are having.

Maybe make a GIF of what is happening at the moment when you shoot? and try to make a picture of what you would like to happen?

Did it work before you added the random scatter?

1 Like

Hard to tell the problem is, you need ot state what you expect to happen vs what really happens for us to bridge that gap.

I’m guessing this is because you only copy the raycast’s rotation to the isntance.

Try using ray_cast.global_rotation, it may also be helpful to add the arrow as a sibiling or to the root instead

	instance_arrow.spawn_rot = ray_cast.global_rotation_degrees
	add_sibling(instance_arrow)

I need the arrow to fly in the direction in which the RayCast is turned, and also before adding scatter everything worked (but the code was completely different). Now the arrow either flies in any direction, or flies only upward, or all of the above but without turning at all.

Doesn’t work…
Modified part of the arrow code :

extends CharacterBody2D

var speed : int = 200

var dir
var spawn_pos : Vector2
var spawn_rot : float

func _ready() -> void:
	global_position = spawn_pos
	global_rotation_degrees = spawn_rot

func _physics_process(delta):
	dir = Vector2(0, -1).rotated(global_rotation)
	velocity = dir * speed
	move_and_slide()

Modified part of the bow code :

func shoot():
	rand_direction()
	var instance_arrow = arrow.instantiate()
	instance_arrow.spawn_pos = global_position
	instance_arrow.spawn_rot = ray_cast.global_rotation
	add_sibling(instance_arrow)

Why do you have spawn_rot if you can set it’s rotation before it spawns anyways?

extends CharacterBody2D

var speed : int = 200

func _physics_process(delta):
	var dir = Vector2.UP.rotated(rotation) # do not use global_rotation here
	velocity = dir * speed
	move_and_slide()

func shoot():
	rand_direction()
	var instance_arrow = arrow.instantiate()
	instance_arrow.global_position = global_position
	instance_arrow.global_rotation = ray_cast.global_rotation
	add_sibling(instance_arrow)

What about this code doesn’t work? Does it have the same results you are seeing? Could you give a screenshot of the rotation in-action?

I followed the tutorial from Gwizz on shooting (here is the link:https://www.youtube.com/watch?v=YPvPqOqbx-I), in the tutorial there was a variable spawn_rot and spawn_pos which I simply rewrote into my script