Godot Version
4.4
Question
I am making a shmup bullethell. One of the thing I need is a big list of bullet patterns and enemy types.
These enemies are gonna have extremely minor variation between each-others (like instead of shooting 15 bullet, they shoot 16 bullet). Likewise with bullet patterns, I would need many slightly different variation (for many purpose such as to accommodate different difficulties).
Right now, each enemy and their corresponding bullet patterns is one scene each. However, I fear having to create hundreds of scenes for enemies on every stages on every difficulties (I estimate this will lead to having as least 500 different scene) .
Is there a better way to go about this?
This sounds like a job for composition.
I’m assuming the main thing you’re doing here for variation is shot emission patterns. Personally, I’d be inclined to do that sort of thing in code rather than make individual scenes.
You can do something in your enemy script like:
var emit_shots: Callable = _do_nothing
func _do_nothing(delta: float):
pass
func _process(delta: float):
[...]
emit_shots.call(delta)
[...]
Whatever function you assign to emit_shots
can take that delta and accumulate it so it understands the passage of time, and use that to generate shots. You might, for example, have a simple radial emitter:
func _radial_shots(delta: float):
var old_time = accumulated_time
accumulated_time += delta
var old_count = old_time % RADIAL_EMIT_TIME
var new_count = accumulated_time % RADIAL_EMIT_TIME
if old_count < new_count: # We crossed a time threshhold...
var emit_angle = (TAU / 6.0) * floor(fmod(new_count, 6.0))
var shot = preload("res://shot.tscn").instantiate()
shot.vector = Vector2(SHOT_SPEED, 0.0).rotated_by(emit_angle)
add_sibling(shot)
You could also make emit_shots
an array of callables, which would let you stack up shot emission behaviors for bosses:
func _process(delta: float):
[...]
for emitter in emit_shots:
emitter.call(delta)
[...]
The advantage of this is it’s easy to compose complex shot behaviors. The disadvantage is that coordinating complex shot behaviors becomes more difficult; if the player can interrupt the boss, all the emission routines have to understand that.
2 Likes
Oh wow, this is extremely helpful, thanks you so much. So all I need to do is make 1 big script storing all the shot emission behaviors in the game but composed as callable, which I can then attach to enemies using the composition method? Then I can just call the right callable based on value like the time at which the enemy spawn? That sound like a very elegant solution!
I didn’t even know composition was a thing! Thanks for mentioning it, I will now be researching on it.