[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)