Sunday, March 13, 2016

7DRL Post Mortem

I have officially declared my attempt this year as a failure, but I was able to get quite far in this in spite of a major service interruption in the web services that I maintain (which soaked up about half the week to remedy) and a project due for an Android class I was taking (which took up a solid day of time). I was able to gain some shaky footing in the Godot engine and start to understand how you might make a game with it.

I think that while this attempt didn't get to the point of a playable game, it was a success in many ways and I think I'll keep at it and perhaps have something to demo at my next Indie Game Developer meet up. If I can get the basic mechanics of the game in place before then, even if it lacks the rogue-like aspects I wanted, I think that I will be pretty impressed with the accomplishments. Further, I'll have this project at a pausing point just in time for our development sprints using Unity3D.

However, the challenge is over and I wanted to put together a post about what I learned regarding this process.

The Good

Using Godot it was very quick to get certain things up and running and even getting some of the behavior I wanted basically for free. That isn't even considering all of the things it gives me for free like handling input in a reasonable way, being portable to half a dozen platforms, and abstracting the graphics and sound to an easy to use interface. These tend to be things you get from any game engine, but it is important to note them here as they are something that Godot does pretty well.

Godot seems to be well thought out. No matter what exactly I want to do, there seems to be something in place to support that. This is pretty great feeling when you are coming from the world of either incomplete engines or building something by yourself. I feel like I'm programming, which is a good thing, but I also recognize that the scaffolding that they provide makes this all go much faster. Godot Script isn't that bad of a language and, while the text editor sucks and the developers seem to have something against embracing the one true faith, it works well enough to limp through basic editing tasks.

  • I was able to get an avatar walking around the screen using keyboard for motion and mouse for looking/aiming.
  • I was able to get basic collision detection for the player with walls, enemies, objects in the levels.
  • I was able to use the collision system and ray casting to allow interaction of the player with elements in the level. For example, the player can open a chest, but only if they are standing facing it and within the range of their arm.
  • I was able to use the 2D light occlusion to provide line of sight out of the box.
  • I was able to get some of the visual feel I wanted by using a pixelating shader.
  • I was able to get some animations close to how I would like them (the walking and aiming animations) and incorporate some of the mechanics (such as movement while aiming is slowed).
  • I was able to use the navigation polygon facility in the engine to route enemies around the map.

All in all, this got no where near a 'game', per se, but it did quickly become something where you could walk around and interact with things and it was clear how to move forward.

The Bad

Most of the 'bad' things that happened were basically because I underestimated all of the work that goes into making a game. I knew I would underestimate it, but I think it bears mentioning anyway.

Even as your ideas start to gel in your head, implementing them in the editor is quite the bottleneck. I basically can't imagine a world where this won't be true, but it sure is aggravating. You have a vision, be it good or bad, but it takes time to get things out. For example, while the art was difficult to brainstorm (how do you make something scary from a top-down view), it was even harder to create somewhat decent sprites and to get them all exported from Inkscape to their separately moving components and then key frame the animations in Godot. Only then do you see that what you were trying to do actually doesn't achieve the effect you wanted, and you need to go back to the drawing board all over again. This iteration process takes a lot of time.

One limitation that Godot caused was that performance is somewhat suspect in the Godot engine. Very early in this process I needed to decide between making a 3D game and a 2D game. I felt that a 3D game would provide more flexibility in how the visuals would appear and would require less fiddly tweaking of animations. In 3D I wouldn't need to worry about splitting my sprites into separate pieces to key the animation, this would all be handled by the renderer. However, after playing with the 3D platformer demo, I was struck by how poorly it performed on my Intel graphics chip. Using the discrete card gave passable performance, but I was looking to make a lightweight game and this engine was struggling to run a demo on my system, so I chose to go the 2D route. This directed many of my decisions from then on… and it makes me wonder if they directed them in bad directions.

I think these are basic limitations of working with sprites. Not much to do about it. Godot has some functionality to render 3D models into 2D sprites, but I didn't experiment enough to know if that would work. I had limited time and a decision needed to be made.

The Ugly

There were parts of Godot that are just awful, or at least awful from someone that approached it like I did. I thought that developing a game would be something like writing a program. It is not, or at least it is not if you are using Godot and probably any other engine with a GUI interface.

