Player GameObject

2D Sprite as Player

To create a player character, we need to create a gameObject => 2D Sprite. Then, we can set the sprite-Renderer component to refer to an image that we've added to our project assets folder. To import an image as a 2D sprite, you select the image in the assets panel and set the component: texture-type set to *Sprite(2D - UI).

Moving GameObjects: RigidBody2D

Then we need to attach a RigidBody2D component to our Girl-player gameObject. The Unity Manual explains that we need to add a RigidBody2D component so that we can use the Unity Physics Engine to move our Girl-player in the scene. We can update the player's RigidBody.velocity or add a force to the RigidBody2D each frame in response to the user key-presses, to cause the gameObject to move in a realistic way.

Custom Sorting Layers

We need to define sorting layers for our sprites, this will allow us to define the ordering that sprites will be rendered in, where items with a higher order in the sorting layer list being rendered prior to sprites from a sorting layer lower in the list. Sprites rendered first appear behind sprites that are rendered later in the order. First we need to select the layer dropdown tab from the top of the inspector panel and then we choose to add new layers. We select to add new sorting layers, we create a Background and a Foreground sorting layer. The ordering of the layers in this list defines the ordering of layers in our scene. Then for each GameObject that we assign with Sorting Layer Background those objects will be behind the GameObjects that have been assigned to the Foreground Layer. We can define additional layers, and we can change the layer ordering dynamically using C# scripts. (We don't do that in this project) In addition, the Z transform value for an object can also determine sprite visibility layering for objects on the same sorting layer. The Main Camera has a transform position vector of (0,0,-10) by default. This means that to move objects closer to the camera, can give them a Z transform value that is between 0 and -10.

RigidBody2D

In the PlayerMove code below, we write code to allow the user to move the player using various input methods. We're using the UnityEngine Input default mappings so we want to provide access to move the player along the horizontal and vertical axis. We need to use a RigidBody2D component because it allows us to use UnityEngine physics engine to create realistic character movement.

Unity RigidBody Documentation Rigidbodies enable your GameObjects to act under the control of physics. The Rigidbody can receive forces and torque to make your objects move in a realistic way. Rigidbody 2D, the difference that in 2D, objects can only move in the XY plane and can only rotate on an axis perpendicular to that plane. Remember to set gravity to 0 if you don't want it to impact your objects.

2D-Colliders

Collider interactions Colliders interact with each other differently depending on how the Collider and Rigidbody components are configured. Collider Components define the shape of an object for the purposes of physical collisions. A collider, which is invisible, does not have to be the exact same shape as the object’s mesh. A GameObject that has a Collider but no RigidBody component will act like an immovable object that other objects can run into, the collider gives the gameObject a physical presence in the scene. When isTrigger is selected, then the collider does not show physics-based collision behavior, instead, an event is generated that can be used to execute related actions or behaviors.

Constrain Player Movement using Box Collider to create a Floor

If we want to constrain the player, to keep her on the screen, we can create an empty game object and attach a collider2D component to that gameObject. We can use this to create a floor in our scene, this will allow us to have a non-zero value for gravity on our player's Rigidbody2D component. We can also create a leftBorder as an empty gameObject, again, add a BoxCollider2D component. If we don't set this gameObject to be a trigger, then it will act as a physical barrier to our playerGame object so it can't leave the camera view area.

PlayerController.cs Code:

  • Includes Animator Component Logic

  • Reminder: PickUp objects must have Tags:

    • PickUp items must have Tags set to match logic in PlayerController.cs: Collectible, Hazard

The code in the PlayerController.cs file is responsible for checking for user-input, determining if the input should cause the player-gameObject to move, and for determining actions or game-logic to be executed if the player-gameObject collides with other gameObjects.

PlayerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public enum HeroState { idle, walk, jump  }  //create custom data-type - have integer values

    public HeroState currentHeroState;  //will display the current enum 

    private Animator animator;  //- null - reference variable to access animator component

    public bool facingRight;  //keep track of sprite direction - used in Flip
    private Rigidbody2D myRBody2D;
    public float forceX; //used for adjusting velocity

    public Transform groundCheck; //transform component on GroundCheck object
    public LayerMask groundLayer; //allows us to interact with a physics Layer 
    public float groundCheckRadius ;  //
    public float jumpForce;
    public bool grounded = false;  //will let us see if the gameOjb is grounded

    // Start is called before the first frame update
    void Start()
    {
        currentHeroState = HeroState.idle;    //initialize to show it's in idle to start
        animator = GetComponent<Animator>();//is on the same game object as this script
        animator.SetInteger("HeroState", (int)HeroState.idle);  //send in the signal: 0
        facingRight = true;
        myRBody2D = GetComponent<Rigidbody2D>();
        forceX = 100.0f;  //force value may need adjusted

        groundCheckRadius = 0.2f; //may need modified
        jumpForce = 10f; //may need modified


    }

    // Update is called once per frame
    void FixedUpdate()  //physics methods executed - want consistant time between frames
    {
        float inputX = Input.GetAxis("Horizontal");  //values of -1, 0 , 1 
        bool isWalking = Mathf.Abs(inputX) > 0;

        if (isWalking)
        {
            //check for flipping
            if( inputX > 0 && !facingRight)  //moving right, facing left
            {
                Flip(); //flip right
            }else if( inputX <0 && facingRight) //moving left, facing right
            {
                Flip(); //flip left
            }
            animator.SetInteger("HeroState", (int)HeroState.walk);
            myRBody2D.velocity = new Vector2( 0, myRBody2D.velocity.y);  //reset the velocity to 0 //may come back and change
            myRBody2D.AddForce(new Vector2(inputX * forceX, 0)); //add horizontal force to move the player
        }
        else
        {
            animator.SetInteger("HeroState", (int)HeroState.idle);
        }

        bool jumpPressed = Input.GetButtonDown("Jump");   //is spacebar pressed
        grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);

        if (jumpPressed  && grounded)
        {
            animator.SetInteger("HeroState", (int)HeroState.jump);
            Debug.Log("Jumping");

            ///Vertical Force for Movement
            myRBody2D.velocity = new Vector2(myRBody2D.velocity.x, 0);  //reset the velocity to 0 //keep horizontal movement
            myRBody2D.AddForce(new Vector2(0,jumpForce),ForceMode2D.Impulse); //add horizontal force to move the player

        }

    }//end FixedUpdate

    //we have determined it is facing the wrong direction, it must need flipped for this to be executed
    private void Flip()
    {
        facingRight = !facingRight; //toggle direction variable
        //get Scale Vector
        Vector3 theScale = transform.localScale;  //get the current values for Scale Vector
        theScale.x *= -1; //modify the X component    //mirror the sprite
        transform.localScale = theScale; //set the actual Scale vector with our temp Vector
    }

    /// <summary>
    /// This is the start of the Event-Chain for Game Score, health to be changed
    /// </summary>
    /// <param name="collision">Collision.</param>
    private void OnTriggerEnter2D(Collider2D collision)
    {

        //check tag on gameObject that has this collider on it
        if (collision.CompareTag("Collectible"))
        {
            //get the PickUp component from the gameObject with this collider on it
            PickUp item = collision.GetComponent<PickUp>();
            Debug.Log("collided with a collectible of value: " +   item.Value);

            GameData.instanceRef.Add(item.Value);
            Destroy(collision.gameObject); //destroy GameObject of the object we collided with
        } 
        else if (collision.CompareTag("Hazard"))
        {
            PickUp item = collision.GetComponent<PickUp>();
            Debug.Log("collided with a hazard of value: " + item.Value);
            //update gameData database

            GameData.instanceRef.TakeDamage(item.Value);
            Destroy(collision.gameObject); //destroy GameObject of the object we collided with

        }
    }



}///end of Class

Last updated