dukope







Level 3 Re: Return of the Obra Dinn [Playable Build] « Reply #584 on: March 29, 2016, 06:58:19 AM »



In typical fashion, I finished the GDC demo build just in time. I flew to SF with the final build on a USB stick, showed the game for a week, came home, decompressed for a few days, then took care of all the stuff that I'd put off during the democrunch (taxes). I'm still planning to release the GDC demo publicly, but I found a shader problem when running the build under OpenGL that I want to track down and fix first. I'm still a little gun-shy on jumping back into development full time though so I thought I'd update this devlog before worrying about the demo.





The Demo







Title screen hasn't changed much Title screen hasn't changed much



First, a brief summary of what's present in the GDC demo: not much more than the development release from October 2014. I made a proper settings/pause menu, fleshed out the starting sequence, modeled more of the main deck, remastered some of the music, added one additional flashback, incorporated some blur effects, and did a few other small things. Everything else I've been working on is not visible in the demo.



Something that bothered me during this 1.5 months of democrunch was just how much fucking work I was doing just to get back to the level of functionality the old development build had, 1.5 years ago. That build was a pretty nice vertical slice of the game; stuff was missing but for the first ~20 minutes of gameplay it turns out to be fairly representative. This is something I've experienced before - kicking out a solid vertical slice in X months, then breaking everything badly while scaling up the tools/pipeline/systems for the full game. Years later you look back and wonder, based on the quality of the initial slice, wtf took so long.



Well the game isn't done yet but I wanted to establish a bunch of excuses look back now on why the current GDC demo isn't clearly 1.5 years better than the old development build. The primary culprit is that the tools/pipeline/systems that I built for the vertical slice did not scale up (at all) to making a full game. A lot of time was spent on small obvious stuff and I spun my wheels here and there just waiting for random inspiration at times. Fortunately for this devlog there are also some specific blog-worthy things that came up in the last year and a half. Specifically:





Unity 5







I'm still very happy with Unity but man, that switch to 5.0 was a bitch. A lot of random stuff broke, which is normal, but the big kicker was their new lighting system: based on Enlighten and entirely unready to ship. After giving up on a fix ever coming in time I spent a few weeks and wrote a custom lightmapping system that fit my exact needs. I'm glad that sort of customization is possible but I doubt many developers are happy with the current state of Unity's lighting system.





Maya LT







Trying to save some cash, I bought Maya LT instead of Maya Full when starting this project. That turned out to be a huge mistake and wasted hundreds of hours of my time. Too many missing features that I had to work around and an insulting upgrade process when I finally sprung for the full version after finishing the development release. None of my Maya LT scenes could be moved to Maya Full unscathed. I spent several days just getting everything ported over to the full version.





The Ship



Upper deck before and after



This isn't a lost time kinda thing, just a mention that progress was made outside of what's obvious in the demo. A good chunk of my time was spent modeling the rest of the ship's decks, rooms, cargo, detritus, etc. That's 85% done now but I can't really prove most of that so just trust me.





Lower deck stuff



Neverending Ropes







Building out the ship's rigging was always going to be a pain in the ass. I initially wrote some rope-generation scripts that you can see in action in my old timelapse here: youtube.com/watch?v=wBYxDprgHPg. These scripts were only necessary because Maya doesn't have a usable system for curve editing and dynamic extrusion. Instead, I worked with 2-point linear curves and had a script generate the actual rope and pulley geometry. Everything worked great with a simple static ship but one of the main challenges with this game is how the ship needs to change/articulate in the flashbacks. And once I introduced elements that would need to pull and stretch on the ropes (eg: moving booms or a crew member climbing the rigging), things got scary quickly.



The solution I ended up with was to replace all the 2-point linear curves that define the ropes with joint chains (curve editing, even with just two endpoints is unsurprisingly a huge pain in Maya). The rope-generation script was updated to create a curve passing through the joints before running the old code to create the geometry. Joint chains are first-class citizens in Maya so I can use constraints to pin the ends or middle of a rope to different things. This makes it possible to, say, move a mast and have all the rigging stay attached.





Ropes as joint chains with constrained endpoints



