I spent my holidays with gamer friends and had the chance to show them some of my work. Meanwhile, I got my first pose started... and it was a lot of work! I already need to change how it works.
The Character() class has a pivot point that originally was located inside the model hip. It is used primarily to move the entire model across the X and Y axis. The hip cube serves a similar purpose, but now I see that I need to give them very distinct responsibilities.
The pivot point will be moved to the ground, Y=0. The hip cube, as its only child, will be moved up along the Y axis enough so the feet touch the ground. That's the function of the "Drop to Ground" button in the interface above. The position of the hip cube, relative to the pivot point, will be baked into the pose record.
With the pivot fully grounded, I will now be able to create characters of varying heights. That was worrying me before. The model size will affect hitboxes, so I won't give way too much liberty to players to make really tiny characters, as it would be unbalanced. I am aiming for one head taller, one head shorter the most, just so the shortest character is two heads shorter than the tallest one. I believe it's a reasonable compromise for now. Of course things can change later if needed.
Another advantage of the grounded pivot point is inverse kinematics, which I probably won't be working with in this game. If I were doing a game where the character interacted with the scenario (example: climbing stairs), or a dynamic dancing game (where I'd need to know which foot is touching the ground), then IK would be essential. I do intend of making other games with this model, shall this become a thing.
Back on reality... the hip cube is used to move the character slightly across the X and Y axis during some attacks or stances (like crouching). A far kick would thrust the hip forward, without moving the pivot point. That could maybe yield some weird situations, for example, an hurt box extending forward as a result of the far kick that is countered with a sweep: if the reach is too far, the character would "snap back" to its pivot location with the knock-down effect. I am guessing each case will be different, some will move the hip cube, some will move the pivot point.
I've also separated body poses from hand poses.
A "body pose" contains rotations for head, neck, chest, shoulders, arms, abdomen, hips, legs, and feet. It also has two extra fields that hold the pose names for each hand. Hand poses are already solidly defined: you have the fist, the spread, one/two/three pointing, the V sign, the chop, a couple of rested poses, and that's it. Probably a couple extra more. (Tempted to do a Vulcan salute one.) If I were to blend those with the body poses, it would add quite some overhead to the pose definitions, not to mention it would be hell to animators to define hand poses with each pose. A hand has 15 cubes with rotation parameters along their three axes. It's almost as much as the body parts (19 cubes). So it makes sense to separate them, both for storage and animator sanity.
Although body and hand poses will be separate, when I load a body pose during game execution, it will automatically merge the hand poses parameters to form a complete "pose definition" object. Pose definitions are shallow objects that contain all rotation values that are different than zero. So poses that do not change much of the model will be smaller. Also, shallow objects allow tweens to work seamlessly, without the need of extra functions or blocks to parse data or call functions, decreasing code complexity.
Example of a pose definition that only tilts the head forward:
{Hx: 0.5}
The capital letter(s) represent the body part (in the example above, H means Head), while the last lowercase letter represents the axis it will be rotated around. Values are in radians. I've assigned capital letters for every bone in the skeleton. I could have given them longer names, but I will be transferring that data in Ajax/socket calls, so the less metadata the better. They're still somehow readable, so I'm good with that.
When I get the above object to animate a character with a Tween, I just need to do the following:
var character = new Character(); var pose = {Hx: 0.5}; new TWEEN.Tween(character).to(pose, 1000).start();
The character instance also responds to the same properties as the pose definitions, so the above tween would change character.Hx property from 0 (current value) to 0.5 in 1 second, effectively creating an animation. I haven't got this to work yet, but I am hoping I can keep things really that simple.

No comments:
Post a Comment