I am participating in the nuggets Community Game Creativity Submission Contest. For details, please see: Game Creativity Submission Contest.

preface

It took three days to finish. I was thinking of writing the tutorial directly from the project I was working on; Writing writing found a lot of bad places to do, and then rearrange and modify. It’s just a whole new project. This article takes you step by step to complete the pixel bird game which can be made with zero foundation. Restore the classic gameplay, let’s try it

The final effect is consistent with the opening GIF, online play: address

After the completion of production can not only release web, but also release mobile oh ~

How’s that? Have a heart? Want to feel the sense of accomplishment of making your own? Let’s start the process


1. Create a directory

1.1 Create a directory after creating a project as shown in the following figure:

The created directories store the following resources:

  • Audios, Materials, Prefabs, Scenees, Scripts, textures

1.2 Import the audio and image resources prepared in advance and put them in the corresponding directory:

1.3 After import, change the image resource format used by UI to Sprite(2D and UI). Press Ctrl to select Gameover, Score and Start to modify the number of images, as shown below:

Then find and click the “Apply” button below:

The result is as follows:


Two, make material

2.1 Making material Balls (backgrounds, pipes and pixelbirds)

Right-click on the Materials file and select Create –> Material to Create a new Material ball:

Then change its name to bg and change its Shader to Unlit/Transparent:

Finally, assign it to the background image –> Click the Select button –> Double click the BG image in the popover to do it:

Then select the BG material ball and use the shortcut Ctrl+D to copy the three material balls:

Change their names and repeat the steps above to change them one by one to back, brid, tipe (don’t forget to re-specify the texture of the material ball). The result is as follows:


Third, scene construction

3.1 Modifying attributes of the Main Camera

  • Change its coordinates to (0,0,-2), rotate to (0,0,0), scale to (1,1,1)
  • Change it to Orthogonal camera (Projection –> Orthographic)

3.2 Changing the Size of the Game Click the resolution selection panel under Game view and click “+” at the bottom to create a new resolution. Set the property value as follows:

Then click on the Resolution palette again and select the property you just created:


Create a map

4.1 Creating a Background Right-click in the Hierarchy blank and choose 3D Object > Select Quad to create the background.

If it is not displayed in the Game view, change its Position coordinate to (0,0,0), change its Scale to (10,12,1), and finally assign the bg material ball we made before to Quad. The result is as follows:

4.2 Creating a Bottom

Select the background “Quad” created above, right-click on 3D Object –> Select Quad and create one, then assign the material sphere of back to it, resulting in the following image:

4.3 Arranging Positions

Rename the background “Quad” to BG and its child object to Back. Then change the Position coordinate of BG to (-4,-1,0) and make it appear at the left end, the effect is as follows:

4.4 Removing the Collider

Select BG, on the Inspector “Mesh Collider” Component, right-click and select “Remove Component” to Remove the Collider Component:

Similarly, select the Quad and remove the Mesh Collider component.


Five, make pipes

5.1 Copy Background covers the screen

Select Hierarchy –> BG and use shortcut key Ctrl+D to make a copy and adjust its coordinate to (6,-1,0). After adjustment, the effect is as follows:

5.2 Make a pipe

Create an empty object under the newly copied BG (1) named Pipe1 as the parent of the upper and lower tubes, set the coordinates, rotate to (0,0,0), scale to (1,1,1):

Then select Pipe1 and follow the steps above to create the Quad named Up and the material sphere named Tipe. Set its coordinates (0,0.7,0), rotate (0,0,0), scale (0.07,1,1);

Then select Up, Ctrl+D to copy it, change its coordinates to (0,-0.5,0), leave all other attributes unchanged, and the result is as follows:

5.3 Adjusting Positions

Now you can see that the pipe below is now exposed from the map. Adjust the z axis of the Back background to -1, so it looks like this:


Six, create the protagonist

6.1 Creating a Bird

Create a Quad again and name it Brid, set Position to (0,0,-1), and set the material sphere to Brid.

6.2 Setting the Brid Tag as Player:

6.3 Modifying material Sphere Properties

Offset(0.3333,1) and Tiling(0.3333,1) are modified as follows:

6.4 Let the birds fly

Create a BridHandler script and mount it to Brid.

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

public class BridHandler : MonoBehaviour {

