Monday, September 12, 2022

Driving Game - introduction to visual scripting


Welcome to the Unity. In this project, your are going to make vehicle driving game by using real physics simulation, just like it's done in games done by professional studios! Open provided starter project and take a look around, you should see the car is already there, waiting for code to make it go!

Quick introduction to unity interface


The window in the middle shows our game scene. On the left side, we have the Hierarchy panel, which lists all objects in our scene. On the right side, the Inspector panel shows various components and properties of currently selected object. And finally, on the top of the screen, we have very important Play button, that will allow us to start and stop our game. Don't worry if it looks a bit overwhelming at first, you will soon figure out what everything does!

Make the car move

As you can see, our car is very basic, it has a body and three wheels. Let's make it move. First, select the “rear right wheel” in the Hierarchy panel on the left (you might need to "open" the car by clicking gray triangle next to it) and then click on the Edit Graph button on the Inspector panel to the right. This will open our script. Alternatively, you can just click the wheel in the scene view.

Now this is where programming begins. It’s a bit similar to scratch, where you connect various blocks together. On Update Event will fire every frame (many times per second, just like forever loop in scratch). While the Wheel Collider Set Motor Torque is going to make the wheels rotate, and in turn, propel our car! 

Before continuing, click the “Play” button on top of the screen, that way we will be able to see what is happening to our car while we are coding. 

Let’s make our car move. Connect On Update Event to Wheel Collider Set Motor Torque, and set the value of the latter to 500, so it’s going to add plenty of torque (torque is just a force, but rotational one). Now watch the car go, and promptly crash into the orange cube... Congratulations, your first unity program is working!

Feel free to experiment with different values. What happens if you set the value to -500? Or 5000? If at any time your car becomes unusable, just restart the scene by clicking the "Play" button to turn off the play mode and then click it again to restart it. 

Control acceleration with keyboard or game controller



Controlling the car by typing value into the script is not the most convenient way, lets make it better. Note the other two nodes in the graph, one of them is Get Input Axis. This one will output a value between -1 and 1, depending on how far we move gamepad/joystick, or, if we don't have a game controller, which keys we are pressing on the keyboard. The up and down arrow keys control the "Vertical" axis, while the left and right arrow keys control the "Horizontal" axis. But since -1 and 1 is not enough to move our car, we need to multiply it with the Multiply node, before finally setting it as our torque. 

Connect the nodes together as shown, make sure to put 500 as the B argument of the Multiply node, and now you can control acceleration of the car with up and down arrow keys. Congratulations, you are half way to having a working car!

Note how values change on the graph while you are pressing the up and down arrow keys. It will come in handy whenever we try to understand what is happening in our code. 

Make our car turn

Let's switch to the "front wheel" now by clicking on it in the Hierarchy panel. The Script Graph window should automatically switch to its script, but if you closed that window, just click again on Edit Graph in the Inspector panel.

Does it look similar to the previous script? The main difference is that now we will be setting steering angle of the wheel. If you click on the Wheel Collider Set Steer Angle node, The Script Graph window will display its description, which can be very handy!

Can you connect the nodes and setup the value in order to let the player steer the wheel with left and right arrow keys? Feel free to take a peek at the image below if you need a hint.



Congratulations, you can now drive the car around!

Lets add a proper goal to our game. While we do have a finish line, it does not show us how fast we got there. Let's fix that!

Counting the time to reach the finish line



Click on the "Finish Line" to open its script. It's slightly more complicated, but don't worry, it's pretty straightforward.

The Timer node is very convenient node that makes counting the time very easy. It not only keeps track of the time for us, it also fires its Tick output every frame for as long as its active, working a bit like loops in scratch. Additionally, the Elapsed output will give us the value of how long the timer is active so far (in seconds).

First, let's start it by connecting it to the Start Event. Since the event only fires at the start of the game, you need to restart your game for that to work. Then, connect the Tick output to the Set Text node, which will set the displayed text to the value we provide. But how do we get the value?

Elapsed to the rescue, connect it to the To String node, which will change it into neat text value. And finally, connect the output of the To String node to the value input of the Set Text node.




