Friday, December 12, 2014

How to make a game like Fez in Unity: Part 2


In the next step of our Fez game tutorial, we’ll begin by setting up our sprite based character.


Meet our 2D hero, Gato. I’ve provided the spritesheet for this little guy right here:




Save this spritesheet for your use
 

Add the image to your project and change the import settings. We need to tell Unity to consider this image as a sheet containing multiple sprites. Each sprite was designed to be 16x16 pixels, so we will enter 16 into the Pixels Per Unit field. Configure the settings like so:



 Click the Sprite Editor Button
 In the top-left select the Slice drop-down
 Make sure the type is set to Automatic




 Click Slice and Unity will identify the various sprites that make up our sheet
 Hit Apply and close the window



Unity will separate the spritesheet into individual sprites with an _x appended to the name


Create an empty GameObject and name it “Player”
Drag the FezSpriteSheet_0 sprite onto our GameObject and position it at (0,0,0)

 
 

Rename the FezSpriteSheet_0 GameObject to Sprite








Add the Animator component to the Sprite GameObject, unselect the box for Apply Root Motion
With the Sprite GameObject still selected, open the Animation Window





Select the double arrows box and create a New Clip
Name the clip “Idle”





Drag and drop the _0, _1 and _2 sprites onto the timeline
Now we will create a new clip and name it “Walk Right”
Drag and drop the _3, _4, _5 and _6 Sprites onto the timeline to look something like this:




Now repeat the same process and make a “Walk Left” animation using the _7 through _10 sprites
The next step is to setup the Animator that will control which animation is playing throughout our game. 

Add an Integer called “Horizontal”


 Make Transitions by right-clicking on Idle and connecting the white line to Walk Right and another to Walk Left

 We will disable the Atomic checkbox, when checked this will prevent transitioning to a different animation until the current animation ends which is unnecessary for what we’re doing. In the Conditions settings, you will need to click the double arrow button to select Horizontal. For the Walk Left Animation, it will need to be Equal to -1, for the Walk Right animation, it will need to Equal 1. Finally make a transition from the blue Any State box and connect it to our Idle animation state. Configure the Idle animation similar to the Walk Left and Walk Right, but with Horizontal Equals 0 instead.




Our movement script will change the Horizontal integer to change animations
 
 


Now if we hit Play, our cat Gato should be doing a little dance for us



A few problems arise here, it’s awfully dark for one and our cat appears to be floating off the ground.
We need to do a few more things before this Fez-like game is playable. Let’s start by adding some light!


Add a Directional Light to the scene, drag it onto our Player GameObject. Reset the Rotation to (0,0,0) and change the position to (0,0,-15) so that it’s not sitting right on our character. That takes care of the lighting, now we need to add some code to make our little guy move.


  
using UnityEngine;
using System.Collections;

public class FezMove : MonoBehaviour {

 private int Horizontal = 0;
    public Animator anim;
 public float MovementSpeed = 5f;
 public float Gravity = 1f;
 public CharacterController charController;
 public float JumpHeight = 0f;
 public bool _jumping = false;
 private float degree = 0;


 // Update is called once per frame
 void Update () {
  

  if (Input.GetAxis ("Horizontal") < 0)
   Horizontal = -1;
  else if (Input.GetAxis ("Horizontal") > 0)
   Horizontal = 1;
  else
   Horizontal = 0;

  if (Input.GetKeyDown (KeyCode.Space) && !_jumping) 
  {
   _jumping = true;
   StartCoroutine(JumpingWait());
  }

  if(anim)
  {
   anim.SetInteger("Horizontal", Horizontal);

   float moveFactor = MovementSpeed * Time.deltaTime * 10f;
   MoveCharacter(moveFactor);
   
  }


      transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, degree, 0), 8 * Time.deltaTime);
       
 }

 private void MoveCharacter(float moveFactor)
 {
  Vector3 trans = Vector3.zero;
        trans = new Vector3(Horizontal* moveFactor, -Gravity * moveFactor, 0f);
  
        if(_jumping)
        {
            transform.Translate( Vector3.up * JumpHeight * Time.deltaTime);
        }
  charController.SimpleMove (trans);
 }
 
 public IEnumerator JumpingWait()
 {
  yield return new WaitForSeconds (0.35f);
  _jumping = false;
 }
}




This script will monitor the A and D keys to control our Horizontal movement. By default Unity maps the Horizontal axis to the aforementioned keys. By checking these keys each frame, we can tell when the player inputs either key and adjust the Horizontal integer we created earlier. The Spacebar is monitored as well, each time it is pressed we set the _jumping flag and a co-routine is started. The co-routine will wait 0.35 seconds before returning the flag to false. This flag is used in the MoveCharacter function to move the character upward. A Character Controller is used to move the character in worldspace via the SimpleMove function.

Add the FezMove script and a Character Controller component to our Player GameObject. Drag the Sprite GameObject into the Anim field of the FezMove script and attach the Character Controller to the Char Controller field. You can play with the values of the Movement Speed, Gravity and Jump Height to change the way the character moves. You will need to change the Height of the Character Controller component to 1 with a radius of 0.5.

 

These are the values I chose, you can adjust these as you see fit



Now that we can move around in 2D, we’ve got a few more tweaks to make to improve the graphics of our game. First, let’s update the camera. Until now we’ve been using the default Perspective view which is fine for 3D games, but not desirable for 2D. Change the Projection to Orthographic which will render all depths at the same point on the screen. This will allow us to have multiple Z depths for our platforms, but allow them to appear at the same distance. You can also change the Size or move the Y position of the camera to improve our view. We also need our Camera to follow the player as they move on screen, to do this simply drag the Camera onto the Player GameObject. Since we have no background image, let’s use one of Unity’s Skyboxes to do the work or us.




Right-click the Assets Folder, navigate to Import Package and then Skyboxes. Unity will do its thing and bring in some assets for us. 

At the top menu, select Edit and choose Render Settings. Drag one of our new skyboxes onto the Skybox Material field



Now that our Skybox is in place, we can fix a few more little details. My cat is still floating off the ground, if you’ve got the same problem, you may need to position him so his feet touch the ground.



To do this, select the Sprite GameObject in your scene and lower the Y position till his feet touch.


Things are starting to shape up, we’ve built a simple 2D platformer! However, there’s still a problem if we fall off our platform. Currently, we will fall infinitely. To remedy this we will make a simple script to catch our fallen player and return them to the first platform.



  
using UnityEngine;
using System.Collections;

public class ReturnPlayer : MonoBehaviour {
 
 public Transform ReturnPoint;
 

 public void OnTriggerEnter(Collider other)
 {

  other.transform.position = ReturnPoint.position;
  
 }
}


This script requires a collider with the IsTrigger option selected. When another object collides with one that has this script, the other object will be moved to the ReturnPoint.



Add a Plane to your scene and position it below your level. Remove the Mesh Collider Component and add a Box Collider. Select the Is Trigger option on the box collider. Add the ReturnPlayer script to the plane. Lastly we need to create an empty GameObject to tell our script where to return Gato if he should fall to his death.  Position one in your level like below and drag it onto the ReturnPlayer script.



You may need to reposition the return object if Gato is not returned correctly




That’s all for now! Next time we will add Fez-like 3D rotation and wrap up this project.

On to Part 3

No comments:

Post a Comment