Magivoid Devlog #1 - Terrain, locomotion, fireball!
Initial project setup and some basic systems.
In the last post I mentioned not knowing what game to make. This isn’t entirely true. I don’t have a solid design or specific goal to achieve, but I do have some thoughts on which direction to move towards to get things started.
To begin with, this will be a third person game made in Unreal Engine 5. The idea is to make it multiplayer in order to keep the scope narrow. One map, one game mode, a small amount of assets, endless fun. Sounds reasonable, right? I realize “multiplayer” and “narrow scope” in the same sentence might be hard to digest, but Unreal offers a pretty solid foundation. With this setup we also have the ability to easily extend the game with additional maps, modes, and items, if, through some miracle, the game is completed.
Multiplayer-wise I’m thinking it’ll be session-based (obviously) and probably low player count. Perhaps some sort of a MOBA-like in a 4v4 fashion. I believe Steam can be used to launch a game like this and get a bit of help when it comes to server discovery and whatnot. Maybe I’ll even do an early access release and distribute builds that way. But, I’m putting the cart before the horse now. Let’s start by looking at some basic systems I put in place so far.
For the environment I was considering some sort of island to justify a small environment. Having everything surrounded by water and the familiar protagonist player character that never learned to swim gives the entire thing a believable vibe. But I don’t really want to deal with water to be entirely honest. Maybe we’ll do a small pond or a creek at some point for aesthetics if everything else goes smoothly, but for now I decided to keep it simple and ignore what the edge of the world looks like.
With the type of game being a MOBA-like I’m imagining we’ll have some sort of lane on which AI will move. This led me to think about putting the entire gameplay within a canyon surrounded by steep slopes on each side that block player movement. The cliffs would neatly handle two of the four sides of the map in the “edge of the world” conundrum. We’ll figure something out for the other two sides later.
I considered a couple of different tools for generating the terrain and decided to go with Gaea. It works great and has a nice and easy workflow to export terrain heightmaps and texture masks to Unreal. The node-based generator makes it super simple to quickly generate really cool looking terrains. Here’s the graph I ended up with and the result it generated.
Gaea has presets for exporting maps of the correct size required by Unreal, and with a bit of math to set up proper scale after import into the editor you get a nice looking landscape for your game.
With Gaea you can use a color palette selector to visualize terrain materials but this doesn’t get transferred to Unreal. You can optionally export various masks and use them to apply different materials to your terrain once you get it into the editor. This is cool for things like erosion but specifying where different terrain materials should be applied with a mask felt too restrictive. Instead I went with a slope-based blend material to get the above result. It has the added benefit of “just working” if we later modify the terrain in Unreal, which is possible since we’re dealing with a heightmap at this point.
The heightmap resolution for the above result is 1k and scaled to cover a 1km^2 area. The 1m/texel resolution is a little bit low I’ve noticed, and the 1km^2 area is a bit too large for what I had in mind. I could re-export it all from Gaea at a different resolution and change it, or just make the terrain cover a smaller area, but I’m lazy and decided to keep it like this for now. We’ll see if I get back to this at some point. I figured it would be easy to cut away terrain if the area is too large.
Unfortunately, the low resolution of the heightmap can cause visually jarring artifacts due to self-shadowing, but it’s an easy fix with the smooth tool inside UE.
With the game being in third person it’s safe to assume the player character will be somewhat important. At least it needs to not be annoying since it’s one of the things you’ll see the most. Not to mention the way the character interacts with the world will directly contribute to how the game feels to control. Now, I don’t have anything against the default setup that comes with UE. It’s a solid and responsive system. I only prefer something slightly less arcadey for this project.
To solve the arcadey feel I added the Advanced Locomotion System plugin. There’s a bunch of cool features in there and even using only the basic locomotion animations gives an improved result for character control.
Lastly, I added a fireball attack because this is a game after all. It doesn’t do much beyond spawning a sweet looking projectile that explodes on impact, but it’s a start. Epic, the beautiful humans they are, released quite a lot of assets for free from their Paragon game. I ended up using a nicely fitting animation from one of their characters for the fireball launch, which goes to show how easy Unreal Engine is to work with when it comes to sharing and reusing assets.
Funnily enough this attack feature exposed an interesting issue in third person games. Namely, how do you make a projectile hit what the player thinks they’re aiming at? It’s a harder problem to solve well than you’d expect. Mostly because the player aims through the center of the screen but the projectile travels from a different location (e.g. the player’s hand in this case) towards the target. For that matter, how do you know what the target needs to be?
I went with tracing a line from the camera out into the world (i.e towards what the player sees in the center of the screen) and based on what it hits try to guess what the player meant to aim at. If the trace hits nothing, pretend there’s something X meters away and launch the projectile in that direction. It works fairly well, but there are edge cases where it breaks. Perhaps that will be a problem to solve at some point but for now this will do.
Until next time.