And don't forget to pause the timer once we cross the finish line by using the On Trigger Enter Event node.

Phew, that was some fancy coding. But now you have created real working game, congratulations! Can you beat my 12.5s time from the image?

Additional challenges

Improving the car

As you probably noticed, our car does not look very good, and is very unstable... Can you make it better? Add wheels? Nicer Shape? More windows? Feel free to experiment!

Improving the track with Pro Builder

How about making the track more fun and challenging! Play around with Pro Builder panel, add as many obstacles as you want. Can you make the track so challenging that only you will be able to finish it?

 


 

Pro Tip: Shapes that you add with Pro Builder are static by default, which means they won't move, no matter how hard you crash into them. But if you add Rigidbody component to them (use Add Component button in the Hierarhy panel), they will react according to the law of physics. Experiment by changing their mass, and see how differently they behave!

Adding sound to the car 

This one involves little bit of math, but since computer will be doing most of the work, no big deal. It's all about calculating our velocity, and then modifying pitch of the sound (how fast the sound is playing) depending on calculated velocity. Scary looking Inverse Transform Vector node is there to turn our velocity from world space to car space, so we can get our forward velocity easily. Then we divide it by 5 (feel free to experiment with the value), set it as pitch of our sound and done, our car sounds "faster" the faster it goes!



Make it two player game

This one is going to be fun. Challenge your friends and see who can win!

If we duplicate our car, we do get fully working second one, but one player controls both! How do we tell the care to be controlled by different set of keys? Variables to the rescue!

Note that for Input Get Axis, we can define which axis it reads. Luckily, we have more axes defined in our project, like Horizontal2 and Vertical2, which are controlled by WSAD keys (you can check them all by going to menu Edit->Project Settings->Input). Let's create object variable of type string and read the name of our axis from there. Create it for each wheel, and set it so first car will use Horizontal and Vertical, while second car will use Horizontal2 and Vertical2. Then, modify drive and steer scripts so they read our variable.

Success, each car now can be controlled independently!

Wednesday, November 6, 2019

Player Controllable Physics Ball

Just two scripts for now without proper explanation, but they should work as long as you have a sphere with sphere collider and rigidbody, add those scripts to it and point first one's head property to your camera :3
using UnityEngine;
 
public class BallPlayerController : MonoBehaviour
{
 public Transform head;
 
 public float movementTorque = 6.0F;
 
 private Rigidbody rb;
 
 private float pitch;
 private float yaw;
 
 // Use this for initialization
 void Start()
 {
  rb = GetComponent<Rigidbody>();
  head.parent = null;
 }
 
