- Home /
Getting animations to play relative to player's direction?
New code:
var speed : float = 1;
var gravity : float = 20;
var lookSpeed = 4.0;
function Start () {
var abdomenMix : Transform = transform.Find("Armature/Pelvis_C/Abdomen");
animation["HGun_Fire"].wrapMode = WrapMode.Once;
animation["HGun_Fire"].layer = 2;
animation["HGun_Fire"].AddMixingTransform(abdomenMix);
}
function Update(){
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist)) {
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, lookSpeed * Time.deltaTime);
}
var velx: Vector3 = Camera.main.transform.forward * Input.GetAxis("Vertical");
var velz: Vector3 = Camera.main.transform.right * Input.GetAxis("Horizontal");
var vely: Vector3 = transform.up * -gravity;
velx.y = 0;
velz.y = 0;
var flatVel = velx + velz;
var localVel = transform.TransformDirection(flatVel);
var controller = GetComponent(CharacterController);
controller.Move((flatVel + vely) * speed * Time.deltaTime);
if (localVel.x >= 0.25) {
animation.CrossFade("Walk");
}
else if (localVel.x <= -0.25) {
animation.CrossFade("Backpedal");
}
else if (localVel.z >= 0.25) {
animation.CrossFade("StrafeR");
}
else if (localVel.z <= -0.25) {
animation.CrossFade("StrafeL");
}
else {
animation.CrossFade("Idle");
}
}
////////////////////////
Hi all! I am trying to get a movement script to play nice with animations. The game uses an ortho-isometric camera and so the movement is based on Camera.main.transform, which works perfectly, but I'm having trouble getting animations to play relative to player direction.
Basically, what I need to accomplish is this - when the player is actually walking in his forward direction, play Walk. When he is walking in his left direction, play StrafeL. And so on, etc. I have tried comparing the if statement to various movement-related things, but the obvious choices don't seem to work. Comparing it against Input.GetAxis("foo") likewise doesn't work, because those axes are relative to the camera, not the player.
EDIT: Forgot to mention, the player's look direction is always based on the position of the mouse cursor relative to a plane.
Here's the script as it currently is:
var speed : float = 1;
var gravity : float = 20;
var lookSpeed = 4.0;
function Start (){
var abdomenMix : Transform = transform.Find("Armature/Pelvis_C/Abdomen");
animation["HGun_Fire"].wrapMode = WrapMode.Once;
animation["HGun_Fire"].layer = 2;
animation["HGun_Fire"].AddMixingTransform(abdomenMix);
}
function Update(){
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist)) {
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, lookSpeed * Time.deltaTime);
}
var velx: Vector3 = Camera.main.transform.forward * Input.GetAxis("Vertical");
var velz: Vector3 = Camera.main.transform.right * Input.GetAxis("Horizontal");
var vely: Vector3 = transform.up * -gravity;
velx.y = 0;
velz.y = 0;
var controller = GetComponent(CharacterController);
if (!Input.GetAxis("Vertical") && !Input.GetAxis("Horizontal")) {
animation.CrossFade("Idle");
}
if (velx == true) {
animation["Walk"].speed = 0.65;
animation.CrossFade("Walk");
}
if (-velx == true) {
animation["Backpedal"].speed = 0.5;
animation.CrossFade("Backpedal");
}
if (vely == true) {
animation["StrafeR"].speed = 0.65;
animation.CrossFade("StrafeR");
}
if (-vely == true) {
animation["StrafeL"].speed = -0.5;
animation.CrossFade("StrafeL");
}
controller.Move(vely * gravity * Time.deltaTime);
controller.Move(velx * speed * Time.deltaTime);
controller.Move(velz * speed * Time.deltaTime);
}
If anyone knows what I'm missing here, I would greatly appreciate the help :D
Answer by SineDeviance · Aug 21, 2013 at 12:15 AM
I finally figured it out! It was a combination of the x and z axes being mapped backwards and not using InverseTransformDirection. Here is the working code:
var speed : float = 1;
var runSpeed : float = 2;
var gravity : float = 20;
var lookSpeed = 4.0;
private var varSpeed : float;
function Start () {
var chestMix : Transform = transform.Find("Armature/Pelvis_C/Abdomen/Chest");
animation["HGun_Fire"].wrapMode = WrapMode.Once;
animation["HGun_Fire"].layer = 2;
animation["HGun_Fire"].AddMixingTransform(chestMix);
}
function Update(){
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist)) {
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, lookSpeed * Time.deltaTime);
}
var vel: Vector3 = Camera.main.transform.forward * Input.GetAxis("Vertical") + Camera.main.transform.right * Input.GetAxis("Horizontal");
var vely: Vector3 = transform.up * -gravity;
vel.y = 0;
var localVel = transform.InverseTransformDirection(vel);
var controller = GetComponent(CharacterController);
controller.Move((vel.normalized * varSpeed * Time.deltaTime) + (vely * Time.deltaTime));
if (localVel.z > 0.1) {
animation["Walk"].speed = 0.65;
animation.CrossFade("Walk");
//Debug.Log("Should be walking "+localVel.z);
}
else if (localVel.z < -0.1) {
animation["Backpedal"].speed = 0.65;
animation.CrossFade("Backpedal");
//Debug.Log("Should be backpedalling "+localVel.z);
}
else if (localVel.x > 0.0) {
animation["StrafeR"].speed = 0.65;
animation.CrossFade("StrafeR");
//Debug.Log("Should be strafing right "+localVel.x);
}
else if (localVel.x < -0.0) {
animation["StrafeL"].speed = 0.65;
animation.CrossFade("StrafeL");
//Debug.Log("Should be strafing left "+localVel.x);
}
else {
animation.CrossFade("Idle");
}
if(Input.GetButton("Sprint")) {
varSpeed = runSpeed;
animation["Walk"].speed = 1.3;
animation["Backpedal"].speed = 1.3;
animation["StrafeR"].speed = 1.3;
animation["StrafeL"].speed = 1.3;
}
else {
varSpeed = speed;
}
}
Answer by OP_toss · Aug 19, 2013 at 08:25 PM
The best way to do this is to place a gameobject above your animated object's root. Then rotate the parent game object based on input. This will rotate the animating child object.
I recommend always placing at least 1 gameobject between your controller scripts and your animated model. That way you always have another degree of control, and you can easily swap out models if needed.
Hope this helps!
Thanks for the reply OP_toss, but that doesn't answer my question. I have no problem getting the player to rotate. His animations don't play properly relative to his rotation :D
That is still a good idea, and I will make sure I re-create my player prefab with that setup.
I believe that is what you mean... The only reason the animations wouldn't play relative to your rotation, is that either your rotation is being set on the animated object, which will be overwritten by the animation, OR the animation is wrong. If the second is the case, just change your animations to always face straight, then you can rotate the parent in the setup I described above.
Am I still off in my understanding? Sorry if so, hope this helps!
It's actually neither of those things, there's nothing wrong with the animations (they're all at root point with no rotation.) The player's rotation is deter$$anonymous$$ed by the position of the mouse cursor as per the script, not by the animations. I am not using $$anonymous$$ecanim, I am using regular animations with a rig set to legacy.
None of this is related to the problem, though. The problem is that when the character is facing a direction (let's say 270 degrees) on the plane, and he moves forward, I need his Walk animation to play and reflect that he is moving forward. When he's facing that same direction and he moves sideways, I need his sidestrafe animations to play and reflect that he is strafing in whichever direction is relevant (left, right.) And the same goes for the same direction and backpedalling. Does this many any sense? Am I babbling like a madman? :D
If it still doesn't, let me know and I'll post a web build so you guys can see what I mean. Thanks for trying to help, though :D
Answer by Loius · Aug 19, 2013 at 11:35 PM
(I'm not sure what you get when you use a V3 as a boolean (if -vely==true), but I doubt it's what you want)
You should really combine your vectors. You can get down to one Move call (from three!) and you can also translate that movement vector into local space:
flatVel = velx + velz;
localVel = transform.TransformDirection(flatVel);
if ( localVel.x < 0 ) Left;
if ( localVel.x > 0 ) Right;
if ( localVel.z > 0 ) Forward;
if ( localVel.z < 0 ) Back;
controller.Move(flatVel + vely);
Ah I think I see what you mean now... and yes this guy's answer is I think what you want. Didn't know it was as simple as knowing which animation to call hah. GJ Loius
Also it'd be nice if you didn't even have to transform into local space, and you just worked in local space to begin with. And I'd just make a few of those else if
's, but that looks good to me!
Loius, that looks to be exactly the kind of solution I needed. I'll try it out tomorrow and report back. Thanks a bunch!
It's so close to working!
Okay, using the new code example I posted at the top of my original question, the player's animations are AL$$anonymous$$OST working properly. They seem to work in the expected fashion if he is facing up or down relative to the camera. However, if he is facing left or right relative to camera, the animations play backwards for some reason. Any ideas on how I could solve that? Did I do something wrong? =D
Thanks again, Loius, for the idea of combining the vectors into new variables.
EDIT: If you are wondering why I compared the if statements against 0.25, it is because comparing against 0 or 0.1 had odd effects. When the player would stop moving completely, ins$$anonymous$$d of crossfading to 'Idle' it would simply keep looping whatever animation was currently playing (it's as if Unity thinks the player is still moving even though he is not.)
I have no idea why this happens. It'd be nice to figure that out as well =D
$$anonymous$$ore odd stuff happening. In .$$anonymous$$ove() I changed flatVel to localVel just to see what direction the player thought he was moving in. Well, it turns out all the vectors are off by about 45 degrees, but not quite. It's also as if his center of rotation is off by about half a unit.
If he is facing directly up relative to camera, for example, and I try to move him upward, he actually moves in a kind-of up/right direction. If I am moving and rotate the mouse around him to make him rotate, he kind of swings around. I don't know how to explain it any better. All possible directions seem to be affected the same way. I have no idea what is causing this.
I think it might be InverseTransformDirection, ins$$anonymous$$d of TransformDirection. I can never keep those two straight, honestly. Try Inverse and see if that helps first.
If it's just picking the wrong one of the Left and Right options, you can switch the if checks (so that +X becomes Left ins$$anonymous$$d of Right). I've been known to make silly mistakes with simple things :)
Floating point values usually aren't zero unless you set them directly to zero, but I'm not sure why comparing to 0.1 would never go idle. Could be you still have a tiny bit of input co$$anonymous$$g from a joystick.
transform.TransformDirection is using "this" object's transform as the reference point. That transform's forward direction (local +Z) should match up with the graphical representation's forward (the way you expect to walk when you just press W or whatever).
Answer by Machineman · Nov 06, 2015 at 01:44 PM
I know this is an old post, but I have struggled with this issue as well. I have made a way simpler solution to play animations based on movement and direction, and have made an asset on the Unity Asset store.
Check it out!: https://www.assetstore.unity3d.com/#!/content/47778
Happy game developing!