Download

Bomberman type explosions in blueprint.

https://answers.unrealengine.com/questions/245396/how-to-do-bomberman-like-explosion.html

I found this thread, but sadly i’m not that skilled in C++ so i was thinking if anyone would know how to do this in blueprint or guide me towards a way how to.

I think there’s a few things to sort out first.

Firstly, In Bomberman, bombs are locked to a grid. No matter when you place it, it will always align neatly with the level grid so that when it explodes, each of the 4 directions will expand outwards to their maximum cleanly along the level. So are you having the explosions locked to a grid? If so, it makes it a lot easier.

What I would do (and I am by no means a professional so this may not be the correct way) is use a Line Trace By Channel to do a trace outwards from the exploding bomb in each of the 4 directions. You can also pass in the explosion size into the line trace so it will only go as far as the explosion will, saving a headache later (If you’re saving it like “Bomb size = 1” to mean the explosion will extend outwards one grid space in all directions, multiply that value by the size of your grid). Then, for each of the traces, check to see if it hit something.

If it hit a non-destructible wall, get the length of the trace, divide by the grid size then round down to get the number of grid spaces the explosion should affect.

If it hit a destructible object (wall, player, whatever), do the same thing but add one more grid space to the result (because you’d want the explosion to encompass the object). Then, probably use an interface call on the hit object to say “I exploded you. Do what you gotta do”.

If it didn’t hit anything, simply use the bomb explosion size as the number of grid spaces to encompass.

Finally, you’ll need a visual effect to accompany this. You could create a particle effect to represent the explosion and spawn it for every grid space that is encompassed. To obtain the location of those spaces, simply use the bomb’s location and add an offset equal to the number of encompassed grid spaces (found above) multiplied by the size of the grid. So if you found it should encompass 5 spaces, you could run a loop 5 times. For each one, add one to the loop index, multiply it by the grid size and add it to the bomb explosion location in the appropriate axis.

You could also potentially come up with a single particle effect that could span the entire width of the explosion, so even though it encompasses 5 grid spaces you would only need one effect.

I guess you don’t need a particle effect at all, a 2d flipbook would work too if you were doing it that way. I guess I have no idea about the style you’re looking to achieve.

I read through the link you posted again and I see they first suggested a line trace as well but decided against it in favor of the index map. In the first image posted (0bbf057037e8e8b3d0daaf1af47a867d6e64805d.png) it looks like the game map is indexed into 0’s, 1’s and 2’s with 0 being floor, 1 being a wall and 2 being a player. Whenever a player moves, the index map is updated to represent their current position on the map. So when a bomb explodes, you only need to check the map to see what is where in order to determine what needs to go boom. You could accomplish this with blueprints although I don’t know what the performance tradeoff is instead of a line trace.

In order to do this with blueprints … hmm. I imagine your level blueprint would need to handle the index map. So you could create an int array there to represent the level. You could create an actor to look to the map and build the level in a construction script so you can see it in real time. Or just have the level blueprint create the level when it starts. Then you would need something to monitor the movements of the players. I guess in the event tick of the level blueprint, you could check the location of each player, divide the X and Y to get the index into the array and update it appropriately. Bombs would also need to be added to the map too since explosions collide with other bombs (I believe in Bomberman if an explosion hits a bomb, it explodes as well). Is that more performance intensive than a line trace? Don’t know. It certainly seems to overcomplicate things.

So if you were to create a map for this, you would probably pass all the work off to the level blueprint. When a bomb blows up, call an event in the level blueprint to say “Bomb at X,Y exploded”. In the level blueprint, you would need 4 loops, same as what is seen in the “BombExplode” code. For each axis, start at the origin of the explosion and loop for the size of the explosion, checking to see if it’s a 0, 1, or 2. Or 3, if that is used to mean a bomb. If it is … uhh. Hm. In the C++ code, they just say “Explode the tile at X,Y”. But that doesn’t help much. You would need to get the actor filling the space at X,Y. I think the cleanest way to do this might be to use an array of actor references rather than ints. (EDIT: Actually, it might help to have two arrays. One with the map index containing ints which will be used for the initial build of the level. When the level is built, the actor references can then be placed into a second array with the same size. Because if you had ONLY actor references, there would be nothing to reference when it starts. You can’t reference nothing and build a level out of it. ORRR you could make your own structure containing an int and an actor reference then have the map be an array of that structure. You would need to manually initialize the array with ints and all of the actor references would be null until the game actually populates the map). You can simply contain more information there and don’t need to worry about trying to find an actor once it is triggered.

