Construct supports JavaScript coding in addition to its block-based approach. JavaScript is an industry-standard language used widely across browsers, servers and more, and is one of the most popular programming languages in the world. Some tools choose to go their own way and develop their own programming language used only in their tool. We think this has few upsides and major downsides. To illustrate this, here's a case study in how JavaScript compares to GameMaker Language, aka GML - the language used in GameMaker Studio 2.
Performance
First up, let's examine performance. For games, fast performance is an essential feature to ensure a smooth framerate. To compare the performance of the raw language, we built a simple number-crunching test that just counts how many prime numbers there are between 1 million and 2 million. The key function is IsPrime
, and you can see how close the code is for each in the code sample below.
We ran this test in four ways:
- In JavaScript, in a Construct 3 project - download C3 project
- In GML, via the VM (an interpreter) - download GameMaker project
- In GML, via the YYC (a C++ compiler), which is only available with a subscription
- And despite not being a text-based language, also an equivalent in Construct's event blocks for comparison - download C3 project
In both GML cases we used the newer 64-bit runner/compiler, which performs better on this test. Modern browsers have all been 64-bit for some time already, so this also helps ensure a fair comparison. We tested with GameMaker Studio 2 v2.3.3 and C3 r260 in Chrome 92 on a Windows PC. All the files used in this test are linked above, so you can check them out and replicate results yourself. The results may surprise you! The time taken to calculate how many primes there are between 1 million and 2 million is summarised below (after a brief warmup period to ensure CPU caches and JITs are operating at peak performance).
JavaScript is far faster than GML on this test. The VM proves much slower - in fact, over 40x slower. Even if you pay for a GameMaker subscription and use YYC to compile to native code, it still comes out over 5x slower. Modern JavaScript JIT (just-in-time) compilers are incredibly sophisticated and have been fine-tuned by entire teams of dedicated engineers at the biggest tech companies for years. This also dispels the myth that just because something is compiled to C++ it's fast. JavaScript is not just 10% or 20% faster, but several times faster. Further, JavaScript JITs are also tuned for fast startup, so there's no need to sit around waiting for code to compile. It just starts running with an interpreter right away, compiles code in the background, and then switches over to it as soon as it's ready - all of which happens surprisingly quickly. And all this raw performance comes for free with the very browser you're reading this in!
Perhaps there are some obscure tricks or performance hacks that can improve the result somewhat for GML. However this still proves the point that JavaScript is super fast with straightforward, idiomatic code, and you don't need to resort to time-consuming experimentation and research to get an excellent result.
In fact, JavaScript is so fast that even our equivalent made in Construct's drag-and-drop event block system clocks in relatively close to the result for the YYC. In intensive benchmarks like this, the event system has quite a high performance overhead compared to text-based programming languages since it's essentially interpreted by JavaScript code; despite this, thanks to JavaScript's extreme performance it ends up surprisingly close to the C++ code compiled by YYC, and also far ahead of the VM interpreter. So Construct's event blocks are no slouch either.
Many games run intensive code for purposes like pathfinding, bullet hell games, and more, and high performance is key to maintaining a smooth framerate no matter what your player is battling through. This test result shows that if you want peak performance, choose JavaScript.
Ease of learning
One reason sometimes cited to develop a separate language is to customise it to be easy for beginners to learn. However the fundamentals of GML and JavaScript are very similar. They're both languages with a C-like syntax, a dynamic type system, and garbage collection to simplify memory management. Just take a look at the code samples for IsPrime
above - the syntax is pretty close, and so it's likely both are about equally approachable for beginners.
Being such a widely-used language, JavaScript has several advantages for beginner learners though. There are free coding tutorials and learning resources for it all across the web, such as the MDN Learn JavaScript guide and The Modern JavaScript tutorial, some also with interactive samples where you can edit and run the code. Further there are schools, colleges, coding "bootcamps" and other educational institutions that include teaching JavaScript coding, providing more options to learn in the wider world.
Finally JavaScript is a highly transferrable skill, being widely used in industry both in browsers and on servers, and with plenty of jobs available around the world for a promising career. Learning a language only used by one tool throws extra hurdles in your way if you want to go further, having to learn the new aspects of an industry-standard language, and unlearn the quirks and bad habits that you may have picked up with the the previous language.
So overall JavaScript should be just as easy to learn, but offer a much better path onwards in future.
Language features
New JavaScript features go through a rigorous standardisation process, where proposals are thoroughly reviewed and consensus achieved before implementing and releasing them. In theory a single organisation could move quicker. However JavaScript still has many major features that are limited or entirely missing in GML. In this section we review some of them. The standardisation process also helps ensure features are designed well, with thorough reviews from technical experts across the industry.
While JavaScript has a great many language features, beginners can pretty much just ignore the more advanced parts, so this should not have any impact on how easy it is to learn the language basics. It's a great benefit to more experienced coders though, providing a wide range of tools to help you best express what you want to do, and ensuring you can go a long way without running in to limitations or missing features.
Modules
JavaScript Modules provide a useful way to write code in isolated modules, only importing and exporting what they need. It helps keep code clear with separated concerns, and helps make it easy to re-use code and third-party libraries across projects. The syntax is shown below.
// In utils.js:
export function add(a, b)
{
return a + b;
}
// In main.js:
import * as Utils from "./utils.js";
console.log(Utils.add(2, 3)); // logs 5
There are many more ways to import and export functions, objects and variables in JavaScript, including with dynamic imports. GML does not appear to have any equivalent to this.
Promises & async functions
Some tasks, such as loading textures, or fetching resources over the network, are fundamentally asynchronous: they take some time to complete, so they happen in parallel to code continuing to run, and then they finish at some later time. JavaScript makes this convenient with Promises and async functions. A short example is included below.
async function LoadDataFromURL(url)
{
const response = await fetch(url);
const blob = await response.blob();
return blob;
}
There's a wide range of related features here, such as using Promise.all to conveniently wait for multiple parallel tasks to all complete, and various error-handling mechanisms, but there's too much to easily cover here. Suffice to say, JavaScript has this well covered.
GML supports asynchronous events, but has no special syntax for it, requiring looking up in a special async_load variable to establish the result. JavaScript provides many more language features to make it easy and convenient to write asynchronous code.
Arrow functions
Arrow functions are a convenient shorthand for functions based around the =>
arrow syntax, which helps make code clear, especially in cases like event listeners. They also carry over the this
scope from the containing scope, which is especially useful in class methods. Arrow functions can even be async as well. A simple example is shown below, with both versions working equivalently.
// Using normal function:
async function onStartup(runtime)
{
// do startup stuff...
}
runOnStartup(onStartup);
// Using arrow function:
runOnStartup(async runtime =>
{
// do startup stuff...
});
GML does not support arrow syntax for functions.
for..of & generators
This is another area of JavaScript with too much to easily cover here, but in summary the related features for..of and iterators and generator functions provide useful tools for iteration. In its simplest form, for..of
is a simplified syntax for iterating collections like Array, Map and Set:
for (let i of myArray)
{
console.log(i);
}
You can also use generator functions to easily define your own iterator:
function* oddNumbersUpTo(limit)
{
let n = 1;
while (n < limit)
{
yield n;
n += 2;
}
}
for (let i of oddNumbersUpTo(10))
{
console.log(i);
}
As you might expect, this logs 1, 3, 5, 7, and 9. This and many other capabilities allow you to do far more sophisticated things than the usual for
loop. You can even use for await..of with async generators! GML appears to have no equivalent to these features.
Class syntax
JavaScript has a full class syntax for declaring classes, including with inheritence, constructors, public and private methods, setters and getters, static methods and properties, public and private field declarations, super calls, and more. GML appears to support constructor functions and inheritence, but not a full class syntax like the JavaScript sample shown below.
class Rectangle {
constructor(width, height)
{
this.width = width;
this.height = height;
}
// Class method
setSize(width, height)
{
this.width = width;
this.height = height;
}
// Class getter
get area()
{
return this.width * this.height;
}
// ... and many more syntax features ...
}
Destructuring
Another feature only to mention in brief that GML is missing, destructuring allows for unpacking values from arrays and objects. It's useful for things like returning multiple values from a function, as shown below.
function getTwoValues()
{
return [10, 20];
}
const [firstValue, secondValue] = getTwoValues();
// now firstValue is 10 and secondValue is 20
Much more
JavaScript is a mature and sophisticated language with many syntax features, tools, standard library features, and more. Here's just a few more things there isn't space to go in to more detail on:
From all this, one thing is clear: JavaScript has far more language features than GML. It even seems unlikely GML will ever catch up - far more resources are being poured in to the development of JavaScript, as it's backed by the likes of Google, Apple and Microsoft, who all have their own teams working on it, and there are plenty more proposals in the pipeline. So if you want the best features in your programming language, choose JavaScript.
Cross-platform consistency
JavaScript engines are rigorously tested with an industry-standard test suite to ensure they all implement the specification exactly correctly across every platform. This kind of thorough testing process helps ensure the same code runs identically across a wide range of platforms, whether it's Windows, iOS or Raspberry Pi.
The GML manual indicates various places where the language does not work the same across platforms. These include:
- Function argument evaluation order can change across platforms (ref)
- The precedence of operators can change across platforms (ref)
- Code as simple as
obj_ball.speed = 0
works on different instances between HTML5 and other platforms (ref)
- Changing gml_release_mode can improve performance but produce unexpected behavior like memory corruption bugs. JavaScript always works reliably and at maximum performance.
Quirks like these throw hurdles in your way when trying to port your game to another platform. JavaScript is thoroughly tested to ensure all cases like these are clearly defined in the specification and work consistently across engines. And Construct uses JavaScript on all platforms, ensuring its own engine is equally consistent. So if you want cross-platform consistency, choose JavaScript.
Independently developed
JavaScript engines like V8 are developed by the big tech company heavyweights like Google. With their dedicated teams on the job, there's no need for us to spend our limited resources designing, developing and optimising a separate language for Construct. This frees up our time to focus on making a better product, introducing cool new features like scene graph, mesh distortion, and some new 3D features. Browsers also auto-update bringing the latest performance improvements and language features, so JavaScript keeps getting better even within the same version of Construct!
Conclusion
JavaScript beats GML in multiple ways: it performs much better on our benchmark; it has far more language features and many more in development; and it is more consistent across platforms. It's probably just as easy to learn as GML, but has a major advantage in being an industry-standard language that better prepares you for a future career. And the fact it is independently developed allows us to focus on what we do best: making a great game creation tool. We picked GML for comparison as it illustrates the point well in another game creation tool, but these benefits are likely to apply relative to any tool that develops its own non-standard programming language. It's extremely difficult to get anywhere close to the vast development resources that industry-standard languages like JavaScript have had poured in to them for years, and so many of the same pitfalls are likely to come up.
So why does GML exist? There may be some minor benefits around novel language features or integration with the tool, but these hardly seem worth losing so much in language features and in the performance results we observed. The main reason is probably simply the fact GameMaker is old, having been originally released over 20 years ago in 1999. At the time there may have been a better case for going with a non-standard language since languages like JavaScript were still in their early days. But over the years JavaScript has overtaken GML by a considerable distance. Improving GML to compete with JavaScript may well be infeasible, and changing to a different language would be difficult and disruptive. It's the kind of legacy of an early decision that very old software tools can end up lumbered with.
You can avoid the pitfalls though! If you're just starting out and wondering which to choose, it's an easy choice: jump in with JavaScript. In Construct you can also mix and match event blocks and JavaScript code, providing an easy transition from blocks, to your first lines of code, to full JavaScript files. So get started with Construct today.
Update 12:41pm BST: the original post incorrectly identified which subscription tiers the YYC came with. The post has been edited to correct this. Apologies for any confusion.