 // Update physics
 void FixedUpdate()
 {
  //Add torque to rotate ball in the direction we are looking
  rb.AddTorque(-head.forward * Input.GetAxis("Horizontal"* movementTorque);
  rb.AddTorque(head.right * Input.GetAxis("Vertical"* movementTorque);
 }
 
 // Update is called once per frame
 void Update()
 {
  //Rotate head around and make it follow the player
  yaw += Input.GetAxis("Mouse X") * 10;
  pitch = Mathf.Clamp(pitch - Input.GetAxis("Mouse Y") * 5, -70, 70);
  head.rotation = Quaternion.Euler(pitch, yaw, 0);
  head.transform.position = transform.position - head.forward * 5 + Vector3.up * 1;
 }
}
using UnityEngine;
 
public class PhysicsJump : MonoBehaviour
{
 public float jumpForce = 5;
 
 public bool grounded;
 
 private bool jump = false;
 
 private Rigidbody rb;
 
 void Start()
 {
  rb = GetComponent<Rigidbody>();
 }
 
 private void Update()
 {
  jump = Input.GetButtonDown("Jump");
 }
 
 void FixedUpdate()
 {
  if (rb.IsSleeping())
   grounded = true;
 
  if (grounded)
  {
   if (jump)
   {
    rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
   }
  }
  jump = false;
  grounded = false;
 }
 
 private void OnCollisionStay(Collision collision)
 {
  for (int i = 0; i < collision.contactCount; i++)
  {
   var cp = collision.GetContact(i);
   if (cp.normal.y > 0)
   {
    grounded = true;
   }
  }
 }
}

Thursday, May 9, 2019

First Person Controller

Let's make simple first person controller, that will let us move around level in first person mode. Start by making empty game object and call it FirstPersonConttroller, then add character controller component to it. This will represent body of our character, but we still need head so we can see anything. Your scene should already have camera, drag it on top of your newly created FirstPersonController in Hierarchy tab (on the left) so it will become child of it. Then, position it so it's in the center and a bit above (where head should be). When you are done, it should look like on this picture:
Next, create new script and add it to your FirstPersonController

using UnityEngine;
 
public class FirstPersonController : MonoBehaviour
{
    public Transform head;
 
    private CharacterController cc;
 
    private float pitch;
    private float yaw;
 
    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
 
    private Vector3 moveDirection = Vector3.zero;
 
    // Use this for initialization
    void Start()
    {
        //Initialize various usefull things
        cc = GetComponent<CharacterController>();
        pitch = head.transform.localEulerAngles.x;
        yaw = transform.localEulerAngles.y;
 
        //Let's hide lock cursor so its not going outside the window
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
    }
 
    // Update is called once per frame
    void Update()
    {
        if (cc.isGrounded)
        {
            // If we are touching the ground, calculate movement and jumping
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetButton("Jump"))
                moveDirection.y = jumpSpeed;
        }
 
        // Always apply gravity
        moveDirection.y -= gravity * Time.deltaTime;
 
        //Move our character
        cc.Move(moveDirection * Time.deltaTime);
 
        //We rotate whole body when looking around
        yaw += Input.GetAxis("Mouse X") * 10;
        transform.localRotation = Quaternion.Euler(0, yaw, 0);
 
        //But only rotate head when looking up and down
        pitch = Mathf.Clamp(pitch - Input.GetAxis("Mouse Y") * 5, -70, 70);
        head.localRotation = Quaternion.Euler(pitch, 0, 0);
    }
}

Next, we have to show our FirstPersonController script where our head is. With FirstPersonController oject selected, drag your head (Main Camera) into 'Head' property of your script, as in following picture.
Congratulations, you now have fully working first person player controller. Add some geometry to your level and test it!

Thursday, November 8, 2018

2D Platformer Character 5 - Triggers

This time we will use small but useful script to add simple trap to our level. We are going to make red crystals fall down when player enters particular area. First, lets prepare our object that will fall on unsuspecting player.

Put new sprite of your choice into the scene, add 'Rigidbody 2D' and some kind of 'Collider 2D' to it. Make sure to uncheck 'Simulated' property on Rigidbody, so it wont fall down straight away. You can also change its Tag to 'Kill', so it will kill the player when touched. Next, create empty Game Object, add 'Box Collider 2D' to it and check it's 'Is Trigger' property. Adjust its size and position to encompass area that should trigger our red gem to fall. Feel free to rename our new Game Object to something more appropriate (like 'gem red fall' for example). Add PlayerTrigger.cs script to it
using UnityEngine;
using UnityEngine.Events;
 
public class PlayerTrigger : MonoBehaviour
{
    public UnityEvent onEnter;
 
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Player"))
            onEnter.Invoke();
    }
}
And set it up in inspector, so it will turn on 'Simulated' property of our 'gem red' game object. The only thing left to do is to make sure our player object has 'Player' tag assigned, otherwise PlayerTrigger.cs script wont recognize it. Congratulations, you made your first trap. Of course this is just simple example, you can use PlayerTrigger.cs script in many other ways, limited only by your imagination :3

Thursday, November 1, 2018

2D Platformer Character 4 / 4 - Collectibles

Lets enable our cat to collect things. Add sprite of your choice (can be animated or not) to the scene (I used animated gems from here), add some kind of 2D collider to it and mark it as a trigger. Next, add this script to your player cat.
using UnityEngine;
 
public class Collector : MonoBehaviour
{
    // How many things we have collected
    public int collected;
 
