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

Game Design and Theory

For my second SMB 3 post, I took a look at worlds 2 through 8 and picked out 30 stages that exemplified clever level design. World 8 is the last standard zone in the game, but I decided to write one more article detailing SMB 3’s hubs.

The unique piranha nodes lead to stages filled with venus fly traps and an end-level treasure.

Hubs are an old video game trope, but in SMB 3 they are much more involved than in previous incarnations.

Each hub in the game has its own visual theme and unique layout, e.g., World 7 is a scrolling archipelago, while World 8 comprises multiple skull-filled maps. These areas are not only littered with standard level nodes, but also contain unique stage-icons such as quicksand pits, tanks, and piranha plants. Offsetting these challenges are shops and sporadic minigames that provide bonus rewards.

All these elements — and plenty of additional ones — turn the overworlds into individual mini-levels that are also connected to the main gameplay stages. Here are 10 examples of how that’s done:

## 1). Pipeline Shortcuts

Entering pipes on the hub transports Mario to tiny, single-screen levels. These levels contain no enemies and simply serve to ferry Mario from one point on the overworld to another. The game could’ve simply teleported Mario on the hub and avoided this element altogether, but it accents the link between the hubs and the main gameplay stages. It also serves to cement an internal logic that pipes are gateways anywhere in Mario’s universe.

In addition, pipe detours can facilitate alternate routes through the hubs, allowing the player to skip entire batches of levels. This approach of making stages optional is something that became more and more prevalent in each Mario sequel. The notable point here is that it allows the designers to isolate the more challenging levels so that fewer players ever get stuck.

## 2). Wandering Enemies

Adding a bit of life to the hubs are various types of Hammer Bros. that move around non-level nodes whenever the player exits a stage (by either completing it or dying). Stepping on a node occupied by Hammer Bros. teleports Mario to a single-screen arena where a battle ensues.

Defeating the Hammer Bros. yields a random power up from a set different than that of the stores, e.g., the player can receive a Starman or a Hammer.

The Music Box power up can also put all the Hammer Bros. to sleep, allowing the player to safely pass across the nodes they occupy.

## 3). Fortress Destruction

Beating the mini-boss Boom Boom releases a “?” Ball that, when touched, destroys his home. This is a nice connection to the hub itself as the fortress blows up when Mario exits the level, clearly linking the two events. This is the only way to get past a Fortress Node as it’s not possible to fly over it with Lakitu’s Cloud.

This sort of hub-updating is common to completing non-standard levels, e.g., blocking doors are removed and bridges are lowered to allow passage.

## 4). Hand Traps

Hand Traps are special nodes located in just a single part of World 8. They can randomly drag the player into a level whenever he walks over them, adding variety to the overworld’s mechanics. This event is accompanied by an animation of a large hand pulling Mario down, further emphasizing the link between the hubs and the stages.

Collecting all the coins in certain levels unlocks a special blue (white in the original) Toad House on the hub. Unlike the standard houses, these only contain a single chest that yields either a P-Wing or an Anchor.

Aside from providing an optional challenge and an extra reward, the bonus houses are another great link between the core stages and the overworlds.

## 6). Destructible Obstacles

Various hubs contain rocks that the player can destroy using a hammer. These usually open up a path to an extra reward or serve as shortcuts that allow the player to skip some levels.

This sort of interaction with the environment prevents the hubs from feeling static, and World 2 actually uses the mechanic to hide a secret!

If the player uses the hammer in the top-right corner of the map, he’ll open up an additional path to a Hammer Bros. duo that drops a Warp Whistle. There’s no obvious hint of this secret as there are plenty of rocks in the level and the map doesn’t scroll to reveal the path until the rock is destroyed. Despite this, it’s a very satisfying secret to discover with an equally worthwhile reward.

## 7). The Canoe

World 3 allows Mario to hop in a canoe as an alternative mode of transportation. The canoe moves gradually instead of jumping from node to node, and it allows the player to visit an island filled with power-ups and mini-games.

Aside from breaking the monotony of traversing hub-nodes on foot, the canoe can also be used to navigate to a second, secret island that holds another Toad House.

## 8). Airships

Each airship in the game represents the last levels of a world (except World 8). If the player fails to finish the level on his first try, the airship will randomly travel to another node on the hub. This effectively makes the player chase the last level, which is a novel and amusing conceit.

This mechanic can also cause a few headaches as the ship can move to locations hidden behind Hammer Bros. or unfinished stages, but this can be avoided with the anchor power up.

In either case, the airships add life to the hub and also have coin-filled counterparts that act as another fun reward.

## 9). The Tower (of Babel?)

World 5 is actually composed of two different hubs linked together by a rather clever gateway.

The first hub is a typical grassland with a few clouds on its lower-right side and a spiral tower that takes Mario to a largely vertical level. Climbing the tower to the top and activating a Beanstalk deposits the player in the second hub: the cloudy sky. This hub turns out to be a large cloud-kingdom that contains even more levels and a miniature version of the previous hub in its top-left corner!

It’s also possible to travel between the two hubs — and necessary if an airship moves from one to another — although the tower needs to be traversed each time going up.

The visual link between the two hubs is a small, aesthetic touch, but it fits perfectly with the in-game logic and Mario’s penchant for cloud-platforming.

## 10). World 9

Finally, the warp zone itself is presented as a hub, World 9.

The warp zone allows the player to skip entire worlds, but it’s not implemented as a custom piece of UI. Instead, it’s a meta-world of sorts, beyond the regular worlds yet connected to them. This anchors the warp zone to the in-game universe and utilizes an existing interface that’s familiar to the player.

SMB 3’s hubs might not be the game’s most defining feature, but they help tie together its various components into a cohesive whole. Consequently, the hubs are much more than just abstract menus; they’re part of a larger, interconnected picture that’s fun to explore.

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

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

Report Article

## User Feedback

There are no comments to display.

## 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!

• 3
• 0
• 4
• 0
• 3

• 12
• 30
• 9
• 16
• 12
• ### Similar Content

• 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?
×