    / / the singleton
    public static BridHandler intance;
    private void Awake()
    {
        intance = this; 
    }
    
    private Renderer _renderer;      / / material
    
    private float timer;        // Timer,
    private int frameNum =10;   // Displays several frames per second
    private int frameCount;     // Frame counter

	void Start () {
        _renderer = this.GetComponent<Renderer>();
    }
	
	// Update is called once per frame
	void Update () {
        timer += Time.deltaTime;  // Add a frame time
        if (timer >= 1.0 f / frameNum)  // It takes longer than 1 frame
        {
            frameCount++;   // The number of frames increases
            timer -= 1.0 f / frameNum;

            // three frames (0,1,2 display each frame)
            int frameIndex = frameCount % 3;

            // Update the offset x attribute
            _renderer.material.SetTextureOffset("_MainTex".new Vector2(0.33333 f * frameIndex, 0)); }}}Copy the code

After running, you can see the bird flying, the effect is as follows:


Seven, the bird moves

7.1 Add Rigidbody component on main character Brid:

Check all XZY’s constraints –> Freeze Rotation to prevent it from being rotated:

7.2 Adding the following script to the BridHandler script:


private Rigidbody _rigidbody;    // Rigid-body components
private float x = 3;             // Bird running speed

void Start () {
    _rigidbody = this.GetComponent<Rigidbody>();
    _rigidbody.useGravity = false;
}

void Update()
{
    if (Input.GetMouseButtonDown(0)) { StartGame(); }}public void StartGame()
{
     _rigidbody.useGravity = true;
     _rigidbody.velocity = new Vector3(x, 0.0);
}

Copy the code

7.3 Then run and click the blank, you can see the bird moving:

7.4 Error Handling If an error is reported after your project runs (it can be ignored if no error is reported)

To check the Convex property of the Brid Mesh Collider:

Add a Sphere Collider component

Adjust the radius of the collider to 0.28 and look at the Scene to keep it consistent with the outline of the bird:


Game state control

8.1 Creating a GameManager Script and mounting it to a Scenario

Add the following script content:

using UnityEngine;

public enum GAME_STATUS
{
    // Start the game
    GAME_START = 0./ / in the game
    GAME_PLAYING = 1.// Game over
    GAME_END = 2 
}

public class GameManager : MonoBehaviour {
    / / the singleton
    public static GameManager intance;
    private void Awake()
    {
        intance = this; 
    } 
    /// <summary>
    ///Current Game State
    /// </summary>
    public GAME_STATUS GameState = GAME_STATUS.GAME_START;    
    // The background needs to be moved
    public Transform moveBgTrans;

    void Start(){}void Update () {

        switch (GameState)
        {
            case GAME_STATUS.GAME_START: 
                // Tap the screen to start the game
                if (Input.GetMouseButtonDown(0))
                {
                    GameState = GAME_STATUS.GAME_PLAYING;
                    BridHandler.intance.StartGame();
                }
                break;
            case GAME_STATUS.GAME_PLAYING:
                break;
            case GAME_STATUS.GAME_END:
            
                break;
            default: break; }}}Copy the code

8.2 Right-click Hierarchy, create an empty GameObject, and change its name to GameManager.

8.3 Modify the bridhandler. cs Update method to add the game state control and birdie jump logic as follows:

void Update()
{
    if (GameManager.intance.GameState == GAME_STATUS.GAME_PLAYING) // Can jump state
    {
        Vector3 vel = _rigidbody.velocity;
        / / jump
        if (Input.GetMouseButtonDown(0))
        {
            vel.x += 0.05 f; // Increase speed a bit with each hop
            _rigidbody.velocity = new Vector3(vel.x, 5, vel.z);
            Debug.Log(vel);
        }
        
        // Whether to play this animation is controlled by the game state
        timer += Time.deltaTime; // Add a frame time
        if (timer >= 1.0 f / frameNum) // It takes longer than 1 frame
        {
            frameCount++; // The number of frames increases
            timer -= 1.0 f / frameNum;
            // three frames (0,1,2 display each frame)
            int frameIndex = frameCount % 3;
            // Update the offset x attribute
            _renderer.material.SetTextureOffset("_MainTex".new Vector2(0.33333 f * frameIndex, 0)); }}}Copy the code

8.4 Change the initial position of the bird to the upper left corner of (-2,1.8,-1):