    // What should happen if we enter trigger
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // If it's collectible
        if (collision.gameObject.CompareTag("Collectible"))
        {
            // Destroy it
            Destroy(collision.gameObject);
 
            // Increase count of objects we collected
            collected++;
        }
    }
}
If you play the game now, cat should be able to collect objects you placed, and number of items collected should increse whenever you pick something. Hovewer, there is no way currently to tell player how many items they collected. Lets fix it by displaying number of items collected on the screen. Add UI->Text object to your scene. Notice it also created 'Canvas' object automatically. This is just an object that represents whole screen under which all UI elements will be placed. In the Scene View, Canvas and all UI elements are usually much larger than your game world, so if you have problems locating it, select Canvas object and press 'f' key, which should center 'Scene View' on Canvas and your New Text object.

Rename our 'New Text' object to 'Score' for clarity sake and place it wherever you want by using 'Rect Tool' (marked on upper left of corner the screenshot). Also make sure to set anchor correctly under Rect Transform. It tells unity to stick your UI element to one side of the screen, which is important if your screen will change sizes (without it, your element might end up outside of the screen if you make game window smaller for example). And finally, make sure default text is "0". Now we need to tell unity to update this text whenever we collect something. Update our Collector.cs script to look like this.
using UnityEngine;
using UnityEngine.UI;
 
public class Collector : MonoBehaviour
{
    // How many things we have collected
    public int collected;
 
    // Text UI for displaying score
    public Text score;
 
    // What should happen if we enter trigger
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // If it's collectible
        if (collision.gameObject.CompareTag("Collectible"))
        {
            // Destroy it
            Destroy(collision.gameObject);
 
            // Increase count of objects we collected
            collected++;
 
            // Update our score
            score.text = collected.ToString();
        }
    }
}
Assign our 'Score' Game Object to Score property of Collector.cs script. Congratulations, your cat can now collect items :3

Wednesday, October 24, 2018

2D Platformer Character 3 / 4 - Win and Lose

This time, we are going to make a real game out of our little 2D cat project. First, lets enable player to lose our game by touching 'bad' platforms. We need a way to tell our scripts which platform we hit. There are many ways to do it, simplest is to create a Tag, lets call it 'Kill', and then assign it to every object that we want to cause player death.

Duplicate platform we have in the scene, change its color to red so it looks differently (or you can just use different bitmap if you have one). It's good idea to rename it too, for example to 'kill block'. When it's done, create new Tag 'Kill' and assign it to our new platform. Next, add these two methods to the PlyerCat.cs script
// What should happen if we collide with anything
private void OnCollisionEnter2D(Collision2D collision)
{
    // If we touched object with a 'Kill' Tag
    if (collision.collider.CompareTag("Kill"))
    {
        // Disable player GameObject
        gameObject.SetActive(false);
 
        // Restart after one second
        Invoke("Restart", 1);
    }
}
 
// Handy method for restarting current scene
private void Restart()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
If Visual Studio haven't done it for you, add this clause at the beginning of the PlayerCat.cs script:
using UnityEngine.SceneManagement;
Now when you touch red platform, game should restart after one second.

Before we'll enable player to win our game, let's make more platforms. It's good idea to make prefab out of everything we are going to use multiple times in our scene. That way, if we'll need to change anything later, it will be enough to change one prefab, and every object created out of it will update automatically. Create prefab out of our block by dragging it from scene into Assets window. Now we can finally create more platforms to make our level more interesting. If you try to play now, you will notice that player has tendency to 'stick' to platforms sides. That's because platforms have friction, we need to disable it from sides. Select your platform prefab, add Platform Effector 2D and set everything like in following screenshot. That should prevent player from sticking to the sides.

Let's enable player to win our game! Like before, make another platform, change its color to green, create and assign 'Victory' Tag to it, and change it's name to 'victory block'. Let's also create some kind of victory screen so player knows they actually won. I just made simple sign for it by using www.textfx.co generator. When you put it in the scene, make sure to set 'Order in Layer' to some big number (like 100), that way it will be always displayed in front of everything. Now lets change PlayerCat.cs script to show our victory sign when player touches platform with 'Victory' Tag, and restart the game after 5 seconds.
using UnityEngine;
using UnityEngine.SceneManagement;
 
