SpaceMarine's Walking Animations

Good day to everybody.

I’m really enjoying the ‘Unity Games by Tutorials’, as well as the other books I have from this site, and after I successfully (thanks to the authors) cleared the BobbleheadWars Chapter, I challenged myself to use those animations that we have from the .unitypackage in the BobbleMarine-Body model. Because, well, I felt that the hero deserves something more than moonwalk regardless of direction (which surely is pretty fun too).

So I

  • created the five states in the animator;
  • made transitions between them;
  • created four bools for each direction;
  • and inside the else branch of the FixedUpdate( ) wrote a pretty hard code of four repeating if statements conditioning Input.GetAxis “Horizontal” and “Vertical” to be more or less than 0 containing all the variations of bools for each side.

As a result I have SpaceMarine’s animations for four directions transitioning between each other pretty neatly. So if he faces direction from the camera, he walks back if I press “S” and sidesteps left and right if I press “A” or “D”, and of course when I press “W” the animation of walking forward also runs. But it makes sense only if he is facing in that one direction. When mouse moved so the hero faces, say, right side of the scene, the animations keep responding to the same Input like this:
hero facing right (the direction of the mouse input), I press “Right” or “D”, and the hero himself moves forward, but the animation played is for the sidestepping right. Same thing with the other directions.

I would appreciate if somebody could explain how to make all those animations depend also on the mouse input or the hero’s facing direction. And some better solutions instead of those if statements’ hard code. :slight_smile:

Well done! Do you mind taking some video and posting here? I would love to see it.

Regarding the avoiding of hardcoding of ifs blocks, you don’t have to work with boolean values. The animator is very powerful and you can encapsulate all of your movement logic into the animator itself. All you do is pass information to the animator, and based on your logic in the animator, Unity switch between states.

In essence, the marine walks on a 2D plane. You can create two ints. One for the x value, another for the y value, and then you set conditions on your transitions. If your character is walking up, then the y value is +1. If down, then -1. Same for the x position.

When the player moves, just send the x and y position to the animator, and let your transitions do the logic, so essentially, you’re just writing two lines of code in C#.

That’s just off the top of my head but I’m sure there’s a more elegant way of doing this.

I hope that helps!

1 Like

Thank you for reply!
Here is what I did that time:


the chunks for walking in the PlayerController.cs:

void FixedUpdate() {
	Vector3 moveDirection = new Vector3 (Input.GetAxis ("Horizontal"), 0, Input.GetAxis ("Vertical"));
	if (moveDirection == Vector3.zero) {
		bodyAnimator.SetBool ("IsGoingFw", false);
		bodyAnimator.SetBool ("IsGoingBw", false);
		bodyAnimator.SetBool ("StepsL", false);
		bodyAnimator.SetBool ("StepsR", false);
	} else {
		head.AddForce (transform.right * 150, ForceMode.Acceleration);
		if (Input.GetAxis("Vertical") > 0) {
			bodyAnimator.SetBool ("IsGoingFw", true);
			bodyAnimator.SetBool ("IsGoingBw", false);
			bodyAnimator.SetBool ("StepsL", false);
			bodyAnimator.SetBool ("StepsR", false);
		}
		if (Input.GetAxis("Vertical") < 0) {
			bodyAnimator.SetBool ("IsGoingFw", false);
			bodyAnimator.SetBool ("IsGoingBw", true);
			bodyAnimator.SetBool ("StepsL", false);
			bodyAnimator.SetBool ("StepsR", false);
		}
		if (Input.GetAxis("Horizontal") < 0) {
			bodyAnimator.SetBool ("IsGoingFw", false);
			bodyAnimator.SetBool ("IsGoingBw", false);
			bodyAnimator.SetBool ("StepsL", true);
			bodyAnimator.SetBool ("StepsR", false);
		}
		if (Input.GetAxis("Horizontal") > 0) {
			bodyAnimator.SetBool ("IsGoingFw", false);
			bodyAnimator.SetBool ("IsGoingBw", false);
			bodyAnimator.SetBool ("StepsL", false);
			bodyAnimator.SetBool ("StepsR", true);
		}
	}

	RaycastHit hit;
	Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
	Debug.DrawRay (ray.origin, ray.direction * 1000, Color.green);

	if (Physics.Raycast (ray, out hit, 1000, layerMask, QueryTriggerInteraction.Ignore)) {
		if (hit.point != currentLookTarget) {
			currentLookTarget = hit.point;
		}

		Vector3 targetPosition = new Vector3(hit.point.x, transform.position.y, hit.point.z);
		Quaternion rotation = Quaternion.LookRotation (targetPosition - transform.position);
		transform.rotation = Quaternion.Lerp(transform.rotation, rotation, Time.deltaTime * 10.0f);

	}
}

