Thursday, January 18, 2018

Simple Side Scroller - A Unity Game

Guest Post from Siddhant Gupta

If you have always wanted to create your own game but felt intimidated by game development, this project is a great place to begin. In this tutorial we create a simple side-scrolling shooter in Unity using freely available assets and a few straightforward C# scripts.

By the end of this tutorial, you will have:
• A scrolling background
• A controllable aircraft
• Bullet firing mechanics
• Smooth acceleration and movement
• An understanding of Unity Prefabs and scripting basics

The best part is that every feature can be extended to create your own unique game.

This Simple Side Scroller is a game made from resources mentioned in the site at the end of this post. 
In this game, the player pilots a fighter plane through an endlessly scrolling world while firing bullets at enemies. The project demonstrates how a few simple ideas—scrolling backgrounds, object prefabs and player controls—combine to create an engaging arcade game. 
This is a description of the features of the resources:

Free plane sprite for your side scrolling shooter games

Features:
  • 1 Plane with 3 animations: fly, shoot, & dead
  • Simple background
  • Fully editable vector source files in SVG and AI file formats.
  • Separate PNG sequence files for quick integration in your game projects
Here is how you set up the background image:



You may consult YouTube videos on how to change background.
Create a big Background Quad and apply a texture to it like this.
Change the background sprite to repeat (default is clamp) and hit the Apply button. 
This will allow our background to scroll freely without any artifacts. You may not perceive it but our plane will be stationery and the background will move up and down.
Now click and drag the BG sprite/texture to the Quad, the quad will be UV wrapped by this texture now.
At first the texture will appear very dark, because it is a Standard Shader with an Albedo texture so it interacts with all the lights in the world, since this is a simple 2D game we wont be interacting with lights, so we have to change the texture to an Unlit shader which supports a texture.
Browse to the mesh Renderer of the Quad and click on the Shader Dropdown and select Unlit/Texture. Now u have a properly lit textured quad, doesn't Unity make such complex things so simple! 😃



It is always a good idea to rename our objects in the scene to something that makes sense , so we will rename our Quad to Background (name it to whatever u want).

Now Comes the Fun Part – Coding the Scrolling Background

So first lets make out background scroll to give the fake illusion of player moving
Create a new Script , called Scroller.cs.


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

public class Scroller : MonoBehaviour {
//Public field shows up in the inspector so it can be easily 
//tweaked even while the game is 
//running
public float scrollSpeed;
//Private fields dont show up in the inspector
private float scrollValue;
private MeshRenderer renderer;
// Use this for initialization
void Start () {
renderer = GetComponent<MeshRenderer>();
}
// Update is called once per frame

void Update () {
// Update the scroll value .....Time.deltaTime is used to make sure the 

// scrolling is independent of the fps the game is running on.
scrollValue += scrollSpeed*Time.deltaTime;
// UV values range from 0 - 1 so there is no point in exceeding the 
// value > 1 , so we reset the value back to 0 , in order to loop it.

if(scrollValue >= 1f)
{
scrollValue = 0f;
}
//Update the Main texture offset X value to make it scroll horizontally.
renderer.material.mainTextureOffset = new Vector2(scrollValue,0f);
}
}

````

Challenge yourself: Try changing the value of scrollSpeed and observe how the feel of the game changes. Small modifications like this are one of the best ways to learn Unity.

The idea of this script is to update the UV Offset of the Main Texture (Background texture) of the quad. This will allow us to scroll it in real time.

Time.Delta time is very important to make Your calculations independent of frames per second, I would suggest u too try this code without Time.deltaTime (Comment that out) and see
What happens?
(Spoiler : The scrollValue in Scroller.cs will take unpredictable jumps which will cause the bg to scroll unevenly.)

Q. What is Awake()?
A. Unity invokes the Awake method on all the gameObjects active in the scene when the scene starts.

Q. What is Start()?
A. After Awake, Start method is called, so these two methods can be used as constructors for our objects and classes, all the initial requirements of the code can be put here, like assigning references or grabbing the MeshRenderer component like we did in the Scroller.cs script, because before we can use the component in the code, we need a reference to it. The Mesh Renderer component can be grabbed in Awake() or Start() , it wont make a difference in this example as the first use of the renderer is in the update script.

Q What is Update()?
A This is the main method , which u will end up using a lot , basically Unity calls this method each frame, so all the code under this method will get Updated each frame. Anything that requires to be run/executed each frame should be done inside this method.

It has all the details u need to know about Unity's Script Execution order

Ok so we r done with bg scrolling now lets move on to the player movement and firing bullets
Before we move on to scripting, lets talk about Unity Prefabs.




Prefabs are a great way to change multiple instances of the same GameObject from only a single object called prefab. Imagine if u have 10 point lights in the scene now u want to change their color from say yellow to red, instead of clicking each and every light and changing its property, what u can do is drag and drop one point light from the scene to the asset folder(we have created a prefab folder under assets, I urge u to do the same, keeps our hierarchy clean) to create a prefab of that object, now u can drag this prefab and put it in the scene multiple times. So now say we have 10 Point lights in the scene which are clones of that prefab, but the good thing is now if u change the color of the prefab to red then all the clones of that prefab in the scene will also change to red color.
Isn't that amazing how Unity simplifies small things, that make a huge difference in the development process.
Here is a much better explanation of Prefabs than I could give, please refer to this link before proceeding from Here.
Prefabs are one of Unity's most powerful productivity features. Learn them early and they will save you countless hours as your projects become larger.