I develop software for a living. I might be doing all sorts of things with that software, automating processes on our servers, creating web pages, creating intricate back end networks, modeling complex systems, or scientific/data analysis, but I'm always writing code. As part of that I'm a bit of a snob when it comes with comes to how this should be done. When you develop code, you should be doing it with a text editor and a version control system. You develop by finding something you would like to change, making that change, and testing it to make sure it works (and potentially modify the change over several iterations), and the select those and only those changes to make a commit with at least a somewhat descriptive commit message to the repository. I pride myself on the fact that each commit only deals with one thing and it does it in a clear and concise of a way as possible. You can look at the code that was changed and it will only be code that relates to the purpose of the commit.

This mode of development is incredibly hard, if not impossible, when using Godot.

Adding a node to a scene generally changes many lines in the file. At minimum, because the nodes in the scene have an integer index, all later indexes are shifted. I have no idea why they have an integer index and they don't just use the location in the file, my guess is that they couldn't be bothered to write a decent parser for their text based scene format.

But that isn't the worst of it, general state of the editor window is also saved in the scene file. This includes things like the transformations (position, rotation, scaling) of all of the nodes even if those transformations are part of a animation. Seriously. If you advance the position in an animation, the new positions of the nodes is actually saved to disk! Why? Why not simply save the baseline transformation and then calculate the effective transformation using the animation and animation position before drawing? My guess is that they didn't think this through entirely. Whatever the case, I started getting into the habit of moving all of your animations back to 0 time before you make a commit in order to work around this.

The scene file also tracks metadata about the state of the editor, like what view is open, the 2D screen or the editor window. I think this is pretty dumb, but I think they are just following suit from Blender which does something similar if I recall correctly.

However, I will say that I think that this is just pretty difficult to do right. The point of the graphical interface is that it automates many menial tasks for you. Unfortunately, by covering up a bunch of menial tasks, the editor is quick to produce changes that are large and far reaching with the simple click of a button. I have opened a scene clicked the scene one time, and saw the diff of the file with what is in the repository develop hundreds of changes. In these cases I usually see no changes at all in the scene, nothing appears to be different in the editor, but it did something very significant to the file on disk. Invisible changes to your file are the root of many a head ache in software systems. All those times your spouse is tearing their hair out cursing at MS Word or Excel and trying to understand why everything looks the same but things are working differently, these invisible changes are often why. I want reproducibility. How can I get reproducibility if I can't even be sure of the contents of what is on disk?

This is not something that is in any way limited to Godot. Heck, it isn't even limited to graphical editors like Godot and Unity (or Inkscape and Blender, for that matter), it is something that you see in any editor that seeks to abstract some process so that the user doesn't need to worry about it. Even things like Eclipse or practically any 'enterprise' (a.k.a. bloated) IDE, tend to hide stray whitespace from the user which tends to encourage users to produce far from clean commit diffs (and causes good maintainers to reject their pull requests).

So, in total, I think that they need to seriously rethink their format for saving files. The new text based scene and resource files were advertised as a version control friendly format. I very much love the idea that there could potentially be a version control friendly format, and I think the great step forward they made here was making the format a human readable text format, but the goal of making the scenes and resources somehow source control friendly has simply not been met.

Update: After writing this, I think I have come to a 'solution' here. While far from my ideal solution, I'm simply not going to develop any Godot projects under source control. I am going to treat Godot as I would Inkscape or Blender, I'm going to treat it as a way to edit visual media and I'm not going to care what is going on under the hood in the file formats.

Perhaps I will put my scripts under source control, but for the rest of the project I am going to do something much simpler, I'm going to treat the entire thing as a black box and take periodic backups. I wrote a script that takes a backup of my working directory every 10 minutes (if changed) and thins out the old backups as I go (using rsync with hardlinking). This will be a better way to work on this. I don't get to keep track of changes, but at least I know I can restore a relevant previous version of the project if something goes wrong. If we are being honest, unless you can look at the content of each commit diff and understand what is happening, you basically have a file format that is a black box and you shouldn't attempt to use version control. I expect that I will be using a similar setup for my Unity3D projects. Perhaps some good has come of what I originally thought of as an unmitigated failure of the Godot engine. This was a hard lesson to learn and I feel a bit naked without a version control safety blanket, but I needed to realign my thoughts on how this sort of GUI based game development works.

No comments :

Post a Comment