• # Super Mario Bros 3 Level Design Lessons, Part 1

Game Design and Theory

I recently decided to play through the All-Stars version of SMB 3 without using any Warp Whistles.

SMB 3's playful title screen has Mario & Luigi messing around with a bunch of enemies and powerups.

The sequence is fun to watch, but it also serves as a great preview of numerous game mechanics.

I suspect that the majority of people who replay the game are familiar with the secret and use it to skip to the last world. This also means zooming past a plethora of well-designed levels. It’s been my habit as well, but this time I resolved to experience SMB 3 in its entirety.

A lot of small, geometric stages later, here’s an overview of what I found to be the most notable points in the first world:

## 1)  World 1-1

As with the original Super Mario Bros., the “?” Blocks are encountered as soon as the game begins. Since they utilize a fairly universal symbol for a question, they inherently invite the player to investigate.

In addition to being positioned over Mario’s head, a slowly approaching Goomba encourages the player to jump up and discover that hitting the blocks from below can yield rewards (in this case, some Coins and a Super Mushroom).

The red Venus Fire Trap is also introduced here and — in typical Mario fashion — doesn’t respawn if killed and only comes out if Mario isn’t standing next to its pipe (or on top of it). Although the player can’t go down this particular pipe, the fact that an enemy emerges from it hints at the possibility of Mario being able to do the same.

## 2) World 1-1

Immediately after collecting the mushroom powerup, the player is presented with a red Koopa Troopa, an enemy that hides in its shell after a successful jump attack.

If the Koopa Troopa is touched while in this state, it quickly slides away from Mario. Although the big white block is a bit in the way, the player can still accomplish this feat fairly easily. If he does, he’ll learn that shells can be used to activate “?” blocks (which is the only way to do it in this case as the block cannot be hit from below) while discovering the game’s new powerup: the Super Leaf.

Immediately to the right, a strip of flat land with three enemies — one of them a red Paragoomba — lets the player experiment with Raccoon Mario’s glide and spin-attack mechanics.

## 3) World 1-1

Following the three Goombas (which don’t respawn if killed, leaving the strip clean of enemies), a diagonal trail of coins leads up into the sky. The player must jump over a bottomless pit at the end of this runway and is encouraged to collect the coins, so it makes sense for him to get a running start and jump as high and far as possible.

When the player starts running, a HUD meter fills up, the running animation changes, and an urgent sound effect begins looping in the background. All these events signify that something important is happening, and when the player jumps and soars into the sky, the screen — for the first time in a Mario game — begins to scroll horizontally and vertically at the same time.

## 4) World 1-1

As soon as Mario lands on a series of clouds, he finds an isolated Brick Block that floats in the air much like the “?” blocks. This similarity encourages the player to interact with it in much the same way, i.e., by hitting it, which yields the first 1-Up Mushroom.

The clouds continue to the right creating another clear runway that ends with a trail of coins. In a dare of sorts, the coins ask the player to throw caution to the wind and make a blind leap into the unknown. The newly acquired flying ability is quite thrilling and liberating, and having just earned an extra life, it stands to reason that most players would want to pursue the extra treasure. Doing so takes Mario off-screen and gradually lowers him by a tall pipe.

With no other obvious place to go, the game stresses the significance of the pipe. If the player figures out how to enter it, its path leads him to a neat little Easter Egg: a room filled with coins that are arranged to form the number 3.

## 5) World 1-1

If the player misses the opportunity to fly up to the cloud passage, the next two sections serve to introduce some new enemies. The first contains a green Koopa Troopa and three green Koopa Paratroopas that drop from the sky (hinting that there’s something up above). The Paratroopas demonstrate their ability to jump onto and fall down from platforms, while the two pits to the sides serve as an opening to show that enemies can also fall to their deaths.

The second area contains a Piranha Plant and a green Venus Fire Trap. Their proximity makes it more likely that the player will have to stop by one of them on his route to the level’s end. If he does, he’ll have another opportunity to discover that the plants can’t come out of pipes if Mario is standing near them. The immobile version of Super Mario will also encourage the discovery of crouching in order to dodge the fireballs, and a Raccoon Mario will get a chance to dispatch the plants with his spin-attack.

## 6) World 1-1

Right before the level’s end, the player encounters two grounded piles of Brick Blocks. Since the player had two previous chances to pick up a Super Leaf, he’s likely to try the spin-attack on these glowing objects as there’s no way to hit them from below.

In addition to this lesson, there’s also a solitary red Koopa Troopa pacing atop the second group of blocks. Since the player already had a few chances to learn that Koopa Troopa shells can take out other enemies and activate powerups, he might try to do the same here. If he does, the shell will break through a bunch of Brick Blocks and leave one of them unobstructed. If Mario hits this block from below (or spin-attacks it from the side), it will reveal a P-Switch.

The P-Switch functionality immediately turns all the remaining bricks into coins and plays a jaunty countdown theme. When the countdown ends, the remaining coins turn back into Brick Blocks, teaching the player that the transformation is only temporary. The music change is important as there are no other visual cues to indicate if and when the blocks will return to their original form.

## 7) World 1-1

The final part of the stage is segmented by a jagged black line that spans the height of the map. This clearly denotes the end of the level while keeping with Super Mario Bros. 3’s stage motif — crossing this boundary is almost like stepping behind a curtain.

The only object in this area is an animating Goal Panel that instantly draws the player’s attention and ends the stage when touched. Since the floor leading up to it is flat, it encourages the player to run in at full speed and jump into the panel. More often than not, this rewards the player with a star, the best possible Goal Panel prize.

## 8) World 1-2

As soon as the second level begins, the player is introduced to slopes and gets to experiment with how they affect Mario’s movement. Once Mario reaches the first peak, he can also dispatch a Goomba with the slide-attack while being pursued by more Goombas spawning out of a horizontal pipe.

## 9) World 1-2

The second major area in the level shows an almost unreachable series of coins, a floating pipe with a Venus Fire Trap, and some Brick Blocks located just above the ground. The player is likely to collect most of the coins and then attempt to break through the Brick Blocks, and perhaps learn the run-then-duck-to-slide maneuver.

