• 📢 Blog homepage: juejin.cn/user/139024…
  • 📢 Welcome to like 👍 collect ⭐ message 📝 if there is any error please correct!
  • 📢 this article is written by silly knock code of small Y original 🙉
  • 📢 The future is long and worth all we can for a better life ✨

🎉 bomb people

📢 preface

“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

  • This blog post is about a simple bomberman game that will bring back your childhood memories
  • Project source code at the end of the article, interested in can download try to play, can also try to make their own play oh ~
  • Everyone must have played this game when I was a child, bomb person is also a classic in the classic 🤪~
  • Hope to see this little game, can let you pick up childhood with friends together to play games in front of the big ass TV good time 😁!
  • Time is slowly passing, those who accompany you through childhood friends how long have no contact 😃~
  • After reading this bomb person, have time to find their own childhood friends chat, together to find childhood memories and dreams 😊!

Return to the theme, bomb small game production began!


🎁 body

Take a look at the bomb man small game effect!


💫 Production Ideas

As usual, before we do this let’s go through the whole idea of how to do this little game let’s go through our heads and think about a bomb man little game what are the things in it

  • The first step is to have a game scene. This scene is where we can see the game running

  • There will be many walls in this scene, and there will be a game edge wall around it, which can’t be destroyed by our bombs. Call it a super wall!

  • There will also be some walls in the scene, which can be destroyed and we become normal walls

  • Some are fixed, some can be destroyed, this is a classic bomber gameplay!

  • Second, we have to have a protagonist, our bomber!

  • Our hero can move up, down, left, or right, and then he can “lay an egg,” which is to set a bomb, to blow up the enemy

  • And then you have to have health and so on

  • Of course, there were enemies. We added an enemy to the scene that could move from side to side at random, and would bleed us when it touched us

  • This is also one of the most classic and basic gameplay

At first glance, it seems that it is only so much, and it is not very difficult

So let’s start to operate now!


🌟 Start production

  • Import the material resource bundle
  • After import, the engineering resources look like this

There are some Sprite images for us to use as protagonists, enemies and walls

There are also a few simple sound and animation effects to support the logistics of our game!


Step 1: Create the game scene

  • We are a 2D game, and in the game scene here, the map is made of Sprite pictures

  • Let’s write a script here and have it generate the map when the game is running

  • The ObjectPool script is used to get all the resources in the project, and then generated from the ObjectPool into the scene when needed

  • I won’t go into object pooling here, but there are many ways to do it

  • Here is a reference that can be hung directly into the scene and used

The code:


public enum ObjectType
{
    SuperWall,
    Wall,
    Prop,
    Bomb,
    Enemy,
    BombEffect
}
[System.Serializable]
public class Type_Prefab
{
    public ObjectType type;
    public GameObject prefab;
}

public class ObjectPool : MonoBehaviour
{
    public static ObjectPool Instance;
    public List<Type_Prefab> type_Prefabs = new List<Type_Prefab>();
    /// <summary>
    ///Gets the prefab by object type
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private GameObject GetPreByType(ObjectType type)
    {
        foreach (var item in type_Prefabs)
        {
            if (item.type == type)
                return item.prefab;
        }
        return null;
    }
    /// <summary>
    ///Object types and their corresponding object pool relationship dictionaries
    /// </summary>
    private Dictionary<ObjectType, List<GameObject>> dic =
        new Dictionary<ObjectType, List<GameObject>>();

    private void Awake()
    {
        Instance = this;
    }
    /// <summary>
    ///Gets something from the corresponding pool of objects by object type
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public GameObject Get(ObjectType type, Vector2 pos)
    {
        GameObject temp = null;
        // Check whether there is a pool of objects matching the type in the dictionary
        if (dic.ContainsKey(type) == false)
            dic.Add(type, new List<GameObject>());
        // Check whether there are objects in the pool of objects of this type
        if (dic[type].Count > 0)
        {
            int index = dic[type].Count - 1;
            temp = dic[type][index];
            dic[type].RemoveAt(index);
        }
        else
        {
            GameObject pre = GetPreByType(type);
            if(pre ! =null)
            {
                temp = Instantiate(pre, transform);
            }
        }
        temp.SetActive(true);
        temp.transform.position = pos;
        temp.transform.rotation = Quaternion.identity;
        return temp;
    }

