Capstone – Postmortem

Well, here’s a brief history of our Capstone project this semester.

Ever since the beginning of the project there was a disconnect between our second programmer and the core team – myself, our artist, and our designer. At first, everyone seemed to be getting along, we met fairly often, and everything seemed fine. Admittedly, the three of us felt more comfortable by ourselves, but everyone seemed to get along at the start. I had worked with both our designer and our artist on 2 other (albeit smaller) projects in our Production I class sophomore year.

Then the middle weeks of the project arrived – Weeks 5 and 6. These were certainly dark times for our project. We had made our final choice for the game we were moving forward with and we began working on the core systems – I began working on the grid system and our other programmer started working on exploring Unity’s networking system. During this time, we didn’t meet often as a team. Sickness was going around and communication sort of fell off. During this time, I felt like I was taking too long to complete the grid system and got more and more anxious, as I felt I should be working on other systems.

We definitely underestimated the complexity of incorporating the networking. Our other programmer’s exploration of the system during these weeks just barely scratched the surface of the intricacies of Unity’s system. Sure, the current system (UNet) is much simpler than working with a lower level library like RakNet (although, you can delve into the intricacies if you want to), but there are a lot of caveats that you largely have to learn from actually doing complex things with it. The complexity of the very simple demo project versus what our game required was a pretty big gap, and that became apparent when we finally started trying to incorporate networking into the game.

The advent of Week 7 brought a boost to the progress of the game, as well as the morale of the team. I managed to network the game after finally making breakthroughs in this week, leading to a “complete” rough networked game loop (of a single round of the game) in Week 8. Starting in Week 8, progress started to pick up at a rapid pace. Networking had been the bottleneck for a lot of aspects of our game, and now that the networking in was in an ~okay~ state, we could start moving ahead at full speed. Incorporating art, animations, level design – all of that started happening quickly. During this time, however, the disconnect between the core team (myself, our artist, and our designer) and the other programmer began to widen. By the time Weeks 10 and 11 hit, the three of us were often working in the labs together late into the night. Before, we had mostly been working late into the night in separate locations. Ultimately, the 3 of us seemed to be a better team than the 4 of us.

Even so, I won’t deny that we could’ve handled this disconnect better. Perhaps, I could’ve delegated programming tasks better earlier in the project. Overall, we should’ve addressed the problem sooner. Our attempts at resolving this disconnect throughout the semester ended up only being temporary solutions that didn’t pan out.

Another problem was that we basically ended up producing a “horizontal slice” of our game rather than a vertical slice. Perhaps we got caught up in augmenting what we already had instead of iterating on and solidifying our core systems. At the end of the day several of the systems weren’t as polished as they should’ve been. But overall, we put in a ton of work, and in the end, made something pretty cool.

-“david” “hartman”

Advertisements

Capstone – week 12 retrospective

wow week 12

This week involved a lot of work.

environmental traps

I added the functionality for environmental traps – traps which you don’t place, but rather just exist in the level and you can purchase them if you see fit. After adding the ability to select an environmental trap using a raycast (I added some logic to the pre-exisiting raycast-handling function in SnapToGrid), I added a large arrow that appears if you are selecting an environmental trap.

arrow.gif

rounds

Yeah I also implemented the new simplified best-of-3 round mechanic. So now, whoever wins 2-out-of-3 rounds, wins the whole set. This involved adding some logic in the GameManager.

more art

Alexis finished the environment art and added it to the build. Also, I finished adding Alexis’ trap art to the build.

cage.gif
ooo looks good

the final days

We met and worked through the night several days during the weekend. Friday, Saturday, Sunday.

Sunday we worked on ironing out a bunch of stuff. Eva got us coffee and we had an intense work session throughout the afternoon. But then, something broke in the build as we were trying to add control screens and more UI, and we had to revert several things. After going to a dry run of the presentation (where we got some harsh feedback) we returned to the lab to work into the night and fix things. At this point, we were out of coffee.

After this all-nighter from Sunday-Monday, Alexis bought a cold coffee and I bought some juice, then we went to our actual Capstone class (8am Monday yay). After presenting our revised presentation and barely staying awake through the rest of our class, we went home. I managed to get 2 or 3 hours of sleep before waking up to shower and get dinner before the presentations.

The presentations were fairly stressful. The teams presented in a random order. We ended up presenting like third to last or something.

the end

I spent most of Tuesday trying to fix things before our Demo Night slot. We needed those controls screens in, which I managed to accomplish, then I added the win screens for each team, and fixed the background music.

postmortem to follow, it’s over

here’s a teaser trailer I made sometime during week 12:

-“David Hartman”

Capstone – Week 11 Retrospective

w e e k 1 1

My two biggest tasks for this week were the core economy (basically the purchasing system for traps) and the energy system.

Previously we had a set amount of traps you could place, but we wanted to weight the traps so that players couldn’t spam the powerful ones.

Core Economy

The core economy was a fairly basic purchasing system. The player has 15 “cores” represented by an int. Each trap has a cost, and you can’t purchase a trap if you don’t have enough cores to cover the cost. That was fairly simple to implement.

cores.gif

Energy System

The energy system was a bit more complex. Basically, I created an EnergyHandler class which I then attached to each trap. This keeps track of the current amount of energy the trap has, and it slowly decreases this supply it if the trap is not currently being charged. Now, instead of activating a trap being a binary on/off, a trap would only be activated if it had more than zero energy.

I also created a DroneEnergy class which handles the drone’s supply of energy. The drone replenishes its own supply by flying over to the goal area of its base. Basically the scripts which handle the drone’s activation radius colliding with the traps (if the drone has any energy left it will remove the energy) grab an amount of energy from the drone (if it has any left), store this in a local variable, and then give it to the trap.

energy.gif

Additionally, I added this collider which blocks traps from being placed if they are colliding with a wall (this is so players can’t place traps inside walls). It changes color based on whether you can currently place a trap or not.

previewCollider.gif

-“David Hartman”

Capstone – Week 10 Retrospective

Week 10 was a set of seven days that occurred. I’m “David,” a programmer for Turtle Collective, as you may or may not know.

Player Feedback

This week one of our biggest priorities was player feedback. From our QA testing results, it was clear that there were several points in the game where players were unsure what to do or were unsure of what was happening.

One of my first tasks was to add some player feedback for the jetpack. This consisted of two things: particles that emit from the jetpack to simulate the jetpack’s thrust, and secondly, a meter on the back of the jetpack to display how full it is. We wanted the meter to be somewhat diagetic.

jetpackUI.gif

More player feedback: another thing I did was add particles that would flow from the drone to a trap when the drone was activating that trap. This helped to show players if they were activating a trap, and if they were, which trap they were activating. I also fixed some bugs with adjusting the drone activation sphere across the network because unfortunately, NetworkTransform doesn’t automatically handle scale across the network, so you have to set it up manually (using Commands/ClientRpcs, or SyncVars).

activationParticles.gif

More player feedback: I added a little UI popup (using coroutines) to display info to the player like notifying them when a round starts or if they are waiting for the other player to finish placing their traps.

popup.gif

New Traps

Another one of my priorities for this week was to get the new traps that Eva had designed into the build. Two new traps were designed (actually there were three, but we decided to focus on the two most important ones): the quicksand trap and the laser trap.

The quicksand trap consists of three lanes. The drone can either decide to activate the two outer lanes, or the inner lane. If the runner steps into one of the activated lanes, they are slowed down.

The laser trap consists of a panel inset into the wall. The laser is invisible at first, but flickers if the runner gets close, so they have some time to avoid it, but they have to react fast. If the runner gets caught in the laser’s beam, they are stunned for a short duration. The laser, in theory, will encourage players to be more carefully when going through a level so that they don’t get stunned. Implementing these two traps was fairly simple.

laser.gif
The laser trap in action. It uses a coroutine to handle the flicker of the laser beam

More Animations

Alexis finished up some more animations for the runner – the idle and backwards walking animations – so I implemented these in the build. At first I was going to have a separate state for the backwards walking animation, but then I realized I could incorporate it in a much simpler way: by having a blend tree containing both the forwards and backwards walking animations, and then just adjusting the blend value depending on whether the player was moving backwards or not. This way both walking states could be contained in one blend tree, and I wouldn’t have to over-complicate the animation state machine.

blendTree.png

Grid Code

This week, I also refactored some of the Grid code a bit. Originally, all objects with the “environment” tag were populated with invisible grid cubes on all of their surfaces, which are used in trap placement. However, this posed a problem with our wall objects, which were fairly sizeable, but obviously, we didn’t need grid cubes on most of the faces/surfaces of the wall objects except the ones facing inwards towards the level. So, I first refactored the code so that it was now only one small function, and all you have to do was pass in the direction of the face you want to populate. This way I could make it so that certain objects could only populate one of their faces with grid cubes.

buildGridCode.png
The new buildGrid() code

To improve performance, I also increased the size of the grid cubes by 2 (thereby cutting the number of grid cubes in half). It didn’t really seem to affect gameplay that much, and it definitely improved the performance of our game.

 

So, that’s what happened in Week 10.

who am i

-“David Hartman”

Capstone – Week 9

Week 9 has been another week of rapid progress. We successfully challenged on the Monday of Week 9 and moved into the Proof of Concepts stage. My two primary goals for this week were to implement any animations that Alexis made, and to implement the activation system for the traps.

Trap Activation