If the first block is hit, it reveals a P-Switch. Unlike the P-Switch in the first level, this one turns coins into other Brick Blocks. This results in the coins (or at least what’s left of them) being transformed into a path that leads up to the pipe. This clearly labels the pipe as a destination and allows Mario to use it to get to another bonus room.

## 10) World 1-2

The final new object introduced in level 2 is the Jump Block. Much like the other types of blocks, it’s uniquely (if a bit abstractly) decorated, naturally drawing the player’s attention.

The first two Jump Blocks are spotted in a valley with a Paragoomba, increasing the chance that the player will bump into them while dodging/attacking the enemy. The bouncincess of the blocks is quite intuitive as it’s reminiscent of a trampoline — or a really springy bed, which most anyone will immediately understand — encouraging the player to jump off of them as they dip to their lowest point.

The second block also spits out a powerup, and it’s possible to initiate this by bumping it from below or landing on top of it. In case the player misses this point, the next area contains a pit and a stairway of Jump Blocks. In order to safely traverse the pit, the player is likely to use the Jump Blocks above it (instead of risking bumping into them from below), the last of which drops a Starman.

## 11) World 1-2

The level end introduces a new enemy, a flying Paragoomba that bombards Mario with Micro-Goombas. Since there are no other enemies or obstacles in sight, it’s a safe place to demonstrate the mechanic of Micro-Goombas slowing down Mario if they attach themselves to him.

If the player lets the Paragoomba follow Mario, he might also learn that any enemies on screen will instantly perish when Mario touches the Goal Panel.

## 12) World 1-3

As the third level begins, the player is greeted with a few large blocks and a Koopa Troopa. Both of these elements seem to be an aid in dispatching the Boomerang Bro. that stands behind ’em, i.e., the Koopa Troopa’s shell can be rocketed into him, while the higher vantage points makes it easier to dodge his boomerangs and squash him from above.

## 13) World 1-3

Following the Boomerang Bro., another Brick Block pile is presented where a red Koopa Troopa can be used to set off a chain reaction that destroys many of the bricks. This time around the pinballing turtle shell shows how Jump Blocks react to its touch (simply deflect it like other blocks) while rewarding the player with some extra coins.

When the turtle shell leaves the screen, the player is encouraged to jump down into the cavity it created and investigate the leftover blocks. One of them yields a powerup , while another proves to be a Coin Block . The newly formed brick configuration leads the player to jump back out once he’s done, at which point he has a chance to encounter an invisible Jump Block. This pink block can only be hit from below, and when activated, it sends Mario into the Coin Heaven bonus section.

## 14) World 1-3

Although Level 3 is mostly flat, it doesn’t hold any rewards up in the sky. The Cloud Heaven, though, contains a bunch of extra coins and a 1-Up if the player uses it as a runway.

## 15) World 1-3

Past the pile of Brick Blocks, the player encounters a series of stacked Wooden Blocks. The reason they’re grouped this way is to encourage the player to press against them as he jumps forward, giving him a chance to discover that Wooden Blocks can yield powerups if hit from the side.

## 16) World 1-4

Although level 4 is not incredibly challenging, it’s much more difficult than the previous three stages. It’s almost completely devoid of solid ground, and its auto-scrolling nature makes it a much more intense experience. This is perhaps the reason why it’s skipable on the overworld map.

In addition to the automatic scrolling that can push Mario to his death, the stage also introduces moving platforms. The platforms only move horizontally, and drop as soon as Mario lands on them. This is a pretty intuitive mechanic as it’s easy to imagine Mario’s weight overpowering the ethereal strings that hold up the platforms.

Once the player learns this, he can use it to his advantage in an area where a vertical stack of coins is positioned next to a wall. With some quick thinking, the player can figure out that if he jumps on the incoming platform, it’ll drop and he’ll collect all the coins, and then still be able to jump off of it and through a gap in the wall. This is a great example of rewarding the player for proper environmental analysis and making him feel like he’s mastering its traversal.

## 17) World 1-4

Unlike the previous stages, level 4’s main area ends with a solid wall and a pipe. Since there’s nowhere else to go, the player — for the first time — must learn to travel through a pipe in order to finish the level. On the other side, he’ll be ambushed by a Boomerang Bro. and find the standard Goal Panel.

Somewhat emphasizing the level’s optional-challenge nature, if the player collects all the coins in the map, Toad’s Blue House will also open up in the overworld area.

## 18) World 1 Fortress

Podoboos and Roto-Discs are first introduced in spaces where it’s easy to avoid them. Once the player gets used to their functionality, the difficulty is ramped up: multiple Podoboos emerge from lava (with different timing), while Roto-Discs occupy platforms that Mario must jump on in order to proceed through the level.

## 19) World 1 Fortress

The Fortress marks the first in-level appearance of the Fire Flower. This is significant as there are no regular enemies in the Fortress that can be defeated with Fire Mario’s fireballs. This is a tactic that’s used multiple times in the game, but because powerups carry over from level to level and it’s always adventagous to be in “big” Mario mode, it never feels like a handicap.

## 20) World 1 Fortress

If the player chooses to trade in the Fire Flower for a Super Leaf, he can discover another secret in the sky. This is hinted at by the open ceiling and — if the Dry Bones is temporarily dispatched with a stomp — a runway right next to it. This particular secret leads to a Warp Whistle, and is much more intuitive than the obscure duck-on-a-white-block-for-an-extended-period-of-time maneuver required to get the first whistle.

## 21) World 1 Fortress

The first door the player encounters leads him to a room with a spiked ceiling. The ceiling starts to descend as soon as the player enters the area, but he is also shown a gap that might keep Mario safe. With no other options in sight, it’s natural for most players to strive to reach it before the ceiling crushes them.

When the ceiling drops down all the way, it begins to recede and Mario is forced to jump over a bottomless pit. There is no second hiding spot in sight, so the player has to trust the game to provide one for him. This creates tension and forces the player to perform a leap-of-faith, but he’s ultimately saved by a final tiny gap (much smaller in width and height than the first one) at the end of the area. The gap is located next to a wall so it’s fairly easy to get into it, but its small size makes the whole sequence feel like a nail-biting escape.