    /// <summary>
    ///recycling
    /// </summary>
    /// <param name="type"></param>
    public void Add(ObjectType type, GameObject go)
    {
        // Check whether there is an object pool for this type and whether the object does not exist in the pool
        if (dic.ContainsKey(type) && dic[type].Contains(go) == false)
        {
            // Put into the object pool
            dic[type].Add(go);
        }
        go.SetActive(false); }}Copy the code
  • With this simple pool of objects in place, let’s write a script called MapController to generate some walls in the scene
  • Two two-dimensional vector lists are used to generate the normal wall and the super wall

We need to Tag the prefab with different tags to distinguish their respective attributes

Add all of the following preforms, only the walls need to be added with a layer, which will be used when the monster moves randomly, the rest of the preforms need to be added with a Tag

The code:

public class MapController : MonoBehaviour
{
    public GameObject doorPre;
    public int X, Y;
    private List<Vector2> nullPointsList = new List<Vector2>();
    private List<Vector2> superWallPointList = new List<Vector2>();
    private GameObject door;
    // represents the collection of all objects taken from the object pool
    private Dictionary<ObjectType, List<GameObject>> poolObjectDic =
        new Dictionary<ObjectType, List<GameObject>>();

    /// <summary>
    ///Determine if the current location is a solid wall
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public bool IsSuperWall(Vector2 pos)
    {
        if (superWallPointList.Contains(pos))
            return true;
        return false;
    }

    public Vector2 GetPlayerPos()
    {
        return new Vector2(-(X + 1), (Y - 1));
    }
    private void Recovery()
    {
        nullPointsList.Clear();
        superWallPointList.Clear();
        foreach (var item in poolObjectDic)
        {
            foreach (var obj in item.Value)
            {
                ObjectPool.Instance.Add(item.Key, obj);
            }
        }
        poolObjectDic.Clear();
    }
    public void InitMap(int x, int y, int wallCount, int enemyCount)
    {
        Recovery();
        X = x;
        Y = y;
        CreateSuperWall();
        FindNullPoints();
        CreateWall(wallCount);
        CreateDoor();
        CreateProps();
        CreateEnemy(enemyCount);
    }

    /// <summary>
    ///Generate solid walls
    /// </summary>
    private void CreateSuperWall()
    {
        for (int x = -X; x < X; x+=2)
        {
            for (int y = -Y; y < Y; y+=2)
            {
                SpawnSuperWall(newVector2(x, y)); }}for (int x = -(X + 2); x <= X; x++)
        {
            SpawnSuperWall(new Vector2(x, Y));
            SpawnSuperWall(new Vector2(x, -(Y + 2)));
        }

        for (int y = -(Y + 1); y <= Y- 1; y++)
        {
            SpawnSuperWall(new Vector2(-(X + 2), y));
            SpawnSuperWall(newVector2(X, y)); }}private void SpawnSuperWall(Vector2 pos)
    {
        superWallPointList.Add(pos);
        GameObject superWall = ObjectPool.Instance.Get(ObjectType.SuperWall, pos);
        if (poolObjectDic.ContainsKey(ObjectType.SuperWall) == false)
            poolObjectDic.Add(ObjectType.SuperWall, new List<GameObject>());
       poolObjectDic[ObjectType.SuperWall].Add(superWall);
    }
    /// <summary>
    ///Find all the empty points on the map
    /// </summary>
    private void FindNullPoints()
    {  
        for (int x = -(X + 1); x <= (X - 1); x++)
        {
            if (-(X + 1) % 2 == x % 2)
                for (int y = -(Y + 1); y <= (Y - 1); y++)
                {
                    nullPointsList.Add(new Vector2(x, y));
                }
            else
                for (int y = -(Y + 1); y <= (Y - 1); y += 2)
                {
                    nullPointsList.Add(new Vector2(x, y));
                }
        }

        nullPointsList.Remove(new Vector2(-(X + 1), (Y - 1)));  // Leave the first position in the upper left corner empty and use it to generate the bomb-maker.
        nullPointsList.Remove(new Vector2(-(X + 1), (Y - 2)));  // The upper left corner of the first position below the position, to ensure that the bomber can not be killed himself
        nullPointsList.Remove(new Vector2(-X, (Y - 1)));  // The first position in the upper left corner is the position on the right to ensure that the bomber can get out without being killed by himself
    }
    /// <summary>
    ///Create walls that can be destroyed
    /// </summary>
    private void CreateWall(int wallCount)
    {
        if (wallCount >= nullPointsList.Count)
            wallCount = (int)(nullPointsList.Count * 0.7 f);
        for (int i = 0; i < wallCount; i++)
        {
            int index = Random.Range(0, nullPointsList.Count);
            GameObject wall = ObjectPool.Instance.Get(ObjectType.Wall, nullPointsList[index]);
            nullPointsList.RemoveAt(index);

            if (poolObjectDic.ContainsKey(ObjectType.Wall) == false)
                poolObjectDic.Add(ObjectType.Wall, newList<GameObject>()); poolObjectDic[ObjectType.Wall].Add(wall); }}private void CreateProps()
    {
        int count = Random.Range(0.2 + (int)(nullPointsList.Count * 0.05 f));
        for (int i = 0; i < count; i++)
        {
            int index = Random.Range(0, nullPointsList.Count);
            GameObject prop = ObjectPool.Instance.Get(ObjectType.Prop, nullPointsList[index]);
            nullPointsList.RemoveAt(index);

            if (poolObjectDic.ContainsKey(ObjectType.Prop) == false)
                poolObjectDic.Add(ObjectType.Prop, newList<GameObject>()); poolObjectDic[ObjectType.Prop].Add(prop); }}}Copy the code
  • In this script, we generate the wall by using a two-dimensional vector list, and determine whether there is an object in the current position before generating it

  • Once the map is initialized, the list is cleared before any other operations are performed

  • Then we create a new GameController object and mount the GameController script

  • This script is the game controller we’ll need later, but for now we’ll just let it generate the game map

The code:

    /// <summary>
    ///Level controller
    /// </summary>
    private void LevelCtrl()
    {
        time = levelCount * 50 + 130;
        int x = 6 + 2 * (levelCount / 3);
        int y = 3 + 2 * (levelCount / 3);  // Add 2 for every 3 levels
        if (x > 18)
            x = 18;
        if (y > 15)
            y = 15;

        enemyCount = (int)(levelCount * 1.5 f) + 1;
        if (enemyCount > 40)
            enemyCount = 40;
        mapController.InitMap(x, y, x * y, enemyCount);
        if (player == null)
        {
            player = Instantiate(playerPre);
            playerCtrl = player.GetComponent<PlayerCtrl>();
            playerCtrl.Init(1.3.2);
        }
        playerCtrl.ResetPlayer();
        player.transform.position = mapController.GetPlayerPos();

        // Recover the explosion effects left in the scene
        GameObject[] effects = GameObject.FindGameObjectsWithTag(Tags.BombEffect);
        foreach (var item in effects)
        {
            ObjectPool.Instance.Add(ObjectType.BombEffect, item);
        }
        
        Camera.main.GetComponent<CameraFollow>().Init(player.transform, x, y);
        levelCount++;
        UIController.Instance.PlayLevelFade(levelCount);
    }

    public bool IsSuperWall(Vector2 pos)
    {
        return mapController.IsSuperWall(pos);
    }
Copy the code
  • This is what a simple map looks like after random generation


Step 2: Wall code

  • We just generated the wall in the map in the last step,
  • Each of these game objects has to have a script attached to them to make them do their job
  • Because these walls do different things!

For example, the script Wall code on a normal Wall:

public class Wall : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.CompareTag(Tags.BombEffect)) { ObjectPool.Instance.Add(ObjectType.Wall, gameObject); }}}Copy the code
  • The script on Door is a little special, because it starts as a wall, and after we blow it up with a bomb, it will become a Door leading to the next level
  • This is also the classic bomb play!

Look at the Door script code!

    public Sprite doorSprite,defaultSp;
    private SpriteRenderer spriteRenderer;
    private void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        defaultSp = spriteRenderer.sprite;
    }
    public void ResetDoor()
    {
        tag = "Wall";
        gameObject.layer = 8;
        spriteRenderer.sprite = defaultSp;
        GetComponent<Collider2D>().isTrigger = false;
    }
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag(Tags.BombEffect))
        {
            tag = "Untagged";
            gameObject.layer = 0;
            spriteRenderer.sprite = doorSprite;
            GetComponent<Collider2D>().isTrigger = true;
        }
        if (collision.CompareTag(Tags.Player))
        {
            // Determine if all enemies in the current scene are destroyedGameController.Instance.LoadNextLevel(); }}Copy the code

Step 3: Bomb-making

  • After making the map above, we have a scene that can play

  • Then, of course, the next step is to add the protagonist bomber!

  • Although our bomber is just a “paper man”, but does not affect us to drop bombs to blow up the enemy haha ~

  • The bomber in this game is automatically generated through the game controller, we need to mount a script on the character, let him control the movement of the bomber and the method of dropping the bomb

On the script PlayerCtrl code


    /// <summary>
    ///Mobile method
    /// </summary>
    private void Move()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        anim.SetFloat("Horizontal", h);
        anim.SetFloat("Vertical", v);
        rig.MovePosition(transform.position + new Vector3(h, v) * speed);
    }

    private void CreateBomb()
    {
        if (Input.GetKeyDown(KeyCode.Space) && bombCount > 0)
        {
            AudioController.Instance.PlayFire();
            bombCount--;
            GameObject bomb = ObjectPool.Instance.Get(ObjectType.Bomb,
                newVector3(Mathf.RoundToInt(transform.position.x), Mathf.RoundToInt(transform.position.y))); bomb.GetComponent<Bomb>().Init(range, bombBoomTime, () => { bombCount++; bombList.Remove(bomb); }); bombList.Add(bomb); }}Copy the code

The bomber also has an animation controller that plays different animations as he moves up, down, left and right

Resource pack animation segment all have, we set up on good, very simple animation segment execution

Animation segment switching effect:

Simple movement in a scene:

There is also a method code to play the animation when the character dies

    /// <summary>
    ///Play end animation
    /// </summary>
    public void PlayDieAnim()
    {
        Time.timeScale = 0;
        anim.SetTrigger("Die");
    }
    /// <summary>
    ///End The animation is finished
    /// </summary>
    private void DieAnimFinish()
    {
        GameController.Instance.GameOver();
    }
Copy the code

Death animation effects:


Step 4: Bomb disposal

  • Now we have the bomber, and we have the prefabricated bomb, which is the picture of the genie
  • And now we need to mount the script to make the bombs explode in all directions!

There is a script Bomb on the Bomb, Init is called in PlayerCtrl when the bomber drops a Bomb! The DealyBoom method in the script is used to deal with the explosive range around the parade after being dropped by our bomber

Then there is a prefab after the bomb explodes, and we need to mount a script on it to perform an explosion effect after the bomb explodes!

Script Bomb and BombEffect:

public class Bomb : MonoBehaviour
{
    private int range;
    private Action aniFinAction;
    public void Init(int range, float dealyTime, Action action)
    {
        this.range = range;
        StartCoroutine("DealyBoom", dealyTime);
        aniFinAction = action;
    }
    IEnumerator DealyBoom(float time)
    {
        yield return new WaitForSeconds(time);
        if(aniFinAction ! =null)
            aniFinAction();
        AudioController.Instance.PlayBoom();
        ObjectPool.Instance.Get(ObjectType.BombEffect, transform.position);
        Boom(Vector2.left);
        Boom(Vector2.right);
        Boom(Vector2.down);
        Boom(Vector2.up);
        ObjectPool.Instance.Add(ObjectType.Bomb, gameObject);
    }
    private void Boom(Vector2 dir)
    {
        for (int i = 1; i <= range; i++)
        {
            Vector2 pos = (Vector2)transform.position + dir * i;
            if (GameController.Instance.IsSuperWall(pos))
                break; ObjectPool.Instance.Get(ObjectType.BombEffect, pos); }}}Copy the code
public class BombEffect : MonoBehaviour
{
    private Animator anim;
    private void Awake()
    {
        anim = GetComponent<Animator>();
    }
    private void Update()
    {
        AnimatorStateInfo info = anim.GetCurrentAnimatorStateInfo(0);
        if (info.normalizedTime >= 1 && info.IsName("BombEffect")) { ObjectPool.Instance.Add(ObjectType.BombEffect, gameObject); }}}Copy the code

Step 5: Make enemies

  • Now that you have the scene and the main character, you need to create enemies
  • We included the enemy generation in the script that controlled the wall generation, because the enemy is also a moving wall
  • We just gave him different materials, made him more special than the wall
  • So we’ve added a new method to MapController to generate enemies

Generating enemy code

    private void CreateEnemy(int count)
    {
        for (int i = 0; i < count; i++)
        {
            int index = Random.Range(0, nullPointsList.Count);
            GameObject enemy = ObjectPool.Instance.Get(ObjectType.Enemy, nullPointsList[index]);
            enemy.GetComponent<EnemyAI>().Init();
            nullPointsList.RemoveAt(index);

            if (poolObjectDic.ContainsKey(ObjectType.Enemy) == false)
                poolObjectDic.Add(ObjectType.Enemy, newList<GameObject>()); poolObjectDic[ObjectType.Enemy].Add(enemy); }}Copy the code
  • Then after the enemy generation can also be free to move, and then look for our bomber, as long as the encounter our bomber, bomber will be hurt

  • There’s a lot of detail to pay attention to here, but first we need to get him to move up, down, left and right randomly

  • Movement is determined by radiographic detection. Here, we set the layer of the wall in the scene to 8 layers

  • Then when the monster detects, it only detects the eighth layer of objects to determine whether it can move in that direction

  • Also dealt with is the fact that enemies will change their colors when they encounter the Bomber and their kind, which creates a simple visual interaction

The script EnemyAI script code

public class EnemyAI : MonoBehaviour
{
    private float speed = 0.04 f;
    private Rigidbody2D rig;
    private SpriteRenderer spriteRenderer;
    private Color color;
    /// <summary>
    ///Direction: 0 up 1 down 2 left 3 right
    /// </summary>
    private int dirId = 0;
    private Vector2 dirVector;
    private float rayDistance = 0.7 f;
    private bool canMove = true;  // Whether it can be moved