One of my goals for the week was to make it so that each of the traps could be “activated” by a defender. Basically, if the defender is in close proximity to a trap and presses a certain button (the left bumper), that will “activate” the trap, usually granting it some sort of buff. Activation is different for each of the traps:

  • Spring: activating the spring increases its knockback
  • Gate: activating the gate raises the gate
  • Bear claw: used to “re-activate” a bear claw after a player has broken out of it
  • Cage: used to reset a cage after a player has already triggered it

So, I first added a sphere GameObject to the defender prefab that had a SphereCollider attached to it to determine when a trap would be activated. After figuring out how to scale it across the network (since NetworkTransform doesn’t sync scale across the network) I then worked on implementing the different activation logic for each trap.

springactivate_360.gif
Activating the spring

Implementing Animations/Art

We also made a lot of progress this week implementing the animations and art. Alexis finished the first pass of the walking and running animations on Wednesday night/Thursday morning, and I brought those into Unity and set up the basic animation state machine using the AnimatorController in Unity.

animStates.png
The animation state machine with the walk animation
walkAndRun.gif
The walk and run animations implemented

Getting animations in the build was crucial for us to have a chance at successfully challenging out of the Proof of Concept stage, so both Alexis and I were really excited to get these up-and-running (so to speak) in our game.

 

We decided in a meeting on the Wednesday of Week 9 that we wanted to attempt to challenge out of the Proof of Concept stage on Monday (the first day of Week 10). Originally we were planning to stay in Proof of Concept for two weeks, but we thought that we might as well try anyway after one week. At least we’d get some feedback, and at best, we might even pass into the next stage. However, this meant that we needed to test our game at two QA sessions this week. So, on Thursday (the first QA session) we quickly incorporated Eva’s newest iteration of the level and Alexis added his environment art to it. This, combined with the animations, made it really start to seem like our game was actually going somewhere.

The art progressed even further. A certain John Parsaie showed Alexis the PostProcessingStack, a beta Unity feature that allows easy and simple management/addition of post-processing image effects. After Alexis added these effects, the environment looked even better.

before.PNG
Before the PostProcessingStack
Capture.PNG
After

Anyway, on Saturday, Alexis completed the first pass of the jump animation and I got that in the build. Now we had three animations that would certainly demonstrate the animation pipeline and our ability to implement them in the game.

jumpAnim.gif
The jump animation in action; (also, in this gif you can see some of those fresh image effects)
animStates.png
The current animation state machine with all three animations

 

 Other Features Implemented

  • The ability to stand on moving platforms – seems simple but it’s a bit more complicated than I thought it would be at first glance. A common solution I found online was to parent the object to the moving platform temporarily. After some unsuccessful attempts, I got this working by parenting the entire player GameObject (the parent of both the attacker and defender) to the moving platform temporarily.
  • Timer system – now the timer actually tracks each team’s time during the attack phase.
  • Fixed-camera zones – zones that, when entered as the defender, lerp the camera position to a fixed point to allow us to show the defenders points of interest in the level

 

So, that’s what we did in Week 9.

-“David Hartman”

Capstone – Week 8

More networking;

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.

switching.gif

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.

Grid System

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.

Game Loop

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.

transitionTraps.gif
Both teams finish placing traps; Team B begins attack phase; Team A begins defense phase
transitionTeamB.gif
Team B finishes attack phase and the teams switch roles

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.

-“David Hartman”

Capstone – Week 7 Retrospective

At last, some breakthroughs in the networking. Here’s the main problems I was having:

In the original prototype, I had three “trap preview” objects that the defender had references to. To “place a trap”, I would just instantiate a trap at the location/rotation of the current trap preview object. However, networking makes this much more complicated. In the original prototype, I could just instantiate the three previews and have immediate references to those three GameObjects. However, with networking, you have to first spawn them through the server using NetworkServer.Spawn (since the previews should be visible on all clients). Unfortunately, spawning something through the server and then trying to get a reference to it on only one specific client is quite difficult. Here is essentially what is happening: the client version of the defender initializes and calls a Command function. This Command function is run on the server instance of that defender, and it spawns the trap previews across the network. But, there’s no easy way to really connect the code to get references to these newly created GameObjects easily.

So, what I ended up having to do is spawn them with a Command using NetworkServer.SpawnWithClientAuthority (this gives the client that called the Command authority in regards to that GameObject), then cycling through all the traps in the scene until it fills the three slots with the corresponding traps that it has authority to. A bit of a roundabout solution, but it works.

trapSpawn.png
Spawning the trap previews
trapAssign.png
Assigning the trap previews

As a side note, I only just recently realized upon reviewing the Unity Networking documentation that it appears as though ClientRpc functions don’t have to be called on a script attached to a player object (unlike Command functions, which have this requirement). I previously thought that both Commands and ClientRpc functions had to be called from a player object, but I guess not. Because of this, I also previously believed that you had to route a lot of your networking code through the player object, but according to this discovery, this may not be the case. This might solve some of my problems.

-“David Hartman”