## 22) World 1 Fortress

The Fotress level ends with a boss battle against Boom Boom, an enemy that needs to be stomped three times before being defeated. If the player still possesses the Fire Flower, he can also dispatch him with its fireballs.

When Boom Boom perishes, he drops a “?” Ball that ends the level when touched, adding to the “specialness” of the Fortress level.

## 23) World 1-5

In case the player never discovered that he could slide down slopes to take out enemies back in World 1-2, this level does it for him.

Unlike all the other stages, it begins with Mario on a slope already in a butt-scoop position. He then proceeds to barrel through some Buzzy Beetles that just happen to be climbing up the hill.

This not only shows the mechanic, but also displays its usefulness. In addition, sliding is pretty much a universally fun activity, and its presence is another incentive for the player to experiment with the moveset.

## 24) World 1-5

The level contains another Fire Flower that allows the player to test out the enemies, but it’s only accessible after the section pictured above. This is notable due to the pipe that hosts a Piranha Plant located close to the ground, making it likely that the player will stop and wait for the plant to recede. During this interval, an approaching Buzzy Beetle will prevent Mario from running through the opening.

When the Buzzy Bettle finally reaches Mario, the player will likely jump on top of it, learning that the beetles’ shells act much like those of the turtles. At this point, the careening shell will have a high chance of taking out the Piranha Plant as it comes out of the pipe, teaching the player another useful combat mechanic.

## 25) World 1-5

And in case the player missed the pink Jump Block in World 1-3, he gets another chance to discover it here.

Walking up slopes is never fun so the player is encouraged to jump through the area, and in the process possibly bump into the invisible Jump Block. As usual, the pink Jump Block leads to a Coin Heaven area where — once again — he can discover extra coins and a 1-Up if he uses it as a runway.

## 26) World 1-6

Although this level is not autoscrolling like World 1-4, it’s similarly devoid of a floor. This creates some interesting airborne hijinks with the red Koopa Troopas that do not walk off of platforms by themselves.

As shown in the above example, it’s very easy to start off the level by stomping a Koopa Troopa and sending its shell flying to the right. In turn, the shell will fall off the platform, travel through empty space, land on another platform, and eventually take out another Koopa Troopa that patrols it.

## 27) World 1-6

Unlike the floating platforms in World 1-4, these ones are attached to a thin path and are buffeted by end pieces. This allows the player to easily guage the platform’s movement and plan his jumps accordingly.

The first platform is introduced with no enemies in sight, but the second one runs head-first into a Koopa Paratroopa. Also, its path doesn’t contain an end piece, forcing it to eventually fall off the path itself. This in turn forces the player to quickly jump to a nearby platform.

## 28) World 1-6

More opportunities for mid-air stunts are presented via the flying red Koopa Paratroopas. By the time the player encounters them, he’s more than familiar with the mechanic of clipping the wings of enemies and sending them plummeting to the ground.

Since there’s never any solid ground below these turtles, the stomped Koopa Paratroopas simply fall to their deaths. This creates some rather satisfying scenarios where the player can kill two birds with one stone: dispatch an enemy and make a piggy-back jump onto a new platform.

## 29) World 1-6

The area above is a runway, but it’s punctuated by a single gap that slightly drains the run meter. If the player jumps onto it while running from a previous platform, though, he retains part of the run-charge and is able to take off into the air.

A path of coins beyond the platform shadows Mario’s flight arch, and when he finally floats down, he’s safely deposited on a moving platform.

## 30) World 1 Airship

The airship levels start off with a short cutscene of Toad pleading for help and Mario heroically leaping onto a moving airship in pursuit of Bowser’s minions.

Like all “artillery” stages, the level auto-scrolls and is filled with unique enemies such as Cannonballs and Bullet Bills. This approach makes it feel almost like a shmup as the player is forced to concentrate on avoiding multiple projectiles while waiting for the end-segment to scroll into view.

However, unlike most shmups, Mario has to deal with gravity, the movement of the ship, and the cramped architecture. This makes avoiding bullets much harder, but also steers the player into making another discovery: not only can Mario kill the projectiles by jumping on them, they can also perish if they touch his feet (even while he’s standing still). A single Fire Flower stresses this point as all the enemies in the level are invulnerable to its fireballs.

When the end-boss is defeated, the significance of the level is further accentuated by a series of events: Mario grabs the stolen Magic Scepter , jumps down to the ground, cures the king, receives a congratulatory message, and finally reads a letter from Princess Peach that comes packaged with a powerup.

Super Mario Bros. 3 contains many obvious design lessons that are also present in other games, e.g., the gradual layering of complexity that allows players to master a specific mechanic. What surprised me during my playthrough, though, was how some of these lessons were completely optional.

For example, it’s possible to send a turtle shell skittering in the opposite direction of destructible bricks, or to take the cloud-route and skip certain powerups and interactive objects. Of course these same lessons are repeated multiple times, but they’re not always as heavily hinted.

Personally, this hits a sweet spot for me. The game doesn’t have any forced hand-holding, and it isn’t afraid of the player simply exploring it at his own pace (even if it means circumventing chunks of the experience). This approach also serves to encourage multiple replays, and — back during SMB 3’s initial release — it probably sparked many playground discussions.

Note: This article was originally published on the author's blog, and is reproduced here with kind permission.  Check out his work at Incubator Games

Full Series:
Super Mario Bros Level Design Lessons, Part 1
Super Mario Bros Level Design Lessons, Part 2
Super Mario Bros Level Design Lessons, Part 3

Report Article

## User Feedback

I love this game, and I will be looking forward for the part 2. This was a great analysis.

##### Share on other sites

Posted (edited)

Reminds me of the Extra Credits, on YouTube, series on the same subject.

Edited by Navyman

## Create an account

Register a new account

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 0
• 0
• 4
• 3

• 14
• 30
• 9
• 16
• 22
• ### Similar Content