Ok so a lot of this was maybe rambling a bit but it was kind of a vague question so the answer is a little vague too. But I hope it gave you some ideas and feel free to ask for more details about stuff.

I’ll try to work something out along those lines, but how would i make a grid for my map and could you by any chance try to make some blueprints explaing some of your ideas. Cause i am kinda lost in all that text.

Sorry, yeah I’m not very organized and a lot of that was me just typing as I was thinking of stuff.

What is your level of experience with UE4 blueprints? I don’t want to spend all day going into too much detail and insulting your intelligence and I don’t wanna be too brief either.

Kinda new to unreal, i know the basics and stuff

OK well I’m at work for the next 45 minutes and unfortunately probably wont be available to load up UE4 for the next … 3 days. Busy weekend :-/ . But I’ll see what I can do here. I’ll use google image search to find stuff. Please note: I am not performing these steps as I type them, I’m doing this from memory and this may not be 100% accurate.

  1. Right click in your content browser and create a new struct under blueprint > Structure. Name it something like “TileStruct”. This will be used to represent one tile.
    bp41f.png
  2. Add two variables to this struct. The first is an INT (Can name it “Type” I guess?) and the second should be an actor reference (“ActorRef” is a good name). Compile it and you should be able to set the default value for the INT. Set it to 0, leave the actor ref alone. Structure creation will look like this:
    15022-struct.png
  3. Compile save and close this struct. Then, create another struct, named something like “TileRow”.
  4. Add one variable to this struct, make it type “TileStruct” and make it an array by clicking the icon to the left of the variable.
  5. Compile save and close the struct. Open the level blueprint.
    toolbar_level_editor.jpg
  6. Create a new variable by clicking the “+” next to variables and make it an object type of “TileRow”. I believe you turn this into an array of TileRows by clicking the small icon to the left of the variable. Call it “MapIndex”
    yKfuw7i.png

So what you have at this point is an array of arrays or what is known as a 2D array. It’s a good way to represent 2D data like a map. Now we need to populate it.

Ok I just deleted a huge section of stuff I’d typed because I realized I was going about it in a stupid way. I’m down to 20 minutes … gotta hurry up!!

  1. Ok so you need a loop. The index above has 11 rows and 15 columns so we’ll replicate that. What we need is a “For loop” (I think there’s a “ForLoopWithBreak” as well but we don’t need that, even though that’s whats in the picture).
    ForLoopWithBreak_Network.png
  2. First index is 0, last index is 10 - so the loop will execute 11 times.
  3. Now, drag the “MapIndex” variable into the grid, using “Get” when asked. Drag off the pin on the right side and look for the “Add” node.
    4352-capture-2.jpg
  4. Then off the remaining pin from the “Add” node, drag off it and select “Make TileRow”. Might say “Struct” on there too, not sure.
  5. Once done, add another ForLoop from 0 to 14. For now you should have something that looks like this:
    XaHxUBF.png

Great… MSPainting that took another 5 mins…

  1. Ok, now drag another “MapIndex” reference into the event graph as a “Get”. Drag from the pin and type “Get”. The “Get” node on the right side of this image is what you’re looking for:
    HT11.jpg
  2. Now, off of that get, drag an “Add” node similar to what we just did before. Off the remaining pin on the left, drag and select “Make TileStruct”. End result should be something like this:
    ad7OJqC.png

At this point, we have two loops running. The first loop creates a row. As soon as the row is created, we loop to create columns in that row. So MapIndex contains 11 TileRow’s with each one of those containing 15 TileData’s. Unfortunately at this point, nothing is set. So it’s a 15x11 grid of emptiness. We need to to initialize the values.

