Architecture of CrossCode #1 – Overview

botchan-architectWe got several requests from readers to write more about game add-ons and features. However, talking about add-ons and features alone might be confusing and difficult to understand without knowing the rest of CrossCode’s architecture.

So that’s why we decided to start a small series about the architecture in CrossCode in general. This series will not be about concrete implementations and features, but more on how code is structured in a way that is easy to maintain.

We will start a small overview of the whole structure, pointing out the difference to the original structure of impact.js

Hacking impact.js

Impact is a well written engine for HTML5 games with one striking advantage: it’s very minimalistic. While other engines promote the creation of game without programming knowledge (which requires a large amount of features already being covered by the core engine), impact.js is simply a very clean and basic starting point for an engine that can be extended by writing additional JavaScript code.

There are basically two approaches one can take when working with impact.js:

  1. Take the engine as it is, only write entities and code that can be applied on top of the existing engine
  2. Rewrite major parts of the engine to do some things the exact way you want it.

The second approach is feasible exactly because impact.js is so minimal – you can easily adapt it to your own requirements without dealing with an overly bloated code basis. Of course the disadvantage of this approach is that it is difficult to integrate official updates of the engine – you’ll be your own master of your code. However, for control freaks (like us :D), who absolutely want to tweak everything themselves, that’s the price we accept to pay.

For Cross Code we decided to hack the engine. Because impact.js is optimized for 2D Jump’n Runs, but we want to have a top-view game, with the option to jump up, we felt that modifications of the core engine were necessary.

The architecture of impact.js

A blank slate impact game (version 1.18) has the following structure:

  • lib – All the code of your game
    • game – Code specific to your game
      • entities – All entities of your game (at least those accessible from impact)
      • levels – All levels of your game
      • main.js – The main file of your game
    • impact – Code of the engine
    • weltmeister – Code for the weltmeister level editor
  • media – All media of your game
  • tools – Some tools for baking your game etc.

In the following we want to point out two short comings of this architecture that we addressed when adapting impact.js for CrossCode: modularity and separation of assets from code.

With respect to modularity, there are basically two ways to extend your impact game in a modular way

  • Create levels with weltmeister and put them in the lib/game/levels folder
  • Create new entities and place them in lib/game/entities

For any other kind of extension, you will need to implement new modules (e.g. classes) and integrate those in the game by modifying main.js. This extend of modularity is sufficient for small game projects and prototyping – it is very easy to get first results really quickly by hacking something in main.js. However, for a larger game project constantly hacking/extending main.js with modules, which can be arbitrary placed inside the project, will lead to a bad code structure that is hard to maintain. It’s about the classical trade-off between freedom/flexibility versus maintainability and impact.js tends strongly towards the former. What we need are additional options to extend the game in a modular way to avoid hacking main.js continuously.

The second short coming is the separation of assets from code. Media assets (images/sounds) are of course placed in the media folder and correctly separated. However, level data is not. Levels are included as JavaScript modules that are directly connected with the game code. This has one striking consequence: All levels of the game are part of the game coded which is entirely loaded before the game starts – i.e. all levels are loaded when the game starts! This is again fine for small games and prototypes. However, CrossCode is planned as an RPG with multiple hundreds of levels in the final game. You really don’t want to load all of those completely before starting the game. The way to go here is to provide level data and other, non-binary assets as JSON files that are loaded asynchronously and only when required. Luckily, weltmeister already supports the creation of JSON files for map data. The only thing we had to do was to teach impact.js to load JSON data asynchronously when switching maps.

The architecture of CrossCode

Without further ado: an excerpt of the file structure of CrossCode:

  • data – All non-media assets, e.g. JSON files used by the game (e.g. levels)
    • animations – Animation data (for moving entities)
    • effects – Data to describe effects
    • maps – Level data (we renamed levels to maps in CrossCode)
  • lib – All the game code
    • features  – Any game code that goes beyond the basic engine
      • ig – Namespace for features reusable across games
        • camera – A feature that implements camera movement
        • gui – A feature that implements the display of GUI elements (not entity based)
        • ….
      • sc – Namespace for features specific to CrossCode
        • combat – Combat functionality and entities
        • player – Code for the players avatar
        • puzzle – entities for puzzle objects
    • game
      • config.js – Basic configuration of the game
      • features.js – Selection of features used by the game
      • loader.js – A custom loader when the game starts
      • main.js – The main file of the game
    • impact – Code of the engine
    • weltmeister – Code for the weltmeister level editor
  • media – All media of your game
  • tools – Some tools for baking your game etc.

There are two major changes due to the shortcomings discussed previously:

  • We added features to structure extensions to the game engine in a more modular way. Entities are now distributed among features, there is no more global entity folder
  • We added a new data folder that includes all JSON assets used by the game, which includes data for levels, effects, animations and much more. There is no more level folder with JavaScript modules.

The general design principle of CrossCode with this architecture can be summarized the following two rules:

  1. If possible, use JSON assets to reduce the code size.
    For example: We use JSON assets for enemy types and behaviors, which are fed to one highly configurable enemy entity. That way we avoid having one entity for each new enemy, drastically reducing code size
  2. Whenever you extend the engine, do it as a feature, try to make it reusable and do not extend main.js
    For example: The camera of CrossCode is provided as a feature, which can be simply integrated in any other game we plan to do with the engine.
    The main.js of CrossCode is very small (290 lines) and mostly contains debugging code and small hacks to test features.

This concludes our first post on the architecture of CrossCode!

In the next post, we will talk about features in more detail, introducing another option to extend the game in a modular way: GameAddons.

Go questions? Curious about details? Think I write bullshit about impact.js? Whatever it is, let us know in the comments!

4 Comments

  • Awesome! MAKE MOAR POSTS LIKE THIS NAO-

    You did a good job of letting people who had no idea whatsoever impact.js was understand it, so good job on that.

    So now I can conclude that the logo and stuff is all done in loader.js and sound like I know way more then I do.

    One other thing: how do you calculate animations for things like the intro? I know you do it on a frame-by-frame for the actual game, but is that JSON or just hardcoded?

    • Hi there!
      loader.js just contains the code to display the load bar at the beginning.
      The intro is actually part of the game code.
      Internally, it’s a GUI that plays a predefined animation.
      We didn’t use JSON for the animation, but still use some generic object structures in the JavaScript code to describe the animation in a kind-of timeline fashion.
      Then some JavaScript runs over these structures to display the animation.

      This timeline mechanisms can be reused for different GUI entities. So in the end, since everything is in the code, it is kinda hard-coded, but with a system that can be reused easily (also with JSON data).

  • Hi there, wondering if you’ve shared any of these modifications you did to impactjs with it’s creator, and if so, do you know if he planning on implementing any of them in future releases of impactjs?

    • No we did not share much of the code beside our technical posts. This is mainly because at this point we changed about 80-90% of the original engine to suit our needs. So you can imagine we want to hold to these changes. There are also quite the number of changes that are only useful for our specific game. Basically all impact.js provides everything you need and you just go ahead and implement your own stuff.
      Maybe we will share some of the code after we released the game! :)

One Trackback

Post a Reply to R.D. Cancel reply

Your email is kept private. Required fields are marked *