Using joints and constraints also allowed me to create a fairly complex control rig for the mast shrouds. These were especially tricky since I wanted them to deform in a natural way without manually adjusting each of the many, many ropes and their intersections.





Adjusting the shroud rig by moving one control box (in green).



There's still the downsides that I need to run a "generate geometry" pass after adjusting the joint chains, and each flashback's custom rigging needs to be exported separately, but I'm prepared to live with those inconveniences at this point. Probably.





Moments



Final moment editor. A visually stunning 3,000 lines of Python code.



This was a long and winding road. "Moments" are flashbacks in game lingo, and each moment is basically a snapshot of the ship in a certain configuration plus a collection of posed characters. Creating, exporting, and interpreting these moments is pretty complex along the whole pipeline and it took me several tries to find a system that handled the functionality and scale that I wanted. I'll try to summarize the different implementations I worked through.



Version 1



My first attempt at defining the moments was to use a single rigged character inside the ship Maya scene. Different blend targets for the character's skin mesh were added/weighted to change the appearance, and individual frames of animation were used for all the different poses of all the different crew members in all the different moments. Eg: frame 120 is the captain in Moment01, frame 121 is the first mate in Moment01, etc. The single modified character was then baked and exported for each frame to generate the many individual posed crew member meshes. The original development release of the game used this system.



This was a huge pain to manage, error-prone due to poses leaking into later animation frames, and required lots of individual meshes in Maya and the game. It also offered no solution for hiding or articulating parts of the ship - only crew members could be posed. Not scalable at all.



Version 2



This iteration moved the character skin, rig, blend shapes, and accessories out of the ship scene and into a separate "human" scene. I wrote a custom character builder UI in Maya that let me choose/edit blend shapes and accessories and export each character from human.ma to its own stripped Maya scene. Those stripped scenes are then referenced into the ship scene. "Referencing" is a Maya feature that lets you nest scenes together without copying the data. Posing was done using Maya's built-in animation layers for the separate moments. If a moment had 10 characters, all 10 rigged character scenes would be referenced in, the animation layer for that specified moment activated, and Maya selection sets would be used to hide/show different ship elements.



This covered all the bases (posable ship, posable characters), and the "moment selection" script/UI I wrote made switching between moments easy. But Maya's animation layers are, again, painful to use. It was pretty common for the wrong animation layer to be selected, which would blow out old poses and cause all kinds of problems. Copying poses between characters or moments, a common operation, was also extremely difficult. And finally, using references and animation layers in Maya is a bit of a black box - it's difficult to track and audit how you've changed a reference by say, posing or animating it. An even if you could track down a problem, references/animlayers themselves are flaky enough that "fixing" is often the same as "redoing". That's pretty dire when dealing with 60 characters across ~50 moments so I wanted something both more flexible and more transparent.



Version 3



Finally I went nuclear and wrote my own simple keyframe/pose system that could apply equally across in-scene ship objects and referenced-in character rigs. That was a lot of work but the end result is that I can build and edit moments much more quickly. I also have a lot more control over the small tools that make posing easier (copy/paste/rig pinning/simulation/etc). And since moment poses are implemented as a simple text file format, I can manage many things externally (and safely) outside of Maya. All characters for a particular moment are referenced in as-needed, which improves Maya's performance, all characters are exported as one FBX scene, and the ship's articulations are exported in a custom format that's applied in Unity on import - this saves time on exporting the ship itself for every small moment change.





Clothing



There were no clothes on the characters in the original development release. Well, there's clothes but they're implemented as modifications (blend targets) to the character's base skin mesh. When posing characters the clothes stay unnaturally smooth and look sorta fake.





This poor soul's shirt was modeled straight into the body mesh.



In many cases this is fine but for the more dynamic scenes the rigidness of the skin-bound cloth bothered me and I really wanted to use Maya's simulated cloth instead. Unfortunately, that's difficult given the Maya scene setup and especially the way moments are built - simulating cloth requires keyframing characters from their starting pose (where the cloth was modeled) to the final pose you actually want.





Simulating cloth from the start pose to the final pose.