• By Pepsidog
I'm wanting to create a hybrid game between turn based and action.  I'm looking to create a system where the player has a list of attack or move options on their turn, but I want to add a skill minigame in order to make the game more engaging for non-strategists.  I figured some sort of minigame or something.  Any ideas are welcome.  Thanks in advance!

You are leading a team of a handful of programmers and artists to port a good-looking PS4 VR game to Oculus Quest. You have six months to complete it. Well? What's your first move? Let's bring Unity Addressables to the table.
You do realize you have to tackle quite many challenging tasks at once. I bet some might be personally more concerning than others, depending on your expertise level in each area. If you had to pick one that robbed your sacred sleep the most, which one would it be?
My initial guess would be this: above 70% of the readers would say CPU/GPU performance is the biggest concern when porting a title to Quest. And to that I say: you can very well be right. Performance is one of the toughest areas to improve on in a VR game. For optimizations of this kind, you require in-depth knowledge about the product, which is a time intensive process. Sometimes you even cannot just optimize further, which usually ends in dropping expensive gameplay or graphics features. And not meeting people's expectations is a dangerous place to be.
Performance, performance, performance.. The word might let some chills go down your spine. What can you expect in this regard from the Quest platform? How does it perform? The thing is, if you have had some development experience in it, you will probably know that in spite of being mobile hardware, it is astonishingly powerful.
But Ruben! Don't give me that crap. I tell you my phone slows down significantly the time I open a second browser tab. How dare you say mobile platforms can be so performant?
I read your mind, didn't I? The massive difference lies on Quest's active cooling system, which gives it a huge boost on its attainable CPU/GPU hardware levels that no other mobile platform can offer. It is a powerful fan that will prevent your hair from gathering dust and avoid melting the CPU together with your face (the GoT crown scene comes to mind).
Additionally and on the side of the Quest software, the more specialized OS is better optimized for virtual reality rendering (surprise) than the generic Android variant. Mobile hardware has been catching up with standalone platforms so quickly in the last few years.
But, at the same time, I cannot deny that our task of constantly rendering at 72 fps will prove to be challenging, especially for VR ports coming from high-end platforms. To be more precise, when we talk about the Oculus Quest, you have to picture yourself a Snapdragon 835 with a screen, a battery, four cameras and a fan.
What could look like a disadvantage can actually be thought of as an edge. This mobile platform is a well researched piece of s*** hardware. One can say there are a myriad of known tricks you can pull off to quickly reduce the CPU and GPU load up to an acceptable point. If it is of your interest, you will be able to read about it in upcoming posts. As of now, we will take performance out of the equation for this post.
What might catch your attention in our challenge is that, compared to the PS4, there is a single hardware characteristic literally halved on the Quest: the RAM capacity. That's right, we go from 8 to 4GB RAM. This is an approximation since, in both platforms, the operating system does not allow you to use it all so it can keep track of a few subsystems for the ecosystem to work. On the Quest you will be able to roughly use up to 2.2 GB of RAM before things get messy.
Ruben, what do you exactly mean by messy? The thing is, proper memory handling is crucial for your game. This is so because you have two constraints:
Hard memory constraint: if you go above a certain threshold, the OS will just kill your game Soft memory constraint: above another certain limit, the OS might decide to kill your game when your user minimizes your game, takes the headset off or you go out of the Oculus Guardian area Obviously, you do not want any of the two to happen in your game. Can you picture an angry player who just lost his last two hours of gameplay? Yes, they will go to your store and nothing pretty will come out of their mouth.

Disgruntled Player - RUN!
The thing is, the guaranteed availability of 2.2GB of RAM is not much, honestly. It's usually not a problem for new projects where you track your stats constantly from the beginning, but it definitely is an issue for a port to a severely downgraded hardware.
If you dealt with similar ports in the past, you will quickly realize how extremely challenging it can become to decrease your game's RAM budget by half. It grandly depends on how well the game architecture was prepared for such a change, but in most cases this will temporally transform you into a tear-producing machine.
The most popular strategies to reduce memory pressure include tweaking asset compression settings, optimizing scripts, reducing shader variants, etc.. Depending on the specifics of your project, tweaking texture import settings is your first go-to solution, but if you need to you can also resort to compressing meshes, animations and audio. The problem is that those techniques are usually complex in nature and will have a ceiling limit.
Not all platforms support the same import settings; targeting several devices will dramatically increase your build pipeline overhead, not to mention QA, art, design and programming complexity. Does this Android device support ASTC, or just ETC2 (if at all)? Oh, we also want to build 64 bit builds, but also keep the players on the 32 bit versions. How many split-APKs should we create, and worse, manage and test, for each update we do on the game? You want to make your life easier, so you should not rely exclusively on these techniques.
We would like to go further. As usual, we want to keep things as simple as possible (TM), especially if you are doing a port. Redesigning the entire game for performance's sake is a worse option than just not porting it. For that matter and in today’s topic, I will offer you one of the biggest gains for the buck: I will show you how to halve a project's memory budget in matter of hours. Boom!
Wouldn't that be awesome?
Go ahead, go ahead... ask me: is it really possible for me? The answer is: it depends on your starting point, but in my experience, YES. Unity Addressables can be of a great value here. The catch? You must be willing to put in the work and to master the process. But this workflow will earn you the title of employee of the month.
If you are interested, keep reading.
In this post you and I will go through the journey of moving from a traditional asset management to an addressables-based asset management system. To illustrate the process,  we will port a simplified old-school project to the new era of Unity Addressables.
Now, you might ask me: why don't you just show me the real-life work you did?
In a non-competitive world I would just show you all the material I created. In the real world though, that is likely to get me canned. And worse, busted.
What I will do instead is to offer you my guidance so you and I iterate on project that absolutely represents the difficulties you could find tomorrow in your next project. And we will do so by first welcoming Unity's Addressables to our family of suggested packages.
In this blog post I will get you started in Addressables ASAP so you can implement your own Unity Addressables system in a matter of minutes.

