I've got the basics of collision detection and response with the map working, based on a dynamically generated bounding box for the character that correctly approximates the currently interpolated pose based on the extremity of its bones in the position.
Standing right up against a wall and moving a leg or arm forward now pushes the character away from the wall by the correct distance.
It is all basically AABB based, so I am doing four separate edge tests. For each edge, I construct a list of rectangles describing the map blocks that the character could be colliding with, then test to see if the relevant edge of the character is penetrating the nearest edge of the block, generating a minimum translation distance if so.
Using a standard SAT test and generating a MTD vector can cause problems when trying to slide against a wall or floor made up of a row of rectangles, as I described a few months ago in relation to a 2D game. The SAT can register the edge between two adjacent blocks as the first collision edge, causing the sliding object to get stuck.
Doing separate edge tests as above solves this problem. It may actually be cleaner to just have a horizontal and a vertical test rather than a test for each edge, since it should only ever be the case that one edge penetrates the block from a pair of parallel edges, unless something fails badly and one rectangle ends up entirely enclosed within another. The current system wouldn't actually deal with that any better really, so I guess that is a better way.
But either way, a shape can now slide against a floor or wall made out of a row of rectangles without ever getting stuck, and the calculations (since this is all AABB-based) are trivial.
Once gravity is working, I'll start dropping in animations and make my animation transition system a bit more sophisticated. Some animation blending works best the traditional way of running both animations together and blending between the two, but other transitions would be better to freeze the end frame of animation a, blend into the first frame of animation b then start playing animation b.
Other, non-cyclic, animations need to play once then signal the owner of the controller that they are finished so another animation can be blended into or whatever, so I need really to make an abstract AnimationControllerCallback interface that an object owning an animation controller can be derived from, so it can pass itself into the controller's Update() method to recieve this information at the appropriate times.
In other news, I have a screaming tooth infection and haven't had more than about two hours sleep a night for the last week, but I've got antibiotics now and at least it means I've got lots of development time.
[LATER] Hmm. It turns out to be a lot harder than I thought to get all this working once the bounding box starts changing shape.
I've been playing with this for hours and the conclusion I've come to (and tested) is that I can only vary one dimension of the box. As long as I do the edge tests on that dimension first, all is then well.
So now my skeleton records its min and max Y values when it loads and keeps returning these as the min and max Y of the bound box, regardless of what the animation is doing.
The horizontal dimension of the box can vary as much as it wants and correctly pushes the model away from objects if it animates into them.
I've also added a method to my skeleton to return the Y value (in local space) of the currently lowest bone at any given moment. By subtracting this from the world Y co-ordinate when creating the world transform to render, it is pretty trivial to keep feet stuck on the floor when in walking animations etc.
Obviously I could add an alternative GetHighestBoneY() method to use if dangling from monkey bars, say.
The only issue is ducking, since that will need to shorten the bounds box so that you can crawl into spaces that you can't walk into, but I'm pretty sure that I can shorten the bounds box as long as it is only done instantly and after any horizontal pushing is resolved.
So when you eventually duck, the horizontal pushing will stop the duck animation intersecting an object but once it finishes, the bound box height can be manually adjusted to the correct height in one step. Similarly, when standing up again, it will be necessary to first check the cell above the character to make sure standing up is an option, the do the same in reverse.
Collisions with moving objects were probably not going to use the bound box anyway apart from a broad phase so that won't matter.
This may cause some unexpected problems later but I'm not going to worry until it does as I can't think of a better solution.