GCO Online Jam 2018 - How I did it


A little bit of background:

So to start with, I'm one of the co-founders of the South Dakota State University student organization that hosted this Game Jam. This is the 3rd jam we hosted and the 5th jam we attempted. But this year was a little different. I just recently graduated, and we had a few other graduates who wanted in on the fun, so we decided to have a graduates vs undergrads. In addition, only the undergrads knew the theme, as they were the ones to decide it. 

Two of the grads worked from their homes each working on their own project, while I was in Brookings with the undergrads working close to them and occasionally providing them tips and other helpful feedback. There were also two free agents that helped with both my project and the undergrads. One was a graduate, and the other was an undergrad who hosted us and also made some of the music tracks in my project.

Friday:

So unlike previous years, I didn't know the theme going into things, though I had a few guesses, and it turned out one of those guesses was right. Whoops. Oh well. I had a list of game concepts I wanted to try and planned to pick the one that most closely matched the theme. 

Reflections Overpowered was one of my preferred ideas. It was a multi-level game with an interesting story, and my goal was to complete at least one level but if time permitting complete more. It was a "see how far I can get and how impressive I can make this" sort of deal. Each additional level would feature a graphical "improvement" as well as new gameplay features.

But there was one thing I wasn't sure about, and that was the level design. So I decided that would be something I would sleep on, and instead I would work on the opening cinematics and title screen. I started actual work at around 7:30 PM.

Title Screen:

The title screen simply consists of two assets: Volumetric Clouds and Unity's Water Pro prefab.  The volumetric clouds used raymarching and had values exposed in the material for animation. But because I didn't want to write a script to fetch the material and modify the material properties in an update loop, I modified the shader to add the time progression directly in the shader itself and used the scroll values as speed values. I calmed the water down so that the reflections looked good, and I added some pink to the light source and clouds to really get the dreamy effect. I originally tried getting a moon reflection in the bottom right corner, but couldn't get that to render through the clouds properly. A modified skybox shader could solve that problem in the future.

UI was TextMeshPro text. Nice, simple, and clean. 

Intro Cinematic:

One of my goals of this game jam was to give this game some sense of story and cinematics. Unity has some really cool tools for such things that I wanted to try out in a game jam. But at the same time, I needed to keep things simple enough that I could finish them quickly. So for the intro sequence, I built up the text sequence using Timeline and TextMeshPro text again. I snagged the text swapper playable from the Unity Hover Racer workshop pack and got right to work trying to sculpt my story. 

The reflection text was really special. I started by using a second camera that looked at the text and rendered to a render texture. Then I had a quad mesh game object render with this render texture to the main camera, and was enabled and disabled using an activation track on the timeline. To prevent the rest of the text from being visible, I created a black plane in front of the rest of the text that was set to a layer only visible by the reflection camera. Lastly, I wrote a custom shader that applied mipmap sampling blur, color remapping based on the UV horizontal component that worked in HUV space, and some sinusoidal animation. 

I think I wrote the skip cutscene functionality that night too. I don't remember. It was pretty trivial. It was about 1 AM when I finished these two scenes, and they looked fantastic! So I set up my blankets and pillows, watched an episode of Miraculous on Netflix, and then fell asleep.

I don't know at what point I transitioned from trying to fall asleep to dreaming about trying to fall asleep, but that was a very weird night.

Saturday:

I woke up at like 6 AM, but didn't get out of bed until 7 AM. Then I ate donuts for breakfast and got to thinking about level design and platforming gameplay. 

Level 1 Gameplay:

For level 1, the player would be a simple primitive, a box. But that also meant using a character controller with a capsule collider wouldn't work. So I did something stupid and built my controls around a Rigidbody that would calculate a desired velocity based on acceleration parameters and then translate those into forces.

DO NOT DO THIS!

I ran into bugs with friction with this setup. If I turned up friction, I couldn't accelerate the player up to max speed and the player would stick to walls when jumping and holding a direction into them. If I had no friction, the player wouldn't be carried by the moving platforms. I solved the issues using some hacky workarounds. But ultimately that caused a little bit of jittery motion on the platforms. And also the game sometimes loads with completely incorrect jump heights and no proper moving platform behavior. I don't know why this is yet, but I am suspicious it occurs when there's frame drops. 

There were a couple of things I got right though. I checked the y value of velocity and based on whether it was positive or negative applied a different value of downward acceleration. This nonlinear jump felt really good. I also used boxcasting (Raycasts with boxes) to detect if I was on the ground. 

After the game jam I looked up how to solve the problems I ran into and realized that I should have gone without a rigidbody and just used boxcasts and my own very simple collision resolution to get the exact movement behavior I wanted. That also could play nicely with root motion in the future.

Level 1 Design:

So the other aspect of level 1 that I was stuck on was the design. I had no idea how to make a challenging platformer without enemies nor parkour abilities. But fortunately after getting some sleep, the idea of moving platforms came to mind, and I ended up running with that idea a lot. Platform movement used smoothstep transformation to get the non-linear movement that felt really good. There's an awesome GDC talk on non-linear 1D transforms that goes into this in more detail. I came up with the idea of introducing a jump, introducing a jump gap, and then introducing the moving platforms and a couple of different configurations. And then finally I would set the player up for a crazy maze of moving platforms. This was mostly meant to be a little bit of a troll move to the students working around me during the jam when they would eventually play my game on stream, but it didn't quite get the effect I wanted because the camera didn't show how expansive the maze was. A little trigger that pulled the camera back would have probably been enough to get that "Oh <censored>!" reaction I was going for. 

