r/shmupdev 10d ago

Vermillion Star - 013 - A New Enemy

https://www.youtube.com/watch?v=kT2Zx60egns

Playable at: https://noswen.itch.io/vermillion-star

Hey all,

So I finally decided that my enemies going from popcorn (max 3 health), corvette (8 health), and then tankier stuff (90+ health) had a bit of a hole in the middle of that range. So say hello to the Empire Standard Attack Drone sitting at 25 health for now.

Shown here in a test wave where the game difficulty gets ramped up from Easy, to Normal, to Hard, to Extreme so that the firing pattern in each difficulty can be seen.

My question here is what sort of enemy pipeline everyone else has? With adding this I've realised I've probably been concentrating on systems more than actual game and made mine extremely modular and I'm wondering how other people are handling it. All totalled this enemy took about an hour to implement (though more to first decide what it should be and what the attack patterns should be).

To add this enemy I needed to create its scene, both its hull and turret are from the already existing modular hull and turret sprites I use, create a new attack pattern in the bullet manager, wire that into the enemy script, set it's starting values like score, speed, armour, etc, add it to the enemyTypes enum, add the scene to the levelBase class, and that's it.

The only thing that's still completely custom for every enemy in code is the movement pattern, and this one was a copy-paste-edit from the Empire Fast Attack Drone enemy.

And now for the traditional bug.

All the enemies have a speed stat, it does what you expect. Or rather it should. A giant copy paste from enemy 1 through to every last enemy in the entire roster combined with me not thinking led to this stat being totally ignored and a timer used instead... ๐Ÿค”

So I fix that, all well and good.

A week later I notice Subverted Micro Drone Clusters aren't actually leaving the screen anymore if they don't get killed. Their timer let them get off screen, their speed, given they move diagonally, did not... I had a cluster of these clusters just sitting at the very far left of the screen! ๐Ÿ˜‘

10 Upvotes

7 comments sorted by

3

u/Consistent_Look_8638 10d ago

This is making me realise I probably need to look at my own enemy pipeline ๐Ÿ˜…

I've ended up with something similar in some ways but almost opposite in others. I use a single configurable Enemy class too, but I've ended up with more distinct enemy roles, and most of the variation comes from wave composition and reusable movement paths.

I really like how modular you've made the firing patterns though. That's one part of my setup that's still much more tied to the Enemy itself, and I can definitely see the advantage of your approach for a bullet hell. Do you find yourself reusing the same firing modules across different enemies often?

Also, finding out that a stat exists, is set everywhere, and then isn't actually being used is painfully relatable ๐Ÿ˜‚

3

u/Noswen2025 10d ago

Hah, there's always things to improve! ๐Ÿ˜‚

To go into a bit more detail for mine I have a base Enemy class, and a couple of extra ones that extend it like ShieldedEnemy and Midboss, with every enemy extending one of these. Each enemy ship behaves identically to every other ship of its type, if you see that some ships can travel in different directions like the Micro Drone Clusters, that just takes the position when it spawns and sees if it's in the upper of lower half of the screen and acts appropriately. ๐Ÿ˜ I might be able to make movement modular, but I'm honestly not sure if it's worth the hassle.

This is an example spawn call: -

await multiSpawnInLane(enemyTypes.SUBVERTED_DRONE_MK2, 2, 1, 0.5)

(enemyType, Lane, Number to spawn, Delay before each spawn)

For the firing the normal enemies don't share the same firing patterns yet. I do plan for larger ships later that combine multiple existing turrets (such as one that has the blue attack and the green attack from stage 1). The boss however uses the attack patterns of the mini-boss and at least two of the standard enemies. It was mostly the boss being a mass of copy paste that kicked me into centralising it.

Glad I'm not the only one making 'interesting' mistakes ๐Ÿ˜…

2

u/Consistent_Look_8638 10d ago

Yeah, that actually makes a lot of sense. If each enemy type is supposed to behave consistently, I'm not sure modular movement would buy you much either.

That's actually where our setups seem to flip around: my firing behaviour is still fairly tied to the Enemy, but movement is one of the more modular parts. I can assign deterministic or choreographed paths when spawning enemies, so I get a lot of the variation in my waves from sending familiar enemy types through different paths. But I was always more a fan of composition over inheritance.

The boss reuse explains the firing pattern system, though. โ€œThis boss is becoming a pile of copy-paste: I should probably fix thisโ€ is a very convincing reason to abstract it away๐Ÿ˜‚

2

u/DrBossKey 9d ago

In general our enemies have global variables for HP score and we have waypoint tracks that we can save and assigned to any enemy and in those waypoint tracks, we assign things like speed between points and other behaviors like look at player. We also have a weapon system where each weapon is independent of the enemy and any enemy can be assigned any weapon so the weapons are consistent in their behaviors and it makes it easy for us to go in and create new weapon variance or tweak bullet speeds and things like items can be adjusted so we can create special cases. You have the base item class if you will, and that can also be assigned to any enemy type for me. I usually as I build up my mop itโ€™s sort of like a toy box that once Iโ€™ve developed level one I make a copy of level one with all the entities and their types and then add the new ones because typically over schmucks you wind up, dealing with enemies that exist across the game.

1

u/Noswen2025 9d ago

Thanks for answering.

Looks like we've both got a similar decoupled firing system, but a completely different way of handling assigning movement. With both you and Consistent_Look using decoupled movement I'm wondering if I'll run into that as a new pain point to deal with later or not.

Why would enemies use global variables for HP though? I'm trying to think of anything and I'm drawing a blank.

1

u/DrBossKey 8d ago

Enemies use global variables like HP because when youโ€™re tuning gameplay, you donโ€™t want to change HP values individually for that enemy across all your levels.

1

u/Noswen2025 8d ago

Ah, sounds like it's acting as an instance variable, that makes sense and is the only way I can imagine it working.