Switching the Player State
So, the goal for Week 8 was to get the prototype to a testable stage. My first goal for the week was to implement toggling the player state (switching between being an attacker and defender). Initially, my first thought was to have two separate GameObjects (one for the attacker, one for the defender) on each client, and switch between them when needed. This involves calling NetworkServer.ReplacePlayerForConnection in order to tell the server that the client is switching player objects. However, I ran into some networking bugs when trying to do this from a client, rather than the host. After several errors I decided to try a different strategy: have both the defender and attacker be children of the same prefab. Then, I wouldn’t even have to mess around with ReplacePlayerForConnection and possible bugs (in hindsight, this was a very good decision). It took a bit of script refactoring, but once it was implemented, it worked quite smoothly. However, changing the visibility – across the network – of the prefabs depending on whether or not they were in use was a bit more challenging. I eventually got it working using a combination of Commands and ClientRpc functions.
After smoothing all of that out I decided to try and reintegrate the traps, because they hadn’t been working for a while (since we started focusing on the networking). I managed to get them to a decent state where they mostly worked across the network.
Unfortunately, it became apparent early in Week 8 that my original grid system was not be scalable. It worked on small maps, but after a certain point it would basically freeze the game. The problem is that I would create a huge number of empty GameObjects (that hold a BoxCollider) and then perform SweepTests on each one to see if it hits geometry in the level. Sure, I disabled the grid cubes that weren’t adjacent to a surface, but I was still creating thousands (or tens of thousands) of GameObjects (in addition to performing SweepTests on each one) before disabling them. So maybe it works when the grid is fairly small, like 10 x 10 x 10. But get too much larger than that and it’ll freeze Unity. I should’ve realized this before, but, anyway, I ended up having to rework it a bit.
So, I decided on a different strategy: rather then creating a huge amount of grid cubes and then testing each grid cube, why not just loop through each environment asset and place grid cubes on each of its surfaces? This would mean I would only need to create the grid cubes that I need, rather than create a bunch of cubes that end up being disabled and unused. So, after a bit of trial and error, I got it working, and it was much faster than my previous method. I’m a bit afraid that if the maps get too big then it might still be too inefficient, but I’m fairly confident it’ll work for now. At least it’s a step in the right direction.
After I got player switching to work, my next task was to get the basic game loop up and running (both teams place traps -> team B attacks while team A defends -> team A attacks while team B defends -> place traps -> repeat). My plan was to have a GameManager script that would primarily run on the server, and check the PlayerState of each player and adjust the GameState accordingly. For example, if the GameState is PlaceTraps and each player is in a transitional state (either TransitionToAttack or TransitionToDefend), then it knows that each player has finished placing their traps and it changes the GameState. Like most tasks involving networking, this was more complicated than I thought it would be at first, since I had to make sure certain aspects of the player objects were synced across the player and client. But I managed to get the game loop into the build before QA on the Saturday of Week 8.
Overall, this was a week with substantial progress to the prototype. With the basic networking now in, we would now be able to shift our focus to the traps and the platforming (the two most important parts of our game) for Week 9.