Wow! It’s been a long time since I posted a tech article on the Orangepixel website, but this is a pretty good one so it’s been worth the wait.
I’m currently in the process of trying to see what I can do with HTML5 / Web games in terms of having my games available to play everywhere and somehow also make some money from those versions.
The obvious first step is then of course to get my games running as web game!
Framework to Framework
I release my games on every platform I can, and that means PC (Steam, itch.io, Humble), Android, iOS and since a few years Nintendo Switch. For the PC and mobile versions I use Java for the simple reason that I started Orangepixel back in the day of feature phones and they only ran (a smaller version of) Java.
When Android and iOS took over the mobile market, Android was only using Java so for me it was easy to move onto that one and then I ported my Java games to Object-C for iOS. This process often took me a week to have those games ported, not bad, but a week of tedious work!
For the Nintendo Switch release (and hopefully soon the Playstation and XBox) my framework gets ported over to Monogame by my buddy SeriousLion. He uses some sort of transpiler and manual grunt work to make it happen.
Sadly, none of these solutions provide me with a web release. The monogame html5 output we tried at some point was just WAY too big to make sense, and the LibGDX (Java) option has never really seemed to work for me. It can do HTML5 export, but it always fails on many things.
So I decided to build my own Javascript framework that mimics the base things I need to run my games on:
- WebGL rendering – which means SpriteBatching for speed, and FrameBuffers for having different resolutions between game and hud or other overlay’s.
- Audio handling – playing sound effects with a pitch effect, looping sounds, and playing music
- Input handling – keys, mouse, and even gamepad
I wrote all those things to be as close to the base framework as possible, so that calling logic barely needs changes.
The big test
So once that framework was up and running, I had to test it one something.
I recently released Gauntlet of Power on PC and it was the most current full release game I had available, what better way to test the new framework!
The porting process was boring grunt work: Going through all the game’s class files line by line and making them work for Javascript. Some of the code structures could be Search + Replaced to make it easier and go a little faster. But overall.. boring!
It took me a little over a week to have the game up and running in Javascript and fit on the new Javascript WebGL framework.
This was proof that my “ForgeGL” framework (I named it) was ready for serious game development.
However.. this was also proof that I wasn’t feeling up to the task of porting all my games manually like that!
Search and Replace grunt work
A new tool had to be found! Since most of my porting work is literally two things:
- Replace some code with other code. Example:
- Public final static void coolFunction() had to simply become coolFunction()
- “for (int ” always had to become “for (let “
- .length() almost always translates to .length
- Adding this. in front of almost all the variables
As you can see the differences are not a lot, but if you have to go through thousands of lines of code just to do those changes.. time could be used in better ways!
I set out to find a “Search and Replace” tool that could take an input from a config file of sorts, and then brute force it’s way through all my class files replacing these things in seconds. Asking around on my Discord for some tools people knew about spawned a little conversation and ended in my buddy PetSkull Games taking 30 minutes to write me a simple Java class that would read in a directory (recursively) and all it’s files and replace the words based on an input file.
I decided to give it a quick test and see what would happen, and it did exactly what I wanted AND it did a lot of my tedious grunt work within 5 seconds (on 20+ files).
This started a couple of days of me wasting time on this tool and taking it a bit further…
Brute Force Replacinator
I decided that having regex options instead of simple word-for-word search+replace would give me more power. So I started working on regex functionality (luckily very easy to implement in Java).
Then my biggest problem was having all the variables that need “this.” added in front of them in Javascript.
But some variables need to be class constants and others are function parameters. So I needed to figure out if I could brute force this as well.
Most of my code across all my games and codebases is setup the same way. Since I’m not writing a tool for other people but just for my own code, this could work in my advantage.
I always have all my variable definitions at the top of my Java class files (actually, not always, but those errors are quickly remedied before I use my tool on a file). We can then also determine which variables should be constant for a Javascript class module by looking for “public/private final static ” definition in Java.
If a variable does not have the “final static” in there, it should get the “this.” prefix otherwise it get’s a “static” prefix.
EXCEPT! If we just got into a function() and that function has arguments with the same name (ugly, but I have to admit that it happens in my code).
ListClassVariables=new ArrayList<>(); List GlobalsVariables=new ArrayList<>(); List FunctionVariables= new ArrayList<>();
So I had setup these array lists to keep track of which variables are there and in which category they belong. Then it’s just a matter of constantly checking, line by line, if a “variable” is mentioned that matches a variable name in any of these lists, and we then either add the Class name. (class variable) in front of it’s usage or we add the “this.” prefix or we don’t do anything with it if it’s a function specified argument.
A few days later
Okay so a few days later I now have a very BRUTE Brute-Force search and replace tool that goes through my Java files line by line (either one file at a time or a whole directory of files) and turns Java code into almost flawless Javascript code.
The features I added:
- Skip comment blocks between /* and */ and ignore // comments
- Grab all variable definitions and group them accordingly for adding the right prefix
- Check if this class is extended (recursively) from another class – we also need those variables and function names!
- Grab all function declarations and place them in either the ClassVariable list or Globals list (depending if “static” is in front of the Java definiation)
- Check on first function declaration, see if it as Class initialisation function, if so turn it into the “constructor()” method needed by Javascript class files. If NOT an class initialisation (not needed in Java) then make sure we dump a constructor() method in there and have all the variable definitions placed in it.
- If we are in a function declaration, grab all it’s arguments, we need those variables in a separate list!
- Search and Replace obvious changes between Java and Javascript (see above) reading it from an input file
- Do some hard-coded changes on things like:
- “new SpriteList[x]” has to turn into new Array(x)
- “new Texture(Gdx.files.internal(” is loading sprites, done differently but always the same change
- floating point declarations like “0.1f” can lose the “f” in Javascript
- Inline array structure declarations are done between { } in Java and we can detect them and change them into [ and ] for Javascript
if (!line.contains("class")) { if (line.contains("=[")) inArrayDefinition=true; if (inArrayDefinition || (!inFunction && !foundFirstFunction) ) { line = line.replace("{", "["); line = line.replace("}", "]"); } if (line.contains("];")) { inArrayDefinition=false; } }
And a few other things left and right that I keep running into and adding to the tool.
Flawless execution
No! This is not a flawless tool in any way, BUT having run it on my current project Space Grunts 3, I can say that at least 95% of the work is flawlessly ported, which will save me DAYS of work.
I still want to add proper “import” code to the top of the module, which shouldn’t be difficult to do just haven’t gotten around to it. But right now a lot of the manual work I still have to do is make sure those imports are added to each file.
There is also a lot of room for errors, mostly if my Java code isn’t following the proper structure. So if I have variable declarations AFTER some of the function definitions, my tool won’t understand it and just leave it as is. Meaning those variables are not recognised by the code. Fairly easy to spot these errors tho and then a quick fix to the Java version and a re-run on the tool will fix it.
So this was a couple of days work, with a nice kickstart from PetSkull and it should in the end save me weeks of porting my existing games over to web versions!