Created
September 30, 2015 01:55
-
-
Save JSandusky/340b09e9d104bae4c16b to your computer and use it in GitHub Desktop.
Animation motion controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//===================================== | |
// MotionControl.as | |
// | |
// Controls animations based on the movements of a node: | |
// Automatically switches between strafing/forward/reverse/run/fall/jump | |
//===================================== | |
//===================================== | |
// class: AnimSet | |
// | |
// Helper class that let's us quickly swap out entire animation sets, mostly for "state" purposes | |
//===================================== | |
class AnimSet | |
{ | |
String walkForward; | |
String walkBackward; | |
String walkLeft; | |
String walkRight; | |
String fall; | |
String jump; | |
String run; | |
String idle; | |
void Serialize(Serializer& stream) | |
{ | |
stream.WriteString(walkForward); | |
stream.WriteString(walkBackward); | |
stream.WriteString(walkLeft); | |
stream.WriteString(walkRight); | |
stream.WriteString(fall); | |
stream.WriteString(jump); | |
stream.WriteString(run); | |
stream.WriteString(idle); | |
} | |
void Deserialize(Deserializer& stream) | |
{ | |
walkForward = stream.ReadString(); | |
walkBackward = stream.ReadString(); | |
walkLeft = stream.ReadString(); | |
walkRight = stream.ReadString(); | |
fall = stream.ReadString(); | |
jump = stream.ReadString(); | |
run = stream.ReadString(); | |
idle = stream.ReadString(); | |
} | |
} | |
//===================================== | |
// class: MotionController | |
// | |
// Controls a Node's AnimationController based on | |
// how the position of the node changes | |
// Selects and blends between Cross direction walks and running | |
// Running + jumping | |
//===================================== | |
class MotionController : ScriptObject | |
{ | |
private Vector3 lastPosition; | |
private Quaternion lastRotation; | |
private Vector3 relativeMotion; | |
float animSpeed; | |
String walkForward; | |
String walkBackward; | |
String walkLeft; | |
String walkRight; | |
String fall; | |
String jump; | |
String run; | |
String idle; | |
int DefaultLayer = 0; | |
float runThreshold; | |
float moveThreshold; | |
float fallThreshold; | |
float jumpThreshold; | |
float rotationOffset = 0; | |
bool active = true; | |
private float nextUpdate = 0.0f; | |
AnimSet@ GetAnimSet() | |
{ | |
AnimSet@ ret = AnimSet(); | |
ret.walkForward = walkForward; | |
ret.walkBackward = walkBackward; | |
ret.walkLeft = walkLeft; | |
ret.walkRight = walkRight; | |
ret.fall = fall; | |
ret.jump = jump; | |
ret.run = run; | |
ret.idle = idle; | |
return ret; | |
} | |
void SetAnimSet(AnimSet@ anims) | |
{ | |
walkForward = anims.walkForward; | |
walkBackward = anims.walkBackward; | |
walkLeft = anims.walkLeft; | |
walkRight = anims.walkRight; | |
fall = anims.fall; | |
jump = anims.jump; | |
run = anims.run; | |
idle = anims.idle; | |
} | |
void FixedUpdate(float td) | |
{ | |
if (!active) | |
return; | |
nextUpdate -= td; | |
if (nextUpdate > 0) | |
return; | |
nextUpdate = 0.02; | |
Vector3 dist = node.worldPosition - lastPosition; | |
lastPosition.x = node.worldPosition.x; | |
lastPosition.y = node.worldPosition.y; | |
lastPosition.z = node.worldPosition.z; | |
const float verticalSpeed = 1 * dist.y * td; | |
dist.y = 0; | |
float linearSpeed = 1 * dist.length * td; | |
if (linearSpeed < 0) | |
linearSpeed = -linearSpeed; | |
const float pi3rd = M_PI/3.0; | |
const float pi2 = M_PI*2.0; | |
//we're not sufficiently moving vertical | |
if (verticalSpeed > -fallThreshold && verticalSpeed < jumpThreshold) | |
{ | |
float direction = Atan2( -dist.x, -dist.z ) - (node.worldRotation.eulerAngles.y + rotationOffset); | |
direction *= M_DEGTORAD; | |
// Normalize direction angle to [-PI, +PI] | |
// To get less if cases | |
if( direction > M_PI ) | |
direction = direction - pi2; | |
if( direction < -M_PI ) | |
direction = pi2 + direction; | |
if (linearSpeed > 0 && linearSpeed > moveThreshold) | |
{ | |
if (direction > pi3rd && direction < 2*pi3rd) | |
{ //play strafe left | |
if (walkLeft.length > 0 && walkLeft.length > 0) | |
PlayAnimation(walkLeft, false, false, true, DefaultLayer); | |
else if (walkRight.length > 0 && walkRight.length > 0) //reverse right walk to use as left walk | |
PlayAnimation(walkRight,true, false, true, DefaultLayer); | |
} | |
else if (direction > -2*pi3rd && direction < -pi3rd) | |
{ //play strafe right | |
if (walkRight.length > 0 && walkRight.length > 0) | |
PlayAnimation(walkRight, false, false, true, DefaultLayer); | |
else if (walkLeft.length > 0 && walkLeft.length > 0) //reverse left walk to use as right walk | |
PlayAnimation(walkLeft,true, false, true, DefaultLayer); | |
} | |
else if (direction >= 2*pi3rd || direction <= -2*pi3rd) | |
{ //play walk backwards | |
if (walkBackward.length > 0 && walkBackward.length > 0) | |
PlayAnimation(walkBackward, false, false, true, DefaultLayer); | |
else //reverse forward anim to walk backward | |
PlayAnimation(walkForward,true, false, true, DefaultLayer); | |
} | |
else if (linearSpeed > runThreshold && run.length > 0) | |
{ //play run forward | |
PlayAnimation(run, false, false, true, DefaultLayer); | |
} | |
else | |
{ //play move forward | |
PlayAnimation(walkForward, false, false, true, DefaultLayer); | |
} | |
} | |
else if (idle.length > 0) | |
{ | |
PlayAnimation(idle); | |
} | |
} | |
else if (-verticalSpeed > fallThreshold && fall.length > 0) | |
{ | |
//play fall animation | |
PlayAnimation(jump, false, true, true, DefaultLayer); | |
} | |
else if (verticalSpeed > jumpThreshold && jump.length > 0) | |
{ | |
//play jump animation | |
PlayAnimation(fall, false, true, false, DefaultLayer); | |
} | |
else if (idle.length > 0) | |
{ | |
PlayAnimation(idle); | |
} | |
} | |
private void PlayAnimation(const String&in animName, bool reverse = false, bool restart = false, bool loop = true, int layer = 0) | |
{ | |
AnimationController@ animCtrl = node.GetComponent("AnimationController"); | |
if (animCtrl !is null) | |
{ | |
const float animDir = reverse ? -1.0 : 1.0; | |
if (restart) | |
{ | |
animCtrl.Play(animName, layer, loop, 0.2); | |
animCtrl.SetTime(animName, 0.0); // play from beginning | |
} | |
else | |
animCtrl.PlayExclusive(animName, layer, loop, 0.2); | |
animCtrl.SetSpeed(animName, animSpeed*animDir); | |
} | |
else | |
{ | |
String msg = "Missing Animation controller in node for MotionController script: "; | |
msg += node.id; | |
log.Error(msg); | |
} | |
} | |
// Update our history of positions | |
void TransformChanged() | |
{ | |
//lastPosition = node.position; | |
lastRotation = node.rotation; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment