RAoT is a multiplayer, pvp-focused take on Attack on Titan. Featuring 14 playable characters, 3 unique weapon classes, and 10 game modes supporting up to 32 players and 4 teams.
The game is made in Unity and uses Mirror networking. You can download it on Itch or GameJolt
I joined the RAoT team post-release in October 2021, and up until September 2022, I contributed to most of the post-release updates as the second gameplay programmer, besides the creator of the project known as Roark.
I worked on a wide variety of tasks from performance optimization to ping compensation. Working closely with playtesters to find and resolve bugs and improve the game's competitive balance.
When I joined the team the game was not very optimized, so trough using Unity's build in profiling tools I was able to find a lot of low hanging fruit on the CPU side.
These optimizations mostly involved adding culling to various systems on the players, such as occlusion culling for IK and animations, and distance culling for audio systems.
On the GPU side I was also able to improve the performance significantly by enabling static batching on the map geometry. And by working together with our 3D artist to reduce the amount of materials used.
All in all these optimizations halved the average frame time in full lobbies. Allowing us to increase the max player count from 16 to 32. Which still ran better than the 16 players did originally.
High level players often complained that hits that should or shouldn't have hit were doing the opposite. Of course players report these types of issues in any competitive game, regardless of if there is actually a problem.
But in this case there was also a lot of video evidence. So i investigated all the weapons' hit detection and found some issues.
First up the APG. To give some context, the APG fires like a shotgun, but it does not have individual pellets that need to hit, instead it's like an expanding cone,
but the "bullet" does have travel time and is implemented trough a single raycast chain which checks for an intersection with two spheres on the enemy player that expand with the bullet's life time.
This all works great but the issue was with when or when to not block a hit if a player is obscured by map geometry.
Swords had an issue where you would pass trough players during your swing without hitting them. This happened because the sword hit detection simply checked if you overlapped the other player's hit box (sphere) every frame.
But at high relative speeds or when you have a gracing hit this can easily lead to tunneling. Add on top of that players with very high jitter, and you have a disaster.
To solve this, I implemented shortest distance between two line segments and checked that distance between the line segments of the local and enemy player's last and current frame positions.
This is effectively the same as doing the sphere overlap an infinite amount of times between the two frames.
The biggest issue with this game, in my opinion, is ping. Because the player base is small, you are always playing with people across the continent and often with people from other continents. And the combination between high ping and very fast movement results in getting killed by things that you dodged on your screen. This is a nearly unsolvable problem unless you do server-side movement. However, I tried mitigating it a bit by adding player position extrapolation. The game used the Mirror networked transform for syncing player position. This transform has a small buffer of received player positions to smooth out packet jitter. I extrapolated from this smoothed position, but by using any positions already received, I was able to do so more accurately. I also took into account the acceleration players were undergoing, making any smooth motion arcs (like swinging when cabled) perfectly extrapolate. But of course, any time the player changes their rate of acceleration, the extrapolation will cause overshoot. Through lots of playtesting, we found that about 50ms of extrapolation was the best tradeoff, but this is from the smoothed position which is about 33ms behind. A very small victory but it still slightly increased the amount of situations where reactively dodging is viable. To solve overshoot causing players to clip into geometry, I added collision response to the extrapolation.
In the video above, you can see the extrapolation in action. The small cyan cube represents the smoothed player position, and the small yellow cubes are player position packets that arrived in that frame. I used the tool called Clumsy to simulate bad network conditions locally for this test.
The camera had some clipping issues and would sometimes behave strangely, so I reworked the camera object avoidance.
I ensured that all collision traces happened from a "safe" position to avoid false negatives.
I also altered the raycast fans that were used by remembering hits and tracing to that point to avoid issues with thin obstacles that fit between the fan rays.
Additionally, I created a better spectator camera with adjustable smoothing, which allowed for more cinematic shots. This was a big hit with content creators.
This project was a very impactful learning opportunity for me. With a lot of firsts.
It was my first time joining a large existing project, my first time working on a released game with an active player base, and my first time working on a multiplayer game.
I learned a lot about writing clean and maintainable code just from looking at the existing codebase.
Additionally, I gained valuable experience in using Git beyond the basics, such as working with branches, making pull requests, and conducting code reviews.
Furthermore, I learned much about multiplayer networking, including how to mitigate latency issues.
I also learned how to profile effectively and optimize systems with the highest impact.
On the soft skill side I learned the importance of clear communication and keeping the team informed about what I was working on,
especially when working remotely without any standard meetings. Not doing so can lead to misunderstandings.
Furthermore, I learned the difficulties of developing a game for a passionate player base, and how a small but vocal number of players can have a big impact on the community and the team's morale.
Click the email address to send a message. I look forward to hearing from you.