Ranger
Ideation
This summer my wife and I made a road trip to Banff. We visited during the week of Canada day, and the national pride was awesome. The park was beautiful, citizens were covered in maple leaves, and all roads pointed into the wilderness. We happened to get lucky and visit during a travel Canada period, so no tolls, no park passes, and any easy going drive all the way to-and-from Oregon.
While driving through the National Park, I daydreamed about what it’d be like to push the speedometer to the max. Really, truly, floor it. I imagined casting across the basin between these vast mountain ranges at ludicrous speeds, pulling G’s that were dangerously foolish.
Imagine seeing a glacier in the distance and just deciding to race towards it at Mach speed. Trees, rocks, and terrain are just blurs as you cast through the wilderness. Rivers and lakes leave only wakes and a mist as you pass over them. You hurtle towards the side of a mountain, pitching just enough to take the climb. As you pitch more and more steeply, you reach snow bluffs and a dangerous glacier. You continue to climb, approaching a summit. Faster and faster, eventually launching off it’s crest. You’re airborne, casting into the unknown wild.
I wanted to make something like this. A space that blended speed with natural landscapes, and one that allows players to explore in ways that you can only fantasize.
Ranger is the working name I’m using as I prototype and workshop this game.
Movement and state
At the start of this project I had zero experience in Godot. I ran through a few different tutorials, including Brackeys, and felt pretty good at a high-level about Godot’s node-based architecture. I saved a few more tutorials to a playlist but inevitably just decided to play around.
I started with a motion controller for a few weeks. I wanted hovercraft-esq movement, fantasizing about the old Star Wars podracer games. Basic steering, acceleration and deceleration were straightforward. Forward/reverse and horizontal movements were split into separate functions, each of which has a “casting” nature.
A single, quite large, raycast function is used to check for ground, set distances for hovering, and assign enum state machines (grounded vs airborne).
At first I used a single ray from the object center of mass to define down, ground normal detection, and similar, but it was quite crunchy movement. On flat ground it works fine, but casting over surfaces with angles was likely to misbehave. I expanded the raycast to include both forward/backward and lateral rays, mathematically identifying an average surface normal to help smoothen transitions over rough surfaces.
A state machine dictates airborne mechanics vs grounded mechanics. They are largely the same, but being airborne means the craft is pitching forward and backward depending on the tangent of the parabolic trajectory. Steering and acceleration/deceleration is lost while airborne too, as well as an artificially large gravity to help exaggerate falling mechanics.
The player can boost, albeit without a cap and in a way that jenks the physics a bit. The boost is 100% necessary, and I’m planning some camera trickery to illicit a zoom-on-boost behavior.
The most challenging part of the character controller was handling pitch and roll. There is a surprising amount of vector math for creating the illusion of turning and boosting. Cross products and dot products are common throughout, much to my frustration and old linear algebra skills.
Environment and emotion
The original test environment was just a flat plane and some simple pyramid shapes. It worked well but quickly needed to scale. Per some Reddit recommendations, I downloaded Terrain3D, watched some tutorials, and then started pulling height maps.
My first attempt was a bit grand… I grabbed an .exr height map of nearly 100 sq km worth of Banff. After a bit of debugging and versioning issues with Terrain3D, I got the map into Godot. My first ride with the character controller was wild…. So much broke. Clipping through the ground when moving too fast, rolling over, unmanageable steering, bad flight controls, the list goes on.
It was perfect. Exactly the sort of test data I needed to clean up the controller.
My major hangup with the imported map was that the scale was off. I don’t know the exact scaling, but the player was huge relative to the landscape. There was no anticipation, no grandeur. It was a good proxy for a giant ship using mountains as half-pipes, but it was entirely the wrong scale. The speed wasn’t visceral.
It’s funny that my second pass at heightmap data was on an area that was 10 times smaller, and yet it felt so much bigger. I downloaded a 12 sq km space around Lake Louise and pulled it into the main scene. Unlike my first attempt, I also pulled a satellite image of the same area and overlaid it atop the geography as an albedo map.
The first map was a space to learn. The second was a space for speed. Think high-speed Skyrim. Continental land mass with speed and scale, and snowy mountains that dart into the sky.
My first shot in this world was actually quite emotional. Sure, heightmaps are rolling hills without rugged details, I barrel roll over surfaces if the physics act up, and there are random holes in the ground ready to dump the user into a gravity well… BUT IT WORKED.
I visited a place in the real world, hiked the very same trail, and just did it digitally in 5-6 minutes at speed. What’s more, I could go farther than reality, crest the plain of six glaciers and launch off local topology.
I planted myself at the top of a local peak, disabled hover to prevent sliding during idle, and cried a little bit.
IRL, I’m expecting my firstborn soon, my job is demanding more than I can give, and there’s plenty of collapsing walls around me. The small victory of having ideated and executed a prototype that works brought so much joy.
I am creative, and I want to make things. To do so in a way that I can also game? First of a kind moment for me.
Next on deck
There is so much wrong with the current prototype… A laundry list of barriers, opportunities, and next steps. It is immediately clear that I am not wanting for work. Rather, I have to figure out what doesn’t deserve the attention. Some recent commentary by Jonas Tyroller struck a chord, such that games are often made better by being best in class at one thing, not mediocre at many.
I see two branches to workshop. In one, I pursue realistic world building. Rocks, terrain, trees, textures, water. A space that feels real. In the other, deliberate decontent. Low poly environments, assets, and movement prioritization.
Both paths have merits. I suspect the path forward is the one that brings more joy to a new dad.