Hacker News new | past | comments | ask | show | jobs | submit login
Racing Game in ClojureScript (github.com/ertugrulcetin)
161 points by winkywooster on June 22, 2021 | hide | past | favorite | 57 comments



The more surprising/interesting thing to me is that it uses React. I'd be curious to see a performance breakdown (how much headroom is left for a more complex game?)

I am also curious how Clojure(Script)'s persistent data structures work out for data structures that update 30 or 60 times per second. That's a lot of allocation and deallocation


You could argue that Clojurescript early adoption of React was one of the reasons for it's rise. The early work of David Nolan (Om) and Dan Holmsand (Cloact->Reagent) were, at least in my opinion, pretty influential. Clojure's immutable data structures were (are) a perfect fit. iirc, the fact that "shouldComponentUpdate" could be performant with equality was a huge, easy performance/simplicity win. I may be way off about that, if so, I apologize.


It makes well enough sense. I was mainly surprised specifically because this is a game, not a DOM-based web app


Om was late, not early, around mid 2015, turned out to be experiment and eventual abandonware. There were much earlier react wrappers, and frameworks like reagent that remain popular today. Dave was influencial in cljs but don't think he ever got a full spa framework off the ground, unless it happened in last few years


Om came first, Cloact (eventually renamed Reagent due to an unfortunate similarity with a certain body part of a snake) came after it.

Here is the original HN post about Cloact: https://news.ycombinator.com/item?id=7037038

You can see people comparing it to Om.

Here is a blog post of his from 2013 that mentions Om: https://swannodette.github.io/2013/12/31/time-travel/

And yeah, Reagent "won" because it was way simpler but I'd find it hard to believe that it wasn't influence or inspired by Om.


Hmm ah okay I meant the write-off omnext, my bad, didn't realize there was previous history, I stand corrected


Fulcro is the successor of OM, a full-stack framework, with some very interesting characteristics and features.


You are right. Equality checks for any complex data-structure in JS (and TypeScript) are cumbersome as hell, yet for a React architecture they are crucial for performance.


This is how remember things historically.


Like Svelte, Clojurescript can "compile" to reactive code (one advantage of being lispy) via Mr. Clean [1]. No VDOM, no library overhead.

[1] https://bitbucket.org/sonwh98/mr-clean


This exists in JS/TS too. Check out SolidJS (and most relevant its underlying dom-expressions Babel transform).


I don't think they're actually doing any compiling in this demo though, but maybe I'm mistaken?


This example has less than 20 components in total and the max depth is 3. (The whole arena is a single object). And it's still using 10% of cpu. Production games have a lot more components in comparison:

https://www.youtube.com/watch?v=GuzRQ1IJkaI


The baseline performance for any sort of react-based web app is going to be pretty bad if you're comparing it to a state-of-the-art game engine. The build status page for the CI/CD pipeline we use at my work has around 2x the CPU usage as this demo, for instance. It would be surprising if cljs's persistent data structures are incurring any real user-perceivable cost over JS arrays and maps, given how small this project is.

That being said, it would be interesting to know how much of a penalty you pay as N gets big using a deeply nested persistent record vs a flatter component system with immutable persistent structures vs a pile of mutable structures.


React-three-fiber is a renderer for Threejs but does not introduce overhead. Games and webgl is loop driven, so React solves that with a hook, useFrame, which binds components to the render-loop in a managed way. It could in theory outperform Threejs because it can schedule: https://twitter.com/0xca0a/status/1383165072554532865 or scale quality: https://twitter.com/0xca0a/status/1407371461447368705 These things would require a framework around Threejs.


Re React, it just uses the same interface: in this case performance is basically just what threejs' performance is (there's naturally a very slight overhead, but what you're looking at is a very thin wrapper over three)

Edit: a sibling mentioned the React ART library and Ink, which are other good examples of the same thing. You can also see same principle used for many of the React animation libraries -- they use the same semantics, so they interop with "normal" React code just fine, but in actuality they're using the underlying animation APIs directly, bypassing the repatively expensive reconciliation process.


There's a lot you can do with a custom reconciler. I didn't look to see if that's what's going on, but it's the foundation for many React adaptations to unlikely interfaces, such as Ink and some of Netflix's smart tv UIs.


It is a using custom renderer indeed: https://github.com/pmndrs/react-three-fiber it doesn't wrap Threejs, just expresses it via JSX similar to how react-dom expresses the dom.


Is this doing any dom stuff in gameplay after React optimizes away unchanged elements? Looks like just a WebGL canvas. I'd guess the React/dom time ends up near invisible in a profile.


It looks really cool (I love the flat poly aesthetic), however some hopefully helpful feedback:

- Framerate isn't wonderful (20 - 30 fps on my laptop, which will happily run graphically more intensive JS demos at 60fps usually), and I see you're using React: is using a relatively heavy framework the best way to go here? Possibly this is fine and the optimisation is required in other areas instead (e.g., are you creating loads of garbage?),

- Car physics and handling is way off: clearly for this game realistic handling probably isn't the goal, but it's bad by the standards of more recent arcade racers (Burnout et al, Cel Damage for something that has a slightly similar aesthetic), or 1980s style 2D racers like OutRun (or more recently 80s/early 90s-esque racing games).

It's certainly an interesting demo - and, as I say, I love the way it looks - but in terms of demonstrating ClojureScript as a viable platform for game development, definitely needs more work. And in terms of this being a game, it's a long way from that: no objectives, no other drivers (depending on the objectives, may or may not be required), no hazards, pickups, etc., no sound, and so on.


