Categories: Devlog | Game Design | Game Development | News | Retrospective | Technical | Web Development |
  • Instance vs. New in Godot

  • Technical · Godot · 2018-09-25 · nightblade
  • godot logo

    Summary

    Godot provides a way to separate the presentation part of game entities from their underlying data. You can think of this as something akin to the Model-View-Controller design pattern, where scripts (classes/code) respresent the model and instanced scenes (sprite, animation, etc.) represent the presentation and control (eg. collision resolution).

    During the development of Eman Quest, we continuously ran into a problem around instancing scenes that are strongly typed and have methods from their corresponding scripts. In fact, there's even an open bug about it as of Godot 3.0.6.

    You can find a description of the problem below, along with the solution, and recommendations.

    Why This Became a Problem

    We created Eman Quest as a procedurally-generated RPG; the idea is to generate a persistent, complete world (maps, enemies, etc.) By itself, this proves to be an interesting and troublesome problem to solve, because:

    • In Godot, everything is a scene. Your world map, forest map, etc. are scenes.
    • You can't easily persist scenes or their entities.
    • When you change scenes, the old scene -- and all entities -- get garbage-collected.
    • Fundamentally, you need to separate data from the view/presentation.

    To solve this, we started initially by generating scenes and saving those; when the GC reared it's dragonish head, we instead moved to saving data as arbitrary JSON (dictionaries) of key/value pairs; when this required maintaining a set of properties twice (eg. monster strength in JSON vs. strength attribute in the instanced scene), we finally moved to creating scenes and matching scripts/classes.

    Then we broke Godot.

    The Problem and Symptoms

    Near the middle of development, while creating a TreasureChest class, I ran into an interesting problem: although my script file defined several methods and properties (like .open() or .contents), I couldn't call any of them; Godot complained:

    Invalid set index 'contents' (on base: StaticBody2D') with value of type 'Nil'

    Godot identified/typed the instance as StaticBody2D, not TreasureChest. Why?

    It turns out the answer lies in the two methods Godot offers to create objects: .instance and .new

    Scenes vs. Scripts as Classes

    Naively, Godot offers two ways to create an entity: instance and new.

    If it's a Scene with sub-objects (such as a Sprite), you load/preload the .tscn, and call instance. For example: var treasure_chest = load("res://Entities/TreasureChest.tscn").instance().

    This creates the entire hierarchy of sub-scenes. When you call add_child to add it to the scene, Godot calls the _ready function; this is where you put constructor-like code.

    Alternatively, if you just have a "class" defined in a script, you load/preload the .gd file and call new on it. For example: var treasure_chest = load("res://Entities/TreasureChest.gd").new(contents, coordinates, etc.).

    In the latter case, you define an _init function for a constructor, and specify whatever parameters you like. This conveniently allows you to specify state and guarantee invariants, such as "treasure chests always have non-null contents."

    However, Godot breaks when you cross these two together. If you load a .tscn definition and then call instance, and the class/script back-end has an _init function, the instanced scene doesn't have any of the scripts defined methods/properties.

    Solution and Combining the Two Approaches

    This could be because of timing (when in the life-cycle we're creating the script), I don't know. What I do know, is that removing _init fixes the problem. But then, how do we re-add initialization of the entity's state?

    For entities where we use both the instanced scene (in the place where we populate the tilemaps, etc. on-screen) and the script only (as the generated back-end data/object), we decided on the following approach:

    • Don't use _init. It could lead to this obscure bug again later, and suck up a ton of time to figure out.
    • To construct a new object class/script instance, create an initialize method and use that as the constructor. This is where we can set state/invariants, etc.
    • Keep a single scene for the presentation, and use a script to keep all the back-end class code (properties/methods)
    • When we need to instance the actual scene tree for that object -- such as with monsters or treasure chests -- keep the data object separate, and create an initialize_from instance.
    • initialize_from sets all the properties on the scene (such as presentation: is the treasure chest already opened or not?) based on the properties of the class/data object underlying.

    This approach also solved other problems, such as keeping references to instances across scenes. Godot doesn't like this, because it tries to GC everything. Storing the data separately neatly (sometimes in a singleton script) solves this problem.

    Conclusion and Future Improvements

    This solution solves our problem neatly. It keeps our code DRY, by using one definition of an entity's properties. It allows us to separate presentation from model/data, which is useful to prevent coupling.

    But, it's not ideal. At best, we can use _init judiciously for entities that we know we'll never show in a scene. We can always resort to using data (dictionaries/JSON) instead of classes; we miss out on code completion, but this better represents entity-component systems with data-driven design.

    Did you ever run into this problem? Do you see a better way of solving it? Drop a comment and let us know, we would really love to hear about better solutions to this problem.

  • How Tiny Rails Quietly Normalizes Islam and Muslims

  • Game Design · Game Design Analysis · 2018-06-25 · nightblade
  • One of our main goals at Deen Games is to represent the views of Islam and Muslims in games. Muslims have something of a negative image in games. To paraphrase one video from Extra Credits: "Enemies in FPS games have gradually changed from Nazis to Arabs [Muslims]." One of the games that casually but positively portrays us is Tin Rails.

    Credit: Tiny Rails Wiki (The Great Mosque of Djenne, Africa. Credit: Tiny Rails wiki)

    Tiny Rails is something of a cult hit on Google Play, with over a million downloads and more than 50k reviews averaging 4.5 stars. You play the role of a small up-and-coming mom-and-pop train company, working to build a name for yourself and grab a cut of the market from bigger, established railroad companies like RailCo.

    The game plays out as something of an idle game. While you can select upgrades, equip cars, plot your destiation, etc. most of the travel time takes place completely automatically with little or no intervention.

    Moments provide one exception to this. While travelling between certain cities, you can randomly stumble upon a real-world landmark, such as the Atlanta Airport or the CN Tower; snapping a picture of this (the in-game camera view automatically appears) nets you a few gold.

    Both of these mechanics subtly and humbly add Islam and Muslims to the mix. Tiny Rails includes eight different moments that document mosques in different parts of the world, ranging from Africa to the Middle East to Russia. Like any other moments to discover, you receive an in-game reward, encouraging discovery of these moments.

    You can also take a look at which passengers inhabit your train at any given time. Passengers include a visibly-Muslim cast.

    Credit: Mobile Syrup (Getting feedback from train passengers. Credit: Mobile Syrup)

    Both these gameplay elements normalize an otherwise negative image of Muslims and Islam in games. And Tiny Rails pulls it off without any fuss or fan-fare.

    You can grab Tiny Rails from Google Play, here if you want to give it a try. It's a great example of how a game can be positive and inclusive and part of their core gameplay.

  • The Brilliance of Bastion's Flexible Builds

  • Game Development · 2018-05-15 · nightblade
  • Bastion character upgrade choice

    In RPGs (especially those of the 90s and early 2000s), game designers typically increase difficulty by creating increasingly powerful enemies (and more dangerous groups). To balance this, player characters engage in combat, gain experience points, and level up. Obviously, you want the game should increase in challenge/difficulty over time, or it starts to bore the player.

    With this approach, players have an advantage: if stuck, players can grind (kill monsters over and over again) and be able to progress further (in contrast to remaining stuck in the same impassable area). However, it also includes a couple of drawbacks for the player:

    • Which Choice to Pick: When faced with multiple choices (eg. two options to upgrade your character), the player often lacks enough information to decide. Even if they know which option they want to pick, the player almost never has the ability to actually try both options and see which one works best.
    • Fixed Builds: Once the player chooses, there's no going back. This is partly the cause of decision paralysis where players take forever to choose. Worse, if your game is not carefully balanced to cover all possibilities, the player may end up making a series of decisions that leave them with an impossible-to-win build, although grinding can help here.

    The Brilliance of Bastion

    Bastion solves both these problems by allowing you to "re-spec" or change your upgrade decisions at virtually any point in the game.

    In Bastion, when the player levels up, they unlock a slot for "Spirits," which provide stats boosts; the player also receives a few unique choices per slot. The player can always return to the Distilliary building and change which spirits they've selected.

    With weapons, Bastion follows a two-step process: first, you find an upgrade item, and pay to unlock it. Once you do that, the game presents you with two options per upgrade; you can pick between them (and change your choices) at any time.

    Bastion weapon upgrades

    At a micro-level, the user can pick individual upgrades. However, with both spirits and with weapon upgrades, the player can create builds at a macro level. Many of the options harmonize well with other options; and between the choice of player upgrades and weapon upgrades, the player can craft a large number of builds that suit their particular preferences of playing style and their choice of weapons.

    Best of all, the player can test and tweak their builds, and change their minds at any time. This, in addition to the unparalleled flexibilty, gives the player a lot of freedom.

    But, it comes at a cost: some combinations are obviously more powerful than others, and some are quite unbalanced. This makes the game design a bit more challenging, because the designer needs to handle a wider range of possibilities.

    Takeaways

    As game designers, I think we can learn a lot from Bastion's design:

    • Providing a flexible upgrade system gives players the ability to tweak and test their builds
    • Flexible builds makes it less likely for the player to be really stuck (there are lots of alternatives to try)
    • But, flexible builds requires care to make sure some builds are not over-/under-powered, and that levels are balanced

    Finally, many games already implement flexible builds today, including League of Legends and DOTA 2, and even classics like Final Fantasy 5. We can see, from this, that the concept of flexible builds can apply to different game genres.

    If you think flexible builds can add to your game, try it, and see if the benefit of multiple progression paths outweighs the cost of slightly more complex game balancing.

  • Game Design in Open-World

  • Game Development · 2018-05-11 · chemicalink
  • According to many, open-world is fun. Perhaps it's the sense of freedom, progression, or influence upon the world which tickles a player's funny bone. Whichever it is, if there's anything we game designers know, it's that it's hard to pull off.

    Open-World?! What's That Mumbo-Jumbo's All About?

    Firstly, what is an open-world game? Trusty Wikipedia reports,

    A video game in which a player can roam a virtual world and approach objectives freely, as opposed to a game with more linear gameplay.
    

    Yet with such a notion of a player freely wandering into wherever they please comes bundled with a set of issues which, if not dealt with properly, will make or break your game. Most prominently...

    Player Power Level vs. World Power Level

    Imagine you're making a game with a linear main quest where monsters gradually get stronger as the player progresses and gains more power. You wake up one day and decide open-world is the one feature which has to be included in your game. So you go ahead and remove all travel restrictions, and add a bit of side content.

    The ingenuous player decides to delay your main quest and spend some time on side quests. "Those monsters sure keep getting stronger," thought the player. "I need to do some side quests so I can stay one step ahead of them."

    Lo and behold, your carefully crafted power balance is completely destroyed, leaving you with an overpowered player to wipe the floor with any poor monster who dares cross his path.

    I'm sure you can imagine an alternative where the player is wrecked in side quests meant for a more powerful player.

    The Solution

    So how do you solve this? Let me just quote a little thing I've read in the vast cosmos of the interwebz:

    Game design is pretty much one giant [CENSORED] ball of borrowing
    

    In other words, in order to do things properly, we need to study the work of others, and see how they've done it.

    Let's take a look at the amazing Skyrim. How does it handle its level scaling?

    Different locations in Skyrim have different inherent difficulties. In other words, some dungeons are designed to be too difficult for low-level characters to enter.
    

    That is to say, every location has a minimum and a maximum level. Say we have a dungeon from level 5 to 30.

    If the player enters before the minimum level at, say, level 2, they enter a dungeon with stronger level 5 enemies and better loot. If the player enters within the level range, for example, level 15, the dungeon would contain level 15 enemies. And if the player enters after the maximum level, that is, 30+ they get to wipe the floor with level 30 enemies.

    Such a system allows for intricate risk/reward balancing. As in, "Just defeated a horde of trolls 10 levels above yourself? Here's some awesome loot to compensate." and "Done wiping the floor? Here's your two septims."

    In Conclusion

    Well there you have it. You've learned to avoid a game-breaking problem with open-world games. And in the solution, apply a new fun mechanic giving the player choice; and lots of rewards for daring ones.

    What do you think of the proposed solution? Have you encountered other problems with open-world games? Leave us a comment with your thoughts.

  • How to Get Your Game to Done

  • Game Design · Project Management · 2018-05-09 · nightblade
  • image

    Most games never reach completion. Most of us know this -- especially programmers, who typically leave a trail of dead projects in their wake. Well-intentioned projects, but incomplete projects none-the-less.

    What steps can you take to increase the chances of actually finishing, and get your game to that glorified "done" state?

    At Deen Games, we work in a team of two (or I sometimes work alone), part-time, without funding. The steps below outline our process -- one which, if we applied it consistently, would lead to us finishing many more games. Each step in the process fulfills a specific purpose, which I will explain along the way.

    But first, a quick detour on why games fail.

    Why Games Fail

    Why do we fail to complete games so often? When you look at the bigger picture (across mutliple projects and teams), you find a number of common reasons:

    • Overambitious: Many games require much more time and effort than the instigators realize; often, when realization dawns, the thought of "it'll take how many years for us to finish?" causes a game to reach the trash pile. This can be anything from requiring tons of game content to requiring art or audio capabilities beyond what we can deliver.
    • Motivation: Motivation dies near the middle of the project. Great teams can forage onward; but, many projects fail early because the original motivation just isn't there.
    • Time Scale: Some teams, like ours, are very sensitive to time; if a game starts to slog on, and on, and on forever, we lose motivation (see above) and throw in the towel.
    • Content Complexity: As an indie, we can innovate without worry. However, projects that require complex features (eg. procedurally-generated branching storylines and quests) or complex content (hundreds of maps and events and quests) can stretch us beyond what we can achieve.

    Having summarized the main failure points, let's dive into the process and see how we get around some of these issues.

    Game Development Life Cycle

    We don't really use agile; we just work linearly given whatever amount of time and energy we have (since we're part time). However, you can always break these stages into different stories and apply them to an agile/iterative life-cycle.

    Craft a Motivational Vision

    Every good game starts with a good vision. What are we trying to build? Is it a completely procedurally-generated 2D RPG, an Android game that teaches Arabic vocabulary to kids aged 4-8, or a stealth-based MMO? Write it down.

    The vision should be clear, and should list what we want to achieve by releasing this game; it should also be composed of highly motivational statements for the team. When motivation slumps, we can review this, and get a burst of re-energizing/motivation.

    Inject the Learning Goal

    At Deen Games, we develop Islamic and educational games. The next step is to write down our goal: what do players get out of playing this game? The learning goal can be grand (eg. acquire fluency in a new language) or benign (get exposure to Muslim culture specific to Yemen), but it needs to be decided up-front. Again, write it down.

    Without this, we tend to abandon projects because they don't make the world a better place in some way.

    Brainstorm the Core Game Loop(s)

    The core game loop (or loops) of your game, are those activities and actions the player plays over and over and over again. In a typical platformer, that's running, jumping, dodging; in an FPS, it's seeking weapons/ammo/armour, shooting, and dodging.

    This is really the fruit of the game design; the place where we codify the vision and learning goal into the actual gameplay. This is how players learn (through experience), and how we communicate that through the actual mechanics (instead of simply a story or dialog).

    This forms the core of your game; without this, your game won't be fun; motivation fizzles, fast.

    Risk Analysis

    I learned of Risk Analysis during my studies as a PMP. You want to analyze your project and find any risks -- those sneaky issues that, if they occur, could (or will certainly) cause the downfall of your project.

    Using risk analysis, you can quickly identify risks like the following:

    • The game requires a large world (overambitious or content complexity)
    • We actually need a really good, custom-made level editor to make it (technical complexity)
    • The procedural generation is really hard (technical complexity)
    • The game won't work without very high-quality or a large quantity of good art (eg. interactive books)
    • The game will take us years to build
    • The game doesn't really achieve what our vision entailed

    Here in the process, you want to mitigate or minimize the risks. For example, maybe you're working on an underwater sea-life themed infinite runner, and your risk is that you need really good art. Your options might include:

    • Change the theme to something else (eg. cubes instead of animals).
    • Settle on a simpler, achievable art style. Pixel art is often a choice here, because it's easy to create decent pixel art.
    • Team up with someone who can create the art you need.
    • Find an artist for hire who will charge a decent rate and get you the quality you want.

    In the worst case, if the project just can't be done, this is the time to go back to the brainstorming phase and see if you can come up with something different. Alternatively, you can acccept the risk and move on (but this often leads to failure).

    Prototype to Find the Fun

    Many games are not fun. And nothing is more demotivational than investing hours and hours into a game that's boring or tedious. In this stage, prototype your game and find out what combination of features makes it fun.

    While prototyping is an art (and science), and something you should read more about, here are some of the key take-aways for this stage:

    • Use the most minimal art possible -- coloured boxes. If it's fun at this stage, it'll be fun when it's full-blown production pipelined content; if it's not fun now, no amount of polish can make it fun.
    • Focus on core game mechanics, or technical risk (eg. PCG algorithms)
    • Avoid superficial things like stories, characters, names, etc. unless these are really key to make or break your game
    • If the controls are okay, and it doesn't hurt the fun of the prototype, leave it as-is.
    • Don't write a tutorial; writing good, interactive tutorials is really time-consuming. Ditto for writing the UI.
    • Use feature toggles so you can quickly turn features on or off; this helps decide what the final game will be.

    Chances are, you will find that your prototype isn't the fun experience you thought it would be. No problem, recycle -- add things, change things, remove things, and iterate until you find the balance that is fun -- or until you get tired (there's no way to make a butterfly simulator fun ... or is there?).

    Validate your Prototype with Others

    Show your prototype to your team members (hopefully they worked on it with you), friends, and family. Provide them with instructions (since the game likely has none). Listen to the feedback people give you on what works and doesn't; but be weary of suggestions for improvement (these are usually terrible and have nothing to do with your game vision and objectives).

    If you can get someone else (or a number of players) to agree that your prototype really is fun, even at this stage, you're in business.

    If you didn't go back to the drawing board on your game, congratulations! You have an idea that sounds and plays fun. This is the hardest part -- all you need to do now is complete it and ship it.

    Create a Minimal Viable Product

    Your game probably requires a lot of stuff -- levels, entities, art, algorithms, characters, text, a tutorial, and more! At this stage, you probably realize that you can't possibly finish this game in a decent time-line (unless it's a very, very simple game).

    You now need to focus on shipping. To do that, you need to pare the game down to the core essence of the game. In a way, you already did this: you focused on your core game loop, and prototyped it until it was fun. You should now have a good idea of what your game entails.

    Now, think about every feature, every level, every piece of content. Ask yourself constantly: can I live without this? Can I ship my game without this? Or maybe not -- maybe, without this one element, there really is no game.

    Organize your list of stuff into two broad buckets: MVP (really really need it) and a v2.0 bucket. Anything you don't need, keep it in the v2.0 bucket until after you complete the release (we'll come back to this).

    Keep your list of MVP items close at hand; ideally, you want to also prioritize it (in case you lose motivation in the middle and still want to ship something).

    Get it Done

    Once that's done, crank out your game. There's no magic to this; focus on the code, the content, everything and anything you need. As you work through things, you may come up with new ideas or realizations of things you need to do; constantly ask yourself again, can I ship without this? And keep focused.

    I18N on the Cheap

    Translation is a difficult and complex process. Chances are that, within your circle of team members (and possibly family members or good friends), you will find people who are fluent in more than just English.

    Enlist them to translate your game into their native language! While the translation might not be great, it's much better to ship something than to wait endlessly for that perfect translation to spring into being.

    Of course, if your game isn't easy to localize, you need to fix that first. And next time, make it localizable from the start! (Tip: it's easy enough to make a single class that fetches strings for the current language and returns them, and loads a simple JSON/XML/etc. file that contains the game strings.)

    Test Thoroughly

    When you finally finish your slog through the backlog of work, test the game thoroughly; test every possible feature, level, piece of content, and option. Enlist your teamies and friends -- they often find bugs by trying different workflows. (You tend to test the same content over and over and over during development, and get blind to the other options.)

    Once that's done, congratulations! You're ready to ship your game. Build the final executable, prepare your website/marketing material (eg. tweets), and unleash it on the world.

    Beyond v1.0

    At this point, we're technically done. You could put your game down and walk away, or take a breather to work on something else and come back. Either way, if you decide to invest more in your game, here's the good news: we're not done yet!

    Monitor for Feedback

    If you're blessed enough to have a big following on Twitter, or Itch.io/Steam/etc. (or the app store for your mobile platform), you will hear feedback. Listen to everything, and make a note somewhere. You need to sift through and prioritize this feedback, and decide what to ship (and not ship).

    Remember that v2.0 backlog of deferred work we created while finding our game MVP? Revisit it, look critically through it again, and rework it or reprioritize it.

    Restart the Process

    Given this combined backlog of stuff to work on, you can go back to the "brainstorming" phase. Pick a set of features, dust off your prototype, and add them. How do they affect the user experience? Are they worth integrating into the main game?

    When you know the answer, you can put those changes into your game and ship another small release. (Testing thoroughly is a good idea, and test automation helps here.)

    Publishing multiple small releases tends to give you more visibility and feedback across the internet, so repeat this as many times as you like.

    In Conclusion

    In this article, we covered a lot of ground. We started by looking at some of the common reasons game development projects failed, and then looked into our Deen Games current (ideal) process to see how we work around many of these failures.

    In doing so, we take a project through the stages of:

    • Creating a vision
    • Crafting a learning goal
    • Prototyping the core game mechanics
    • Creating a small MVP
    • Shipping our game
    • Localizing our game on the cheap
    • Monitoring for feedback
    • Iterating and repeating to create incremental releases

    Do you see any holes in our process? Do you have another process or different steps that work for you? Drop us a comment and let us know.