Making a player move in Unity

Last time we left off we had some animation going. Since then Unity has released the 4.3 build so it's out of beta and into my eager hands. They even released a nice demo project. I've created a script called TestControl which mimics a lot of the PlayerControl script they ship in the project. I even left their comments in.
The public variables show up in the Inspector and allow you to change values even while the game is running. This is very helpful for tweaking settings and finding a good balance of things, especially when trying to learn the good values for forces for the first time. Setting them in the inspector while the game isn't running will have them be the values when the game runs again regardless of the value set in your code.

1:  using UnityEngine;  
2:  using System.Collections;  
3:  public class TestControl : MonoBehaviour {  
4:    public bool facingRight = true;  
5:    public bool jump = false;  
6:    public float moveForce = 365f;  
7:    public float maxSpeed = 8f;  
8:    public float jumpForce = 1000f;  
9:    public Transform groundCheck;  
10:    public bool grounded = false;  
11:    public Animator anim;  
12:       // Use this for initialization  
13:       void Awake () {  
14:      groundCheck = transform.Find("groundCheck");  
15:       }  
16:       // Update is called once per frame  
17:       void Update () {  
18:      grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));  
19:      if (Input.GetButtonDown("Jump") && grounded)  
20:        jump = true;  
21:       }  
22:    // Updates with each physics update.  
23:    void FixedUpdate()  
24:    {  
25:      // Cache the horizontal input.  
26:      float h = Input.GetAxis("Horizontal");  
27:      // If the player is changing direction (h has a different sign to velocity.x) or hasn't reached maxSpeed yet...  
28:      if (h * rigidbody2D.velocity.x < maxSpeed)  
29:        // ... add a force to the player.  
30:        rigidbody2D.AddForce(Vector2.right * h * moveForce);  
31:      // If the player's horizontal velocity is greater than the maxSpeed...  
32:      if (Mathf.Abs(rigidbody2D.velocity.x) > maxSpeed)  
33:        // ... set the player's velocity to the maxSpeed in the x axis.  
34:        rigidbody2D.velocity = new Vector2(Mathf.Sign(rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y);  
35:      // If the input is moving the player right and the player is facing left...  
36:      if (h > 0 && !facingRight)  
37:        // ... flip the player.  
38:        Flip();  
39:      // Otherwise if the input is moving the player left and the player is facing right...  
40:      else if (h < 0 && facingRight)  
41:        // ... flip the player.  
42:        Flip();  
43:            // If the player should jump...  
44:            if(jump)  
45:            {  
46:                 // Set the Jump animator trigger parameter.  
47:                 //anim.SetTrigger("Jump");  
48:        // Add a vertical force to the player.  
49:        rigidbody2D.AddForce(new Vector2(0f, jumpForce));  
50:        // Make sure the player can't jump again until the jump conditions from Update are satisfied.  
51:        jump = false;  
52:      }  
53:    }  
54:    void Flip()  
55:    {  
56:      // Switch the way the player is labelled as facing.  
57:      facingRight = !facingRight;  
58:      // Multiply the player's x local scale by -1.  
59:      Vector3 theScale = transform.localScale;  
60:      theScale.x *= -1;  
61:      transform.localScale = theScale;  
62:    }  
63:  }  

Attach the script to your parent object. This code depends on a few things to be added to our scene to work. First off we need to add an empty game object to the parent player object called groundCheck. This should be positioned at the base of your character or just below them. Line 14 depends on that otherwise you'll get a lovely null reference exception. (Why don't you just try setting the object to an instance of an object?)
I put mine close to -2 Y.
A couple of other things you will need to create to have this script work are some layers created and named. In Unity this is pretty easy to do, click on the Layer dropdown for any game object and select Add Layer... If a layer is selected on a parent object it will prompt to cascade it through to any child also. The layers you'll need to create are Player and Ground. In my scene the Quads have Box Collider 2D components and are set to the Ground layer and the Player is set to Player. Line 18 depends on the Ground layer for the line cast, otherwise you'll never be able to jump as grounded won't be True.
Using Layers can be really helpful.
Honestly the physics in Unity work really well right out of the box and feel great. A couple things I tweaked to keep the character from falling over is adding a Circle Collider 2D for the feet and checked the Fixed Angle for the Rigidbody 2D component. I immediately tried to think of ways to toggle that or rotate the physics via scripting but haven't figured it out just yet.
Check the Fixed Angle box to keep the Rigidbody 2D from tipping over. The circle collider makes it easier to move up and down slopes too.

So with that you have a simple way to move a 2D character around in a platform style. Next up I'm working on getting the Camera to follow me around properly. The demo project also shipped with one of those so I'm digging into it.

As for game consumption I finished up Tomb Raider (Amazing game), The Legend of Zelda: Wind Waker HD (Rad),  and Super Mario 3D World ( One of the best games I've ever played). I've toyed with the idea of making a short quick minigame or arcade style game similar to the guy that did 31 games in October to challenge himself. Maybe that will help me get some more projects off the ground.

Comments

Popular Posts