Time to pay attention to this very important section. Our goal is to diagnose easy memory gains and implement them fast. There are several ways to do this, but one of the most powerful yet simplest methods to pick the low-hanging fruits by loading the initial scene and opening up the profiler. Why this?
Because an unoptimized game architecture can frequently be diagnosed at any point during gameplay, so the quickest way to check this is by profiling the initial scenes. The reason for this is the common over-usage of singleton-like scripts containing references to every single asset in the project just in case you need it.
In order words, in many games there is usually an almighty script causing an asset reference hell. This component keeps each asset loaded at all times independently from whether it's used or not at that time point.
It depends. If your game is likely to be constrained by memory capacity, it is a very risky solution, as your game will not scale with the amount of assets you add (e.g. think of future DLCs). If you target heterogeneous devices, such as Android, you don't have a single memory budget; each device will offer a different one, so you settle for the worst case. The OS can decide to kill your app at any point if our user decides to answer a quick message in Facebook. Then the user comes back and surprise, all their game is gone for good.
How fun is that?
Zero. Unless you are overworked and sleep deprived, situation which might grant you a desperation laugh.
To complicate matters further, if later on you decide (or someone decides for you) to port your game to another less powerful platform while keeping cross-play working, good luck. You don't want to get caught in the middle of this technical challenge.
On the other side, is there a situation where this traditional asset management solution works just fine? The answer is yes. If you are developing it for a homogeneous platform such as PS4 and most requirements are set from the beginning, the benefits of global objects can potentially outweigh the extra added complexity of a better memory management system.
Because let's face it: a plain, good old global object containing everything you need is a simple solution, if it works well enough for you. It will simplify your code and will also preload all your referenced assets.
In any case, the traditional memory management approach is not acceptable for developers seeking to push the boundaries of the hardware. And as you are reading this, I take you want to level up your skills. So it is time for just doing that.

Requirements for our Unity Addressables project
If you are planning on just reading this blog entry, your screen will suffice. Otherwise, if you want to do this along with me, you will need:
Functional hands Overclocked brain Unity 2019.2.0f1 or similar The level 1 project from GitHub (download zip or through command line) Willingness to get your hands dirty with Unity Addressables The git repository will contain three commits, one per skill level-up section in the blog (unless I messed up at some point, case in which I will commit a fix).

Level 1 developer: Traditional asset management
We are starting here with the simplest asset management method here. In our case, this entails having a list of direct references to skybox materials in our component.
If you are doing this with me, the setup is a simple 3 step process:
Download the project from git Open the project in Unity Hit the damn play button! Good, good. You can click a few buttons and change the skybox. This is so original... and boring. I take it, no Unity Addressables yet.
In a short moment you and I will see why we need to endure this short-lasting boredom.
To start with, how is our project structured? It pivots around two main systems. On the one side, we have our Manager game object. This component is the main script holding the references to the skybox materials and switches between them based on UI events. Easy enough.
using UnityEngine; public class Manager : MonoBehaviour { [SerializeField] private Material[] _skyboxMaterials; public void SetSkybox(int skyboxIndex) { RenderSettings.skybox = _skyboxMaterials[skyboxIndex]; } } The Manager offers the UI system a function to apply a specific material to the scene settings through the usage of the RenderSettings API.
Secondly, we have our CanvasSkyboxSelector. This game object contains a canvas component, rendering a a collection of vertically-distributed buttons. Each button, when clicked, will invoke the aforementioned Manager function to swap the rendered skybox based on the button id. Put in another way, each button's OnClick event calls the SetSkybox function on the Manager. Isn't that simple?
Once we're done daydreaming how immersive it was to play X2, it's time to get our hands dirty. Let's launch the multisensory experience and open the profiler (ctrl/cmd + 7; or Window - Analysis - Profiler). I take you are familiar with this tool, otherwise you know what to do with the top record button. After a few seconds of recording, stop it and see the metrics for yourself: CPU, memory, etc.. Anything of interest?

Performance is pretty good, which is nothing surprising considering the scope of the project. You could literally turn this project into a VR experience and I assure you that your users will not fill any of the bile buckets that so many players filled when playing Eve: Valkyrie.

In our case, we will be focusing on the memory section. The simple view mode will display something as depicted below:
Level 1 Asset Management - Simple Memory Profiling
The numbers on the texture size look pretty oversized for just displaying a single skybox at any given time, don't you agree? Surprise incoming: this is the pattern you will find in many unoptimized projects you are likely to suffer lead. But heck, in this case it's just a collection of skyboxes. In others, it will be more about characters, planets, sounds, music. You name it, I have it.
Time for magic. Let's switch the memory profiler to detail mode. Have a look!
Level 1 Asset Management - Detailed Memory Profiling
Holy crap, what happened there? All skybox textures are loaded in memory, but only one is displayed at any given time. You see what we did? This rookie architecture produced the whoooooooping figure of 400mb.
This is definitely a no-go, considering this is just a small piece of a future game. Addressing this very problem is the foundation for our next section.
Come with me!
Summary:
Traditional asset management entails direct references Therefore you keep all objects loaded at all times Your project will not scale this way
Level 2 developer: Unity Addressables workflow
In video- games you start at level 1, which is great, but once you know the gameplay rules it is time to leave the safe city walls in our quest to level up. That is exactly what this section is about.
Grab the level 2 project now.
As we previously saw in the profiler, we have all skyboxes loaded in memory even though only one is actively used. That is not a scalable solution, as at some point you will be limited on the amount of different variations of assets you can offer to your players. An advice? Don't limit the fun of your players.
Here, let me help you. Take my shovel so we can dig the so needed tunnel to escape the prison of traditional asset management. Let's add a new fancy tool to our toolbox: the API of Unity Addressables.
The first thing we need to do is to install the Addressables package. For that, go to Window → Package Manager, as shown below:

