Hidden secrets of the Velocity universe
Velocity 2X is all about speed. To achieve fluidity, not only does the player need perfect control of Kai, the world around her has to react in a way which is completely intuitive and natural to the player. In this article, I’m going to talk about some of the tricks we used to achieve that.
Crystals from the sky
When Kai shoots a rock wall, a Rekenium crystal is spawned, which falls down under gravity until it hits the floor. Giving every crystal full dynamic physics behaviour turned out to take too much CPU time, so instead, the floor position is calculated in the level design tool using a raycast, and every crystal is born knowing the y coordinate of the ground upon which it will fall. In other words, we calculate as much information as possible at level design time to save CPU time while the game is running. The spawn position of crystals is randomised a bit so they don’t all appear in the same place, but not so much that they might end up hitting a different piece of ground.
The weapon replenish packs dropped by insect swarms also fall under gravity, but since they appear at the position of the last insect, it’s not possible to calculate where they will come to rest at level design time. Instead, they use a single raycast straight down at runtime to find the ground position.
Rules of attraction
All the pickups attract towards Kai, in the same way as survivor pods attract to the Quarp Jet in Velocity Ultra. If Kai is above a pickup, mid-jump, it will attract upwards, ignoring gravity, and a falling crystal close to Kai will forget about gravity and attract to her.
A raycast is used to stop pickups from attracting to Kai (or to the Quarp Jet) through walls. Crystals and other pickups straddle a strange line between physical realism and “gaminess”, but it feels natural during play.
Hussain wrote about getting telepod throwing to feel right. Telepods also need a great deal of awareness about the world around them, to prevent unfair player deaths and glitches. A telepod “sets” a few seconds after coming to rest, but not if it’s resting on a fatal hazard, since the player would instantly die when teleporting to it;
…not on a door or a piece of glass, since it would have to un-set and drop, which is confusing;
…not on a moving platform;
…and not if it’s in a narrow corridor, since Kai would get squished when she teleported to it.
For the same reasons, Kai isn’t allowed to teleport to a telepod on a fatal hazard or in a narrow corridor, even if it isn’t set. When Kai enters a dock to return to the Quarp Jet, all telepods which haven’t set yet will either set if possible, or return to the pool. This means the player doesn’t have to wait the few seconds for them to set, keeping the pace high.
A shot from the arm
Kai’s Rekenium Rifle and the Quarp Jet’s bombs have pretty big collision radii for maximum destruction. When an object collision is detected, a raycast is used to check that there’s actually an unobstructed path to the object. This prevents blowing things up on the other side of thin walls.
When Kai fires her 360° Palm Cannon while jumping, the shot doesn’t appear precisely where her hand is, but instead at a position which looks more natural as she falls. The position is then nudged to make sure the bullet won’t appear in the middle of a wall (or worse, on the other side), while still appearing at a position which looks visually acceptable.
Having a blast
Not only do the Quarp Jet’s bombs explode, they also create shockwaves which cause even more destruction. This means Vokh turrets which are close to an exploding bomb but weren’t actually hit by it will also be destroyed. This is implemented with a second collision circle, which travels with the bomb but doesn’t react to collisions until the bomb explodes. Again, a raycast is used to prevent damage to objects on the other side of walls from the bomb blast circle.
Bomb blasts were implemented very early on in the project, before raycasting was available. I think it might have been neater exclusively to use raycasting instead of a second collision circle, but this is a good example of not fixing what ain’t broke: the implementation isn’t too CPU expensive, and it works.
Pain in the glass
As in Velocity Ultra, glass in Velocity 2X has very complex, subtle behaviour. When a piece of glass is shattered, its neighbours may also shatter, depending on the strength of the shot fired and the shape of the glass. In the level design tool, each piece of glass stores the IDs of its neighbours, so while the game is running, it can check when they shatter [for those techies out there, we used the Observer pattern]. If a piece of glass determines that it shouldn’t shatter when its neighbour is destroyed, it flashes white instead, and it also notifies its neighbours so the whole glass structure will flash.
On top of all that, there are special cap pieces which never shatter, but will pass on damage to neighbouring glass pieces. This all takes over 900 lines of code, which seems like a lot, but at least some of this is irreducible complexity: there’s a lot of code because a lot of behaviour is implemented.
Aim to miss
We tried making Vokh turrets shoot to intercept Kai or the Quarp Jet, by assuming instantaneous velocity would remain constant and calculating where a bullet would intercept. This turned out to be a bit too accurate: the player’s rhythm was spoiled by having to change course constantly to shake off bullets. Making the Vokh guidance systems fuzzier makes for better gameplay.
This screenshot shows the bullet hell that results from the precise targeting algorithm (which isn’t used in the final game):
Several little touches make docking and returning to the Quarp Jet feel smooth. The ship automatically moves out of the dock, taking control from the player for a split second, to draw attention to the ship and show the player where to go. The dock is then made inactive for a second, to avoid accidental re-entry. After docking the ship, Kai has to move a short distance away before the airlock will function again, again to prevent accidental re-entry.
Vokh me, Amadeus
The Vokh guard battle set-piece took a lot of iteration to get right. It needed to present a challenge, while still being reliably achievable during a speed-run. Players would invariably panic when faced with their first Vokh charge, so we eventually settled for two run speeds, with the second, faster speed introduced later in the game. The animation cycle was remade after finding the run speeds which gave the most satisfying gameplay.
The key gameplay toy also went through several iterations. At first Kai simply had to shoot the Vokh in the back: but this sometimes made it possible to camp on a high ledge and snipe at them. In the final game, the player has to teledash through the Vokh to disrupt their shield; so each Vokh checks a simple timer which counts seconds since Kai’s last teledash.
Vokh battles were too difficult for novice players, and at one point the Vokh guards were at risk of being axed from the game [Nooo!]. In the end, we were able to balance them by not only making Kai invulnerable for a split-second after contact, but also shrinking the Vokh guards’ hitboxes to a single pixel wide. They’re pretty thin under that armour.
As you can see, we used a lot of tricks to make the Velocity worlds react naturally and intuitively, and this post just scratches the surface.
See if you can spot the interactions in the trailer:
If you have any questions, post a comment below!