Godot Version
Godot 4.6
Question
I’m making a bullet hell game where enemies come onto the screen Touhou style, swooping in from the sides. I decided it’d be best to use the AnimationPlayer node and call the animation when the enemy scene first spawns into the screen. I want where the enemies spawn in to be randomised, but I still want them to swoop down.
Problem is, the enemies default to the 0,0 coordinates I have on the animation instead of where they actually spawn. Is there a way to make enemies simply MOVE a direction aimlessly for a set period of time instead of moving to a specific coordinate, or is there any better way to approach this? Should I use a different node?
I’ll be happy to provide more information.
Adding a parent Node2D means you can animate the child relative to 0,0 of the parent and move or place this new parent freely. This could be a deal breaker for some node types but I assume your enemies are mostly working with Area2Ds as opposed to CharacterBody2Ds?
Precisely. I’m using Area2D for the playerbullet collision. I have it set to move the entire node, grouped together with a Node2D, so it’s moving the Node2D to specific coordinates, bringing the rest along.
Yeah something like this scene tree set up may help you. You can place the root anywhere and the “Animated” node can be animated relative to that root.
There is more bugfixing to be done, but for now that works! Thanks!
I actually am going back on this, the problem now is that the enemy’s bullets are spawning in the wrong spot completely. I have it set to spawn the bullets where the enemy currently is. But since the enemy node isn’t actually moving, they all spawn in the same spot.
Here’s the scene tree if it helps.
Settiing the bullets to movement’s position doesn’t work either, because it sets the actual position of it as negative instead of positive.
I’m going to sleep now, I probably won’t reply till morning. Just fyi.
You might be able to use $Movement.global_position but it’s hard to say without seeing the script for context
var bullet_scene = load("res://Bullet.tscn")
@export var health = 13
@onready var movement = $Movement
@onready var player = get_tree().get_first_node_in_group("Player")
func \_ready() -> void:
$BulletCooldown.set_wait_time(2)
$BulletCooldown.start()
$AnimationPlayer.play("Test_1")
# Called every frame. 'delta' is the elapsed time since the previous frame.
func \_process(delta: float) -> void:
position.x += -100 \* delta
if health < 1:
queue_free()
func spawn_bullets():
var b1 = bullet_scene.instantiate()
b1.position = self.position
b1.rotation = self.rotation
b1.dir = Vector2(player.position.x-self.position.x,player.position.y-self.position.y).normalized()
get_parent().add_child(b1)
func \_on_timer_timeout() -> void:
spawn_bullets()
await get_tree().create_timer(0.2).timeout
spawn_bullets()
await get_tree().create_timer(0.2).timeout
spawn_bullets()
func \_on_visible_on_screen_notifier_2d_screen_exited() -> void:
queue_free()
func \_on_area_2d_area_entered(area: Area2D) -> void:
if area.is_in_group("PlayerBullet"):
print("yeouch!")
health -= 1
print(health)
Here’s the script for the enemy.
Use global_position instead of position when positioning the bullet.
The script is on the enemy node, which means it spawns on the enemy’s location instead of movement’s location. It breaks if i move it to Movement I believe.
It doesn’t matter where the script is. Use global positions so the bullet is positioned in global space instead relative to other nodes.
I fixed it, turns out I could change where the bullet spawns to be movement.global_position. It spawns it on the movement node instead, which is what’s moving.