public void Die() {
    marineBody.constraints = RigidbodyConstraints.None;
    head.constraints = RigidbodyConstraints.None;

	bodyAnimator.SetBool ("IsGoingFw", false);
	bodyAnimator.SetBool ("IsGoingBw", false);
	bodyAnimator.SetBool ("StepsL", false);
	bodyAnimator.SetBool ("StepsR", false);
	marineBody.transform.parent = null;
	marineBody.isKinematic = false;
	marineBody.useGravity = true;
	marineBody.gameObject.GetComponent<CapsuleCollider> ().enabled = true;
	marineBody.gameObject.GetComponent<Gun> ().enabled = false;

	Destroy(head.gameObject.GetComponent<HingeJoint>());
	head.transform.parent = null;
	head.useGravity = true;
	SoundManager.Instance.PlayOneShot (SoundManager.Instance.marineDeath);
	deathParticles.Activate();
	Destroy (gameObject);
}

And the video of the result:

Following your advice to use Integers instead of bools (I remember that this is described in the later chapters of the book), I created only one Int for all the animations to switch between, and that really helped to clean up the code :slight_smile: thank you:

void FixedUpdate() {
Vector3 moveDirection = new Vector3 (Input.GetAxis (“Horizontal”), 0, Input.GetAxis (“Vertical”));
if (moveDirection == Vector3.zero) {
bodyAnimator.SetInteger (“WalkInt”, 0);
} else {
head.AddForce (transform.right * 150, ForceMode.Acceleration);
if (Input.GetAxis(“Vertical”) > 0) {
bodyAnimator.SetInteger (“WalkInt”, 1);
}
if (Input.GetAxis(“Vertical”) < 0) {
bodyAnimator.SetInteger (“WalkInt”, 2);
}
if (Input.GetAxis(“Horizontal”) < 0) {
bodyAnimator.SetInteger (“WalkInt”, 3);
}
if (Input.GetAxis(“Horizontal”) > 0) {
bodyAnimator.SetInteger (“WalkInt”, 4);
}
}

and for the Die()

public void Die() {
marineBody.constraints = RigidbodyConstraints.None;
head.constraints = RigidbodyConstraints.None;
bodyAnimator.SetInteger (“WalkInt”, 0);
marineBody.transform.parent = null;
marineBody.isKinematic = false;
marineBody.useGravity = true;
marineBody.gameObject.GetComponent ().enabled = true;
marineBody.gameObject.GetComponent ().enabled = false;

Destroy(head.gameObject.GetComponent());
head.transform.parent = null;
head.useGravity = true;
SoundManager.Instance.PlayOneShot (SoundManager.Instance.marineDeath);
deathParticles.Activate();
Destroy (gameObject);
}

I presume that using switch statement or something else, could let me get rid of four repeating if statements, but I’m still not that experienced in programming and refactoring… :frowning:

Result is absolutely the same as previous video shows… When our hero facing in direction other than “from the camera”, walking animations do not match.

Well done - as they say, writing is all about rewriting. The same goes true about coding. As you continue to progress, you’ll find even better ways to refactor. But nice job and thanks for sharing the code.

Regarding the animation not matching, I wonder if that may have to do with the direction change. Just blue skying, but you maybe need to switch the axis when facing a different direction. Play around with it and see what you find.

Nice work!

1 Like

This topic was automatically closed after 166 days. New replies are no longer allowed.