How To Make A Game Like Bomberman With Unity

Ever want to blow up your friends? Learn how to make a game like a Bomberman with Unity 3D in this step by step tutorial that will have you setting bombs off with ease.

5/5 1 Rating · Leave a Rating

Version

  • C# 6, Unity 2017.x, Unity
 
Please note, this is a STATIC archive of website www.raywenderlich.com from 08 May 2019, cach3.com does not collect or store any user information, there is no "phishing" involved.
Update note: This tutorial has been updated to Unity 2017.1 by Brian Broom. The original tutorial was written by Eric Van de Kerckhove.

Unfortunately, it’s a little difficult to secure C4 explosives along with some willing buddies willing to explore the afterlife. Thankfully, there are some alternatives.

Enter this Bomberman tutorial. Bomberman is a game where four players battle it out by strategically placing bombs across the battlefield with the goal being to blow each other up.

Each bomb has a few seconds of delay before it explodes and spews out an inferno in four directions. For additional excitement, explosions can trigger impressive chain reactions.

The original Bomberman came out in the early 80s and spinoffs have been published ever since. It’s a timeless game formula that’s still a lot of fun to play and build.

The original title was 2D, but you’re going to create a basic 3D version inside of Unity.

In this tutorial, you’ll learn the following:

  • Dropping bombs and snapping them to a tile position.
  • Spawning explosions by using raycasts to check for free tiles.
  • Handling explosions colliding with the player.
  • Handling explosions colliding with bombs.
  • Handling player death(s) to determine a win/draw.

Loosen up your wrists and get ready to shout “fire in the hole”. Things are about to get really explody inside of Unity. :]

Note: This Bomberman tutorial assumes you know your way around the Unity editor and know how to edit code in a text editor. Check out some of our other Unity tutorials first if you’re not confident yet.

Getting Started with this Bomberman tutorial

Download the Starter Project for this Bomberman tutorial and extract it to a location of your choosing.

Open up the Starter Project in Unity and start this Bomberman tutorial. The assets are sorted inside several folders:

AssetFolders

  • Animation Controllers: Holds the player animation controller, including the logic to animate the players’ limbs when they walk around. If you need to brush up on animation, check out our Introduction to Unity Animation tutorial
  • Materials: Contains the block material for the level
  • Models: Holds the player, level and bomb models, as well as their materials
  • Music: Contains the soundtrack
  • Physics Materials: Holds the physics material of the players — these are special kinds of materials that add physical properties to surfaces. For this tutorial it’s used to allow the players to move effortlessly arund the level without friction.
  • Prefabs: Contains the bomb and explosion prefabs
  • Scenes: Holds the game scene
  • Scripts: Contains the starter scripts; be sure to open them and read through them because they’re heavily commented to make them easier to understand
  • Sound Effects: Holds the sound effects for the bomb and explosion
  • Textures: Contains both player textures

Dropping A Bomb

If it’s not opened yet, open up the Game scene and give it a run.

FirstRun

Both players can walk around the map using either the WASD keys and the arrow keys.

Normally, when player 1 (the red one) presses Space he should place a bomb at his feet, player 2 should be able to do the same thing by pressing Enter/Return.

However, that doesn’t work yet. You need to implement the code for placing bombs first, so open the Player.cs script in your favorite code editor.

This script handles all player movement and animation logic. It also includes a method named DropBomb that simply checks if the bombPrefab GameObject is attached:

private void DropBomb() 
{
  if (bombPrefab) 
  { //Check if bomb prefab is assigned first

  }
} 

To make a bomb drop beneath the player, add the following line inside the if statement:

Instantiate(bombPrefab, myTransform.position, bombPrefab.transform.rotation);  

This will make a bomb spawn at the player’s feet. Save your changes to the script and then give your scene a run to try it out:

DropBombs

It’s working great!

There’s a small problem with the way the bombs get dropped though, you can drop them wherever you want and this will create some problems when you need to calculate where the explosions should spawn.

You’ll learn the specifics of why this is important when this tutorial covers how to make the explosions.

Snapping

The next task it to make sure the bombs snap into position when dropped so they align nicely with the grid on the floor. Each tile on this grid is 1×1, so it’s fairly easy to make this change.

In Player.cs, edit the Instantiate() you have just added to DropBomb() like so:

Instantiate(bombPrefab, new Vector3(Mathf.RoundToInt(myTransform.position.x), 
  bombPrefab.transform.position.y, Mathf.RoundToInt(myTransform.position.z)),
  bombPrefab.transform.rotation);  