public class PlayerCat : MonoBehaviour
{
    // How strong force to apply for sidewise movement
    public float movementForce = 15;
 
    // How strong force to apply for jump
    public float jumpForce = 5;
 
    // Where should we check for ground
    public Transform groundCheck;
 
    // Are we standing on the ground?
    private bool grounded;
 
    // Victory Screen
    public GameObject victoryScreen;
 
    // References for various components to use later
    private SpriteRenderer sr;
    private Rigidbody2D rb;
    private Animator anim;
 
    // Use this for initialization
    void Start()
    {
        // Find our components
        sr = GetComponent<SpriteRenderer>();
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
 
        // Disable it initially
        victoryScreen.SetActive(false);
    }
 
    // Update is called once per frame
    void Update()
    {
        // Lets see if we are standing on something
        grounded = Physics2D.OverlapPoint(groundCheck.position) != null;
 
        // Jump only when we are grounded
        if (Input.GetButtonDown("Jump") && grounded)
        {
            anim.SetTrigger("Jump");
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }
 
        // Set Speed parameter to absolute value of our horizontal speed
        anim.SetFloat("Speed"Mathf.Abs(rb.velocity.x));
 
        // Set Grounded animator parameter
        anim.SetBool("Grounded", grounded);
    }
 
    // FixedUpdate is called every Time.fixedDeltaTime
    void FixedUpdate()
    {
        // Get value of horizontal axis (left/right arrow or a/d keys),
        // returns value in range [-1.0f, 1.0f]
        var h = Input.GetAxis("Horizontal");
 
        // Flip sprite depending on horizontal input
        if (h < 0.0f)
            sr.flipX = true;
        if (h > 0.0f)
            sr.flipX = false;
 
        // Move player according to horizontal axis
        rb.AddForce(Vector2.right * h * movementForce, ForceMode2D.Force);
    }
 
    // What should happen if we collide with anything
    private void OnCollisionEnter2D(Collision2D collision)
    {
        // If we touched object with a 'Kill' Tag
        if (collision.collider.CompareTag("Kill"))
        {
            // Disable player GameObject
            gameObject.SetActive(false);
 
            // Restart after one second
            Invoke("Restart", 1);
        }
 
        // If we touched object with a 'Victory' Tag
        if (collision.collider.CompareTag("Victory"))
        {
            // Stop player from moving
            rb.simulated = false;
            rb.velocity = Vector2.zero;
 
            // Show victory screen
            victoryScreen.SetActive(true);
 
            // Restart after five seconds
            Invoke("Restart", 5);
        }
    }
 
    // Handy method for restarting current scene
    private void Restart()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}
We still need to tell PlayerCat script where is our victory sign. Select our cat character, and then drag victory sign to 'Victory Screen' property of PlayerCat script. Congratulation, you now have fully functional game :3

Tuesday, October 23, 2018

2D Platformer Character 2 / 4 - Jumping

Lets teach our cat how to jump. First, we need to modify PlayerCat.cs script.
using UnityEngine;
 
public class PlayerCat : MonoBehaviour
{
    // How strong force to apply for sidewise movement
    public float movementForce = 15;
 
    // How strong force to apply for jump
    public float jumpForce = 5;
 
    // Where should we check for ground
    public Transform groundCheck;
 
    // Are we standing on the ground?
    private bool grounded;
 
    // References for various components to use later
    private SpriteRenderer sr;
    private Rigidbody2D rb;
    private Animator anim;
 
    // Use this for initialization
    void Start()
    {
        // Find our components
        sr = GetComponent<SpriteRenderer>();
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }
 
    // Update is called once per frame
    void Update()
    {
        // Lets see if we are standing on something
        grounded = Physics2D.OverlapPoint(groundCheck.position) != null;
 
        // Jump only when we are grounded
        if (Input.GetButtonDown("Jump") && grounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }
 
        // Set Speed parameter to absolute value of our horizontal speed
        anim.SetFloat("Speed"Mathf.Abs(rb.velocity.x));
    }
 