````
using System.Collections;

using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    public float accel = 0f;
    public float currentSpeed;
    public float targetSpeed;
    public float fireDelay = 0f;

    private float timeElapsed = 0f;
    public GameObject bulletPrefab;

    // Use this for initialization
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        //Detect Keyboard Input
        if (Input.GetKey(KeyCode.S))
        {
            targetSpeed = -5f;
        }
        else if (Input.GetKey(KeyCode.W))
        {
            targetSpeed = 5f;
        }
        else
        {
            targetSpeed = 0f;
        }

      //Lerp the CurrentSpeed towards the targetSpeed
        MoveToTargetSpeed();
        if (Input.GetKey(KeyCode.Space))
        {

/* ADD a delay between each time the player fires the bullet , so we dont spam the frame with multiple bullet objects , usually 0.1s dealy works good
but it all depends on ur game design and difficulty.This variable can also be used as an upgrade option , where the players can change their ships firing speed.*/
           
            timeElapsed += Time.deltaTime;
            if (timeElapsed >= fireDelay)
            {
                Fire();
                timeElapsed = 0f;
            }
        }
    }
    void MoveToTargetSpeed()

    {
        /* Increment or Decrement the currentSpeed value  */
   currentSpeed += accel * Time.deltaTime * Mathf.Sign(targetSpeed - currentSpeed);

/* This is where the bug happens but it is a nice feature to have so i kept this poor piece of logic */
        if (Mathf.Abs(Mathf.Abs(targetSpeed) - Mathf.Abs(currentSpeed)) < 0.01f)
        {
            currentSpeed = targetSpeed;
        }

/* Store the Next Position to update in temp var so that we can check if the player is reaching the bonds of the device's screen you dont want the player to go off the screen. Camera.main.WorldToScreenPoint is a helpful method to convert any Vector in world space to screen space. We need the player Coordinates in screen space so we can compare it to the device height and width which are pixel values  */


Vector3 nextPos = new Vector3(transform.position.x, transform.position.y + currentSpeed * Time.deltaTime, transform.position.z);
        if (Camera.main.WorldToScreenPoint(nextPos).y > Screen.height || Camera.main.WorldToScreenPoint(nextPos).y < 0f)
        {

/* if players next position is crossing the device's screen bounds then stop the movement and return to Update , this skips the actual position update we r doing in the last line of this method*/
            currentSpeed = 0f;
            targetSpeed = 0f;
return;
        }
// if everything is alright then update the player position.
         transform.position = nextPos;
    }

    void Fire()
    {

// Create a clone of the Bullet GameObject at the current player position and the // bullets 
// rotation should be the default prefab rotation.
        Instantiate(bulletPrefab, transform.position, Quaternion.identity);
    }
}
````

The above player script is pretty straightforward, check for inputs, set targetSpeed accordingly and lerp the current speed towards the target speed to get a feeling of acceleration.

The player script holds a reference to a prefab called BulletPrefab, so we can change and modify the bullets from one single object.

The script also allows the player ship to Fire after a delay of 0.1s. It is good to have a delay so as not to spam the frame with multiple bullets(that is just unrealistic and would probably lag out your system).
Now there is a fun part to this code, which I did not realize while writing, 
I produced a bug in the movement code but decided to keep it as a feature 😜. 

One of the most interesting things happened accidentally. A tiny imperfection in the movement logic caused the plane to drift slightly up and down. Instead of removing it immediately, I kept it because it gave the aircraft a subtle turbulence effect, making the movement feel more natural.

Sometimes, bugs become features!

If you notice the player ship keeps floating up and down randomly that's because the currentSpeed variable in the Player.cs never actually sets to 0, it will give a +- 1f fluctuation. It makes the player ship move more realistically cause no plane flies in a perfect straight line, winds cause the plane to have a little turbulence which is showed here by the random up and down movement, isn't that cool !!!

To make the bullets move when fired a simple Bullet.cs script is used

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

public class Bullet : MonoBehaviour
{
    public float speed;

    void Update()


    {
        transform.Translate(new Vector3(speed,0f,0f)*Time.deltaTime);
    }
}
````

Nothing much to explain here, when the bullets are instantiated by the player, the Update() method of the bullet script starts getting invoked which translates the bullet in forward direction. Refer to the code comments for better details.

Just a few lines of Code and we already have soo much going on.

Final Thoughts

This project shows that game development is not about writing thousands of lines of code. With a few sprites, a scrolling background, prefabs and simple scripts, you can already create a playable game.

If you are a student learning Unity, I encourage you to modify this project:

  • Add enemies

  • Add explosions and sound effects

  • Implement a score system

  • Introduce multiple levels

  • Design your own aircraft

Every successful game begins with a small experiment. This side scroller could be yours.


Sources:


No comments:

Post a Comment