So my original problem of “how do bullets hit mobs?” turned into a much more elaborate “how do I collide stuff?”
As I discussed before, I have special logic for hitting tiles (i.e. walls), which is quite efficient and simple square collision to nearest tile check, and so highly specialized. I need a whole separate way of handling different-sized circle collisions between moving entities. It’s not great that I would have two separate ways of determining collisions with different collider shapes. It also complicates the code a bit. But it’s also very reliable and fully controllable. Pros and cons.
(I also briefly went on a tangent experiment where I did use Unity collisions for raycasting. This means every world object had a collider and I would resize it according to the entity collision size:
This didn’t actually work for many reasons. Unity isn’t very good at taking an entire collider and trying to see if it can move (technically, sweeping a rigid body). So I abandoned this approach. I’m also doing fake 2D, so it’s all 3D colliders and consequent issues. Honestly, I keep wanting to use native Unity physics and every time I find they just don’t do what I want or the way I want it and I cannot even compromise on a solution in between.)
Also, the wall collisions are not “disputable”, that is, you cannot move walls, you definitively cannot pass through them, and everything needs to align precisely; there is almost no leeway. Other stuff, however, mobs and props, and projectiles, and such can theoretically bump into each other, push each other around, collide with slight errors, etc.
So I went ahead and made that additional collision step where it first checks tiles, then checks non-tiles. It feels inelegant to me, but I can also justify this by having somewhat different collision requirements for the two cases.
Anyway, the very simplest non-tile collision version is just not allowing (essentially, stopping) the entity from moving into another entity’s space:
This essentially has to check every moving entity against every other moving entity. There are ways to optimize this that I will likely have to do later. In any case, this works fine for now, expect the player doesn’t “slide” along the collision. Collisions are all or nothing:
Here the player’s collider (blue) will intersect the enemy’s collider (red) if the player moves up (blue arrow). So the potential movement is flagged as “collision expected” and the movement is cancelled. The problem is determining which direction do I actually push he player? I would want to convert the movement along the tangent, then return the proposed direction, then run another collision detection with that direction. You know what, screw this.
Entities collide with square collisions:
Can one really tell it’s square collisions? Yeah, probably. But I have bigger fish to fry. Though I can imagine I will get back to this at some point.
Another consideration is exactly which entities collide together. For the player, it is usually intuitive and the first time you see something block something it shouldn’t, you start to wonder what the rules are. This can get pretty complicated when you consider which objects exactly are supposed to interact. Should items be hit by bullets? Should props block dead bodies? Should flying mobs block player? Do friendly projectiles hit each other?
And this doesn’t even stop and a simple yes/no check. I would need to write a huge method which knows about every single entity and checks them against every other entity. I want something more modular with less hard-coded rules.
So instead, every entity implements a function to look up the desired collision with another entity (and vice versa). This way, they can individually refuse the collision (for example, dead mobs might not want to collide with anything), force the collision (for example, bullets might want to hit almost everything), or accept the collision as needed (for example, props are fine to collide with most stuff with no special rules). Only special cases need extra handling. Here’s a graph:
Refuse takes precedence in these rules, but that’s really just the way I structured it. I could add more collision “results”, but for now this is sufficient to describe everything in the game and on the immediate radar.
Okay, this post has went on for a while with lots of text and not a whole lot of stuff to show.