So I’m pretty much out of time. What needs to be done is the index needs to be checked after that last “Add”. The index from the first array is effectively the Y coordinate and the index from the second array is the X coordinate. Walls need to be placed when the following conditions are true

  • X is 0
  • Y is 0
  • X is 14
  • Y is 10
  • X and Y are both even numbers

If you can figure out the logic behind that, you will want to modify the TileStruct at those indices and set the int (“Type”) to 1. You’ll then have a the same index as above.

Next comes putting it to use which involves looping through everything again, checking the type and placing walls if the type is 1.

Then comes updating the index when a player moves.

Then updating the index when a bomb is placed.

Finally, checking the index when a bomb explodes.

I can come back here at some point in the near future to try to help more but I’m simply out of time at the moment, sorry. If someone else wants to chime in to help (or correct some dumb stuff I did), please feel free.

I can’t connect my MakeTileRow to the add node, also you didn’t state what type it should be, i currently i have it as object. And the get node after the second forloop makes an array to the add node.
a7055dd00c82c361456bdd798de04cf1e2ea88ec.png

Ok, I’m sorry for any confusion I caused… it worked out better in my head. A lot of this is trial and error and without having access to UE4 at the time, I didn’t get any errors so I assumed it would work …

I ran through the steps I outlined myself and it didn’t work like I had thought. First problem, I never mentioned what the variable of TileStruct types in TileRow should be called. I simply called it “TileRows”… not super descriptive but it at least shows a different name and indicates it is multiple TileRow structs.

So the way I was trying to accomplish this is

  1. Add a “blank” row to the MapIndex
    >> I’m not sure why you were not able to connect the “Make TileRow” to the Map Index “Add” node … maybe check the map index’s type?
  2. Get that “blank” row, break it apart to get to the “TileRows” array, then loop 15 times, adding blank TileStruct entries to it.

The problem is if we get an element in the “Map Index” array with the “Get” node, it returns a copy of the data in that index. So for example, if we had this array:

Array = {{1,2,3},{4,5,6},{7,8,9}}

This is a 2D array. The Array itself has three entries and each of those has three entries. If I were to say “Get the second entry in Array”, I would get {4,5,6}. But if I then said “Get the second entry in Array, change the first value to an A”, it would LOOK like the array should now be

Array = {{1,2,3},{A,5,6},{7,8,9}}

But the problem is that when I “get” an element from the array, I only got a copy of the values contained there, not an actual reference to the array itself. So any modifications to that value do not reflect back on the original array.

Long story short, I was thinking about this the wrong way. I came up with a way to do this, but unfortunately I needed to create another variable. I can’t help but feel like I could have done it without one but I couldn’t figure it out.

So I created a new variable called “TileRowBuild”, which is an array of TileStruct. Basically the same as the “TileRow” struct created before. (NOTE: I realize now I should probably have made it a local variable as it will never be used outside that initialization, but it will work if you do or don’t) Then I changed the logic to be as follows:

  1. Loop 11 times. For each iteration of that loop …
  2. Loop 15 times. Add a blank entry to the TileRowBuild.
  3. Once done with the second loop, add the finished TileRowBuild to the Map Index. Clear out TileRowBuild for repeated use.

It’s simpler, cleaner and works. Adding a blank row then trying to populate it after wasn’t a good idea. Better to build the full row then add it. Here’s a screenshot of it:
33185439f894963b81a5f2cdb017dc2c9db186b5.png

So now we have the 11x15 array of blank tiles and we can continue.

Next step is to populate the MapIndex. We can do this right inside the logic we already have. As I mentioned above, there are three possible conditions that should result in a “1” being put in the array.

  • Y is 0
    OR
  • Y is 10
    OR
  • X is 0
    OR
  • X is 14
    OR
  • X and Y are both even numbers