Getting this to work was another motivation for rebuilding the moment system so many times. Both versions 1 and 2 above relied on using Maya's animation timeline for custom purposes and made this sort of simulation difficult. Version 3 finally solved that by giving each moment its own unfettered timeline and so it's now possible to simulate dynamics normally - cloth, liquids, and rigid objects.





The difference is subtle here but ratchets up with more complex cloth and action



It's worth noting that Maya's dynamics, while producing decent results, are not straightforward to use. Running a simulation requires creating a raft of scene-clogging nodes and tweaking gobs of parameters through a poorly-design UI. And with the way dynamics relate to the timeline (bizarrely) you definitely don't want to leave dynamic nodes around while you work on other stuff. Simulating things is a process that, if you place any value on your time, basically requires custom scripts for automation.





Wave Motion



Somewhere in the devlog I posted about running a realtime buoyancy simulation in Unity for the gentle rocking of the ship. That worked fine to a point. When I added a small rowboat where the game starts it became clear that a realtime simulation was A) a waste of cycles and B) complicating things beyond comfort with two boats and two separate wave responses in the same scene. Instead of tweaking the simulation script, I clicked over to Maya and set up a representative scene there with an Ocean plane and two dynamic Boats. After a bit of tweaking I got something looking ok, exported the animation to Unity, fixed up the looping, and called it a day. Now the wave motion is driven directly by the animation and there's no realtime simulation at all.





Wave motion simulated with Maya's Ocean/Boat nodes



This is basically the best kind of refactor in my opinion. Start out broad, flexible, and slow, then reduce features and flexibility as the design is nailed down. When you know exactly what you have and what you need, refactor it all to be the least amount of code and smallest asset size possible. The really nice part about this particular refactor is that the existing tools supported it perfectly - Building the initial realtime solution was easy in Unity and creating/baking the simulation was easy in Maya.





Fluid Simulation



Using Bifrost in Maya for fluid simulation. Only the last frame is exported.



Fluid simulation is another dynamic touch that I wanted as a cool way to emphasize the frozen action of the flashbacks. I played around with the demo for RealFlow for the development release but switching between Maya and a separate app was really clunky. Luckily Maya 2015 added Bifrost, Autodesk's acquired answer to RealFlow. For my purposes Bifrost is more difficult to use than RealFlow but keeping everything in Maya is enough of a benefit though that I'll just power through the downsides. Also RealFlow is something like $2,500 and Bifrost is included with the Maya Full license. I got burned trying to save money before but man that's a lot of green.





Controls







Unity's built-in input system is pretty bad but it suited the original development release ok. The primary motivation for this updated release was to show the game at GDC and in that scenario a gaming controller works much better than mouse+keyboard. I first just hooked up Unity's input to the Playstation DS4 but anybody who's tried that can palpably feel the corner they're painting themselves into. The input editing UI sucks and hardcoding random names like "joystick button 5" to the "Open Menu" action is pretty farcical.



For the first time, I hopped onto the Unity Asset Store and surveyed the input managers there with the intent of buying something. InControl and Rewired are both highly praised and I ended up grabbing Rewired since it seemed to drop in mostly easily for Unity's Input calls. Rewired configuration tools are a bit overwhelming but I'm really happy that it's saved me a lot of work for just ~$40.





Settings Menu



Colors by popular request



Making a settings/pause menu is one of those things that I don't normally calculate into my schedule. At some point I realize it's not there, and it should be, and I take a few days to add it. Same deal with the GDC demo. Thankfully I really like Unity's new UI system - it feels like a great realization of component-based entities with a powerful editor and easy scripting support. If only the editor supported nested prefabs it'd be perfect. The main thing I needed from a settings menu was the "Invert Y" option but I also added some color-changing options and a way to smooth the final pixel output (Connection: Analog).





Retrospect



