While thinking of the mob types to add and make, I’ve been playing the game a lot (more than the usual testing) and there’s a bunch of bigger things that have come up that need fixing. In fact, way more than I can do in parallel with mob design.
One of the things is that my mob spawning, that is, mob type/amount selection for the level is somewhat broken. So, first of all, I restored it to working condition with the right number of mobs spawning:
However, a feature I need is to have multiple enemy types per room. That way enemies can “work together” to provide the player with a unique combo/experience. A single enemy type quickly becomes too predictable and thus easy and thus boring. And that means I have to implement how many groups can be supported by the levels and rooms, which I call groups:
And since I have groups instead of raw amounts, I also need to break down the counts based on the group size:
That is, for example, a 1-type group can have 8 enemies, but 2-type group should have 4+4 enemies.
And while fighting these larger enemy pools, I really that my rooms (arenas) are inadequately sized. On full-screen, there is a lot of screen estate, but I am using hardly any of it and movement feels very cramped:
So I’m making arenas 3×3 instead of 2×2, and adding the needed room extras:
I’m also decreasing the sizes of the room sides, because I don’t want the rooms quiet as large as boss rooms:
And this feels much better with a larger room to fight in:
Of course, now I need to adjust everything else — movement speeds, projectile speeds, projectile drop-offs, charge duration, etc. etc.
(I still need to figure out how to make player stay in the room to fight and not just shoot from the halls around the corner.)
And speaking of charging, one this I noticed is that it’s not very good for brief evasion. Enemies can zero in on the player instantly. This makes nay projectile that travels faster than snail-speed almost unavoidable. So I started thinking how to make enemies be slightly sluggish to make charging much more useful. First, I added the debug to see what’s happening (red lines are enemies looking at where they think the player is):
And if the player charges quickly away, this “player location” lags behind, that is, enemies are slow to catch up to the player’s new location. SO the player has a short buffer when they won’t get hit by any incoming projectiles:
There’s a lot to tweak here for balancing. For example, slightly faster projectiles can drastically alter gameplay. While slightly slower ones can make it absolutely trivial.
Another fun problem is with my new cowering logic. Of course, it couldn’t be a simple feature — various problems soon appear. For example, if I shoot all the enemies, they all go into cower mode:
Now, this is completely anti-fun and literally stops the combat. I can’t have all mobs cower. So I am encoding a new belief for the AI:
This will stop mobs from wanting to cower when there are other mobs nearby.
A very similar situation is when I have the last (few) mobs remaining, who are covering:
Technically, they don’t have other mobs cowering nearby, so they are “allowed” to cower. But this is even worse than the previous case, because the player is waiting for just the last mob. So I am encoding that as “negative” belief as well.
I also added parameters to control the actual amounts that these refer to:
Both these beliefs rely on knowing about other mobs. To organize it nicely, I added a new class that provides the values they need for these beliefs, and added a debug script to monitor what’s happening:
And this all somewhat works. Except, there’s a problem I have with my discrete versus continuous belief usages. Discrete values get added instantly on the next frame, which continuous values accumulate over time. But this means that one can easily “overwhelm” the other.
What happens is that if a player hits a mob many times in a second with a fast-firing weapon, this adds a lot of score to the belief. While the number is technically reasonable, its instant effect is bad. This makes the mob cower even if all the other conditions are failing. Basically, the -100/sec never has the chance to actually deduct the -100 over a second, because even the first 60 addition raises the value above all other beliefs and triggers the cowering state. I can’t raise or lower the values either, because that just breaks other beliefs.
The solution I made is to treat the discrete values as continuous, but for a very short time. The enemies still “activate” the belief as before — being shit, reloading, whatever. But the value is not applied instantly, but rather spread out over a specified time:
I even wrote a little explanation for the script while thinking about it for when I inevitable forget it again:
But now cowering actually works the way I want it to and doesn’t “interrupt” combat by literally halting combat.
In some regards, the AI system is pretty cool and robust. But, in other regards, I can’t hand-craft scenarios because everything is inter-connected. I think if I do AIs in the future, the basics will be a big old finite state machine and some step decision based on belief and desires, but not the whole thing.
I also noticed that charging and just navigating in general gets finicky when there are protruding walls and irregular corners:
The simple “solution” for now is to just resize everything to the wide tunnel version. In fact, I’m removing the distinction between big and small tunnels and just making one type of hall/hub rooms.
This also means all the extra connection logic now uses the regular halls and not whatever the operation additionally specifies:
And this kind of works alright, at least there are no immediate issues.
Another thing worth mentioning is that I made all mobs (not just bosses) able to move and shoot. I also gave them infinite ammo and removed AI beliefs about reloading:
This means I don’t have to make enemy reloading states or animations. But this also drastically changes gameplay (which is my main reason) — there are now way more bullets flying around and enemies are much more dangerous. Enemies have much less downtime, which I previously found excessive when they were just moving around or standing still reloading. I couldn’t tweak the AI beliefs to counteract it without making movement erratic or firing over-powered. So I guess I’m dumbing down AI logic, which ironically makes them smarter enemies. Of course, I can balance out some of the difficulty with other things.
Anyway, that’s about it for the big thigns. I also fixed a lot of other things and tweaked a whole lot of values. I won’t cover these and I’ll just pile bigger changes I make for a future post.