Note: I re-arranged the order slightly to make the logic flow better.

  1. Drag an “OR” node onto the event graph. Click “Add Pin” until we have five of them (one for each condition above).
    ec84f6bcbef1d045c77c4cc29572fb56e9bbc52a.png
  2. First condition is "Y is 0. Easy enough. Drag off the index in the first loop and look for an = node. Set the value to 0 and plug it into the OR.
    00452e78a3ab56bc4becef5d000dfd701e575316.png
  3. Second condition, “Y” is 10. Just as easy. Follow the same steps but use “10” instead of 0. (oops, in the screenshot below I still had it at 0).
    639655b027c9976911e6bbeb253b3f7f6ae9b305.png
  4. Third and forth condition are very similar, just drag off the index in the second loop.
    4886a0c2084a16e24807563f22b25f42d6197625.png
  5. Finally, we need to check if both X AND Y are even. Drag off the final “or” pin and add an “AND” node. In order to check if a number is even, we need to use the modulus operator. If you don’t know what that is, it’s basically division except it only returns the remainder. So if we did 10/2, the remainder would be 0. So 10%2 (% is modulus) is 0. If a number is even, it can be divided evenly by 2. So if (number)%2=0, we know it’s even. So add two modulus nodes to the graph and add two = nodes to the graph to check that they’re 0. Plug them into the AND.
    d7aac71c62e840bb499cc68c2ee927d969907775.png
  6. So, if the returning boolean from that OR is true, it means any of the conditions are true and we need a 1 instead of a 0 for the tile type. Add a “Select int” node to the graph. Pass the result into “Make TileStruct” type and the “Pick A” pin to the OR result. What this does it it will pick either int A or int B based on the boolean passed in. The boolean will be TRUE when we want a wall so we want “A” to be 1. Leave B at 0.
    NOTE: You could feed the result of the OR straight into the “Type” pin. A “TRUE” will be converted to a 1 and a “FALSE” will be converted to a 0. This will look cleaner but it may lead to confusion later. Also, this section may need to be added to if you want to dynamically create different types besides just 0 or 1.
    daaaea000673c01b147cce655f646b24af383f68.png

At this point, I have not tested this. Mostly because there currently isn’t a good way to view the contents of an array unless we make a function to print it to the screen but I don’t want to go through that. I’d rather just use it and see if it works. So let’s do that.

I don’t know what your current map looks like, I currently have the starting map with the table. I deleted it all so it’s empty. You don’t have to delete everything if you don’t want to, maybe just shift it off to the side for now. We are going to be building a level at 0,0,0 based off the index.

  1. Functions are always useful. I think right now is a good time for one. In the level blueprint, click the “+ Function” button to add a new one. Name it “BuildLevelFromIndex”. The idea is we’re going to loop through the index one by one and place actors in the world that correspond to the type. So in this new function, drag MapIndex into the graph with a “Get”. Drag a “For each loop” node from that. The For Each loop is a For loop that will get each element in the array one at a time.
    ade94aead75df205db6f10fb678c5f64f14f74cf.png

Hmm… as I type this, I think I see a problem we might have in the near future. I will need to find a way to obtain an array value by reference so that we can set properties of the array dynamically… hmm. Ok, well problem for in a little bit.

  1. From the “Array Element”, drag off a “Break TileRow” node. Now we have our inner array which we need to drag off and select another “For each loop”
    kJOHlhy.png

  2. Now, we need to determine the type of tile that exists at this location. Drag off the “Array Element” node and break the TileStruct. Drag off “Type” and use a = node to check if it is “1”. Drag from the resulting boolean and add a “Branch”. If you’ve never used Branch before, it is essentially an “If” statement. “If boolean is true, do this. Else, do that”.
    UOfVxbZ.png

  3. So if this index has a wall, we want to spawn a wall. So add a “Spawn Actor from class” node to the “True”.
    Is0CVVP.png

But what are we spawning? We don’t have anything yet. Or at least, I don’t. You might. So at this point, I am going to create an actor to spawn.

  1. Right click in the content browser and create an actor. I named it “Wall” because I am very creative. In the viewport, add a static mesh component named WallMesh. Set it to be Shape_Cube. Now we have a cube, woo! It is important to note that the size of this cube is 100 units.
    81b4c6d7194786b62a0c265b5ad581fb23c86c05.jpeg

I don’t think we need to do anything else with this for now. So back to the level blueprint.

  1. In the Spawn Actor from Class blueprint, set the “class” to be “Wall”. Drag off the Spawn Transform and click “Make Transform”. We need to calculate where the wall will spawn.