Mathf.RoundToInt calls for the x and z values of the player position, rounds off any float to an int value, which then snaps the bombs to the tile positions:

Bombs snap to a grid

Save your changes, play the scene and run around while dropping some bombs. The bombs will now snap into place:

BombsSnap

Although dropping bombs on the map is pretty fun, you know it’s really all about the explosions! Time to add some firepower to this thing. :]

Creating Explosions

To start off, you’re going to need a new script:

  • Select the Scripts folder in the Project view.
  • Press the Create button.
  • Select C# Script.
  • Name the newly created script Bomb.

MakeBombScript

Now attach the Bomb script to the Bomb prefab:

  • In the Prefabs folder, select the Bomb GameObject.
  • In the Inspector window click the Add Component button.
  • Type bomb in the search box.
  • Select the Bomb script you just made.

Finally, open the Bomb script in your code editor. Inside of Start(), add the following line of code:

Invoke("Explode", 3f);

Invoke() takes 2 parameters, firstly the name of the method you want to be called and secondly, the delay before it gets called. In this case, you want to make the bomb explode in three seconds, so you call Explode() — you’ll add it next.

Add the following under Update():

void Explode() 
{

}  

Before you can spawn any Explosion GameObjects, you’ll need a public variable of the type GameObject so you can assign an Explosionprefab in the Editor. Add the following right above Start():

public GameObject explosionPrefab;

Save your file and return to the Editor. Select the Bomb prefab in the Prefabs folder and drag the Explosion prefab to the Explosion Prefab slot:

DragExplosionPrefab

Once you’ve done this, return to the code editor. You finally get to write the code that makes things go boom!

Inside Explode(), add the following lines:

Instantiate(explosionPrefab, transform.position, Quaternion.identity); //1

GetComponent<MeshRenderer>().enabled = false; //2
transform.Find("Collider").gameObject.SetActive(false); //3
Destroy(gameObject, .3f); //4

This piece of code does the following:

  1. Spawns an explosion at the bomb’s position.
  2. Disables the mesh renderer, making the bomb invisible.
  3. Disables the collider, allowing players to move through and walk into an explosion.
  4. Destroys the bomb after 0.3 seconds; this ensures all explosions will spawn before the GameObject is destroyed.

Save your Bomb script and return to the editor and give your game a play. Put down down some bombs and bask in the fiery goodness as they explode!

Cool guys don't look at explosions!

Cool guys don’t look at explosions!

Add a LayerMask

The walls in the game are, luckily, bombproof. The bombs are not bombproof, and the players are definitely not bombproof. You need a way to tell if an object is a wall or not. One way to do that is with a LayerMask

A LayerMask selectively filters out certain layers and is commonly used with raycasts. In this case, you need to filter out only the blocks so the ray doesn’t hit anything else.

In the Unity Editor click the Layers button at the top right and select Edit Layers…

EditLayersButton

If necessary click on the expansion triangle in front of the word Layers to expand the list of layers if it is not visible.
Click the text field next to User Layer 8 and type in “Blocks“. This defines a new layer you can use.

BlocksLayer

Inside the hierarchy view, select the Blocks GameObject, inside the Map container object.

BlocksGameObject

Change the layer to your newly created Blocks layer:

SelectBlocksLayer

When the Change Layer dialog comes up, click the “Yes, change children” button, to apply to all of the yellow blocks scattered across the map.

ChangeLayerDialog

Finally add a public reference to a LayerMask so the Bomb script will be able to access the layer by adding the following line just below the reference to the explosionPrefab.

public LayerMask levelMask;

Don’t forget to save your code.

Bigger! The Explosions Must be Bigger!

The next step is to add the iconic touch of expanding rows of explosions. To do that, you’ll need to create a coroutine.

Note: A coroutine is essentially a function that allows you to pause execution and return control to Unity. At a later point, execution of that function will resume from where it last left off.

People often confuse coroutines with multi-threading. They are not the same: Coroutines run in the same thread and they resume at intermediate points in time.

To learn more about coroutines and how to define them, check out the Unity documentation.

Return to your code editor and edit the Bomb script. Under Explode(), add a new IEnumerator named CreateExplosions:

private IEnumerator CreateExplosions(Vector3 direction) 
{
  return null; // placeholder for now
}  

Create the Coroutines

Add the following four lines of code between the Instantiate call and the disabling of the MeshRenderer in Explode():

StartCoroutine(CreateExplosions(Vector3.forward));
StartCoroutine(CreateExplosions(Vector3.right));
StartCoroutine(CreateExplosions(Vector3.back));
StartCoroutine(CreateExplosions(Vector3.left));  