    private void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        color = spriteRenderer.color;
        rig = GetComponent<Rigidbody2D>();    
    }
    /// <summary>
    ///Initialization method
    /// </summary>
    public void Init()
    {
        color.a = 1;  // When an enemy passes through and leaves, it restores its original color
        spriteRenderer.color = color;
        canMove = true;
        InitDir(Random.Range(0.4));
    }

    /// <summary>
    ///Initialize the enemy direction
    /// </summary>
    /// <param name="dir"></param>
    private void InitDir(int dir)
    {
        dirId = dir;
        switch (dirId)
        {
            case 0:
                dirVector = Vector2.up;
                break;
            case 1:
                dirVector = Vector2.down;
                break;
            case 2:
                dirVector = Vector2.left;
                break;
            case 3:
                dirVector = Vector2.right;
                break;
            default:
                break; }}private void Update()
    {
        if (canMove)
            rig.MovePosition((Vector2)transform.position + dirVector * speed);
        else
            ChangeDir();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        // Destroy the enemy
        if(collision.CompareTag(Tags.BombEffect) && gameObject.activeSelf)
        {
            GameController.Instance.enemyCount--;
            ObjectPool.Instance.Add(ObjectType.Enemy, gameObject);
        }
        if (collision.CompareTag(Tags.Enemy))
        {
            color.a = 0.3 f;  // When enemies pass through each other, change their color to translucent
            spriteRenderer.color = color;
        }
        if (collision.CompareTag(Tags.SuperWall) || collision.CompareTag(Tags.Wall))
        {
            / / reset
            transform.position = new Vector2(Mathf.RoundToInt(transform.position.x),
                Mathf.RoundToInt(transform.position.y));  / / RoundToInt integerChangeDir(); }}private void OnTriggerStay2D(Collider2D collision)
    {
        if (collision.CompareTag(Tags.Enemy))
        {
            color.a = 0.3 f;  // Change its color to translucent when enemies are in a blockspriteRenderer.color = color; }}private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.CompareTag(Tags.Enemy))
        {
            color.a = 1;  // When an enemy passes through and leaves, it restores its original colorspriteRenderer.color = color; }}private void ChangeDir()
    {
        List<int> dirList = new List<int> ();if (Physics2D.Raycast(transform.position, Vector2.up, rayDistance, 1 << 8) = =false)
        //1 moves 8 to the left, indicating that only Layer 8 is detected (add Layer). If 0 << 8, layer 8 is ignored
        {
            dirList.Add(0);  // Move upward if no object is detected above
        }
        if (Physics2D.Raycast(transform.position, Vector2.down, rayDistance, 1 << 8) = =false)
        {
            dirList.Add(1);
        }
        if (Physics2D.Raycast(transform.position, Vector2.left, rayDistance, 1 << 8) = =false)
        {
            dirList.Add(2);
        }
        if (Physics2D.Raycast(transform.position, Vector2.right, rayDistance, 1 << 8) = =false)
        {
            dirList.Add(3);
        }

        if (dirList.Count > 0)
        {
            canMove = true;
            int index = Random.Range(0, dirList.Count);
            InitDir(dirList[index]);
        }
        else
            canMove = false;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawLine(transform.position, transform.position + new Vector3(0, rayDistance, 0));
        Gizmos.color = Color.blue;
        Gizmos.DrawLine(transform.position, transform.position + new Vector3(0, -rayDistance, 0));
        Gizmos.DrawLine(transform.position, transform.position + new Vector3(-rayDistance, 0.0));
        Gizmos.DrawLine(transform.position, transform.position + new Vector3(rayDistance, 0.0));
    }
Copy the code

Monster automovement effect:


Step 6: Game controller

Finally, it’s time for the game controller

Careful partners may find, from the beginning to now is mostly code

This article can be a bit boring, since the engine operation of this little game is really small, and most of the logic is written on a script

  • If the above steps have written the game’s gameplay, then this step is the most important one

  • The game controller in this game is used to control the progress of a game

  • If there is no game controller, it is like a game Demo without rules

  • With the game controller is a game rules of the people, in order to make the game in an orderly way!

Then come and play with our game controller!

We through the game controller to the bomb man small game levels

There is also a level counter to determine the progress of the next level, and update maps and monsters!

Finally, there will be a game end screen, which will be triggered when the bomber runs out of three lives

Okay, so that’s the general idea

Look at the GameController script code:

   /// <summary>
    ///Level timer
    /// </summary>
    private void LevelTimer()
    {
        // When time runs out, the game is over
        if (time <= 0)
        {
            if (playerCtrl.HP > 0)
            {
                playerCtrl.HP--;  // Trade life for time
                time = 200;
                return;
            }
            playerCtrl.PlayDieAnim();
            return;
        }
        timer += Time.deltaTime;
        if (timer >= 1.0 f)
        {
            time--;
            timer = 0; }}/// <summary>
    ///Game over
    /// </summary>
    public void GameOver()
    {                     
        UIController.Instance.ShowGameOverPanel();  // Display the game end screen
    }
    private void Update()
    {
        LevelTimer();
       // UIController.Instance.Refresh(playerCtrl.HP, levelCount, time, enemyCount);
    }
    /// <summary>
    ///Load the next level
    /// </summary>
    public void LoadNextLevel()
    {
        if (enemyCount <= 0)
            LevelCtrl();
    }
    /// <summary>
    ///Level controller
    /// </summary>
    private void LevelCtrl()
    {
        time = levelCount * 50 + 130;
        int x = 6 + 2 * (levelCount / 3);
        int y = 3 + 2 * (levelCount / 3);  // Add 2 for every 3 levels
        if (x > 18)
            x = 18;
        if (y > 15)
            y = 15;

        enemyCount = (int)(levelCount * 1.5 f) + 1;
        if (enemyCount > 40)
            enemyCount = 40;
        mapController.InitMap(x, y, x * y, enemyCount);
        if (player == null)
        {
            player = Instantiate(playerPre);
            playerCtrl = player.GetComponent<PlayerCtrl>();
            playerCtrl.Init(1.3.2);
        }
        playerCtrl.ResetPlayer();
        player.transform.position = mapController.GetPlayerPos();

        // Recover the explosion effects left in the scene
        GameObject[] effects = GameObject.FindGameObjectsWithTag(Tags.BombEffect);
        foreach (var item in effects)
        {
            ObjectPool.Instance.Add(ObjectType.BombEffect, item);
        }
        
        Camera.main.GetComponent<CameraFollow>().Init(player.transform, x, y);
        levelCount++;
        UIController.Instance.PlayLevelFade(levelCount);
    }

    public bool IsSuperWall(Vector2 pos)
    {
        return mapController.IsSuperWall(pos);
    }
Copy the code

Step 7: UI controller

  • Then there’s a time limit on the level, so if the level’s time is up, you’ve lost

  • Still have is to give bomb person 3 lives, be met by monster will lose a life, then have an invincible time, restore total time, take life to change time ~

  • Life and time we put in the UI controller, because they’re both UI

  • Display life and time UI control script UIController

  • Show not only life and time in the script, but also the current level and the number of remaining monsters

  • All UI related controls, we put in this script for control!

For example, the first level is like this

Check out the code below:

 private void Init()
    {
        gameOverPanel.transform.Find("btn_Again").GetComponent<Button>().onClick.AddListener(() =>
        {
            Time.timeScale = 1;
            // Reload the currently running scenario
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        });
        gameOverPanel.transform.Find("btn_Main").GetComponent<Button>().onClick.AddListener(() =>
        {
            Time.timeScale = 1;
            SceneManager.LoadScene("Start");
        });
    }
    public void Refresh(int hp, int level, int time, int enemy)
    {
        txt_HP.text = "HP:" + hp.ToString();
        txt_Level.text = "Level:" + level.ToString();
        txt_Time.text = "Time:" + time.ToString();
        txt_Enemy.text = "Enemy:" + enemy.ToString();
    }
    public void ShowGameOverPanel()
    {
        gameOverPanel.SetActive(true);
    }
    /// <summary>
    ///Play the level prompt animation
    /// </summary>
    /// <param name="levelIndex"></param>
    public void PlayLevelFade(int levelIndex)
    {
        Time.timeScale = 0;
        levelFadeAnim.transform.Find("txt_Level").GetComponent<Text>().text = "Level " + levelIndex.ToString();
        levelFadeAnim.Play("LevelFade".0.0);
        startDelay = true;
    }
    private bool startDelay = false;
    private float timer = 0;
    private void Update()
    {       
        if (startDelay)
        {
            timer += Time.unscaledDeltaTime;
            if (timer > 0.7 f)
            {
                startDelay = false;
                Time.timeScale = 1;
                timer = 0; }}}Copy the code

🍓 Resources download

  • Project resource package on here, including the complete small game project source code, 1 points to download to share for everyone to use, points not enough of the private message I good ~

  • Bomb person small game source code can play directly bomb person exe file download

  • This resource contains bomb man Unity source project and I have packaged out of the EXE file, you can directly click on the EXE can play

Click on the image below to play the game directly! Download it and share it with your friends to make or try it out


👥 summary

This article to share a classic bomb people small game, do not know you learned to have no ~

As you may have noticed, a lot of code is used in this article

There aren’t many things to do with the Unity engine, and the hard parts are actually in the script code

So I just want to tell you something through an article:

  • There are a lot of people’s eyes to develop games, may feel very relaxed, and even some people feel that it is idle, in order to play games to go to the beauty of its name – development games 🙃!
  • But the program in the game is actually very boring, very bald most of the time 💀~
  • Some complex operations are developed by programmers using code, that write code is very simple 🙄?
  • The obvious answer is that if writing code were easy, there would be fewer bald programmers 😂
  • So ah, no matter which line, are not so easy to make money, but also need more efforts 🥰~

Ok, the article is for learning, not to say a bunch of nonsense (actually is just to add some words to the article 😳…) Ha ha, accidentally on the truth 😁 feel the blogger write of also ok, a wave of three consecutive comments 😍! See you next time 👋!