[HN Gopher] Porting My JavaScript Game Engine to C for No Reason
       ___________________________________________________________________
        
       Porting My JavaScript Game Engine to C for No Reason
        
       Author : zichy
       Score  : 279 points
       Date   : 2024-08-04 15:26 UTC (7 hours ago)
        
 (HTM) web link (phoboslab.org)
 (TXT) w3m dump (phoboslab.org)
        
       | uberman wrote:
       | Thanks, this was a great read.
        
       | senkora wrote:
       | > Many Web games were created with Impact [the game engine from
       | the article] and it even served as the basis for some commercial
       | cross-platform titles like Cross Code, Eliot Quest and my own
       | Nintendo Wii-U game XType Plus.
       | 
       | Cross Code is an excellent game. I knew that it used web tech and
       | I was constantly amazed by how performant it was on the Nintendo
       | Switch hardware. I would guess that this engine deserves some
       | credit there!
        
         | phoboslab wrote:
         | To be fair, they modified Impact _a lot_. In some of their
         | development streams[1] you can see a heavily extended
         | Weltmeister (Impact's level editor).
         | 
         | Imho, that's fantastic! I love to see devs being able to adapt
         | the engine for their particular game. Likewise, high_impact
         | shouldn't be seen as a "feature-complete" game engine, but
         | rather as a convenient starting point.
         | 
         | [1] https://youtu.be/4lZfnM9Ubeo?t=3215
        
           | pdpi wrote:
           | > To be fair, they modified Impact _a lot_.
           | 
           | You can't polish a turd. There would've been no point in
           | modifying the engine a bunch if you hadn't given them a
           | useful base to work with.
        
             | BadHumans wrote:
             | In game development this isn't true for better or worse.
             | There is a lot of sunken cost mindset in games that we just
             | go with what we have because we have already invested the
             | time in it and we'll make it work by any means.
        
             | Modified3019 wrote:
             | https://en.m.wikipedia.org/wiki/Dorodango
        
             | make3 wrote:
             | that's just crazy bs, starting from open source code and
             | adding specific features needed for a project is a very
             | common strategy, doesn't mean at all that the tool wasn't
             | good to begin with
        
               | xtirpation wrote:
               | I think the point is that Impact is _not_ a turd because
               | it could be polished.
        
               | pdpi wrote:
               | I think we're in violent agreement.
               | 
               | phoboslab was downplaying their own efforts by saying
               | that the Cross Code team customised the Impact engine a
               | bunch. My point was that no amount of customisation can
               | turn a bad engine into a good one (you can't polish a
               | turd), so phoboslab definitely deserves credit for
               | building the base engine for Cross Code.
        
             | dylan604 wrote:
             | > You can't polish a turd
             | 
             | Of course you can. Not really sure why this still is tossed
             | about. You just get a shiny turd with a lot less stink.
             | I've made a career of taking people's turds and turning
             | them into things they can now monetize (think old shitty
             | video tape content prepped to be monetized with streaming).
        
         | otachack wrote:
         | Agreed! While I loath JavaScript it was immensely impressive
         | that a masterpiece like Cross Code came from it.
        
         | Version467 wrote:
         | Thanks for the recommendation. Looks interesting and is
         | currently on sale on steam, so I bought it.
        
           | Modified3019 wrote:
           | One thing to note, is you don't have to feel compelled to
           | master every combat mechanic the game throws at you (which is
           | a _lot_ ), you can just pick your favorites. A "fox with one
           | trick vs a thousand" and all that.
           | 
           | I for example basically ignore the shield for the vast
           | majority of the game, only doing some very basic usage for
           | some bosses, but perfect counters could very well be your
           | favorite thing.
        
         | Mindless2112 wrote:
         | Here's a talk about how CrossCode was ported to Switch:
         | https://www.youtube.com/watch?v=KfBzlzvt8RU
        
           | senkora wrote:
           | Really interesting watch, thanks for sharing!
           | 
           | So, if I understand correctly, this is roughly what he did:
           | 
           | 1. Wrote a transpiler to convert the subset of Javascript
           | used by CrossCode into a dialect of Haxe.
           | 
           | 2. Selectively modified his version of Haxe in small ways to
           | more closely match the semantics of Javascript, to make
           | writing the transpiler easier.
           | 
           | 3. Selectively re-wrote complicated parts of the Javascript
           | code into Haxe directly, so that his transpiler didn't have
           | to handle them.
           | 
           | 4. Transpiled <canvas> and other browser API calls into calls
           | to his own pre-existing Kha framework for Haxe, which
           | provided similar APIs.
           | 
           | 5. Compiled the Haxe output into C++.
           | 
           | 6. Compiled the C++ to native code.
           | 
           | Damn.
        
         | rowanG077 wrote:
         | The switch port required heroic levels of efforts though I
         | recall.
        
           | 0cf8612b2e1e wrote:
           | Huh. Never would have guessed. I am sure there were many
           | "fancy" effects in the game, but during my playthrough, it
           | all felt like it would have been achievable on a SNES.
        
             | Kiro wrote:
             | It's not about that. They are talking about complications
             | in general when porting a JavaScript game to Switch.
             | 
             | See https://news.ycombinator.com/item?id=41155807
        
         | GuB-42 wrote:
         | That switch port took _a lot_ of effort as someone has already
         | commented, it is absolutely not standard impact.js.
         | 
         | For the anecdote, everyone wanted a Switch version, but
         | considering the technical limitation, the team replied with
         | "Sorry but CrossCode will be coming to Switch when Hedgehags
         | learn to fly." [1] When they finally got to do it [2], it came
         | with an extra quest called "A switch in attitude", featuring,
         | you guessed it, flying hedgehags.
         | 
         | [1] https://www.radicalfishgames.com/?p=6581 [2]
         | https://www.radicalfishgames.com/?p=6668
        
       | nottorp wrote:
       | > for No Reason
       | 
       | Out of respect for your player's battery life, perhaps :)
        
       | two_handfuls wrote:
       | Nice writeup! I didn't see mention of the license: it's MIT and
       | the code is on GitHub.
        
       | muragekibicho wrote:
       | Somewhat related. Your QOI lossless file format coupled with 7Zip
       | outperfoms lossless PNG. Amazing work!
        
         | pornel wrote:
         | BMP coupled with 7Zip would outperform too (probably by a
         | bigger margin). It just boils down to gzip vs gzip-replacement
         | compressor.
        
           | zX41ZdbW wrote:
           | I also found that BMP with ZSTD outperforms PNG while
           | developing https://adsb.exposed/ (it streams raw RGBA over
           | HTTP with Content-Encoding: zstd)
        
           | vanderZwan wrote:
           | Not to mention the part where adding compressors like this
           | somewhat defeats the purpose of using a simple format like
           | QOI (although at least zstd is faster than gzip, let alone
           | 7zip).
           | 
           | But if we're modifying things like that, then they might as
           | well make use of Nigel Tao's improved QOIR format, and
           | replace the LZ4 compressor it uses with zstd. That's probably
           | faster and likely compresses better than QOI.
           | 
           | [0] https://nigeltao.github.io/blog/2022/qoir.html
           | 
           | [1] https://github.com/nigeltao/qoir
        
       | Defletter wrote:
       | As one of those 3000 licence holders, I'm happy to see a revival
       | of Impact :) wonder how nicely it plays with Zig.
        
       | kirbyfan64sos wrote:
       | Had to log in to my rarely-used HN account to mention that I had
       | played Biolab Disaster over and over again years back but lost
       | track of it and forgot the name. Kinda wild to find it again by
       | sheer luck!
        
       | leeoniya wrote:
       | now rewrite it back to JS with
       | https://github.com/KilledByAPixel/LittleJS
       | 
       | j/k :D
        
         | nine_k wrote:
         | Why, from C to Zig, from Zig to Rust. Compile the Rust version
         | to WASM to finally make it runnable in the browser.
        
           | Defletter wrote:
           | Doesn't Zig compile to WASM too?
        
             | flohofwoe wrote:
             | Yes, for instance this is mixed Zig/C project (the C part
             | are the sokol headers for the platform-glue code):
             | 
             | https://floooh.github.io/pacman.zig/pacman.html
             | 
             | The Git repo is here:
             | 
             | https://github.com/floooh/pacman.zig
             | 
             | ...in this specific project, the Emscripten SDK is used for
             | the link step (while compilation to WASM is handled by the
             | Zig compiler, both for the Zig and C sources).
             | 
             | The Emscripten linker enables the 'embedded Javascript'
             | EM_JS magic used by the C headers, and it also does
             | additional WASM optimizations via Binaryen, and creating
             | the .html and .js shim file needed for running WASM in
             | browsers.
             | 
             | It's also possible to create WASM apps running in browsers
             | using only the Zig toolchain, but this requires solving
             | those same problems in a different way.
        
             | nine_k wrote:
             | Yes, but the point of the joke was to make the loop longer,
             | while keeping it somehow logical. I wish I managed to
             | insert Purescript, Elixir, Pony and ATS somehow.
        
           | leeoniya wrote:
           | i'm actually quite curious how it would perform relative to
           | the C version. the article shows 1000x particles, but
           | LittleJS has demos with a couple orders of magnitude more
           | than that at 60fps.
           | 
           | e.g.
           | https://killedbyapixel.github.io/LittleJS/examples/stress/
        
             | pjmlp wrote:
             | Not looked into the code, the correct way would be to move
             | the particles engine into shader code, and the limit would
             | be as much as the graphics card can take.
             | 
             | It appears that after all these years, not everyone has
             | bought into shader programming mentality, which is quite
             | understable as only proprietary APIs have good debugging
             | tools for them.
        
             | nine_k wrote:
             | JS engines like V8 are very good at JIT and optimization
             | based on actual profiling. If we talk about pure CPU
             | modeling, I suspect a good JIT will soon enough produce
             | machine code on par with best AOT compilers. (BTW the same
             | should apply to JVM and CLR languages, and maybe even to
             | LuaJIT to some extent.)
        
               | andai wrote:
               | From my cursory reading of v8 blogs, most of its
               | optimizations revolve around detecting patterns in JS
               | objects and replacing them with C++ classes.
        
               | nine_k wrote:
               | Exactly. Detecting patterns that are typical for human
               | coders and replacing them with stuff that uses the
               | machine efficiently is what most compilers do, even for
               | low-level languages like C. You write a typical `for`
               | loop, the compiler recognizes it and unrolls it, and / or
               | replaces it with a SIMD-based version with many
               | iterations run per clock.
        
       | moffkalast wrote:
       | With WASM it might actually run faster in the browser as well.
        
         | echelon wrote:
         | WASM still needs better multi-threaded support. We built a game
         | in Bevy and it took minutes to _sequentially_ load in all of
         | the assets.
        
           | flohofwoe wrote:
           | You don't need multithreading to get concurrent asset
           | streaming, a completion callback or async-await-style code
           | will work too (after all, that's how most Javascript web
           | games load their assets "in the background"). Also, browsers
           | typically restrict concurrent download streams to about 6
           | (the exact number is entirely up to the browser though) - so
           | you can have at most 6 asset files 'in flight'. In the end
           | you are still limited by the user's internet bandwidth of
           | course.
        
             | echelon wrote:
             | None of that worked out of the box, and we also spent most
             | of the loading time CPU bound, processing the individual
             | assets after they arrived over the wire. That was a
             | blocking, non-async operation.
        
               | andai wrote:
               | >processing the individual assets after they arrived over
               | the wire
               | 
               | Could this take place at compile time?
        
         | phoboslab wrote:
         | It does, but the main speedup comes from using WebGL instead of
         | Canvas2D. Sadly, Canvas2D is still as slow as it ever was and I
         | really wonder why.
         | 
         | Years back I wrote a standalone Canvas2D implementation[1] that
         | outperforms browsers by a lot. Sure, it's missing some features
         | (e.g. text shadows), but I can't think of any reason for
         | browser implementations needing to be _that_ slow.
         | 
         | [1] https://github.com/phoboslab/Ejecta
        
           | moffkalast wrote:
           | Ah man, I'm still looking for a general canvas drop in
           | replacement that would render using webgl or webgpu if
           | supported. Closest I've found so far is pixi.js, but the
           | rendering api is vastly different and documentation spotty,
           | so it would take some doing to port things over. Plus no
           | antialiasing it seems.
        
         | pjmlp wrote:
         | In browser games, there is more performance gains to move stuff
         | into the GPU, than using WASM.
        
       | pjmlp wrote:
       | Love the honesty of the headline.
       | 
       | The game looks cool.
        
       | slowhadoken wrote:
       | I used to play X-Type all the time on iOS, it's how I discovered
       | Impact. I love web-based games but lately I've been tempted to
       | write in C or C++. Did you notice dramatic gains in optimization
       | porting Impact from JavaScript to C?
        
       | mgaunard wrote:
       | The history section does not feel quite accurate.
       | 
       | From what I recall, what killed Flash wasn't iOS, but rather the
       | acquisition of Macromedia by Adobe.
        
         | lelandfe wrote:
         | Flash game sites were still huge and popular after Adobe's
         | purchase, so clearly it did not kill it. If you mean something
         | like that the acquisition started the death... that's a hard
         | position to argue against, since it's subjective. Perhaps
         | you're right.
        
           | mgaunard wrote:
           | Adobe had competing products mostly based on open standards.
           | They shut down many active product lines and merged what was
           | left into Adobe AIR, which didn't take off.
        
             | lelandfe wrote:
             | AIR and Silverlight and co. was a weird moment in the web's
             | history
        
           | phamilton wrote:
           | When flash started to fade for games, many developers moved
           | over to adtech where their skills were still valued. Flash
           | continued for a few years to power ads as well as shims
           | around other videos that would collect data and even trigger
           | secondary ad auctions.
        
         | andai wrote:
         | Adobe was well into the development of AS 4.0, then scrapped it
         | after Steve Jobs' psyop.
        
         | phamilton wrote:
         | One of the final nails was the infamous Chrome 45 aka the
         | Chromepocalypse in the video ad world.
         | 
         | Chrome 45, in the name of performance, defaulted to only
         | loading flash from 3rd party domains after a "click to load".
         | This was bad for ads for obvious reasons, but it was much much
         | worse due to an implementation detail.
         | 
         | In order to get the page laid out properly, Chrome loaded the
         | flash component and then suspended it after a single frame.
         | From an ad perspective, that was enough to trigger the
         | impression pixel, signifying that the ad had been shown and the
         | advertiser should be billed. However, the ad was not shown and
         | there was no way for the ad to detect it had been suspended.
         | Just a nightmare. We (I led the effort at BrightRoll) had to
         | shift a ton of ad auction behavior to special case Chrome 45
         | and it limited what kind of ads we could serve.
         | 
         | That was the inflection point away from flash for ads. While ad
         | formats like VPAID supported JS/HTML5, they didn't start
         | getting popular until after Chrome 45 was released.
        
           | hypeatei wrote:
           | > to trigger the impression pixel
           | 
           | I've always wondered how ad companies verify the ad is
           | actually being displayed. Can you explain this in more
           | detail?
           | 
           | I imagine it has to be somewhat "bulletproof" since money is
           | involved.
        
             | dylan604 wrote:
             | > I imagine it has to be somewhat "bulletproof" since money
             | is involved.
             | 
             | The GP comment pretty much shows how bulletproof it wasn't,
             | it isn't, it never will be. You also have bad actors in the
             | space that will load ads under other ads so that the same
             | page load continues to generate impressions. The space
             | behaves as if there is no incentive to be honest.
        
       | fitsumbelay wrote:
       | "Thoughts on Flash" may just have saved the Web platform at its
       | hour of greatest need, ie. creeping dominance of a single piece
       | of software.
       | 
       | I believe that somewhere in there was frustration with Adobe who
       | seemed to abandon the MacOS platform support for Windows' much
       | larger user base, eg. Mac versions were always behind Windows
       | versions. Perhaps Jobs also may've felt that there would be no
       | Adobe without Apple as much as the other way around but that's
       | speculative
       | 
       | The game looks slick af btw,
        
         | golergka wrote:
         | Even PSP had Flash, and it was fairly decent. I wonder how much
         | effort and money Sony put into that.
        
           | olliej wrote:
           | Flash had numerous issues. The processing power available
           | (especially on a PSP) is more than enough to be "good", the
           | problem with flash _performance_ is the power usage while
           | achieving that perf. Even on laptops flash was a significant
           | battery life drain whenever it was running, having it on all
           | websites would kill battery life while browsing on a phone.
        
             | thedragonline wrote:
             | Yeah it did. I'm just sad that it took down ActionScript
             | with it. IMO this is the language Javascript should have
             | been.
        
         | fitsumbelay wrote:
         | ... and the post has me poking around with C again. was always
         | an ecmascript guy with a little Lingo in there from long ago,
         | however I have an itch for all things low-resource and close to
         | the metal (but not assembly lang close) and golfing my way
         | towards somethings that encourage me to dig deeper
        
       | zoogeny wrote:
       | The next logical step is to port this to WASM so that it can run
       | in the browser.
        
         | igor_akhmetov wrote:
         | The engine already compiles to WASM, see TLDR.
        
           | zoogeny wrote:
           | I skimmed right by that. Have you done any feature
           | comparisons against raylib?
        
           | azakai wrote:
           | Direct link to playable wasm version:
           | 
           | https://phoboslab.org/high_impact/biolab/
        
       | hoten wrote:
       | Amazing work!
       | 
       | FYI - in non-fullscreen mode, on my Mac / Chrome, the bottom of
       | the viewport is cut off. So can only play in fullscreen.
        
       | andai wrote:
       | I did 5 game jams this year, 4 of them in various WebAssembly
       | languages (C++, Zig, Odin, Rust).
       | 
       | In the end I switched back to JS/TS, because I found way more
       | benefit from minimizing layers of abstraction and translation (WS
       | is set up so you are forced to interface with JS to actually do
       | anything), more than the benefits of any language or library.
       | 
       | (An exception _might_ be something like Unity, due to the
       | excellent featureset, but the IDE has become so slow it 's
       | unbearable...)
        
       | jokoon wrote:
       | What amazes me is how modern javascript engines are able to
       | optimize for a "hot execution path".
        
       | cubano wrote:
       | ohhh I love your use of UNION to create a polymorphic-type ENTITY
       | data structure. Nice work and design.
       | 
       | I still love futzing around in C...It was the original langauge I
       | learned and God did I struggle with it for years. Like the OP
       | mentioned, C is awesome because its such a concise language but
       | you can go as deep as you like with it.
       | 
       | Thanks for all your efforts and the writeup...the game has a
       | throwback Commander Keen-type vibe to it and I loved that
       | franchise for a minute back in Carmack's pre-3D days.
        
       | esschul wrote:
       | Remember I was working on an impact.js game 10 years ago. Just
       | can't seem to find the source code! First time I hired a guy to
       | create some graphics. Very inspiring gaming platform.
        
       | o11c wrote:
       | > high_impact is not a "library", but rather a framework. It's an
       | empty scaffold, that you can fill. You write your business logic
       | inside the framework.
       | 
       | I normally phrase this in a much more negative way: a "framework"
       | is simply a "library" that does not place nice with others. It's
       | good to hear a sensible positive phrasing for once.
        
       | tomcam wrote:
       | Fun idea, open source for maximum learning value, seemingly
       | flawless execution, vanity-free and clear writeup--what a lovely
       | contribution to the world. I feel privileged just seeing things
       | like this.
        
       | jonwinstanley wrote:
       | Looks like it's a great game engine. Why does the article state
       | its near end of life?
       | 
       | Are there new engines that are far better?
        
       | theapache64 wrote:
       | dude is an OG!
        
       | elfelf11 wrote:
       | Would love to have a ruby binfing.
        
       ___________________________________________________________________
       (page generated 2024-08-04 23:00 UTC)