Godot Version
4
Question
im trying to make a bow enemy, but when the arrow shoots it does not face the player, heres a video to show what i mean
4
im trying to make a bow enemy, but when the arrow shoots it does not face the player, heres a video to show what i mean
Seems like the arrow is added as a child of the enemy (this causes it to move when the enemy moves)
The rotation of the arrow isn’t set when it is spawned, could you paste your code?
Make sure to paste your script between three ticks like so, the </>
button or ctrl+e will create three ticks for you.
```
type or paste code here
```
You need to set flip_h in your sprite or animation. Are you doing that?
The arrow is a child of node 2d,
i will paste code
im gonna paste whole script but, its like 100 line of code.
extends CharacterBody2D
@export var Health : int
@export var MHP : int
@export var Damage : int
var Player_Chase = false
var Speed = 100.0
var Pos = position
@onready var player = $"../Player"
@onready var animated_sprite_2d = $AnimatedSprite2D
@onready var Player_Sprite = $"../Player/AnimatedSprite2D"
@onready var player_hit_sound = $Player_Hit_Sound
@onready var detection_area = $Detection_Area
@onready var arrow = $"../Arrow"
func _process(delta):
if Health <= 0:
Slime_Died(Pos)
if Player_Chase == true:
var distance = player.global_position.distance_to(global_position)
if distance < 28:
Speed = INF
else:
Speed = 100.0
position += (player.global_position - position)/Speed
var canattack = true
await get_tree().create_timer(2).timeout
if canattack == true:
canattack = false
Attack()
Shoot_Arrow(player.position, 50.0)
await get_tree().create_timer(2).timeout
canattack = true
else:
animated_sprite_2d.play("Idle")
func _physics_process(delta):
move_and_slide()
var Reward_Given = false
func Slime_Died(Respawn_Pos):
if Reward_Given == false:
player.XP += 10
player.COINS += 10
Reward_Given = true
position = Vector2(999,999)
await get_tree().create_timer(5).timeout
Reward_Given = false
Health = MHP
position = Respawn_Pos
var CanAttack = true
var ArrowShot = false
func Attack():
if CanAttack == true:
var Attack_Radius = player.global_position.distance_to(global_position)
var Player_last_Position = player.position
var Arrow_Speed = 90.0
CanAttack = false
animated_sprite_2d.play("Attack")
await get_tree().create_timer(2).timeout
CanAttack = true
await get_tree().create_timer(5).timeout
CanAttack = true
func _on_detection_area_body_exited(body):
Player_Chase = false
func _on_detection_area_body_entered(body):
if body.name == "Player":
detection_area.scale = Vector2(2,2)
Player_Chase = true
var Cansetpos = true
func Shoot_Arrow(last_pos,Arrow_Speed):
if Cansetpos == true:
arrow.position = position
Cansetpos = false
arrow.position += (last_pos - position)/Arrow_Speed
func _on_hit_box_body_entered(body):
if body.name == "Player":
player.HP -= Damage
if you could solve the problem that would be great, thank you.
Strange to only have one arrow, does it have a script?
Normally projectiles are created when needed and have a short script to propel them. You’ll see something like this often
# Enemy script
const ARROW_SCENE = preload("res://arrow.tscn")
@export var player: Player
func shoot_arrow(target: Node2D) -> void:
var new_arrow := ARROW_SCENE.instantiate()
new_arrow.direction = direction_to(player.position)
new_arrow.rotation = direction.angle()
add_sibling(new_arrow)
# Arrow script
extends Area2D
@export var speed: float = 90.0
@export var damage: float = 10
var direction: Vector2
func _process(delta: float) -> void:
position += direction * delta * speed
func _on_body_entered(body: Node2D) -> void:
if body is Player:
body.take_damage(damage)
You are right that the arrow is not a child but your current script is using the enemy’s position to update the arrow, so it will act as if it’s a child, at least by position.
can i ask what does
→ void
do?
and also thank you for taking the time to do this, im going to make a new game and use this for it.
it’s a type declaration, in this case it means the function does not return anything.
thank you
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.