Unity Package Manager - Unity Addressables
Once installed, it's time to mark the materials as addressables. Select them and activate the addressables flag in the inspector window.
Level 2 Asset Management (Unity Addressables)
What this will do is to ask Unity politely to include those materials and their texture dependencies in the addressables database. This database will be used during our builds to pack the assets in chunks that can easily be loaded at any point during in our game.
I'll show you something cool now. Open Window → Asset Management → Addressables. Guess what's that? It's our database screaming to go live!
Level 2 Asset Management (Unity Addressables) - Main Window
My dear reader: that was the easy part. Now comes the fun part.
I want you to pay a visit to an old friend of ours from the previous section: Sir Manager. If you check it, you will notice it is still holding direct references to our assets! We don't want that.
We are teaching our manager to use indirect references instead - i.e. AssetReference (in Unreal Engine you might know them as soft references).
Let us do just that, let's beautify our component:
using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class Manager : MonoBehaviour { [SerializeField] private List<AssetReference> _skyboxMaterials; private AsyncOperationHandle _currentSkyboxMaterialOperationHandle; public void SetSkybox(int skyboxIndex) { StartCoroutine(SetSkyboxInternal(skyboxIndex)); } private IEnumerator SetSkyboxInternal(int skyboxIndex) { if (_currentSkyboxMaterialOperationHandle.IsValid()) { Addressables.Release(_currentSkyboxMaterialOperationHandle); } var skyboxMaterialReference = _skyboxMaterials[skyboxIndex]; _currentSkyboxMaterialOperationHandle = skyboxMaterialReference.LoadAssetAsync(); yield return _currentSkyboxMaterialOperationHandle; RenderSettings.skybox = _currentSkyboxMaterialOperationHandle.Result; } } What happens here is the following:
Keep in mind: this code is not production-ready. Do not use it when programming an airplane. I decided to favor simplicity over robustness to keep the matter simple enough.
Enough with explanations. It is time you and I saw this in action.
If you would be so kind to perform the following steps:
In the addressables window, cook the content (build player content) Then make a build on a platform of your choice Run it and connect the (memory) profiler to it. Protect your jaw from dropping.
Level 2 (Unity Addressables) - Build Player Content
Level 2 Asset Management (Unity Addressables) - Memory Profiler
Isn't asset cooking delicious?
I like happy profilers. And what you saw is the happiest profiler the world has ever seen. A satisfied profiler will mean several things. For one, it means happy players playing your game in a Nokia 3210. It also means happy producers. And as of you, it means a happy wallet.
This is the power of the Addressables system.
Addressables which comes with little overhead on the team. On the one side, programmers will have to support asynchronous workflows (easy-peasy with Coroutines). Also, designers will have to learn the possibilities of the system, e.g. addressable groups, and gather experience to make intelligent decisions. Finally, IT will be delighted to set up an infrastructure to deliver the assets over the network, if you opt to host them online.
I have to congratulate you. Let me tell you what we have accomplished:
Appropriate memory management. Faster initial loading times. Faster install times, reduced in-store app size. Higher device compatibility. Asynchronous architecture. Opening the door of storing this content online → decoupling data from code. I would be proud of such a gain. It's for sure a good return on investment.
Oh, and make sure to mention your experience with Addressables in job interviews.

INTERMEDIATE: Instancing and reference counting. Read on it my blog post for information on this topic.

Summary:
Addressables-based asset management scales just well Addressables introduces asynchronous behavior Do not forget to cook content on changes or you'll give your game a pinkish tint!

Level 3 Asset Management (??) - Content Network Delivery
Level 3 Asset Management (??) - Content Network Delivery
In the previous section, we achieved the biggest bang for the buck. We leveled up our skills by moving from a traditional asset management system to an addressables-based workflow. This is a huge win for your project, as a small time investment gave your project the room to better scale in assets while keeping your memory usage low. That accomplishment indeed made you step up to level 2, congrats! However, one question is yet to answer:
Is that it?
No. We barely scratched the surface of Addressables, there are further ways to improve your project with this game-changer package.
Of course, you do not have to memorize all the details regarding Addressables, but I highly suggest you to have an overview of them because down the road you are likely to encounter further challenges and you will be thankful to have read a bit further. That's why I prepared an extra short guide for you.
There you will learn about the following aspects:
The Addressables window: the details matter Addressables profiling: don't leak a (memory) leak ruin your day Network delivery: reduce the time-to-play user experience Build pipeline integration Practical strategies: speed up your workflow, trash your 10-minute coffee breaks
And more importantly, answer questions such as:
What is the hidden meaning behind Send Profiler Events? How useful is the AddressableAssetSettings API? How do I integrate this all with the BuildPlayerWindow API? What's the difference between Fast Mode, Virtual Mode and Packed Mode? In order to grab the level 3 guide check out my blog post
• By Ey-Lord
Hello everyone

I am here to gather your opinion, remarks, ideas or any constructive criticism you may have about what I am going to present. Don’t be shy!

A bit of background:

I am working alone on an indy web-based game, a simulation of RPG (idle game) where the player controls a group of 4 characters that he can sent into battle and that will fight automatically based on some AI preference that are similar to the FF 12 system (but more complex / powerful). He then earns some experience and resources that he can use to improve his unit’s gear, talents and skills. He has a lot of control on what skills his characters will use and how/when.

What brings me here today:

The AI of Monsters. I have the AI settings for players covered (basically a bunch of if/then/and/or/else settings that he can combine and order so that his units will act as he intends in battle). I’ve been working on the AI of monsters for quite some time, made a long break and came back recently to it.

Short description of the battle system:

No movement involved. Battle is fully automated. Players setup its units AI settings before battle and monsters are controlled by a separate AI. This is a 4v4 battle, like FF7 with some kind of ATB and any time a unit fill its ATB, it can play and the then the next unit who will fill it will play, etc. The player is completely free of his playstyle and may create very offensive group or very defensive ones. 4 healers or 4 tanks is completely possible.

The battle system is very complex and allows for very varied and sometimes unusual strategies, like killing your own allies to proc an “on death buff” that will be devastating for the opponent.

What I want for my AI?

It needs to be fun to fight against and challenging. Ideally, I would like an AI as smart as possible (not omniscient but thinking as a human would). I know that a super-smart AI is not always the best way to make a game fun or challenging but in the context of my game, this is the result I want to achieve. It may seem unfair to have the AI try to kill your squishy while your tank is standing right there but my class design gives the tools to players to counter that so it’s not an issue (tanks are not purely aggro based for example). I want players to always be challenged by AI moves and that they must carefully think about their strategy because if they leave a big hole in it, I want the AI to exploit it.

