Over the past week, we’ve been working really hard to fit in a lot of features, fix bugs, and optimize the game. Here’s a large peek at what we’ve done!
One thing that we noticed in other roguelike games was the lack of use of the 3D space. So, to add some more verticality, we’ve gone and added ladders. The logic behind it was to turn off the physics driven controller and turn on some alternative movement, as when a person is on a ladder, they don’t fall gradually like they would in empty space.
With that in mind, the sideways movement was disabled, and the space of movement was translated to vertical movement. However, one issue that came up was distance when the player could start climbing, if too far it felt weird, and if too close it was awkward to use. In the end, we just decided to tween the player close to the ladder when they start climbing.
Here’s a quick demo of it in action:
Bow & Arrow
The sword was a fine tool for dealing with enemies, but what about ranged combat? Like most of the tools available inside the dungeon, the bow and arrow will be either found in the environment or from the shop. We wanted the bow to have a different feel to it than modern projectiles, which typically travel to the point that the crosshair is aiming at.
With some calculations, the arrow now travels in a trajectory based on how far the bow was drawn back. It’s fully affected by physics, but one issue we had initially was that it wouldn’t properly rotate towards the way it was going. A simple fix of making the arrow face its current velocity fixed it though. As for the uses of the bow and arrow - we’re keeping open the possibilities, so it can kill enemies, break ropes, push objects, trigger things, and much more.
Here’s the bow & arrow in action:
In the preview above, you probably noticed the spider; this monster is part of a pass to add greater variety to the things inside the dungeon. Each monster will have features unique to them, and react to environmental changes depending on what they are. They may even come in combat with each other, and the method of dealing with the monsters is completely up to you. With the spiders though, one thing you definitely don’t want to do is destroy the eggs that they guard diligently; who knows what might happen?
With making the dungeon more precarious, the player can obtain another power somewhere in the dungeon to ease their journey. The detect is a RenderTexture that applies as part of the camera’s post-processing which serves to help display interesting objects inside the dungeon.
Here’s the power in effect:
Physics objects don’t like it when they are bound by another attempt of modifying it other than the physics engine. As we’d like to have the player’s character be affected by physics (applications including getting blown up, which you’ll seen in a future update), it was somewhat of a struggle to get it to be parented to the motion of the platform while not interfering with the controls.
The traditional approach would simply be to parent the player to the platform while it moves, but when we tried the easy way, issues such as the rotation not being preserved, the player encountering a ‘sliding’ phenomenon when on top of the platform, made us discard that approach. Plus, another issue was when we’d place objects on top of the platform - the movement would throw our beloved boxes far off to the sky and get stuck in a wall, leaving us without a way to make our way across the room.
To solve this, we ended up offsetting the physics objects of anything that was on top of a trigger which didn’t interfere with the collision by the movement of the platform, and it ended up working great! Whew.
A dungeon should prove to do more than just test your mettle against monsters; it should make the player exercise their wits. To accomplish that, we’ve gone and added even more traps, hazards, and puzzle mechanics to add to the dangers. In this devblog, we’ll preview two new mechanics.
Crystals act to grant zones of power, where the player gains enhancements to their abilities. One of these serves to extend your reach of grabbing objects many times over. However, to actually function, they need to be placed on a special pedestal that provides the link for them to work.
A glimpse of the crystals in action:
These mystical sources of power may appear from time to time inside the dungeon, and it’s up to you to figure out how to utilize the power that they offer. Utilizing some unknown energy, some objects allow the connection to transfer the power across distances. To accomplish this, we created a hierarchy of links, divided into MAIN, LINK, TIE, NONE states. From here, trigger collisions add to the master list, which ends up deciding how the splines are connected to each other.
Connecting the arcs:
Optimization & Bugs
The hidden killer of performance: UI. Having to check for raycasts for interactive objects is fine, but we realized that there are actually a lot of UI objects that don’t need to be clicked, including the world space UI. By separating the canvas into two types, and removing unnecessary raycast checks, the game was running a bit better.
The next culprit was Terrain. Unbelievably, a single parameter having to do with detail distance on the grasses and trees increased our FPS in the terrain areas by around 10. Also, a flaw came up with our custom controller, where we didn’t account for slopes at all all this time, since the highest slope we’ve encountered inside the rooms were the stairs. To fix this, we took the dot product of the surface normal and the up vector, compared it to the angle limit, and adjusted the range of movement accordingly.
Not as much as a performance hit, but combating the dolly zoom (also known as the “Trombone” effect) and giving a custom FoV for the weapons came up as soon as we started to implement the bow and arrow. To deal with this, we ended up using different culling masks and clear flags for the camera, in addition to implementing additional cameras. The end result was a camera setup where one would be for the player, one for the weapon’s FoV, and one for the near planes as well as other functions.
With all of that fixed, we took another look at the GC and cleaned up the code to generate nearly no garbage at all. The next step was optimizing the pathfinding, AI, and occlusion culling. We recently came up with a custom solution to managing large areas that let us go from 35 ‘areas’ at 60 FPS to a couple times that at the same FPS on our test machine.
For the AI and pathfinding, we quickly discovered that physics was hogging a large amount to simulate a lot of enemies at a time. By removing the ability of physics applying to the enemies while they are not remotely close to the player, as well as caching paths and reducing the priority of accuracy of enemies and objects far from the player, we saved nearly 20 FPS in our tests simulating nearly a hundred enemies inside the dungeon.