Developing a Space Flight Simulator in Clojure

113 todsacerdoti 18 9/6/2025, 1:39:01 AM wedesoft.de ↗

Comments (18)

crichter · 30m ago
Jan, This is awesome! I have been following your progress for quite some time now. I actually found your project because you liked my dream chaser model that I put on GitHub some time ago. Really Looking forward to what’s to come and to try out your simulator at some point!
iLemming · 3h ago
I just can't wait to see how Jank gets production-ready and absolutely blows the indie gaming community. Hopefully, very soon.
JoshCole · 1h ago
Very cool work Jan!

Have you tried experimenting with ham-fisted? I've found the libraries in the techascent part of the Clojure ecosystem to be very good performance wise. Ditto for neanderthal.

MathMonkeyMan · 5h ago
Guile has [multi-methods][1] and [fast hash maps][2], but not yet [dynamic vectors][3].

Clojure's data structures are easier to use, though.

[1]: https://www.gnu.org/software/guile/manual/html_node/Methods-...

[2]: https://www.gnu.org/software/guile/manual/html_node/Hash-Tab...

[3]: https://lists.gnu.org/archive/html/guile-devel/2022-01/msg00...

exabrial · 5h ago
Clojure is such a departure for me, coming from C-Like languages. I have absolutely no idea whats going when looking at the code.
JoshCole · 4h ago
Lisps (like Clojure) treat code as data (lists), so you write: `(if x (y) (z))` instead of Python’s `y() if x else z()`. So the code is more concise, but does less to walk a novice through it.

This gains a huge advantage, which allows even more concision: all code is data, so its easy to transform the code.

In Clojure if you want to add support for unless, a thing like if, but evaluating the opposite way you could do this: `(defmacro unless [p a b] `(if (not ~p) ~a ~b))`. Obviously if you wanted to do the same thing in Python you would in practice do `z() if x else y()`. However, you would do it that way because Python isn't as powerful a language. To actually do the same thing in Python you would need to...

1. Add __future__ support.

2. Update the Python language grammar.

3. Add a new AST type.

4. Add a new pass stage to the compiler.

5. Add a python library to integrate with this so you could use it.

Then you could do something like:

    from __future__ import macros

    defmacro unless(pred, then: block, else_: block = []):
        return q[
            if not u(pred):
                u*(then)
            else:
                u*(else_)
        ]

So in the trivial case its just hundreds of lines harder plus requires massive coordination with other people to accomplish the same feat.

This sort of, wow, it takes hundreds or thousands of lines more to accomplish the same thing outside of Lisp as it does to accomplish it within Lisp shows up quite often; consider something like chaining. People write entire libraries to handle function chaining nicely. `a.b().c().d().map(f).map(g)`. Very pretty. Hundreds of lines to enable it, maybe thousands, because it does not come by default in the language.

But in Lisp? In Clojure? Just change the languages usual rules, threading operator and now chaining is omnipresent: `(->> a b c d e (map f) (map g))`. Same code, no need to write wrapper libraries to enable it.

roenxi · 2h ago
That doesn't look like a factor in the article though, he isn't using many if any macros that aren't part of the core language. And the one macro I do spot (defcfn) is pretty mild in context.
roenxi · 4h ago
Fun fact: the big difference isn't the syntax. Lisps only go from foo(bar baz) to (foo bar baz) which is a change but not really much of one. The change is actually the immutable and high performance basic data structures. Clojure can do something that something like C can't do - cheaply create a copy of something with a small change. That leads to a completely different preferred code style in the Clojure community that is a big departure from C-like languages which make heavy use of variables. The code is doing something practically different from what a C-like language can ergonomically handle.
Zambyte · 2h ago
Clojure has a bunch of other syntactic structures not found in other lisps that makes it a lot more visually noisy. I'm very comfortable with Scheme and I can very quickly absorb Scheme code when reading it, but I have to very slowly decipher the code in the article.
iLemming · 3h ago
That's just existing muscle memory. Nothing is wrong with you and nothing is wrong with Clojure. I had the same feeling when I started with Lisp. Give it some time, it's absolutely worth it. Interestingly, every single programmer I introduced to Clojure as their very first programming language had no issues picking it up. Later, they complained about difficulties getting used to Javascript and Python.
rufusthedogwoof · 5h ago
it's not code it's data. :) -macro
shaunxcode · 3h ago
This is awesome! Very nice example of malli in practice!
Fire-Dragon-DoL · 1h ago
This was an amazing blog post, thank you!
nodesocket · 5h ago
Wow, this is impressive not using standard gaming framework like Unity or Unreal.
adastra22 · 3h ago
I mean it is pretty cool, but do people not roll their own graphics engines anymore? When was in to hobby game dev back in 2000 or so, we all wrote our own systems.
seabass-labrax · 1h ago
The hardware graphics acceleration stack is heavily shader-based now, so there's less and less graphics code being written in systems languages like C. In a way, people are still writing their own graphics engines, it's just for such a different platform from the unusual Turing-computer CPUs that all the old techniques go out of the window.

Nothing stopping you from writing it the old fashioned way though - you can just keep generating a single screen texture in the CPU and let the GPU idle!

viccis · 1h ago
No, that's rightfully viewed as a waste of time if you want to make a game (vs if you want to make a game engine)
rookderby · 5h ago
Beautiful visuals. I'd like something to dock with.