In practice, it means a few requirements:

No dumb decision / do not fall into obvious player’s traps Exploit obvious flaws of the opponent Act in coordination when appropriate with other units Able to find who should be their focus in the player’s team (some notion of threat) Find the best move to use and if there is some kind of combo possible, use it

These requirements are harder to meet than it looks. The issue is the sheer number of different mechanisms and strategies available to players and to monsters as well. For example, there are many cases where killing or attacking a player unit might be detrimental (units that return damages or that gain power when you hit then for example).

What I have tried before?

I have tried or at least reviewed many different AI concepts so far.

-          A simple copy of my player’s AI system (hierarchical if/then/else). It was easy to script as I already have the UI in place for players so I can quickly define a basic AI for any new monster’s group. The main drawbacks are that it needs to be written for every monster group, it does not allow smart targeting and cannot find the best target or the best skill to use. It will also make dumbs decision as the targeting options cannot assess threats at all.

I’ve rules out planners since for purely selecting the best pair of (skill, target), they do not seem to match my needs.           (H)FSM or BT does not seems to match my needs as monsters do not have states / transition condition that can lead to something useful for me.        I’ve ruled out aNNs as they might, with proper training, be able to find the best action at a given time but it’s very tedious to implement and will not solve my need of finding combo or coordinating with other units very well. (plus, let’s be honest, I’d be a bit out of my depth to program them)           I have spent an extensive period of time trying with tree searches. Mainly: monte-carlo with random sampling and came to the conclusion that due to the complexity of my battle system, it is excessively costly to compute any kind of reliable data this way.
-        My current AI system is a version of my first one (the same as the players) but with access to some “smarter” targeting function that in theory allow to choose the best target. These functions work by gathering data for thousands of simulated fights during the AI time to play (1 second). It’s a first step to find the best target but not very accurate (lots of big flaws that can be exploited by players) and it is very time consuming and that is something I’m trying to get away from. I do not want to use 100% of the players CPU as I do now.

What is my latest idea?

I started to study more in-depth the Utility theory as described by Dave Marks (I read his book and watched his GDC AI lectures as well). I liked the idea. I like that I can start on something relatively simple and add more considerations as things progress to handle more and more situations. While my work began as something very close to utility theory, it evolved a bit afterward. Here is what I plan on doing to compute a unit’s best course of action:

A – Score every of its move (each move is a pair [skill, target]).

B – Chose the move according to a selection strategy (highest score, weighted random, random amongst the top scores… lots of different selection algorithm can be used there).

So far, easy, right? Let’s dig deeper into our first phase of scoring (A), which is the hard part. For all the damage or healing skills:

Step 1: The final scoring of the move [skill,target] will be function of the a “Survival” scoring for the player team and for the enemy team. An example of this relationship could be: Adding all the survival scores of each unit in Team A and divide the result by the addition of all the survival scores for each unit in team B.

Step 2: The survival score of each unit will be its Health after the move we are evaluating, divided by the total damage per turn that we estimate other units can deal to her (minus the total heal it ca receive). [This a step where we can process damage and heal over time as well]

Step 3: This damage per turn estimation will be, initially, the sum for every unit in battle of the damage or heal per second it can deal to that unit. For example: If I’m alone vs 2 bad guy that can deal 1 dmg/turn and if I can deal 1 heal/turn, the damage per turn estimation against me will be 2-1 = 1. [This is not optimal since we are counting the damage of each unit once per enemy unit but it’s a start]

Step 4: To compute the DPS or HPS of each unit, we review the unit’s skills and compute their output against the unit we want to evaluate it against. From that, we construct a skill sequence to maximize the damage output and once we got the optimal skill sequence, we can compute its DPS or HPS output and pass it along for Step 3.

It might seem like a lot of work, since, in a world with only damage or healing skills, the DPS or HPS sequence of each unit will be the same in every situation and as such only the damage done or healing done by the skill evaluated would be enough. But…

The tricky part comes from buffs and debuffs. If we use the above algorithm, (de)buffs that changes the damage or healing someone does or receive will be evaluated correctly as it will change the damage or heal per second output of units and it would affect the survival score and the final scoring. That is why I chose to include DPS and HPS computations for each unit for each move.

This is all fine until we consider (de)buffs that changes the power of other (de)buffs. Like: I cast a buff that double the length of all my future buffs. My algorithm can’t evaluate it correctly. It’s a situation that will be common enough in my game and I want my AI to deal with it. Note: there are more complex situations where a unit could buff a buff that buffs a buff that buff a buff [….] that will end-up buffing a damage or healing skills, but those cases will not be addressed as they will hopefully be rare and too cumbersome to compute anyway.

So, my goal is to score properly buffs that:

Buffs the damage or healing output of someone           Buffs that buffs a skill that does the above

L    Long story short of how I am doing that. I’m using my initial algorithm but while also estimating damage or healing per second change for each dps or hps sequence.To do that I’m evaluating every move of the unit (or every unit in case of AoE but lets keep it simple with single target) that is targeted by the buff. So, we are switching PoV here compared to the initial unit we are evaluating (unless the move evaluated is buffing itself)

-          I’m doing the above in 2 situations:

o   A : After a cast of the buff skill I’m evaluating

o   B : Without the cast of the buff, just like if it was that unit’s turn to play

-          Using a sort of min/max approach: if the unit targeted by the buff is an ally, we will take the best branch of our tree in A and compare it with the same branch (pair [skill,target]) in B. If the unit targeted by the buff is an enemy, we want to lower their maximum score and will select the tree branch that does that in A to also compare it with the same branch in B.

-          The information we extract here are DPS or HPS delta for each sequence of DPS/HPS for each unit vs each other unit.

-          Then, we go back to our steps 1 to 5 and compute our scoring for the move (buff) while using our new dps/hps deltas to get better and more accurate dps/hps sequence for units affected by the buff.

This is basically it. I’ve ran a manual version of the algorithm in 2 different battle settings to test it and see if it gave good results. It worked. Not flawlessly but it worked. Lots of cases will still require tweak and additions to the basic idea but I think its promising. (taunts and CCs are not easy to deal with but it’s manageable)