So, if the wall is 100 units, every grid space is 100x100. So for every index, we will need to multiply by 100 to get the actual world coordinates.

  1. Drag off the “Array Index” in both loops and multiply them by 100. Then drag off the “Location” node from the make transform and break a vector. Feed the products into the X and Y.
    b8913d39660e6a7e99d64e9726f2b5ebd4d9aad5.png

  2. Final step - go back to the event graph and drag a node off the completion of the first loop. Use it to call BuildLevelFromIndex.
    157584ae42f296b853896c8ef572d042e55385b7.png

And when you start up the game… TADAA!!

4df048032bb9e5941085cce3dd978ba80c956ebc.jpeg

… this doesn’t look right at all. What did I do? Gonna post this for now and keep looking at this.

Ok, so my big problem was I didn’t rebuild lighting so it all looked wonky.

Second problem was this
d8649c7c750809838889ab10c4bdfec89b1a0e95.png

I accidentally dragged the pin into the wrong spot on the mod operation. Fix:
b1fb3f0f2a92a07d8596ac792a0a7187da92ca92.png

And the end result:
cf402521f5f9029049e9398b8db7b1099b85a516.jpeg

Note: I did add a “floor”, just a cube I dragged in with scale set to 15.0, 11.0, 1.0 at location 700, 500, -50. This lines up perfectly with the walls.

OK… So now we have an index that builds the walls. But there’s still a problem. When we spawn the wall, we need to pass a reference to that wall back into the MapIndex… somehow. I will need to work on this and figure out how to do it. We could get the whole row, modify the one we need and replace the whole row in the index but that seems messy as hell. I need to find a way to get a TileRow from the MapIndex as a reference, not as an instance. I’ll get back to you.

I ended up adding this:

(something seems wrong with this attachment, re-uploading)
b4705665871bbb7a67736da5c79fcab319522dda.png

So, when we spawn an actor, we do the following:

  1. Get the row we’re working with (index from first loop). Break it.
  2. In the broken row, get the individual TileStruct we’re working with (index from second loop). Break it.
  3. Create a new TileStruct, passing in the Type from the broken TileStruct and the actor reference of the actor we just spawned.
  4. Use “Set Array Element” to replace the old TileStruct with the new one. We now have a new row.
  5. Use “Set Array Element” to replace the old TileRow with the new one.

The Map Index is now updated.

I feel like this is completely messy and there has to be a better way to accomplish this. But this is all I have for the moment. It may be that the way I had you set this up, this is the only way to handle it. I’m not sure.

Gonna hold off here for now, let me know if you have any questions.

@ Chumble you have spent some time explaining all above so thanks a lot but do you think you can make a video tutorial series even on the fly so it wont consume that much time from you as this will help us a lot ,and i think not that much left to explain to get Bomberman game here.

I’ve never done a video tutorial before, not sure how that would go. Also, a lot of what I’ve posted is trial and error stuff, many of the steps I erased and did again in a different way so if I were to be making a video of the whole thing it would be filled with lots of backtracking and re-doing. I feel like it wouldn’t be a very good video.

I’m still waiting for someone to step in here and say “No no no, you’re doing this all wrong. You should be doing X Y X”. I’m guessing not a ton of people have taken the time to read through all this.

I’ll think about it but for the moment I think I’ll keep it at this.

Still the info you gave is good to start with , lets hope we get everything to make such game .

Holy smokes!
That’s alot of explaining i’ll try to do what you posted earlier when i get enough time. Really appreciate the amount of help you’ve done so far! +1 to you good sir!

Happy to help! I’m trying to add explanations for every step so it helps more with understanding but I know I’m not the best at explaining things. If there are any parts you have questions about, absolutely 100% feel free to ask and I will answer them the best I can.

Edit: I’m going through a couple steps ahead and I’m finding a few things wrong with the way I did stuff above. Firstly, most of the code should be in the GameMode blueprint, not the Level blueprint. Secondly, the adding actors part doesn’t work yet (even though I thought it did). Thirdly, in a normal bomberman game, the players are fixed to a grid. But if they weren’t, you might have two players on the same spot at the same time… so to compensate for this, I made the TileDataStruct contain an array of ints and actor references.