The StartCoroutine calls will start up the CreateExplosions IEnumerator once for every direction.

Now comes the interesting part. Inside of CreateExplosions(), replace return null; // placeholder for now with this piece of code:

//1
for (int i = 1; i < 3; i++) 
  { 
  //2
  RaycastHit hit; 
  //3
  Physics.Raycast(transform.position + new Vector3(0,.5f,0), direction, out hit, 
    i, levelMask); 

  //4
  if (!hit.collider) 
  { 
    Instantiate(explosionPrefab, transform.position + (i * direction),
    //5 
      explosionPrefab.transform.rotation); 
    //6
  } 
  else 
  { //7
    break; 
  }

  //8
  yield return new WaitForSeconds(.05f); 
}

This looks like quite a complicated code snippet, but it's actually fairly straightforward. Here's a section-by-section explanation:

  1. Iterates a for loop for every unit of distance you want the explosions to cover. In this case, the explosion will reach two meters.
  2. A RaycastHit object holds all the information about what and at which position the Raycast hits -- or doesn't hit.
  3. This important line of code sends out a raycast from the center of the bomb towards the direction you passed through the StartCoroutine call. It then outputs the result to the RaycastHit object. The i parameter dictates the distance the ray should travel. Finally, it uses a LayerMask named levelMask to make sure the ray only checks for blocks in the level and ignores the player and other colliders.
  4. If the raycast doesn't hit anything then it's a free tile.
  5. Spawns an explosion at the position the raycast checked.
  6. The raycast hits a block.
  7. Once the raycast hits a block, it breaks out of the for loop. This ensures the explosion can't jump over walls.
  8. Waits for 0.05 seconds before doing the next iteration of the for loop. This makes the explosion more convincing by making it look like it's expanding outwards.

Here's how it looks in action:

BombExplosionDiagram

The red line is the raycast. It checks the tiles around the bomb for a free space, and if it finds one then it spawns an explosion. When it hits a block, it doesn't spawn anything and it stops checking in that direction.

Now you can see the reason why bombs need to be snapped to the center of the tiles. If the bombs could go anywhere, then in some edge cases the raycast will hit a block and not spawn any explosions because it is not aligned properly with the level:

AllignedVsNot

Finally, select the Bomb prefab in the Prefabs folder in the project view, and change the Level Mask to Blocks.

BlocksLevelMask

Run the scene again and drop some bombs. Watch your explosions spread out nicely and go around the blocks:

ExplosionSpread

Congratulations, you've just made it through the hardest part of this tutorial!

Go ahead and reward yourself with a refreshing drink or a delicious snack, think about what you just did, and then come back to play around with reactions to explosions!

Chain Reactions

When an explosion from one bomb touches another, the next bomb should explode -- this feature makes for a more strategic, exciting and firey game.

Luckily this is quite easy to implement.

Open up the Bomb.cs script in your code editor. Add a new method named OnTriggerEnter below CreateExplosions():

public void OnTriggerEnter(Collider other) 
{

}

OnTriggerEnter is a pre-defined method in a MonoBehaviour that gets called upon collision of a trigger collider and a rigidbody. The Collider parameter, named other, is the collider of the GameObject that entered the trigger.

In this case, you need to check the colliding object and make the bomb explode when it is an explosion.

First, you need know if the bomb has exploded. The exploded variable will need to be declared first, so add the following right under the levelMask variable declaration:

private bool exploded = false;

Inside OnTriggerEnter(), add this snippet:

if (!exploded && other.CompareTag("Explosion"))
{ // 1 & 2  
  CancelInvoke("Explode"); // 2
  Explode(); // 3
}  

This snippet does three things:

  1. Checks the the bomb hasn't exploded.
  2. Checks if the trigger collider has the Explosion tag assigned.
  3. Cancel the already called Explode invocation by dropping the bomb -- if you don't do this the bomb might explode twice.
  4. Explode!

Now you have a variable, but it hasn't been changed anywhere yet. The most logical place to set this is inside Explode(), right after you disable the MeshRenderer component:

...
GetComponent<MeshRenderer>().enabled = false;
exploded = true;        
...  

Now everything is set up, so save your file and run the scene again. Drop some bombs near each other and watch what happens:

ChainReaction

Now you've got some seriously destructive firepower going on. One little explosion can set your little game world on fire by triggering other bombs, allowing for these cool chain reactions!