What I like is that I can add more considerations later (as in the utility theory) like: resource cost, general unit strategy (cleave or focus), behavior (careful, lunatic, reckless). While this will still be a bit time consuming it should be a good order of magnitude faster than my current AI. It also does not prevent me from adding hardcoded AI move if I want to “script” more some monsters. Debugging and tweaking might be a bit painful though, especially when fights will involve lots of skills & stats but that’s an issue that most AI for my game would likely have anyway.

To come back with my initial goals:

No dumb decision / do not fall into obvious player’s traps
o   Not perfect but it should choose the best target whenever possible

Exploit obvious flaws of the opponent
o   Same as above

Act in coordination when appropriate with other units
o   This can be done simply by adding weight to some targets or computing moves for all units of a group before deciding which one to take (for example to take the best move vs a specific unit, on average)

Able to find who should be their focus in the player’s team (some notion of threat)
o   It will naturally focus the unit who is the easiest to kill and debuff or CC the ones that deal the more heal/damage. But, to better solve this, we will need to add other considerations to the AI scoring process, It should not be *too* hard

Find the best move to use and if there is some kind of combo possible, use it
o   Combo are very often in the form of buff/debuff setup before an actual damaging or healing skills and my AI can compute up to a 3 moves combo (buff > buff > skill that dmg or heal) which should cover most cases.

I’m quite happy with my initial tests. I’m not going to be coding it now. My goal was to reflect on the subject on paper and try to see if designing my AI would be a roadblock or not for my project. There are a few other area I want to design and take time to really think about before getting back to my project full time. I’d love to hear your toughs and feedbacks about my AI ideas. Do you see huge roadblocks I’m missing? Does it sound ok to you?

If you read that far…. thank you and I can"t wait to hear from you guys😊

• By G-Dot
Hello everyone! I've decided to implement a destructible enemies system.

Description:
When bullet hit enemy in specific part of his body(arm fo example) armour, which covers that part of body, will fall off. Enemies in my game are robots so this means that when shooting them certain plates of their armour will fall off. All enemies will have a different amount of armour plates

My solution:
The only solution I came up with is to make an actor with a static mesh and attach it to the bones of enemy's skeletal mesh. When bullet hit that actor it detaches and fly away with add impulse node.

Question:
Maybe there is a better solution, which I'm missing and it's more efficient.
• By mujina
What could be a way of avoiding using inheritance and virtual methods when designing components for an entity-component-system?
I'll be more specific about my design issue:
I currently have different classes for different kinds of colliders (let's say, CircleCollider and LineCollider).
My system that checks for collisions and updates the positions and/or velocities of my entities should be something like:
for entity_i in alive_entities { collider_i = get_collider_of_entity(entity_i) // components of same kind are stored contiguously in separate arrays transform_i = get_transform_of_entity(entity_i) for entity_j in alive_entities { collider_j = get_collider_of_entity(entity_j) transform_j = get_transform_of_entity(entity_j) if check_collision(collider_i, collider_j) { update(transform_i) update(transform_j) } } } my problem is that I don't have a generic get_collider_of_entity function, but rather a function get_circle_collider_of_entity and a separate one get_line_collider_of_entity, and so on. (This happens because under the hood I am keeping a mapping (entity_id -> [transform_id, sprite_id, circle_collider_id, line_collider_id, ...]) that tells me whether an entity is using certain kinds of components and which are the indices of those components in the arrays containing the actual components instances. As you can see, each component class is corresponding to a unique index, namely the index position of the array of the mapping described above. For example, transforms are 0, sprites are 1, circle colliders are 2, line colliders are 3, and so on.)
I am in need to write a system as the one in the snippet above. I can write several overloaded check_collision functions that implement the logic for collision detection between different kinds of geometric primitives, but my problem is that I am not sure how to obtain a generic get_collider_of_entity function. I would need something that would get me the collider of an entity, regardless of whether the entity has a circle collider, a line collider, a square collider, etc.
One solution could be to write a function that checks whether in my internal entity_id -> [components_ids] mapping a certain entity has a collider at any of the indices that correspond to colliders. For example, say that the indices related to the collider classes are indices 10 to 20, then my function would do
get_collider_of_entity (entity_id) { for comp_type_id in 10..20{ if mapping[entity_id][comp_type_id] not null { return components_arrays[comp_type_id][entity_id] } } return null } This could turn out to be pretty slow, since I have to do a small search for every collider of every entity. Also, it may not be straightforward to handle returned types here. (I'm working with C++, and the first solution - that is not involving inheritance in any way - would be returning a std::variant<CircleCollider, LineCollider, ... all kinds of components>, since I would need to return something that could be of different types).
Another solution could be having some inheritance among components, e.g. all specific component classes inherit from a base Collider, and overrride some virtual collide_with(const Collider& other) method. Then I would redesign my mapping to probably reserve just one index for colliders, and then I would actual colliders in a polymorphic array of pointers to colliders, instead of having a separate array for CircleColliders, another for LineColliders, and so on. But this would destroy any attempt to be cache-friendly in my design, wouldn't it? That's why I am looking for alternatives.
A third alternative would be to just have a single, only, Collider class. That would internally store the "actual type" ( aka what kind of collider it is ) with dynamic information (like an enum ColliderType). Then I would have all colliders have all members needed by any kind of colliders, and specific collision detection functions which I can dispatch dynamically that only use some of that data. (Practical example: a "Collider" would have a radius, and the coordinate for 2 points, and in case its type was "circle" it would only make use of the radius and of one of the 2 points - used as the center -, while if it was a "segment" it would only make use of the 2 points). My gut feeling is that this would bloat all colliders, and, even if the bloat could be reduced - using unions in some smart way for storing members? I wouldn't know how -, then still the design would be pretty brittle.
I'm clueless and open for ideas and advice! How do you handle in general situations in which you have components that can be naturally modeled as subclasses of a more generic component class? Inheritance? Smart hacks with variants, templates, macros, custom indexing? Dynamic "internal" type?
×