Looking back at all these problems it's easy to blame the tools I'm working with (Maya!). But I think the real issue is just with how I build games. I like to work very loosely and non-destructively towards a fairly nebulous goal. I'm always figuring things out, retrying stuff, tweaking the mechanics or feel of the game along the way as I build it. Most tools are not built for that. A more standard process - define what I want, then build it - would make production much easier and I wouldn't need so much flexibility from the tools. There've been several times when I sat down and said: "ok, plot out the whole game so I know what to build", only to give up and go back to noodling on some small thing. Seems like nailing down the whole package is harder than building forgiving tools that let me stay frosty as I go. Ok, back and mostly rested from GDC. I had a great time and scooped up lots of solid feedback. My thanks to Greg Rice and DoubleFine for the opportunity to have Obra Dinn there. And to all the other developers showing their games in the Day of the Devs area, especially my table buddy William Chyr with his fantastic puzzler Manifold Garden In typical fashion, I finished the GDC demo build just in time. I flew to SF with the final build on a USB stick, showed the game for a week, came home, decompressed for a few days, then took care of all the stuff that I'd put off during the democrunch (taxes). I'm still planning to release the GDC demo publicly, but I found a shader problem when running the build under OpenGL that I want to track down and fix first. I'm still a little gun-shy on jumping back into development full time though so I thought I'd update this devlog before worrying about the demo.First, a brief summary of what's present in the GDC demo: not much more than the development release from October 2014. I made a proper settings/pause menu, fleshed out the starting sequence, modeled more of the main deck, remastered some of the music, added one additional flashback, incorporated some blur effects, and did a few other small things. Everything else I've been working on is not visible in the demo.Something that bothered me during this 1.5 months of democrunch was just how much fucking work I was doing just to get back to the level of functionality the old development build had, 1.5 years ago. That build was a pretty nice vertical slice of the game; stuff was missing but for the first ~20 minutes of gameplay it turns out to be fairly representative. This is something I've experienced before - kicking out a solid vertical slice in X months, then breaking everything badly while scaling up the tools/pipeline/systems for the full game. Years later you look back and wonder, based on the quality of the initial slice, wtf took so long.Well the game isn't done yet but I wanted tolook back now on why the current GDC demo isn't clearly 1.5 years better than the old development build. The primary culprit is that the tools/pipeline/systems that I built for the vertical slice did not scale up (at all) to making a full game. A lot of time was spent on small obvious stuff and I spun my wheels here and there just waiting for random inspiration at times. Fortunately for this devlog there are also some specific blog-worthy things that came up in the last year and a half. Specifically:I'm still very happy with Unity but man, that switch to 5.0 was a bitch. A lot of random stuff broke, which is normal, but the big kicker was their new lighting system: based on Enlighten and entirely unready to ship. After giving up on a fix ever coming in time I spent a few weeks and wrote a custom lightmapping system that fit my exact needs. I'm glad that sort of customization is possible but I doubt many developers are happy with the current state of Unity's lighting system.Trying to save some cash, I bought Maya LT instead of Maya Full when starting this project. That turned out to be a huge mistake and wasted hundreds of hours of my time. Too many missing features that I had to work around and an insulting upgrade process when I finally sprung for the full version after finishing the development release. None of my Maya LT scenes could be moved to Maya Full unscathed. I spent several days just getting everything ported over to the full version.This isn't a lost time kinda thing, just a mention that progress was made outside of what's obvious in the demo. A good chunk of my time was spent modeling the rest of the ship's decks, rooms, cargo, detritus, etc. That's 85% done now but I can't really prove most of that so just trust me.Building out the ship's rigging was always going to be a pain in the ass. I initially wrote some rope-generation scripts that you can see in action in my old timelapse here: youtube.com/watch?v=wBYxDprgHPg. These scripts were only necessary because Maya doesn't have a usable system for curve editing and dynamic extrusion. Instead, I worked with 2-point linear curves and had a script generate the actual rope and pulley geometry. Everything worked great with a simple static ship but one of the main challenges with this game is how the ship needs to change/articulate in the flashbacks. And once I introduced elements that would need to pull and stretch on the ropes (eg: moving booms or a crew member climbing the rigging), things got scary quickly.The solution I ended up with was to replace all the 2-point linear curves that define the ropes with joint chains (curve editing, even with just two endpoints is unsurprisingly a huge pain in Maya). The rope-generation script was updated to create a curve passing through the joints before running the old code to create the geometry. Joint chains are first-class citizens in Maya so I can use constraints to pin the ends or middle of a rope to different things. This makes it possible to, say, move a mast and have all the rigging stay attached.Using joints and constraints also allowed me to create a fairly complex control rig for the mast shrouds. These were especially tricky since I wanted them to deform in a natural way without manually adjusting each of the many, many ropes and their intersections.There's still the downsides that I need to run a "generate geometry" pass after adjusting the joint chains, and each flashback's custom rigging needs to be exported separately, but I'm prepared to live with those inconveniences at this point. Probably.This was a long and winding road. "Moments" are flashbacks in game lingo, and each moment is basically a snapshot of the ship in a certain configuration plus a collection of posed characters. Creating, exporting, and interpreting these moments is pretty complex along the whole pipeline and it took me several tries to find a system that handled the functionality and scale that I wanted. I'll try to summarize the different implementations I worked through.My first attempt at defining the moments was to use a single rigged character inside the ship Maya scene. Different blend targets for the character's skin mesh were added/weighted to change the appearance, and individual frames of animation were used for all the different poses of all the different crew members in all the different moments. Eg: frame 120 is the captain in Moment01, frame 121 is the first mate in Moment01, etc. The single modified character was then baked and exported for each frame to generate the many individual posed crew member meshes. The original development release of the game used this system.This was a huge pain to manage, error-prone due to poses leaking into later animation frames, and required lots of individual meshes in Maya and the game. It also offered no solution for hiding or articulating parts of the ship - only crew members could be posed. Not scalable at all.This iteration moved the character skin, rig, blend shapes, and accessories out of the ship scene and into a separate "human" scene. I wrote a custom character builder UI in Maya that let me choose/edit blend shapes and accessories and export each character from human.ma to its own stripped Maya scene. Those stripped scenes are then referenced into the ship scene. "Referencing" is a Maya feature that lets you nest scenes together without copying the data. Posing was done using Maya's built-in animation layers for the separate moments. If a moment had 10 characters, all 10 rigged character scenes would be referenced in, the animation layer for that specified moment activated, and Maya selection sets would be used to hide/show different ship elements.This covered all the bases (posable ship, posable characters), and the "moment selection" script/UI I wrote made switching between moments easy. But Maya's animation layers are, again, painful to use. It was pretty common for the wrong animation layer to be selected, which would blow out old poses and cause all kinds of problems. Copying poses between characters or moments, a common operation, was also extremely difficult. And finally, using references and animation layers in Maya is a bit of a black box - it's difficult to track and audit how you've changed a reference by say, posing or animating it. An even if you could track down a problem, references/animlayers themselves are flaky enough that "fixing" is often the same as "redoing". That's pretty dire when dealing with 60 characters across ~50 moments so I wanted something both more flexible and more transparent.Finally I went nuclear and wrote my own simple keyframe/pose system that could apply equally across in-scene ship objects and referenced-in character rigs. That was a lot of work but the end result is that I can build and edit moments much more quickly. I also have a lot more control over the small tools that make posing easier (copy/paste/rig pinning/simulation/etc). And since moment poses are implemented as a simple text file format, I can manage many things externally (and safely) outside of Maya. All characters for a particular moment are referenced in as-needed, which improves Maya's performance, all characters are exported as one FBX scene, and the ship's articulations are exported in a custom format that's applied in Unity on import - this saves time on exporting the ship itself for every small moment change.There were no clothes on the characters in the original development release. Well, there's clothes but they're implemented as modifications (blend targets) to the character's base skin mesh. When posing characters the clothes stay unnaturally smooth and look sorta fake.In many cases this is fine but for the more dynamic scenes the rigidness of the skin-bound cloth bothered me and I really wanted to use Maya's simulated cloth instead. Unfortunately, that's difficult given the Maya scene setup and especially the way moments are built - simulating cloth requires keyframing characters from their starting pose (where the cloth was modeled) to the final pose you actually want.Getting this to work was another motivation for rebuilding the moment system so many times. Both versions 1 and 2 above relied on using Maya's animation timeline for custom purposes and made this sort of simulation difficult. Version 3 finally solved that by giving each moment its own unfettered timeline and so it's now possible to simulate dynamics normally - cloth, liquids, and rigid objects.It's worth noting that Maya's dynamics, while producing decent results, are not straightforward to use. Running a simulation requires creating a raft of scene-clogging nodes and tweaking gobs of parameters through a poorly-design UI. And with the way dynamics relate to the timeline (bizarrely) you definitely don't want to leave dynamic nodes around while you work on other stuff. Simulating things is a process that, if you place any value on your time, basically requires custom scripts for automation.Somewhere in the devlog I posted about running a realtime buoyancy simulation in Unity for the gentle rocking of the ship. That worked fine to a point. When I added a small rowboat where the game starts it became clear that a realtime simulation was A) a waste of cycles and B) complicating things beyond comfort with two boats and two separate wave responses in the same scene. Instead of tweaking the simulation script, I clicked over to Maya and set up a representative scene there with an Ocean plane and two dynamic Boats. After a bit of tweaking I got something looking ok, exported the animation to Unity, fixed up the looping, and called it a day. Now the wave motion is driven directly by the animation and there's no realtime simulation at all.This is basically the best kind of refactor in my opinion. Start out broad, flexible, and slow, then reduce features and flexibility as the design is nailed down. When you know exactly what you have and what you need, refactor it all to be the least amount of code and smallest asset size possible. The really nice part about this particular refactor is that the existing tools supported it perfectly - Building the initial realtime solution was easy in Unity and creating/baking the simulation was easy in Maya.Fluid simulation is another dynamic touch that I wanted as a cool way to emphasize the frozen action of the flashbacks. I played around with the demo for RealFlow for the development release but switching between Maya and a separate app was really clunky. Luckily Maya 2015 added Bifrost, Autodesk's acquired answer to RealFlow. For my purposes Bifrost is more difficult to use than RealFlow but keeping everything in Maya is enough of a benefit though that I'll just power through the downsides. Also RealFlow is something like $2,500 and Bifrost is included with the Maya Full license. I got burned trying to save money before but man that's a lot of green.Unity's built-in input system is pretty bad but it suited the original development release ok. The primary motivation for this updated release was to show the game at GDC and in that scenario a gaming controller works much better than mouse+keyboard. I first just hooked up Unity's input to the Playstation DS4 but anybody who's tried that can palpably feel the corner they're painting themselves into. The input editing UI sucks and hardcoding random names like "joystick button 5" to the "Open Menu" action is pretty farcical.For the first time, I hopped onto the Unity Asset Store and surveyed the input managers there with the intent of buying something. InControl and Rewired are both highly praised and I ended up grabbing Rewired since it seemed to drop in mostly easily for Unity'scalls. Rewired configuration tools are a bit overwhelming but I'm really happy that it's saved me a lot of work for just ~$40.Making a settings/pause menu is one of those things that I don't normally calculate into my schedule. At some point I realize it's not there, and it should be, and I take a few days to add it. Same deal with the GDC demo. Thankfully I really like Unity's new UI system - it feels like a great realization of component-based entities with a powerful editor and easy scripting support. If only the editor supported nested prefabs it'd be perfect. The main thing I needed from a settings menu was the "Invert Y" option but I also added some color-changing options and a way to smooth the final pixel output (Connection: Analog).Looking back at all these problems it's easy to blame the tools I'm working with (Maya!). But I think the real issue is just with how I build games. I like to work very loosely and non-destructively towards a fairly nebulous goal. I'm always figuring things out, retrying stuff, tweaking the mechanics or feel of the game along the way as I build it. Most tools are not built for that. A more standard process - define what I want, then build it - would make production much easier and I wouldn't need so much flexibility from the tools. There've been several times when I sat down and said: "ok, plot out the whole game so I know what to build", only to give up and go back to noodling on some small thing. Seems like nailing down the whole package is harder than building forgiving tools that let me stay frosty as I go. « Last Edit: March 29, 2016, 07:08:58 AM by dukope » Logged @dukope - Return of the Obra Dinn - Papers, Please - 6 Degrees of Sabotage - The Republia Times - Helsing's Fire