“One security guards problem, or an entire galaxy’s hell? Will you solve her problems?“
- 7th game project at TGA
- Made in a group of 15 people
- Action-packed first person shooter in space
- Scripted events
- Physics driven gameplay
- 16 weeks (half-time)
- Created fully using Cobra (our in-house C++/DirectX11)
One of my contributions to RoboCobra was the implementation of the physics engine. The underlying calculations of the engine are handled by the library PhysX. The goal was to use the engine for cooking, character controllers and ray casting, while at the same time maintaining a self-explanatory interface. The most difficult part of developing the physics engine was how poorly documented PhysX is; so I was more or less on my own.
Another contribution to RoboCobra was the development of the player, camera and all controls, together with its animations. We had decided we wanted the movement and weapon mechanics from Counter-Strike, which meant I had to code movement that supported air strafing, bunny-hopping and surfing. I also had to implement a weapon with a spray pattern, spread and movement inaccuracy.
We decided we would have doors that open when you get close to them. The doors needed to collide with the player but could not collide with the static environment. This encouraged me to implement collision layering. By placing dynamic objects on one layer and static objects at the other, it was very easy to control which object collides with which.
I solved cooking of the environment very early thanks to PhysX, but later faced optimization and generality issues. Cooking times were through the roof (14 seconds) and the engine crashed when trying to load .fbx’s with multiple meshes. I solved this by storing the cooked meshes in an unordered map, with the file path as a key to never cook identical meshes twice.
Between each level we had a segment that locked the player in, while the next level was being loaded on another thread. Because the next level is being cooked while the previous one is being updated, this meant the PhysX scene would be read and written to on different threads, which caused a crash. Together with Joakim Gunnari, we constructed a system that would load the next level and cook it on another thread. My part in this process was the physics side, while he mostly dealt with our scene management.
We had scripted doors that would open and close the locked segment. The player and the scripted doors needed to be in both scenes because they needed to be interacted with in both states. Changing to the loading scene when the game should load freed up the game scene, which meant clearing and cooking the next level was possible. By then keeping the player and scripted doors in both scenes and updating their position when switching, loading async was achieved.
Solving shooting with ray casting was an easy task when the physics engine was in place. My next challenge was adding a spray pattern to the weapon.
To enable full control over the spray pattern, I decided to use an approach that handles offsets between each shot to calculate the direction in which the next shot should be fired. Adding to this, I also created a camera shake that slightly moves towards the current shots position.
We wanted the player movement to be as similar to Counter-Strike as possible, which meant the challenge for me was to find a way to emulate that.
My solution was to add speed in the desired direction, depending on the dot product of the current velocity and the desired direction, then removing the result from the maximum speed allowed. This gave a smooth acceleration in all directions.
Friction is important for the player to not infinitely accelerate. I calculated the amount of speed that should be dropped by multiplying the friction with the speed, or a constant deceleration depending on which one is bigger; I then removed that from the current speed. Dividing the result with the current speed generates a coefficient that I could multiply with the current directional vector.
Air movement is a bit different because the player is not affected by friction. To achieve smooth acceleration in the air, I needed to hard cap both the speed and the acceleration to amounts that seem reasonable, otherwise the player would infinitely accelerate in the air.
Together with gravity and a jump, this yielded the result I was hoping for.