Posts

YEAHBOI! The dopest guide to three.js


yeahboi-screen

There are dozens of really creative projects that demo what's possible with threejs, my favorites include ddance party, Jello Mario, and [adult swim] apps. These games radiate the avant-garde weirdness of the early internet Flash Renaissance.

YEAHBOI is another "inspired" work. The original host served from yeahboi.me is down, but the author open sourced it, so I can host it myself and carry the torch (sound probably won't work in chrome).

Recreating YEAHBOI is a great way to introduce threejs: it only consists of rectangles, some gravity, and a looped soundtrack. Here I'll show you how easy it is to hack a three.js game together, the intent being an example of fast and cheap 0-60 coding in threejs; not necessarily a stable, scalable, or performant application. I'm neither a game dev nor a three.js expert, so in case it's not crystal clear:

THIS GUIDE IS BAD.

Let's get started!

i by i, step by step

# Start with some boilerplate

This boilerplate starts with a spinning green cube.

Commits

# Draw your player box

We want the player to be a "cuboid" like in the original, so let's adjust some dimensions.

Commits

# Draw an obstacle box

Let's add another cuboid in red as an obstacle.

Commits

# Move the obstacle box left

Attack!

I've opted to move the obstacles, but I suppose it would also be valid to move the player. I'm not going to dwell on it, but I imagine this decision has pretty big reperussions on the game's code.

Commits

# Loop the obstacle box after it has passed

I'm not sure if making new obstacles (and removing old ones) is better, or if recycling old ones is better, with respect to game-dev theory. But, since it's easy, we're just going to recycle, using the same obstacles and changing their position on the scene.

Commits

# Move up when space is pressed

Simple IO, when the spacebar gets pressed, move.

Commits

# Stop the game on collision

Now we need some game-over conditions. Then I found these collision examples.

Commits

# Turn on the gravity

We have to think back to high school physics class here, and make gravity.

Commits

# Make many obstacle boxes

Add some more obstacles, and we have the trappings of a game here!

Commits

# Stagger the boxes randomly

What's interesting about this step is that it's where the game actually gets fun! The randomized nature starts to test your timing ability.

Commits

# Camera movement

What's the point of a 3D game if you're only taking advantage of two dimensions? Let's put some camera movement in here so the player can appreciate our hard work!

Commits

# Adjust materials

You'll notice that the "materials" that we're using don't give us any depth. Changing the materials should help with that.

Commits

# Add lights

Lights help improve the reflected surface of the objects, so it will further improve the illusion of depth.

Commits

# Make a trail

Trails also give us the scoring mechanism.

I'm using a clock here because it's the first thing I thought of. Using a clock for this is a bad idea though, because I noticed the clock runs independent of the frame-rate. Slow computers running at 1 fps would have a solid block of a trail and a really high score (before encountering any obstacles). It would be safer to generate trails over distance instead of time.

Commits

# Draw "the ground"

Our game scene is just in a void, let's make a ground and sky.

Commits

# Double jump

The game is pretty difficult so far! Adding the original double-jump feature will add depth the challenge.

Commits

# Flipping double jump

Flipping is a nice effect, but also improves strategy a little.

To jump, I'm going to add some code to make the player angle self-correcting: the player should always try and be upright. If the player isn't upright, rotate until they are. When the double-jump starts, we're going to "poke" the player so they're slightly off balance. Then the player will automatically work to correct their angle. Doing so is surprisingly simple.

Commits

# Add 3D Text

I found an open S3 bucket for the font... it might be kind of discourteous to use someone else's server to get fonts. Just note that if this step fails in the future, the hardcoded S3 url is probably why.

Commits

# Add the sound

The original site used P5.js to play sound, but after some tinkering I don't think P5 plays very nicely with threejs. So in the interest of speed, we'll switch to howler.js. P5 somehow looped the mp3 seamlessly, howler unfortunately has a sound blip when it loops. Still, it drops into the script with no issues, so we'll run with that.

Commits

# "Tally" score when the player loses

One the player loses, show them how many I's they got on their YEAHBOI!

Commits

# Title screen (click requirement)

Unsurprisingly, Chrome (but not Firefox) prevents automatic sound until there is a user interaction with the page, to prevent obnoxious surprises like apps such as this.

Therefore, to make sure the sound gets played, we need a title screen that requires a click interaction.

Commits

End Result

Quickly hacking up a terrible game takes me all the way back to 2002, making Game Maker games. Take a look at the three dimensional majesty of the end result

Praise the sun