Dev Blog

Archives

Coconut Express Bonus Content: Low-poly Mini-Tutorials!

7 minute read

This post is an addendum to my guest blog on the official UnrealEngine website. Enjoy!

How to use flat-shading on a landscape material

This is pretty simple, actually! If it were a Static Mesh instead of a Landscape, you could simply import it without smoothing groups for flat shading, but (as far as I know) there is no way to directly tell a material to ignore mesh smoothing. But you can get around this by deriving the normals from mesh geometry using this setup:

For this to work, you also need to disable “Tangent Space Normals” in the material properties.

To explain why this works, we’ll have to get a little technical for a moment: The DDX and DDY functions return vectors pointing in the direction of the U and V axes of a pixel’s UV Map. Since those two vectors effectively describe a plane perfectly aligned with the mesh’s surface, their cross product will return a vector perpendicular to this plane – that polygon’s normal vector. Voilà, flat shaded materials!

How to make procedurally animated low-poly water

coconuts-ocean

The ocean in The Coconut Express uses a simple but effective shader applied to a rotating circular mesh. The mesh is a (slightly bent) circle with a lot of subdivisions, of around 8000 polys. This high polycount is needed to provide enough detail when tessellation is applied, as you’ll see in a moment. This is the material setup for the ocean blueprint:

coconuts-oceanmaterial

As you can see, it uses the same flat-shading technique as described for the landscape above, so let’s pick apart the other parts! First off, the tessellation. This is pretty standard fare. If you don’t know what it is and how it works, check out this other tutorial I wrote about it a little while ago. The biggest difference is that here, the “heightmap” used for tessellation is not actually a texture, but is procedurally generated from the output of the noise part of this material. So let’s look at that next!

The Noise node is the core of this section. If you click on it, you can adjust a lot of properties, such as algorithm type, minimum and maximum output, quality, etc. In this case, I’ve used Perlin noise with 2 levels of turbulence, a min output of 0 and a max output of 1. That limits the output to the 0.0-1.0 scale used for linear color channels in UE4’s material system.

Now, what about the rest of the noise section? The Noise node’s “position” input can be filled by any three-dimensional vector, but it’s meant to go with positions in world space. You could connect an Absolute World Position node to it and get servicable noise! So what do the rest of these nodes do? First of all, we wanted our water to have animated waves. To achieve that, I used a Time input combined with a factor for animation speed, which works to move the noise’s position input upward over time, creating a nice, subtly bubbling animation.

The Position Transform node (shown as “World to Local”) is used in order to allow us to rotate the mesh, and have its noise function rotate with it. Without it, the noise would stay in place even as the mesh it is applied to moves, which looks really weird. The mesh rotation uses this very simple blueprint setup:

coconuts-oceanbp

With the rotation rate set to a yaw value of 1 with the rest zeroed out, that combines with the noise material to create a nice, slow panning movement of the waves:

Blueprint: Handling Gameplay Zones

As our core gameplay idea, we wanted the player to have to manage their swallows’ stamina, with different terrain areas having different effects on their speed and rate of energy consumption/recharge. Mountaineous terrain would cost much more energy to cross but would speed you up (because of stronger winds, you see! Look, we don’t really know anything about birds). Towns and forests on the other hand would slow you down but recharge your energy, with forests also acting as shelter from the evil falcons.

coconuts-zones

To realize this on a tools level, I made a generic “Zone” blueprint. These Zones can overlap each other, can be assigned a priority, and can be rotated and resized as desired by the level designer. When the player character overlaps with a zone, this zone gets registered in an array in the character BP. On end overlap, it is removed again.

The logic to determine the dominant zone is handled entirely within the character itself. Every time a new element is added to or removed from the “Affecting Zones” array in the character, a check is run over the entire array to pick out the zone with the most dominant type and highest priority. That allowed us to handle the swallows’ energy consumption and speed through state changes based on the single dominant zone the player was currently in.

Blueprint: Custom 3D menus with meshes

coconuts-menutransition

I’ve had some inquiries about how we made the main menu for this game, so here’s a quick overview for everyone who wants to make their own 3D menus. Ours is a composite blueprint complete with a camera component, all menu items, the selector mesh, and logic for handling input events.

To make this work, the level blueprint enables cinematic mode on Begin Play, and switches the player controller’s view target to the Main Menu blueprint with a gradual blend, to create a nice camera transition.

Since events and functions in level blueprints cannot be called directly from class blueprints, our Menu BP contains an Event Dispatcher. The red line you see in the next picture connects to a “Bind Event to” node for that dispatcher, so that when we call the dispatcher after a round is completed, it calls the “SwitchToMenu” event in the level blueprint and the player’s view is reset to the menu camera.

coconuts-menuswitch

Input handling is pretty straightforward. The InputActions for up and down change an Integer variable indicating the currently selected item, and the selector mesh’s position is updated accordingly.

coconuts-inputselector

When the player hits Enter or the confirmation button on their controller, an action is executed based on the currently selected menu item:

coconuts-menuconfirm

And that’s the gist of it. Don’t forget to enable/disable input on the Menu actor as you switch to/away from it, and you’re golden!

 

If you have any questions or comments, or just want to connect, just leave a comment or poke me on Twitter!

You can also download and get more info about The Coconut Express here!


VR support for Euclidia

1 minute read

I finally found the time to polish my December Unreal Engine gamejam entry Euclidia a little bit, and I have just uploaded an updated version. So I thought it was about time for a public release! The biggest newly added feature? Rift DK2 support!

You can check it out right over there in the Games section. It’s still pretty rough, but this is probably going to be the final update. Considering the buggy state it was in at submission time for the gamejam it deserved a little more work, but as far as I’m concerned, with the addition of VR support, that game is done. I’ve learned about all I can from it, and it’s time to move on to other projects! Such as this:

Memory Error Splash

Stay tuned for more on that in the next few days!

The website is also undergoing a bit of cosmetic improvement, which I’m very excited about.


Euclidia

1 minute read

This weekend I made my first puzzle game!

It was pretty fun, except for the part at the end where it turned out some obscure compilation bug makes critical parts needed to advance not work. One of three puzzles can be played though, and as it happens it’s the one I like best! Also, the level itself turned out alright. If you want to play it, you can… Not sure when we’ll be able to fix those bugs (if ever – some weird stuff going on there…) but you can download it from its submission post on the UE4 December gamejam thread.

So, despite everything, all the frustrations, etc. I’m pretty proud of this. Never made a puzzle before! And even if the process was painful in places, it gave me my first proper gamedev-proud moment: watching someone else try to figure out a puzzle I had made on Twitch, that was all kinds of special. Made me feel all warm and fuzzy!

Anyway. I’m gonna sleep for a week now. The next time I say “Yeah, I’m gonna take it easy on this one”, don’t believe a word I say.