    // FixedUpdate is called every Time.fixedDeltaTime
    void FixedUpdate()
    {
        // Get value of horizontal axis (left/right arrow or a/d keys),
        // returns value in range [-1.0f, 1.0f]
        var h = Input.GetAxis("Horizontal");
 
        // Flip sprite depending on horizontal input
        if (h < 0.0f)
            sr.flipX = true;
        if (h > 0.0f)
            sr.flipX = false;
 
        // Move player according to horizontal axis
        rb.AddForce(Vector2.right * h * movementForce, ForceMode2D.Force);
    }
}
Then, add empty GameObject to the cat, rename it to GroundCheck and place it right below cat's Capsule Collider. Now, select cat GameObject and drag your new GroundCheck into Ground Check property of PlayerCat.cs script. If all went good, you should have a jumpy cat!

Lets make jumps look nicer by adding different animation for when the cat is in the air. Prepare cat_jump bitmap like before, by slicing it and creating animation out of it. This time, make animation only out of 3rd and 4th frames. Like before, you can delete cat_jump_2 GameObject and cat_jump_2 Animator that unity created. Open cat Animator and add another parameter to it of type bool this time and call it 'Grounded'. Also add your new 'cat_jump' animation to it and make two new transitions to it, one from 'cat_idle' state and one from 'cat_walk' state. Set them up like in screenshot below. Just make sure you set parameters for both of them. Add one more transition, from cat_jump to cat_idle this time, so our cat can land. And finally, modify Update method of PlayerCat.cs script to look like this.
 
    // Update is called once per frame
    void Update()
    {
        // Lets see if we are standing on something
        grounded = Physics2D.OverlapPoint(groundCheck.position) != null;
 
        // Jump only when we are grounded (Space key by default)
        if (Input.GetButtonDown("Jump") && grounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }
 
        // Set Speed parameter to absolute value of our horizontal speed
        anim.SetFloat("Speed"Mathf.Abs(rb.velocity.x));
 
        // Set Grounded animator parameter
        anim.SetBool("Grounded", grounded);
    }
Congratulations, you taught our cat how to jump properly :3

Of course we could continue improving our jump by adding animation for beginning of the jump and landing, but its not really necessary and it would complicate cat Animator. If you are curious how much, take a look at one that has them implemented. If you are up for a challenge, you can try to figure out how to implement it all by yourself :3

2D Platformer Character 1 / 4 - Basic Movement

Lets make a character for simple 2D platformer type game. I prepared archive with all needed bitmaps here, but feel free to use your own. I used sprite sheet for a cat from opengameart.org, while platform graphics was made by one of super talented participants of our workshop.
Create new 2D project and put all bitmaps in Assets folder. Lets start with making some ground for our character to walk on. Since we want our block to be tiled, we need to change 'Mesh Type' in its import settings to Full Rect. Additionally, change 'Filter Mode' to point if you are going for pixelated look. Once its done, you can put your ground in the scene. Change 'Draw Mode' to Tiled, which will enable you to extend ground as much as you want (with the marked tool in upper left corner), and bitmap will just tile automatically. Also, add Box Collider 2D and check it's 'Auto Tiling' property, so our player wont fall through the ground.
Now we can prepare player character sprite by slicing it. Select cat_idle bitmap, change 'Sprite Mode' to Multiple, and click on the 'Sprite Editor' button. You can also change 'Filter Mode' to Point too if you prefer pixelated look. Within Sprite Editor, open Slice menu and set slicing parameters. We know that each frame in our sprite sheet has size of 64x64 pixels, so it's easiest to pick 'Grid By Cell Size' and set cell size to 64x64. Press Slice when you are done and you can close Sprite Editor. Now we can finally add sprite of our player character to the scene. Select all 4 frames of our 'cat_idle' animation (with SHIFT key) and just drag them into the scene. Unity will ask you for name of new animation, name it cat_idle. If you now enter play mode, you should see your character playing 'idle' animation. However, it might look a bit too small, because most likely camera has incorrect size. Unfortunately, correct size will vary depend on game's window size. On the bright side, we can make script that will update camera automatically. Create and add following script PixelCamera.cs to your Main Camera in the scene.
using UnityEngine;
 
