- Home /
Can I use Animator.bodyPosition for modifying the colliders during an animation?
Hi everybody,
I want to manipulate my player object's collider in realtime during a jump animation.
I've read that this should best be done by using curves, but I am unsure whether this is possible in my case: I am using a blender created model, imported as generic rig. My animations don't seem to support curves (as I can't see a "Curves" item in the animations' properties).
That's why I am trying to maipulate my collider position and height by custom scripting within the Update() function. But I don't know which frame-by-frame values I could use to apply size changes to my collider.
By using the Monodevelop debugger, I've found out by chance that my animator has a property at runtime called Animator.bodyPosition.normalized, which returns normalized Vector3 objects like "(1.0, 1.1, 0.9)". These values seem to change from frame to frame during jumps, so I guess that they reflect the relative position of my model - which would be exactly what I am looking for!
However, trying to apply these values to my collider's position produces strange results (such as making the collider shoot into the air, fall through the ground, or just pop up about 1 unit and then staying there).
This is what I am doing in code, roughly:
private var capsCollider:CapsuleCollider;
private var animStateBase:AnimatorStateInfo;
private var stateJump = Animator.StringToHash("BaseLayer.Jump");
function Start()
{
capsCollider = collider as CapsuleCollider;
anim = GetComponent(Animator);
}
function Update()
{
animStateBase = anim.GetCurrentAnimatorStateInfo(0); // 0 = BaseLayer
[...]
if (animStateBase.nameHash == stateJump)
{
// note that capsColliderYBase has been initialized before when jump animation started with the collider's original Y position
capsCollider.center.y = capsColliderYBase * anim.bodyPosition.normalized.y;
[...]
}
[...]
}
I wonder: Ist it generally ok what I am trying to do, or is it rather crab to rely on anim.bodyPosition.normalized? Or am I doing something wrong apart from that in my code?
I'd be glad if someone could have a quick look at this!
Answer by coffiarts · Mar 07, 2013 at 09:50 AM
Once more an update to my own question. I assume that this can be considered a final answer:
I was completely unaware that there's a much easier way for achieving what I am trying to to:
One can simply use AnimationCurve for defining a custom curve as a script variable, which can then be freely defined in the curve editor. Inside my script, one can then use the current animation's normalizedTime to grab a specific value from the curve and apply it to the collider.
My current solution is still a bit quick & dirty, but it basically works:
#pragma strict
/* This script demonstrates (quick & dirty)
How a collider's Y position can be dynamically adjusted
during a running jump animation
*/
// the following variable will be visible inside the Inspector window as a curve.
// Simply click it to open the curve editor for freely adjusting it to your needs
// Be aware that in the approach suggested here,
// - the curve's X axis values must always cover the range from 0 to 1 (exactly),
// because we're using the animation's normalized time (0-1) as X values
// - the curve's Y axis values are interpreted as multiplication factors for the
// original Y position (i.e. they should have reasonable max values like 1.5)
var colliderYCurve:AnimationCurve = AnimationCurve(Keyframe(0, 1), Keyframe(0.5, 1.5), Keyframe(1, 1));
private var animStateBase:AnimatorStateInfo;
private var stateJump:int = Animator.StringToHash("BaseLayer.Jump");
private var capsCollider:CapsuleCollider;
private var capsColliderYBase:float;
function Start()
{
// initialize the collider and store its initial Y position
capsCollider = GetComponent(CapsuleCollider);
capsColliderYBase = capsCollider.center.y;
}
function Update()
{
// grab the current animator state
animStateBase = animator.GetCurrentAnimatorStateInfo(0); // 0 = BaseLayer
// check if already jumping
if (animStateBase.nameHash == stateJump)
{
// get the jump animation's time passed and use it as X value for reading the related curve Y value
var animTime:float = this.animStateBase.normalizedTime;
var curveValue:float = colliderYCurve.Evaluate(animTime);
// ... then apply that value to the collider
capsCollider.center.y = capsColliderYBase * curveValue;
}