JavaScript vs C++: Creating the same 3D game in both





Then,



"Woha! Why not make a real native app out of my WebGL game? I only put it into Electron and that's it!"



I did that, and Electron worked surprisingly well. Nice piece of software. But the result wasn't very convincing: Although I put a lot of effort into making the electron app feel like a native app instead of a HTML site, it had a lot of drawbacks like input lag, lack of hardware, 3D and fullscreen settings, bad working cursor locking and similar.



So I decided to rewrite the entire game in C++. Because - why not. And it shouldn't be that complicated: The JavaScript code of the game is based on the open source 3D engine



The port was done within a handful of weekends and the game is now a native Win32 C++ program. You can A few years ago, when WebGL started to work in most browsers, I had the idea to write a first person shooter game in JavaScript and HTML. It was a crazy idea back then, but it worked, and the performance wasn't that bad ( try it out yourself ). I extended the game's code in my free time, and after a few years, a lot of features were added, and the game started to be fun.Then, Electron arrived (basically it's a way to bundle your website in a package together with the Chrome browser and pretend you created a native app), and I thought:I did that, and Electron worked surprisingly well. Nice piece of software. But the result wasn't very convincing: Although I put a lot of effort into making the electron app feel like a native app instead of a HTML site, it had a lot of drawbacks like input lag, lack of hardware, 3D and fullscreen settings, bad working cursor locking and similar.So I decided to rewrite the entire game in C++. Because - why not. And it shouldn't be that complicated: The JavaScript code of the game is based on the open source 3D engine CopperLicht (which I created), which has a similar API to the C++ 3D engine Irrlicht (which I created too), on which my game engine Framework CopperCube is based on anyway. So it wasn't that much work, I only had to rewrite the game logic. Everything else, from Window / UI / Collision / Font / Texture / Sound / Image / File handling etc was already there, with a very similar API.The port was done within a handful of weekends and the game is now a native Win32 C++ program. You can try it if you like

Comparison

Performance

Control of the details

Development speed

Recap

I wrote the exact same first person shooter 3D game both in C++ and JavaScript. In this article, I am writing down my findings. Please skip the next indented paragraph if you are not interested in the background details.So now, I have a rare possibility to compare the development of the same app written both in C++ and JavaScript:This was the biggest surprise for me: The performance of both implementations is very comparable. Even the most CPU intensive parts, namely procedural generation of houses and the collision detection for the physics engine run at acceptable speed in JavaScript. And only about twice as slow as in the C++ version. Chrome's JavaScript optimization is really impressive. Unfortunately, the JavaScript version of the gameto be much, much slower. See next why.While I have full control of nearly everything in my C++ implementation, I need to rely on the browser for a lot of things in the JavaScript version of the game. And that's where the problem is. The procedural generation of the world is laggy in the JavaScript version, because some WebGL calls sometimes shortly freeze the browser. It is just a few milliseconds, but these aggregate and slow down the game very much. I wrote several workarounds solving some cases, only for other cases to appear, unfortunately. In C++, you have direct access to everything, so if a problem like this appears, you have much more ways to work around them.The JavaScript version runs at a similar speed as the C++ version, at about 120 frames per second on my development system. But the JavaScript version *feels* very, very slow. Depending on your operating system and hardware, the browser behaves differently, and with a lot of combinations, input is laggy. Even if drawing the scene very fast, mouse input is lagging behind, and especially for a first person shooter game, the game feels very slow because of that. You have two methods of doing a "game loop" when using WebGL: requestAnimationFrame() and setInterval(). One version solves this issueon some systems, one versionon other systems. It's quite frustrating.There were similar problems, but they all had this in common: With JavaScript, you are depending on the implementation of the browser, which isn't always doing what you need, unfortunately. In C++, that's not a problem.I'm quite fluent in both JavaScript and C++, and I feel that both languages have about the same development speed. You have to type quite a bit more usually in C++ than in JavaScript, but C++'s type system makes it easier to find certain types of bugs earlier, usually. Thanks to modern browsers, debugging is as nice in JavaScript as it has been for nearly two decades in C++. For me, personally, both are languages with their weaknesses and strenghts, but after all, they are just tools to get the job done.If you ever want to create a first person shooter 3D game and sell it as native game, I'd recommend not to do it in JavaScript/HTML/WebGL. It's fine for games in websites and prototypes but not to be treated as finished native product. At least not now. But who knows: in a few years, the situation will look better. I know a lot of people are creating 2D games successfully that way. And it seems to work nicely. But for me, 3D from the first person view hasn't worked yet.For now, I'm developing my game further in C++. And hope to have it finished within the next months. You can follow its progress on its website , if you like.

26 comments, already:

It is important to be first.

First - 23 09 16 - 11:57

I am the second one First.

Second - 23 09 16 - 12:11

Am I first too?

1st - 23 09 16 - 12:17

Interesting article, maybe a node.js implementation of the game could resolve the problems of the lagging javascript.

valarionch - 23 09 16 - 13:04

It will be interesting to review your entry in 5 years. :)

