Converting Your Java Game to JavaScript

[Preliminary]

Contents

JavaScript is not Java
  Limits
How To Do It
Problem Solving
Debugging JS

Related Documents

Converting Your Java Game to JavaScript -- What you need to know (You are here)
Your Own Java Game -- Step by step tutorial to build a simple "Pong" game
The Itty Bitty GameEngine -- Overview
Class GameWgt -- The visual components of a GameEngine game
Overriding GameEvent -- The programmatic components of a GameEngine game
The Pong example game as JavaScript: www.IttyBittyComputers.com/Java/GE.php?name=Pong

JavaScript is not Java

JavaScript (JS) is probably more different from Java than Java is from C++. In both cases they look similar, but JS is untyped, that is, you can put anything you want into a variable, and you never know if it's the wrong thing until you try to do something with it that JS doesn't know how to do. C/C++ is weakly typed (you can do dangerous things without knowing it) and Java is better. The JS library more closely resembles Java than either of them resemble C/C++, but there are significant differences. I know, because I built a tool for writing single-source Java/JS code -- basically for Chomp -- and I needed to do my own library of "glue" code to make it all stick together.

Java and JS are both Turing-complete, so in principle you can write a translator from one to the other, but translating an untyped language like JS into a fairly strongly typed language like Java is awkward. I know, I wrote a compiler (the same idea) for HyperTalk, which was also untyped. The other direction is easier, and numerous Java->JS translators exist. So why don't we use one of those? The simple answer (I like simple) is that I can (and did) write a much smaller translator that runs as a part of GameEngine that converts a limited subset of Java to something really small that interfaces directly to a carefully tuned JS version of the GameEngine. This is a game we are talking about, so it needs to be done carefully or it will be too slow to play on your average browser. Chomp was designed with that in mind.
 

Limits

I did say "a limited subset of Java." If you write simple Java of the kind we have been doing throughout this course on learning Java, and don't create nor use any objects of your own (objects are slow), and if you are careful to watch the data types of your variables -- which Java will mostly do for you, but there are occasional surprises -- it will work.

The translator and the JS GameEngine both know about widgets (and you can use them) but the JS version of your game cannot create any new widgets. If you need to add widgets during the game, you should create them all in GameMaker, then hide them until needed. Also text fields cannot get bigger than what GameMaker made them. Again, make it big enough for the largest possible text, then use what you need.

There are some widget and event methods that are not supported, so if their names show up anywhere in your Java code, the translator will refuse it. The translator is not very smart, it only looks for character strings, so don't even use these names as part of larger names:

GameEnding  GetTextWide  SwapData  SetFocus  CheckIt  RadioBtn  FindElemt  DeleElemt  XchElemt  AddElemt  KeyData


If you are testing a widget reference against null, you need to do it this way:

if (myWgt==null) whatever();
and not:
if (null==myWgt) whatever();


When declaring your own methods, you need to put the return type on the same line as the name and the left parenthesis, but the parameters can spill over onto up to eight more lines.

Java allows you to declare the control variable inside the parentheses of a for-loop; JS probably does too, but variable declarations are different, and my translator only looks for declaration type names at the front of a line or inside function parameter lists. Move your control variable declaration out and into a normal variable declaration line.

When you use block-comments, the translator assumes they span more than one line, like JavaDoc comments at the front of each method. Don't confuse it. Anyway, the comments are removed. Publish your original Java if you want people to read your comments.

Alert and input dialogs are not supported at this time. Text input in general is not yet supported. I ran out of time. Work-Around: use DefaultKeyFocus for a widget to accept keys, then enter the text into your fields in your own code.

Changing the size on a Ball widget is not yet supported. You can try, but nothing will happen. Work-Around: there are only four defined sizes at this time, so just make one each size and hide the sizes you are not using.
 

How To Do It