[ExecuteInEditMode]
public class PixelCamera : MonoBehaviour
{
    void Update()
    {
        var c = GetComponent<Camera>();
        if (c != null && c.orthographic)
        {
            c.orthographicSize = Screen.height / 200.0f;
        }
    }
}
Now our game should look nice and crisp. It's time to make our player move around. First, create script PlayerCat.cs
using UnityEngine;
 
public class PlayerCat : MonoBehaviour
{
    public float movementForce = 15;
 
    // References for various components to use later
    private SpriteRenderer sr;
    private Rigidbody2D rb;
 
    // Use this for initialization
    void Start()
    {
        // Find our components
        sr = GetComponent<SpriteRenderer>();
        rb = GetComponent<Rigidbody2D>();
    }
 
    // Update is called once per frame
    void Update()
    {
    }
 
    // FixedUpdate is called every Time.fixedDeltaTime
    void FixedUpdate()
    {
        // Get value of horizontal axis (left/right arrow or a/d keys),
        // returns value in range [-1.0f, 1.0f]
        var h = Input.GetAxis("Horizontal");
 
        // Flip sprite depending on horizontal input
        if (h < 0.0f)
            sr.flipX = true;
        if (h > 0.0f)
            sr.flipX = false;
 
        // Move player according to horizontal axis
        rb.AddForce(Vector2.right * h * movementForce, ForceMode2D.Force);
    }
}
Select our player GameObject (it's probably still called 'cat_idle_0') and change its name to something sensible, like 'cat'. Then, add 'Rigidbody 2D', 'Capsule Collider 2D' and our new PlayerCat.cs script to it. Make sure to set marked parameters accordingly, although feel free to experiment with them, especially with 'Linear Drag' and 'Movement Force'. If all went good, you should be able to move your character around with arrow or a/d keys. Currently, our cat just slides around instead of walking, let's make them walk. Prepare cat_walk animation in exactly the same way like you did with cat_idle, by slicing it and then dragging all frames into the scene, and calling new animation 'cat_walk'. You can delete 'cat_walk_0' GameObject from the scene and 'cat_walk_0' Animator from the assets afterwards, since these wont be needed. Now we have to add 'cat_walk' to our animator. If it's still called 'cat_idle_0', rename it to 'cat' and then double click on our animator to open Animator window. Add parameter 'Speed' of type float Drag 'cat_walk' animation into Animator to create new animation state and set it's Speed multiplier to our 'Speed' parameter. Now we need to tell Animator when to change from cat_idle state to cat_walk. Right click on 'cat_idle' select 'Make Transition' and click on the 'cat_walk' to make transition. With new transition selected, uncheck 'Has Exit Time', change 'Transition Duration' to 0, and add new condition, 'Speed > 0.01' to it. Now make opposite transition, just with condition 'Speed < 0.01'. Finally, lets modify PlayerCat.cs script to set Speed parameter in Animator according to character's horizontal velocity.
using UnityEngine;
 
public class PlayerCat : MonoBehaviour
{
    public float movementForce = 15;
 
    // References for various components to use later
    private SpriteRenderer sr;
    private Rigidbody2D rb;
    private Animator anim;
 
    // Use this for initialization
    void Start()
    {
        // Find our components
        sr = GetComponent<SpriteRenderer>();
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }
 
    // Update is called once per frame
    void Update()
    {
        // Set Speed parameter to absolute value of our horizontal speed
        anim.SetFloat("Speed"Mathf.Abs(rb.velocity.x));
    }
 
    // FixedUpdate is called every Time.fixedDeltaTime
    void FixedUpdate()
    {
        // Get value of horizontal axis (left/right arrow or a/d keys),
        // returns value in range [-1.0f, 1.0f]
        var h = Input.GetAxis("Horizontal");
 
        // Flip sprite depending on horizontal input
        if (h < 0.0f)
            sr.flipX = true;
        if (h > 0.0f)
            sr.flipX = false;
 
        // Move player according to horizontal axis
        rb.AddForce(Vector2.right * h * movementForce, ForceMode2D.Force);
    }
}
Congratulations, you now have animated 2D character. In next part, we will teach our cat how to jump :3