> I see you're using React: is using a relatively heavy framework the best way to go here?

If you read the README, React is kind of the whole point of this demo:

"This project is a showcase for the feasibility of React in gaming."

We'd need to know the cause of the performance issues to know whether it has succeeded or not!


Oh, sure, but I did point that out. I'm suspicious of React but open enough to realise the cause could be any number of other things.


Thank you for the great feedback! The goal was just to show the ClojureScript version of the original demo (the first version of it). So there is no collision detection, sound, etc. I think ClojureScript has too many things to provide in this field.


It's definitely an interesting demo and certainly not the first time a less obvious (i.e., imperative) language has been used in game dev: just today on a separate discussion people were talking about use of GOAL (a compiled dialect of LISP) in PS1 game development. Pretty cool stuff.


> Framerate isn't wonderful (20 - 30 fps on my laptop, which will happily run graphically more intensive JS demos at 60fps usually)

Something I'm curious about is whether the frames are dominated by game logic (ClojureScript/React) or by graphics. If your laptop doesn't have a discrete card, and the author hasn't taken steps to optimize the graphical side via culling, etc, then your fps may not be representative of ClojureScript/React-based games in general


Dell XPS with both onboard and discrete graphics. Funnily enough I just tried it on my 2015 MBP, which likewise has two GPUs, and - ridiculously - it runs much more smoothly.


Core code is here: https://github.com/ertugrulcetin/racing-game-cljs/blob/maste...

Looks pretty amenable to hacking with the boy.

I know we're using an engine, but still shocking how little code it is.


I wonder how maintainable this is even for clojure experts? Simple feature - add 'jump' control. How long would it take you?


It looks quite familiar, it generates a plain data structure and reacts on a set of user inputs. I‘d have to look up how this communicates with threejs (which is done via a wrapper library) and what the semantics of that is, but otherwise the code looks clean and simple to me.

Edit: here https://github.com/pmndrs/react-three-fiber


Same here, it's very concise, love it.


323 lines.


More of a technical demo than a "game", but still pretty amazing how fast it loaded and how smooth it runs


I thought I was doing pretty darn well... until I realized there was no collision detection.


Try this one: https://racing.pmnd.rs/

https://github.com/pmndrs/racing-game

The original project is feature-complete as a racing game


https://github.com/ertugrulcetin/racing-game-cljs/blob/maste...

I know indentation is subjective, but is this file the canonical way of indenting Clojure? I find it hard to read.



Welp, I played to the end an immediately hit the loonie tunes-esque fake tunnel wall, but clipped through everything.

Was expecting to get my course time at least...


It doesn't appear to have any collision detection at all. You can drive through walls, over water, through barriers.

The world state seems to be limited to the 2D velocity and 2D position of the vehicle. There's no instability in the vehicle, no loss of control, no loss of traction, spins, brakes locking up.

I guess my point is there's nothing going on under the hood. This could be done in any language that's got an OpenGL API. (or D3D, GLES, Vulkan...) I'm not sure what the takeaway is.

(it looks cool though)


It's just a tech demo I guess. Should be simple to get car physics working, but getting full collision detection working would be another matter entirely.


No real physics engine and the car leans slightly to the left...


This is a port, the original is here: https://github.com/pmndrs/racing-game It uses cannon-es (physics).


Made my Macbook Pro fans rev up to the max.


That's most likely the discrete graphics card kicking in. It's turned off unless it's needed, but when it turns on it puts out a lot of heat


Serious question: how long have you had the machine? If it's more than a year or two you might want to consider opening it up and blowing out all the dust and fluff. I have a 2015 model that runs it just fine, but would really have struggled two weeks ago before I gave it a clean out. Feels like I just upgraded the thing.

I generally do this every year or two but recently I've been doing a lot of work on the house so it's been particularly dusty with debris from plasterboard, cutting timber, sanding, etc.


Late 2013. The fans rarely rev like this. Only with intense CPU activity. If it was happening every other day then I'd take your point.


I'd still crack it open and blow out the dust: you might be surprised by the results.


So how do I get the three-handled cup and "YOU'RE WINNER" message?


create a pull request


This site should be called Hipster News. I feel like the more obscure a project is, the higher the chance you'll see it on HN. Meanwhile, the bread and butter of regular programmers (c#/php/java) gets barely any mention here (and when it does, it's for major lang releases and it's typically poopooed hard) and you basically see ZERO threads about the news from within these huge ecosystems.


Clojure has a decent sized ecosystem by now. The language is almost 15 years old so there is a fair amount of tooling and protocol support.


Engineers are drawn to novel and exciting things; there's nothing wrong with that

But it's also not been my experience that the typical atmosphere around C#/Java posts that show up here has been "poopoo"


Clojure is hardly what I’d call an “obscure” language. I’ll never understand that insane amount of offense people take from others sharing their personal work built with tools they enjoy/ see fit.

> gets barely any mention here (and when it does, it's for major lang releases and it's typically poopooed hard) and you basically see ZERO threads about the news from within these huge ecosystems.

Sounds like you’re projecting or something. C# tends to get a lot of love and while you’ll probably still find some negative comments about PHP or Java here, there’s always enough people praising them for what they’ve provided.


Don’t you see value in looking at projects in the cutting edge? Ideas from Clojure already appear in more mainstream languages. This is your chance to be ahead of the curve and maybe even learn techniques you can apply today.


There's nothing obscure about ClojureScript. Or React.


You came here for novelty and interesting tidbits, you are getting them.


Make something interesting? I dunno. React is pretty main stream.


I'm reading hacker news at work to distract me. Why would I want to see c#, java or php?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: