[HN Gopher] Technical overview of Kandria, a game and game engin...
___________________________________________________________________
Technical overview of Kandria, a game and game engine developed in
Common Lisp
Author : trocado
Score : 247 points
Date : 2022-07-10 09:08 UTC (1 days ago)
(HTM) web link (reader.tymoon.eu)
(TXT) w3m dump (reader.tymoon.eu)
| gaze wrote:
| I'd really like to understand how live reloading works a bit
| better, especially when editing variables that some running
| thread depends upon. Is there an overall strategy here? Do I
| implement locking around variables that I intend to play with at
| runtime?
| User23 wrote:
| I don't believe the Common Lisp specification says anything
| about threads. For example here[1] is the relevant section of
| the SBCL manual. As you can see it's quite low level. If you're
| using those primitives then yes you'll have to manage barriers,
| synchronization, use atomic operations, or otherwise maintain
| sanity. The REPL (or SWANK) thread is just another thread.
|
| Edit: I should add that the usual pattern is Bordeaux threads
| or some other higher level thing.
|
| [1] http://www.sbcl.org/manual/index.html#Threading
| whartung wrote:
| All of the contention issues that we've had for ages across all
| platforms exist in CL. Loading and compiling new code isn't any
| different than two separate threads calling setq on the same
| element at the same time.
|
| The reality, though, is that the vast majority of the time when
| this is done, the system is idle. If you live update your
| server that's serving 1000 connections and isn't specifically
| coded to handle this potential event, then, for sure, there can
| be trouble.
|
| But if you're hot reloading your dev server, with an idle
| connection, then you're likely to have fewer problems.
|
| However, there's the potential impact of captured state that is
| not properly refreshed. For example, if you have some long
| running state that, say, captured a function via #'my-func,
| then that routine has, indeed, captured the pointer to the
| routine. But when you redefined it, the symbol (i.e. my-func)
| is now pointing to the new code, while your existing state is
| pointing to the old code. Any code that uses the symbol to call
| the routine will update automatically, but anything that does
| not, is stuck with stale data.
|
| And that rock potentially sends different ripples through the
| still pond of your running image. Just something to be aware
| of.
|
| It's a great feature, just need to be aware of what's going on
| when you do it. Most of the time, it's a non-issue.
| newaccount2021 wrote:
| whartung wrote:
| This is a nice write up.
|
| The dark side is that they've put years into developing the core
| infrastructure to empower their Lisp game journey. Ideally that's
| all usable by others to "stand on the shoulders", so to speak,
| but that's always a challenge.
|
| I honestly have never had to work on a "running image" of any
| consequence. I've never worked on anything more than a few
| thousand lines of code. I've never needed any kind of source
| level "step" debugging. The ability to redefine a function
| quickly, I just throw in some prints to figure something out.
|
| Reloading the entire source file was always fast enough to now
| warrant hunting down any of the more interactive mechanisms
| available. This is all across using simple vi, or emacs, or even
| LispWorks. (defun l () (load "src.lisp"))
|
| Just save the file, and type that.
|
| All that said, my current low level fantasy is something akin to
| Electron, only with Common Lisp. First class DOM, first class
| event hooks, into a CL runtime that you can deploy cross
| platform. Dunno if that exists or not.
|
| I'm sure at some point my codebase will grow to the point where I
| would need to "level up" and become more intimate with SLIME,
| packages, system definitions, etc.
|
| I've just not crossed that threshold yet.
| jaccarmac wrote:
| > my current low level fantasy is something akin to Electron,
| only with Common Lisp. First class DOM, first class event
| hooks, into a CL runtime that you can deploy cross platform.
|
| Have you checked out https://github.com/rabbibotton/clog ? I
| have only played with a couple of the tutorials, but it seems
| to be targetting something like that, albeit without an
| included browser.
| dannyobrien wrote:
| The other direction is https://nyxt.atlas.engineer/ , which
| is a CL-driven browser. It's presented as a general-purpose
| browser, but you can also treat it as a standalone CL with a
| browser front-end, and I think that's the developer's long-
| term goal -- a bit like how emacs is a lisp with a text
| editor front-end.
| jomjomv wrote:
| > Reloading the entire source file was always fast enough
|
| The point is that you might want to keep the state.
| nine_k wrote:
| What kind of software do you usually create this way?
| whartung wrote:
| Essentially listener utilities (vs command line utilities).
| Code designed to solve specific problems, typically for their
| side effects and artifacts vs deployed code in production
| systems. One off simulations, etc.
|
| No UI but the listener.
| Shinmera wrote:
| Heya, I'm the author of the article. I've been working on Kandria
| full time for close to two years now, and on-and-off for some
| years while I was doing my Master's at ETH. The engine it's
| running on, Trial, is a few years older still, and initially just
| started out of the good ole university boredom and curiosity.
| Games is how I got into programming when I was about 6, and that
| particular fever hasn't left me yet it seems, ha ha!
|
| Kandria itself started as a "more serious" attempt at a game
| after I'd been making jam games with Trial for some years. I
| wanted to create something bigger, and had just finished playing
| through Celeste, so I just set out to replicate its mechanics in
| my own way. You can still find some demos of those very early
| days on my YouTube channel, if you're curious. In any case, the
| project went through several big changes until it turned into
| what it is now. During the pandemic in 2020 I finally decided to
| drop out of my Master's to pursue the project full time. At that
| point I also brought on a couple more people to help with the
| writing, art, and sound.
|
| We're currently also running a Kickstarter to get us some extra
| funds for the project. It ends on Thursday 14th, 12:00 CEST, so
| there's not that much time left in it. If you'd like to support
| our work, please have a look:
| https://www.kickstarter.com/projects/shinmera/kandria The
| campaign page has a lot more details on the project and the team,
| if you're curious about that.
|
| In the article I primarily cover the programming parts, giving a
| surface overview of the technologies involved and at least giving
| a brief hint at the methodology I employ to create games. I'm
| sure I've left out a lot of details that you might be curious
| about, so if you have any questions, please feel free to ask and
| I'll try my best to answer!
| doty wrote:
| From the post:
|
| > The same doesn't apply to the player sprite, as Aseprite
| takes minutes to compile the atlas for the nearly 1000 frames
| we have.
|
| Why does compiling a sprite atlas for the player take
| 60ms/frame?
| Shinmera wrote:
| I'm sure Aseprite could be further optimised to press down
| the constant factor, but it is performing a rect packing
| algorithm among other things, which is an NP-hard problem.
| dboon wrote:
| How have you funded yourself (prior to Kickstarter)?
|
| I'm in a similar position to you (indie developer, working on
| my first project of size that I am polishing with intent to
| release). I haven't quite been able to square up a way to work
| on my game full time -- I suspect out of a lack of ingenuity or
| resourcefulness on my part. You seem to have solved this
| problem, though.
| Shinmera wrote:
| By being lucky enough to have savings, and having a room at
| my parents' house that doesn't require any rent payments.
| Without those, it definitely wouldn't have been possible.
|
| Recently I've also received some grants, namely the Pro
| Helvetia interactive media grant, and the Poland Digital
| Dragons Accelerator. Both of those only offset a part of the
| money I had already personally invested though, and the
| Kickstarter barely makes a dent in anything.
|
| Selling games is such a gamble, too. If the stats are to be
| believed, only about 15% of games on Steam recoup their
| investment, let alone making profit. For the next project's
| funding, I'm going to try and look at some other source like
| Patreon, to at least offset my own measly costs so I can
| spend longer in pre-production.
|
| Making games is just really expensive, and any funding source
| is heavily fought over, or comes with huge caveats attached.
| I don't think I have this figured out yet either, so all I
| can say is best of luck!
| CraigJPerry wrote:
| >> One thing I do have to mention though is that the workflow in
| Lisp allows me to create these support libraries much faster than
| I can in other languages.
|
| I'm at that stage in my lisp journey (~18 months) where i know
| enough to be dangerous to others around me, i.e. i'm still a lisp
| n00b but have completed a few lisp & scheme books and written
| enough projects that i feel fairly productive. BUT i haven't
| reached, never mind come out the other side of, the "trough of
| disillusionment" yet. So everything lisp is unreasonably tainted
| with a positive glow in my mind.
|
| TL;DR i still think lisp is pretty awesome. It's my newest hammer
| and everything looks like a lisp-shaped nail these days. So i
| have to be deliberate and careful not to over-use lisp but it's
| totally changed how i write js for example. It's infected my
| brain.
|
| Here's the thing - that workflow statement by the OP is a fair
| chunk of the attraction to lisp for me. Before lisp i "knew" what
| a REPL was - i've been using python since i switched wholesale
| from Perl in the 00's, i thought you couldn't teach me anything
| new about REPLs, even quasi-REPLs like Jupyter were entirely
| familiar and "basic" to me. If you're a lisper, you know i was
| wrong about that, if you're not a lisper you're probably
| wondering what's the big deal.
|
| The other chunk - and i'm only really scratching the surface so
| far - has been macros. I think so far i prefer the non-hygenic
| type, but i haven't gone through Let over Lambda yet (although
| the book is on my bookshelf and is only 2 titles away from being
| started)
|
| For me, lisp opened my eyes to a way of working that i just wish
| i could fully replicate in other languages. Lisp has made me re-
| appreciate python and js in different ways now.
|
| If you want a really short version - Brett Victor's famous
| inventing on principle talk sums it up for me (he was using JS
| there, so there is hope...)
| nequo wrote:
| > it's totally changed how i write js for example
|
| This may be a silly question. But could you give a couple
| examples of how you implement something in JS now vs. how you
| would have implemented it 18 months ago?
| zasdffaa wrote:
| Learning a little haskell a million years ago was a
| revelation. In my next bit of JS (a large, non-web project) I
| did lots of FP in it - and for the better, not just because i
| could. I really cut down on boilerplate, made it more
| readable and reusable, and... it was just great.
| chii wrote:
| i would wager that after having used LISP, you start thinking
| bottoms up, rather than top down.
|
| i.e, instead of thinking about a program as a large one, and
| break it down into smaller, and smaller components or pieces,
| you'd start with the most bottom-est, most small piece first.
| Even if that piece isn't useful on its own - or it's only of
| limited use. Then you'd build another small, may be even
| orthogonal piece.
|
| Once you have these small pieces of individual functions, you
| might end up building a glue (sort of a language or custom
| macro?) to bind them together.
| newaccount2021 wrote:
| math-dev wrote:
| Great write-up. Indeed, the journey with Lisp is an interesting
| one and what you have witnessed seems to parallel many others
| experiences.
|
| What I found on my journey with Lisp:
|
| - I learnt Emacs well and learnt the beauty of its codebase and
| the thoughtfulness put into the program. Its' levels of
| documentation and customisation and being a lisp machine in its
| own rights was an enlightening experience for me when designing
| my own software (i.e. document well, document in a standardised
| way, document thoughtfully (think of what the users would want
| to know) and providing customisability to end users (which to
| be honest, dynamic langauges like Lisp excel at because they
| are much better suited for runtime manipulation and
| optimisation
|
| - The power of macros to change one's language. Now admittedly,
| this took some time to get a handle on. You kinda need to be
| proficient in Lisp before you start doing some super funky
| stuff and mould your language and program together into one
| (Ala PG's On Lisp). But having the ability to change the
| language at _compile_ time is simply, utterly, most imaginably
| amazing!
|
| - Writing clearer code: Because Lisp has very little
| punctuation syntax (not to be confused with the syntax of
| certain special forms), you cannot hide behind boilerplate code
| as much and you end up having to face your own thoughts more
| directly in the code you write. It is tough going at the start
| (who would have thought a _simple_ language would actually be
| hard to program in well - basically the more complexity in a
| language, the more restriction to your expressiveness, the more
| simple a language, the more power to you to fully express
| yourself by combining orthogonal blocks...speaking generally
| here as sometimes complexity does help in other ways (e.g. see
| CLOS))
|
| - Learning from the greats in Computer Science - there is so
| many good ideas and thoughts embedded into the lisps, that you
| inevitably learn a lot of good things by immersing yourself in
| the language and its history (of course over time)
|
| And finally, 'Life Beyond Lisp'. I no longer program in Common
| Lisp as my main language because I do need some libraries that
| I cannot do without. But as you alluded in your post on writing
| better JS after Lisp, I too have significantly improved my
| programming and code clarity in these other languages, after
| learning Lisp. Of course, one day I hope to program exclusively
| in CLOS, but until that day, Swift remains my near friend (at
| least it has generic functions).
|
| I can wholeheartedly recommend Common Lisp to anyone who has
| some spare time and curiosity to improve their skills in our
| profession of computer science. Also (and this is something
| Lispers don't seem to do that well), try other languages! Learn
| from them all in my humble opinion. Computer Science is a
| wonderful thing :)
|
| p.s. Congrats to Kandria on their progress. Truly a wonderful
| team and their main author is a wonderful open-source lisper.
| slekker wrote:
| Could you expand on the REPL bit? Having worked with JS, Python
| and Elixir, they feel more or less the same. What's Lisps have
| that these don't?
| bjoli wrote:
| So, I would say the idea of dynamic redefinition is probably
| the big thing: In cl I can redefine a class and have all
| instances updated while the program is running.
|
| I would also say that the error management is also beyond
| fantastic. Say you run a function, and deep inside the call
| stack there is an error. In CL you can actually update the
| faulty function and just continue executing at the point of
| the error.
|
| For someone like me without any intellectual rigour at all,
| this lends itself to a kind explorative programming I really
| like.
| phoe-krk wrote:
| The Lisp instinct is to make a change in a file and
| immediately hit C-c C-c in Emacs, at which point the change
| goes live in the system - no matter if it's a variable or a
| function that you have changed or something else.
|
| You don't need to reload the full module like in BEAM
| languages like Erlang or Elixir, you can modify a single
| function or a form without the need to make a version upgrade
| to the processes running your code - the next time any
| thread, including e.g. an already running game loop, ends up
| calling the new function, it's the new version of the
| function that will end up being called.
| ramchip wrote:
| Version upgrades are not needed on BEAM anymore than they
| are in Lisp, you can just reload a module and code will
| start using the new version.
| phoe-krk wrote:
| TIL, that's a big thing! When was that change made?
| ramchip wrote:
| I don't think it's recent, as far as I know. Versioning,
| appup / relup, etc. are really for upgrading production
| deployments live, when you need special instructions to
| pause processes or update their internal state before
| loading new code. In development, you can ignore all that
| and just reload modules directly. e.g. with "r" in the
| Elixir REPL.
|
| Once that's done any external call (`MyModule.add(1,2)`)
| will go to the new version of the code, while local calls
| (`add(1,2)`) stay on the same version.
|
| The Phoenix web framework will also auto-reload any
| module that has changed on disk when handling a web
| request in dev mode.
| alfiedotwtf wrote:
| Thanks for that. Are you able to tell us what books got you to
| where you are now? I've just started Emacs Lisp An Introduction
| as I'm wanting to dive right into Emacs (coming from a life-
| long Vimer), but I'd also want to expand to other Lisps.
___________________________________________________________________
(page generated 2022-07-11 23:01 UTC)