[This feature is still under development, so officially it is turned off, but you don't need to let that stop you...] Open up the JavaGame class source code (double-click its yellow rectangle, or right-click it and choose "Open Editor") near the top, after a zillion "import" lines, there is a prominent "final static String ... RevDate" and a couple lines below that there is a boolean (constant) variable "Do_JS = false," which you want to change to true. If it's already true, we have decided that the feature is working and maybe you are reading a stale version of this document (try reloading it in your browser).

After your game is running in Java, do one more Build (you may need to make a trivial change, like turning a checkbox on then back off). If the button becomes "NoJS", something went wrong and you can click on it for an error message (see "Problem Solving" below). Otherwise it will become a "->JS" button which you can click on. It will then ask for a "username_password" which you must use the name you created in Chomp (see "Remembering What You Told the Computer to Do"; I ran out of time; maybe a future revision will let you create an account here). When it tells you "OK" with a URL, your game has been uploaded. In general the URL is the same as the Pong link at the top of this page, but with your username in place of the name "Pong". If it doesn't say OK, then something went wrong and you should have a new "NoJS" button to click for the Uploader error message. Bad Things Happen...
 

Problem Solving

If you get the a "NoJS" button, you can click it to see an error message.

These are the error messages you might get from the translator program:

Can't find class name -- When you first Build your game program it creates a Java class file named with your game name. If you alter the class name in that file without changing the file name and game name to match, or if you alter the spacing of the words on the class declaration line, then you could get this error. Solution: recreate your Java file by moving this file to another directory and rebuild your game, then copy your own Java code from the old file into the new file.

Can't find widget list -- The widget list is a string of numbers and other stuff generated when you click the Build button. It will probably fail if you alter the meta-tags that are used to find the widget list, so this error is unlikely (the build will fail instead, and you probably need to recreate your Java file.

GameList front corrupted
GameList back corrupted -- The Java version of the widget list is replaced by a pre-constructed array of numbers, which changes the form of the GameList method. If you made substantial changes to it you might get one of these errors.

Can't do this method -- The following list of GameEvent and GameWgt methods are not supported in this version of the translator, so you should not even mention them (nor anything containing the same substring) in your game code:

GameEnding GetTextWide SetBlinker DrawMe IsValidIDtxt GetIDtxt SwapData FixHaff HexyMore FmtInfo FmtFront LogMe SetFocus CheckIt RadioBtn FindElemt DeleElemt XchElemt AddElemt toStrMash


Invalid GameWgt object in method call -- I never do this, but I think Java lets you use the object returned from a method call directly to access a method in that object's class without storing the reference in a variable. Java may accept it but my translator won't. Make sure your calls to widget methods are of the form "objname.methname(..." with no spaces between the period and the parenthesis.

Unrecognized op after 'null'
Unrecognized op before 'null' -- Because your translated game program running with the JS version of GameEngine has no use for objects in JS, the legitimate Java object references are converted into variables that are not objects in JS. Part of this conversion involves converting the keyword "null" to 0, but the translator tries to verify that it is legitimate. Basically if you are using references to GameEngine objects (one of the three public classes), you can assign them to null or test them against null and it should work, but only if the "null" is on the right of the comparison operator:

wgtref = null; // OK
if (wgtref==null) DoSomething(); // OK
if (wgtref != null) DoSomething(); // OK
methcall(null,wgtref==null); // OK
if (null==wgtref) DoSomething(); // will fail


Generated text too short -- This probably can't happen with a credible game.

Invalid wgt list end
Failed wgt list conversion
Bad widget list form
Invalid line number in widget list
Widget spec line is too short
Invalid negative data length -- The Build process constructs a widget list in the correct form, so you might have difficulty causing one of these errors to happen.

Macros and private widget types not supported -- If you only use the defined widget tools in GameMaker, and if you leave the "Alert+InputDlog" checkbox unchecked, you should not get this error.

No such font -- The GameEngine has seven built-in fonts. I tried to sneak in some other font number, but the input replaced it with one of the built-ins. But if you succeed, you might get this error.


The uploader has its own set of error conditions. You might get a message like this, which I don't know what all the numbers mean, but it's basically a transmission error, and you can try again later or ask one of us for help:

Uploader error #nn
HTTP error code = nnn


Or you might get one of these messages, which come from the server:

Notice: User not found -- which means your name or password failed. Go back to Chomp and verify that you have a valid Login.

Notice: insufficient permission to save
Error: missing data parameter
Error seeking user name
Error: Could not handle save command -- These are all problems inside the Server, not your fault. Let one of us know and we'll try to fix it.

Debugging JS

It is also possible that your Java code just didn't work in JavaScript. My translator cannot find all possible errors -- and this early in the development, I didn't even try. I suggest you open your game in a web browser that has a built-in debugger, like FireFox, then (in FireFox, others may have a different way to get there) choose the menu "Tools->Web Developer->Debugger" which will show you the script of both your game code and also the GameEngine code. Start in your game code and set breakpoints and see if you can figure out what's going wrong, using the debugging techniques you learned previously in Java (for example see "Using the Java (BlueJ) Debugger").

Sometimes JS scripts won't even load, and the only way to figure out what went wrong is to run the script through a "JavaScript validator" which you can find several freebies online (I used this one to debug Chomp). Some of these sites will look at your web page, some want you to you paste your script into a box. If the translator succeeded, then it created a ".js" file which you can use for validation. If the validator gives you more than one error, you can only trust the first. If you can figure it out, great. If not, ask one of us. Maybe we can't figure it out either, but we have more experience finding problems. Don't be ashamed, this is how you learn. JavaScript is a crummy language to learn on, but you never know when you might need it.
 

Tom Pittman
Rev. 2020 August 1