Sooo what I’m doing here is I have a character, rigged and animated. Most animated characters are used for players in third person games or not used for players at all (enemies, friendly NPCs etc.). In my game however I’m trying to use an animated character model and make it into a FPS system which I then hopefully will be able to release for download and use in my game.
Now what am I trying to achieve:
Rotation around the y axis of the character. That’s easy - transform.Rotate however I wanted to add some more realism to that so I decided that I’ll make a system which not only rotates the whole character, but also rotates several bones like the chest, neck and the head. This was also easy to make but what’s not easy to make is make the player even out this rotation. See, I don’t want to rotate the player and in the meantime rotate the body bones, because the body rotation has constraints, it’s limited to some value, because when you turn around in real life you don’t do a 180 with your body, but you gently rotate it. So I thought of this:
When you move the mouse, the whole player would get rotated first, then the system would calculate the difference between player’s last rotation value and the current rotation, divide that difference by the number of all the bones that get affected and that way rotate the body. Now that’s cool, nothing hard, but the hard part is to make the player “even this out”. After I have stopped moving the mouse, I want the body bones to slowly start rotating towards zero and in the mean time, the body to start rotating in the opposite direction so I wouldn’t get any change in the camera rotation (which is attached to the head of the character)
Most of the things I’ve already done, but that last part I highlighted in bold…I’ve been struggling with it for a solid amount of time. Here’s my code:
// I've only copied the variables needed for this effect
var rotationJoints : Transform[]; // An array of all the body joints that we want to rotate
var maxBodyRotation : float = 20; // This is the maximum rotation of all the body joints that we can achieve
var rotationReturnSpeed : float = 5; // This is how fast the bones Lerp to 0 when there's no or low mouse input.
private var lastCharacterRotation : float = 0; //The last transform.rotation.y of the character
private var currentBodyRotation : float = 5; // The sum of all the rotations of the body joints
private var lastBodyRotation : float = 0; // The last sum of all the rotations of the body joints
private var initialBodyRotation : float; //The initial rotation of a bone (the same for all the bones that are affected)
var publicMouseY : float; //Mouse input Y
var publicMouseX : float; // Mouse input X
Start function looks like this:
function Start(){
lastCharacterRotation = transform.rotation.y; // Get the current rotation of the character
maxBodyRotation *= Mathf.Deg2Rad; // Turn the max body rotation into Radians since I've made it so I can set Degrees in the editor
initialMaxBodyRotation += Mathf.Deg2Rad; // Same here
}
Now in FixedUpdate I only rotate the character with a multiplier the number of the affected joints:
transform.Rotate((Vector3.up*publicMouseX*rotationJoints.length));
And now in Update I have this “masterpiece”:
currentBodyRotation += transform.rotation.y - lastCharacterRotation; //Add the difference between the last rotation and the current rotation of the player to the body joints.
currentBodyRotation = Mathf.Clamp(currentBodyRotation, -maxBodyRotation, maxBodyRotation); //Clamp the rotation so you don't "oversteer"
lastCharacterRotation = transform.rotation.y; // Set lastCharacterRotation as we don't need the previous data anymore
initialBodyRotation = currentBodyRotation/rotationJoints.length; // Calculate the initial rotation of the bones that needs to be applied
currentBodyRotation = Mathf.Lerp(currentBodyRotation, 0, Time.deltaTime*rotationReturnSpeed); // Lerp the body rotation to 0
transform.rotation.y -= currentBodyRotation - lastBodyRotation; //Subtract the rotation of the body from the world rotation
lastBodyRotation = currentBodyRotation;
Everything I think works fine except for the last two lines here… I don’t know how to make it so the world rotation would properly even out with the body rotation…
And just so you can see, I rotate the body joints like this:
for(var joint in rotationJoints){
joint.localRotation.z = rotationY*Mathf.Deg2Rad;
joint.localRotation.x = -initialBodyRotation;
}
Note I’m using the X axis rather than the Y…that’s because the coordinates of the bones are kinda f*cked up, but it works great like that.