For the actual level, I modeled it in Blender, except for the moving platforms which were prefabs. I had a little difficulty getting the scale right. I wanted the reflections of the water to be well framed without making the gameplay feel small and slow. I ended up making the player reach a max horizontal speed of 15 units per second. I paid for that one later. 

The water is the same as the title screen, but for the background instead of clearing the camera to the skybox I cleared it to white. And all the foreground elements used an unlit color shader (except for the water). I got a really nice contrast. The only thing missing was shadows on the water, which was suggested to me after the jam. 

Narration:

I never used a dialogue system before. The other guys in the room were writing their own, so I decided I would take a shortcut and find one on the asset store. I ended up using RPGTalk, mostly because Fungus looked to complicated and feature-rich with it's visual scripting system. Looking back, that might not have been the case. Anyways, RPGTalk was pretty cool. It had a couple of bugs, one being that my shared UI canvas would get disabled by the "don't play on start" instances after the "play on start" instance enabled it. I needed to do some script execution order ugliness to fix that one. The other bug was that text advancement sound crashed the game if I didn't have a text scroll sound. I fixed that bug directly in the RPGTalk.cs file. But aside from those two bugs, the system worked flawlessly. Name changing narration was automatic. And I could call a script method at the end of one talk to change some states such as activating player movement, changing some animator parameters, and sometimes starting another talk. With a couple of clever booleans and some trigger colliders, I got the opening cutscene and tutorial to play out seamlessly, and only played the tutorial part after a death (which might be annoying for level 1 but would be much more valuable for later levels). 

And lastly, there's that ??? character. A capsule collider that bends and has a different color reflection. It is actually a mesh modeled in Blender by splitting a UV sphere and bridging the gap with edge loops. And then I used two bones with auto-skinning and made some really simple animation clips. There's actually two instances of this animated mesh in the scene. One is only visible to the main camera, and the other is only visible to the water reflection camera. The character setup took me less than an hour, but really added a lot to the narrative.

Bright Light Scene:

This is a timeline sequence with a script to animate the Bloom on the Post Processing Stack V2, and then there's a custom vignette shader I wrote that did mipmap bias blurring and could bring the vignette radius all the way down to 0. Did I mention I used a heck of a lot of bloom? This cutscene doesn't make much sense until way later in the story (which I never got to). 

Kaceya Model:

So by this point, level 1 was completely done, well except for music and sound which I planned to do in the last couple of hours (well really I had the music on the game jam composer's queue). So I started on level 2. I didn't think I would finish it, but I was going to at least try. For level 2, I needed an actual character model for Kawena. However, while I'm pretty good at modeling things in Blender, I'm terrible at drawing and often require time and feedback to get character proportions right. Well I knew I didn't have time to get the proportions right via trial and error. It was Saturday evening past the halfway marker at this point, and I was getting tired. I also needed some inspiration for the actual character design outfit and hairstyle. I ended up with an outfit based on Juleka's, and used Crescent shapes for the hair and weapon. I then went searching for a base mesh that featured a young (child) anime-ish style girl with the right proportions (not chibi) that I could hack apart. Fortunately I found one on cadnav as well as a site that could convert the 3ds max file into something Blender could use. Then I went into the Blender zone and modified her features to look younger, and completely replaced her outfit and hair. How I did the hair was weird but very effective. I modeled an egg around her head (which looked ridiculous), and then cut out the face and extruded the bangs. Then I just added little divots and cuts to all around to make the hair look natural. And lastly I built the long crescent in the back. I honestly cannot believe I modeled such a crazy anime hairstyle during a game jam, much less rigged it. Heck, that rig was actually pretty good for automatic skinning. Only the knees broke, which I detected a little too late into animation.

But the rigging and animation happened Sunday after I got some sleep.

Sunday:

I overslept SundayI planned to wake up at 7. I woke up at 9. I did the hair that morning and the rig and idle animation in the early afternoon. I tried putting together some root motion walk cycles but quickly realized a fatal mistake. In level 1, my character moved at 15 meters per second! How the heck do you animate a girl only a meter tall to run that fast? I thought about adding roller blades, but wasn't sold on the idea, and the rig was starting to get ugly with those knees and I didn't have time to design a level. I still needed music and sound and some final playtesting. I spent some time downloading and sampling a bunch of sound effects until I got close enough to what I wanted. The jump and landing sounds were frustrating, as most free sounds were too cartoony and exaggerated. For music, the composer accidentally deleted the level 1 track and composed 2 minutes for a 65 second intro cutscene which he sliced down for me. He also composed the ??? theme, but I forgot to turn off the level 1 track when I started playing it. For Level 1 and the title screen, I ended up using free compositions from the Unity Asset Store featuring harps. They worked well enough. 

Lastly, there was the connecting of all the scenes and debugging Timeline not transitioning to the next scene after playing. And then I built that TBD scene featuring the Kawena and her idle animation just to show off where things were headed and where I sunk 8-12 hours of development time.

And then I submitted the game.

Overall, I am pretty happy with what I managed to accomplish in 48 hours. Building so many small cinematics, modeling a young anime-style character that actually turned out decent, and having some interesting platforming gameplay. I was a little disappointed in that I couldn't show off what I had planned for level 2 and the new mechanics. Kawena's weapon was going to generate a force field when swung a certain way. I'll let your intuitive imagination take it from there.

Thanks for reading through this! I hope you enjoyed the game jam entries and maybe learned a thing or two along the way. 

Feel free to ask questions in the comments!

Files

Reflections Overpowered.zip 57 MB
Jun 17, 2018

Get Reflections Overpowered

Leave a comment

Log in with itch.io to leave a comment.