8.5 Now run again, click the screen and the bird can jump:


Nine, the camera follows

9.1 Creating script FollowBrid and Attaching it to the camera:

using UnityEngine;

// The camera follows
public class FollowBrid : MonoBehaviour {

    private Transform bridTrans;

	// Use this for initialization
	void Start () {
        bridTrans = GameObject.FindGameObjectWithTag("Player").transform;
    }
	
	// Update is called once per frame
	void Update () {
        Vector3 bridPos = bridTrans.position;        
        float y = bridPos.y - 4.4 f;
        // Set the maximum and minimum camera positions
        if (y > 1.5 f)
        {
            y = 1.5 f;
        }
        if (y < 0 )
        {
            y = 0f;        
        }
        this.transform.position = new Vector3(bridPos.x + 3.63223 f,y, - 10); }}Copy the code

9.2 Operating results are as follows:


Ten, add collision detection

10.1 Add collision body to bottom:

Select Back and add the “Box Collider”. After adding it set its offset and size to (0,-0.36,0) and (1,0.28,2).

10.2 Pipe feeder collision body:

First select Up to remove its “Mesh Collider” component. Then add “Box Collider” and change the size to (1,1,2). Up (1) also do the above operation, so that both the upper and lower pipes have colliders, the effect is as follows:

10.3 Add game contact detection, create script PipUporDown, mount several game objects with collision bodies, so that the game can be triggered when the bird touches the pillar and bottom.

The script content is as follows:

public class PipUporDown : MonoBehaviour {

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.tag == "Player")
        {
            // Game overGameManager.intance.GameState = GAME_STATUS.GAME_END; }}}Copy the code

10.4 Add a Box Collider to the parent object and set its center to (0,0.1,0) and size to (0.1,0.2,2) between the two tubes. Check Is Trigger to Trigger cross score:

PS: Note that the collider size is (0.1,0.2,2).

10.5 Add pipeHeight random logic and score logic: create PipeHandler script and mount BG(1) –> Pipe1 to display random pipe height as follows:

using UnityEngine;

public class PipeHandler : MonoBehaviour {

    private void Start()
    {
        RandomPos();
    }

    /// <summary>
    ///Random number generation
    /// </summary>
    public void RandomPos()
    {
        float pos_y = Random.Range(0.1 f.0.1 f);
        this.transform.localPosition = new Vector3(this.transform.localPosition.x, pos_y, this.transform.localPosition.z);
    }

    // Pass trigger score:
    private void OnTriggerExit(Collider other)
    {
        if(other.tag == "Player")
        {
            Debug.Log("todo... Points"); }}}Copy the code

10.6 duplicate pipe Pipe1 and adjust its position to (0.5,0,0), so that there are two pipes in one map. This spacing is suitable for the difficulty of the game.


Eleventh, perfect the background

11.1 Processing background Continuous 1:

Select BG (1) and right-click to create an empty object rename it “MoveTrrgger”, adjust its position to (1.3,0,-1), and add the Box Collider component to (0.1,1,1). This will look like this:

11.2 Processing background continuous 2:

Create a MoveTrigger script and attach it to the MoveTrrgger object created in 10.4 with the following code:

using UnityEngine;

public class MoveTrigger : MonoBehaviour
{
    public Transform currentBg;

    public PipeHandler pipe1;
    public PipeHandler pipe2;

    private void OnTriggerExit(Collider other)
    {
        // debug.log (" trigger to background move ");
        if (other.tag == "Player")
        {
            // Move the front background to the back
            // Get the first background location
            Transform firstbg = GameManager.intance.moveBgTrans;
            / / move
            currentBg.position = new Vector3(firstbg.position.x + 10, currentBg.position.y, currentBg.position.z);
            / / updateGameManager.intance.moveBgTrans = currentBg; pipe1.RandomPos(); pipe2.RandomPos(); }}}Copy the code

11.3 Assign a value to the code as follows:

11.4 copy two copies of BG(1) and set BG(2) and BG(3) to (16,0,0) and (26,0,0) respectively. The effect is as follows:

11.5 Assign a Value to moveBgTrans in the GameManager

11.6 Running at this time can realize the background infinite connection:

So far the main logic of the game has been completed for the most part, but the UI and sound effects are still to be completed.


12. UI

12.1 Score Statistics

Right-click in the Hierarchy blank, create UI –> Text, and adjust its anchor point to the upper left corner. Change the Text size to (300,100) and font size:

42. The effect is as follows:

12.2 Game End

Create an Image under the Canvas as a game ending background, spread it all over the screen, change its opacity to 100 and rename it to “UIBG”:

Create an Image under “UIBG” and assign score to it:

Create two texts under “UIBG” to display the Score and the highest Score respectively named “Score” and “Best”. Adjust the position text as follows:

12.3 Restarting

Create a Button under “UIBG” as a restart Button, hide its child Text, assign Image to start, and position it as shown below:

12.4 Logical Processing

GameManager class, the complete code is as follows:

public class GameManager : MonoBehaviour {
    / / the singleton
    public static GameManager intance;
    private void Awake()
    {
        intance = this; 
    }
 
    /// <summary>
    ///Current Game State
    /// </summary>
    public GAME_STATUS GameState = GAME_STATUS.GAME_START;

    // The background needs to be moved
    public Transform moveBgTrans;
    
    / / score
    public Text ScoreText;
    
    // Game over UI
    public GameObject GameOverUI;
    // End of game score
    public Text GameOverScore;
    // Maximum score at end of game
    public Text GameOverBest;
    // Restart button when game is over
    public Button GameOverButton;
    
    // Score in the game
    int score = 0;

    void Start()
    {
        GameOverButton.onClick.AddListener(()=>{
            SceneManager.LoadScene(0);
        });
    }

    void Update () {

        switch (GameState)
        {
            case GAME_STATUS.GAME_START: 
                GameOverUI.SetActive(false);
                // Tap the screen to start the game
                if (Input.GetMouseButtonDown(0))
                {
                    GameState = GAME_STATUS.GAME_PLAYING;
                    BridHandler.intance.StartGame();
                }
                break;
            case GAME_STATUS.GAME_PLAYING:
                break;
            case GAME_STATUS.GAME_END:
                // Game over, display panel, maintain score
                GameOverUI.SetActive(true);
                GameOverScore.text = score.ToString();
                GameOverBest.text = PlayerPrefs.GetInt("Best").ToString();
                break;
            default: break; }}// Update the score
    public void UpdateScore()
    {
        // The score increases
        score++;
        ScoreText.text = "Score." + score;
        // Maintain the highest score
        if (score > PlayerPrefs.GetInt("Best"))
        {
            PlayerPrefs.SetInt("Best", score); }}}Copy the code

Assign to the GameManager public variable drag:

PipeHandler OnTriggerExit() :

private void OnTriggerExit(Collider other)
{
    if(other.tag == "Player") { GameManager.intance.UpdateScore(); }}Copy the code

12.5 Adding a Scenario

File –> Build Settings –> Add Open Scenes to prepare for packaging and replay logic:

Now that the main logic of the game is complete, there is only one last step to add sound effects.


Thirteen, add sound effects

13.1 Adding Background Music

Add the “Audio Source” component to the Main Camera

Assign the BGM sound to the AudioClip property and check the Loop property to play through the Loop:

13.2 Adding Jumping Sounds

Add the “Audio Source” component to Brid, assign sfX_jump to AudioClip, uncheck the Play On Awake attribute to avoid automatic playback:

Edit the BridHandler script and add the following three lines to the location below

// Declare jump sound
private AudioSource Jumpaudio; 
/ / assignment
Jumpaudio = this.GetComponent<AudioSource>();
/ / play
Jumpaudio.Play();
Copy the code

13.3 Adding scoring sounds

Add “Audio Source” component to Brid, assign sfX_Point sound to AudioClip property, uncheck Play On Awake property to avoid autoplay:

Edit the GameManager script and add the following three lines of code to the position shown below:

private AudioSource getSecoreAudio;
getSecoreAudio = GetComponent<AudioSource>();
getSecoreAudio.Play();
Copy the code

At this point, all the game logic is complete and you are ready to play


Fourthly, write at the end

Source code: address

Address of making:

Development environment Unity2019.4.19 (theoretically supports all versions).

Packaged platforms have been tested — Windows, Mac, Android,IOS, WebGL.

Online demo: Address


Although the text of the article is not much, but with illustrations and code has been explained in great detail. The article is very long, suggested collection. Original is not easy, three even support to go ~