mark - 23 09 16 - 13:09

valarionch: Why would it?

disconnect3d (link) - 23 09 16 - 13:21

@valarionch, node runs the same javascript engine as Chrome (V8).



I’m curious if you captured any perf traces that might reveal the issue on the JS implementation. Are you planning on filing a Chrome bug with your repro that demonstrates the input lag?

Brandon - 23 09 16 - 14:14

There are multiple bug reports like this already in the tracker made by other devs, and all of them were closed, with the explanation that Google devs do not have the intention to fix this. When I read that I started the C++ port.

niko - 23 09 16 - 14:30

You could probably improve the feel of the game in the JS version by offloading the WebGL calls to a web worker. A preliminary web search leads me to believe that it’s only supported in Firefox, though.

Kyle - 23 09 16 - 14:52

@valarionch are you just saying node.js because buzzword? it’s the exact same engine as Chrome. it won’t be any faster.

crunchwrap - 23 09 16 - 15:43

The article talked about JavaScript running plenty fast, but input events being slow. The problem isn’t in V8, it’s in event handling – something that Node.JS might do better (I don’t actually know). The question @valarionch posed is valid.

sessamekesh - 23 09 16 - 16:00

EDIT to my last comment – it’s a valid question, but I think the answer is still “no, keep it browser and WebGL. A Node version would likely run into the same problems.”

sessamekesh - 23 09 16 - 16:03

I would be interested in seeing your analysis with a C++ version compiled into asm.js/WASM using Emscripten. I assume iirlicht supports Emscripten as a target?

Daniel - 23 09 16 - 17:36

@sessamekesh @valarionch Uhhhm, electron is nodejs with an API to run/control chromium. They both use v8 as the engine and all scripts running in the chromium instance created by the node process are executed in the same environment. So it node would not make the game faster. How would you do any rendering in node anyway?



@kyle you could use node.js web workers because electron is node compatible.



Very interesting read though. Would love to see how profiling with flamegraphs and stuff help with speeding up your game.

Glen Keane - 23 09 16 - 17:45

I eat butts

Connor - 23 09 16 - 18:48

Garbage collection. You can’t really make a fast reacting game like an FPS unless you can control it. If a GC hits right before you pull the trigger, the user will miss the shot, or get shot himself. Unfortunately, the GC problem affects some native games on Android too.

sundbry (link) - 23 09 16 - 20:43

To those suggesting node.

Node is a server side scripting language. it doesn’t have any of the graphical libraries, canvas or webgl apis that modern browsers have. There might be some libraries that can add support for this but I don’t expect them to be well tested or reliable enough to produce an FPS game in them.



It’s a bit like suggesting OP use bash, perl or php.



The main problem with using javascript for a game is that js only supports a single CPU thread. So while the cpu is processing graphics it won’t pick up UI events. WebWorkers are a relatively new standard to try to mitigate this problem but they are limited in what they can do compared to the main thread.

Ian - 23 09 16 - 20:46

Hi,

Did you tried to use a native lib or to develop one for inputs using electrons ?

Do you have more details about function that are slow in webgl and are not in ogl ?

Thx!!

Nuts - 23 09 16 - 22:28

Nice, the laggy is from browser, which soon or latter will fix, Like chrome book.

Abner (link) - 24 09 16 - 20:49

I was interested, did you try webassembly and emscripten to port you game for web?

Driver - 25 09 16 - 01:16

Hi Niko, thanks for this interesting article. I must say i really admire all the work you have done over the years, it never ceases to amaze me what you are doing all by yourself! I wish i had the balls and persistence to go on such adventure myself

Lenx - 27 09 16 - 08:02

AFAIK, even when using emscripten or webassembly, you still need to go through that WebGL API.

niko - 29 09 16 - 01:49

I have no experience in game development but, have you tried – asm.js – setImmediate or a polyfill (as setTimeout / setInterval take at least 4 ms by spec, even if you set 0 ms)?

garaboncias - 29 09 16 - 22:12

I wonder if a hybrid system would be beneficial, using C++ for the 3D parts (including handling input to control that) and JavaScript for the UI stuff, where the input lag isn’t so important. I seem to remember the most recent Sim City game did this, and games like World of Warcraft use a similar system only with Lua.



As for the node.js suggestion, yes it runs on V8 just like Chome, but the input lag Nikolaus is describing comes from the browser, not the JS engine. Node is just a thing that runs JS code, entirely separate from the DOM, input event handling, etc. stuff that the browser provides on top.

Andy F (link) - 30 09 16 - 08:32

The slowdowns can happen because of two reasons – either garbage collection or code deoptimization.



There was a good talk about it on Google I/O 2013 that’s about just that: https://www.youtube.com/watch?v=VhpdsjBUS3g

Darko - 01 10 16 - 09:50