The last thing to do is to handle players' reactions to explosions (Hint: they're not good!) and how the game translates the reaction into a win or draw state.

Player Death And How To Handle It

Open the Player.cs script in your code editor.

Right now, there's no variable to indicate if the player is dead or alive, so add a boolean variable at the top of the script, right under the canMove variable:

public bool dead = false;

This variable is used to keep track if the player died to an explosion.

Next, add this above all other variable declarations:

public GlobalStateManager globalManager;

This is a reference to the GlobalStateManager, a script that is notified of all player deaths and determines which player won.

Inside OnTriggerEnter(), there's already a check to see if the player was hit by an explosion, but all it does right now is log it in the console window.

Add this snippet under the Debug.Log call:

dead = true; // 1
globalManager.PlayerDied(playerNumber); // 2
Destroy(gameObject); // 3  

This piece of code does the following things:

  1. Sets the dead variable so you can keep track of the player's death.
  2. Notifies the global state manager that the player died.
  3. Destroys the player GameObject.

Save this file and return to the Unity editor. You'll need to link the GlobalStateManager to both players:

  • In the hierarchy window, select both Player GameObjects.
  • Drag the Global State Manager GameObject into their Global Manager slots.

LinkGlobalStateManager

Run the scene again and make sure one of the players is obliterated by an explosion.

HitByExplosion

Every player that gets in the way of an explosion dies instantly.

The game doesn't know who won though because the GlobalStateManager doesn't use the information it received yet. Time to change that.

Declare the Winner

Open up GlobalStateManager.cs in your code editor.

For the GlobalStateManager to keep track of what player(s) died, you need two variables. Add these at the top of the script above PlayerDied():

private int deadPlayers = 0;
private int deadPlayerNumber = -1;  

First off, deadPlayers will hold the amount of players that died. The deadPlayerNumber is set once the first player dies, and it indicates which one it was.

Now that you have this set up, you can add the actual logic. In PlayerDied(), add this piece of code:

deadPlayers++; // 1

if (deadPlayers == 1) 
{ // 2
    deadPlayerNumber = playerNumber; // 3
    Invoke("CheckPlayersDeath", .3f); // 4
}  

This snippet does the following:

  1. Adds one dead player.
  2. If this is the first player that died...
  3. It sets the dead player number to the player that died first.
  4. Checks if the other player also died or if just one bit the dust after 0.3 seconds.

That last delay is crucial for allowing a draw check. If you checked right away, you might not see that everybody died. 0.3 seconds is sufficient to determine if everybody died.

Win, Lose or Draw

You've made it to the very last section! Here you create the logic behind choosing between a win or a draw!

Make a new method named CheckPlayersDeath in the GlobalStateManager script:

void CheckPlayersDeath() 
{
  // 1
  if (deadPlayers == 1) 
  { 
    // 2
    if (deadPlayerNumber == 1) 
    { 
      Debug.Log("Player 2 is the winner!");
    // 3
    } 
    else 
    { 
      Debug.Log("Player 1 is the winner!");
    }
     // 4
  } 
  else 
  { 
    Debug.Log("The game ended in a draw!");
  }
}  

This is the logic behind the different if-statements in this method:

  1. A single player died and he's the loser.
  2. Player 1 died so Player 2 is the winner.
  3. Player 2 died so Player 1 is the winner.
  4. Both players died, so it's a draw.

Save your code, then give the game a final run and test if the console window reads out what player won or if it ended up as a draw:

FInalRun

And that concludes this tutorial! Now go ask a friend if they want to share in the fun and blow them up when you get the chance. :]

Where To Go From Here?

Download the finished Bomberman tutorial Final Project if you got stuck.

Now you know how to make a basic Bomberman-like game by using Unity.

This Bomberman tutorial used some particle systems for the bomb and the explosion, if you want to learn more about particle systems, check out my Introduction To Unity: Particle Systems Tutorial.

I highly encourage you to keep working on this game -- make it your own by adding new features! Here are some suggestions:

  • Make the bombs "pushable", so you can escape bombs next to you and push them towards your opponent
  • Limit the amount of bombs that can be dropped
  • Make it easy to quickly restart the game
  • Add breakable blocks that get destroyed by the explosions
  • Create interesting powerups
  • Add lives, or a way to earn them
  • UI elements to indicate what player won
  • Find a way to allow more players

Be sure to share your creations here, I'd love to see what you guys can come up with! As always, I hope you enjoyed this tutorial!

If you have any remarks or questions, you can do so in the Comments section.

Average Rating

5/5

Add a rating for this content

1 rating

Contributors

Comments