- Bevy (Rust ECS engine), which is nice at first but has a lot of problems with its implementation and can become rather messy. I think it's heavily dependent on the game. Part of it will be my own incompetence.
- Unity. IMO the system of gameobjects with composed modular components is the most utilitarian - it gets out of the way, and it's easy to avoid spaghetti without requiring a really strict engine-dictated structure.
- Godot. I hated it. All of the awful heirarchy of OOP, a really poor builtin language, and "signals", which are meant to decrease spaghetti but only increased it for me. Maybe I was using it wrong? I very rarely use inheritance to the point of being bad at using it.
- Pygame, back when I first learnt to code. It's quite nice for small projects - it's procedural at heart but you can make your own OOP or functional layers over it. There have been some surprisingly large projects made in it.
I don't know Clojure, but it's interesting to see someone make a functional implementation of something that stereotypically seems like a good fit for OOP.
Godots signals are such a huge step up over Unity's built in classes having a lack of modularity.
How do you even make sense of that? Godot vs Unity basically have the same scene/node/component model except Godot does it better imo. Eg) What is the difference between a prefab vs a scene in Unity anyways? Basically nothing, it's just (I'm speculating) a tech debt mistake in their design, probably still going because of how light maps work today.
Unity's advantage over Godot is it's 3D renderer, built in physX, il2cpp backend for C#, profiler, general runtime performance and console support.
Godots design is objectively more cohesive, as Unity has simply splintered into 10 different design directions since ~2018.
I'm not trying to be a hater, I just think signals are a huge advantage for writing modular, simple stuff in Godot. I think there's plenty of great reasons to prefer Unity to Godot but "signals" is not one of em.
Godot is objectively a way way better tool
If you like things like Godot, Godot is the type of thing you will like.
Seriously though, Godot works way better for me using C# than it does with GDScript and the OOP structure means I can refer to classes by their identity.
I would say that. Godot is a way way better tool.
There, I've falsified your claim.
But more seriously, it's a faster dev experience, it's more ergonomic, it's not cluttered with half baked "new" ways of doing things that don't do everything the old ways do. There's no reason to pick up Unity unless you are being paid to, IMO.
> Unity's advantage over Godot is it's 3D renderer, built in physX, il2cpp backend for C#, profiler, general runtime performance and console support.
And correct me if I'm wrong, but Godot doesn't have hot code reloading where you don't have to restart your game.
Hot reloading is supported.
Console support is some work. Possible, but work.
The 3d renderer is okay, but I'm hesitant to call it good. It's not as good as Unity nor Unreal, imo.
The internal profiler really sucks.
Everything is possible if "some work". Porting to PlayStation 5 is probably a lot of work.
I'm a Godot fan boy, but we gotta be honest about its flaws.
If your targeting 3D on console, definitely go with Unity or Unreal imo.
You don't even have to use Nodes much, though they're great for lots of stuff. For real performance, you can drop all the way down to their thin wrapper over Vulkan and do whatever you want.
GDScript is, in my opinion, unsuitable for anything more than a couple hundred lines at most.
> unsuitable for anything more than a couple hundred lines at most.
I work profesionally in ~5 code bases with ~10,000 lines of GDScript each. I think GDScript is great for UI widgets. I dont think you can say it has a 'line number' limit. It has a 'complexity' limit.
If your writing a ton of tiny little classes that do one thing (like play a sound when a button is pressed), then GDScript is probably the best language for that. Certainly c++ is not the best, and C# is perhaps worse as well. Note: GDScript doesnt need to be compiled _at all_. In unity, its common to have an annoying 'hang' every time you alt-tab from vscode back to unity, as the c# is compiled. In Godot, I can write a new UI widget directly in the editor, with no compilation hang, with hot reloading. It's simply a smoother experience for writing the mountain of basic plumbing that you write when making a commercial game. It's not all complex algorithms here, it's just a crapload of boring ass code. And GDScript is great for that.
Most of the code in games is tiny little things that manage sequences of animations. There is seriously so much small code to make a UI look and feel nice. Writing this code in GDScript is way faster and ergonomic than any other language I've used.
I agree, GDScript has many flaws, but from where I'm sitting (small studio, been in the industry for 10 years), GDScript is a massive boost for my productivity.
For complex stuff, I like to figure out the algoirithm in GDScript then rewrite it in C++ if it needs it. Works great. Again, massive increase in productivity.
It is just so confusing to me and took me over a day to get a simple menu aligned how I wanted
it might just be me not understanding how it works though
Yes, your UI will be a tree of Control nodes 20 levels deep, and that’s fine.
Your root UI node will probably be an HBoxContainer, or VBoxContainer, each of which simply arranges their children horizontally or vertically, respectively. Between those two nodes you can create 90% of UIs you’d want to.
Now I have not tried Godot so I don't know how the two compare, but for where I work Zenject was basically the a-ha moment that made it possible to develop Unity apps/games that don't devolve into a huge unmaintanable mess.
Are signals significantly better than Unity events or is it more that the API uses them heavily?
Honestly, why doesn't Unity retool SendMessage() and public API callbacks to be an exposed Unity event? Unlike merging prefabs and scenes, that's not even a breaking change.
Not game dev either but I do have to say that I find Godot's design to be one of the best oop desings I worked with. I tend to not use oop much today (C++ embedded), though I did learn programming with C# so I'm fairly used to inheritance.
For 2D and simple 3D games, I see no reason to use Unity anymore; I predict a steady decline in Unity's market share as Godot slowly overtakes it.
While this is true it does come with a big caveat. Every single AA developer has had access not only to the Unity source code, but in some instances also to Unity employees who became directly embedded in the production cycle. There’s a GDC presentation from the team behind Ori and The Blind Forest where they talk about how some Unity devs were flown to Austria to help out with custom tooling. Playdead also has a really nice blog where they talk about all the changes they had to make to the engine in order to achieve good lighting performance/fps for Inside. https://blog.playdead.com/articles/inside_presentations/insi...
I’m sure that if the Godot foundation had enough resources at hand then you would also see more games like Cuphead and the ones previously mentioned above.
Working with nodes and editor bugs (or features? Hard to know really) is probably the most frustrating - you can really feel that this was initially built for 'smaller' projects.
For this reason, I rarely use the editor outside of setting up the scenes and a general hierarchy.
Daily tools: Emacs (with C# LSP) most of the time. VS Code for debugging. Godot editor for tweaking the scene tree.
Perhaps this perspective is useful for other devs thinking about Godot.
Having programmed for over 25 years now, this was my experience. I feel like a little more IDE introspection or tooling to make the signal/listener connections more manageable, is the special sauce that's missing. The event pubsub moel becomes unmanageable to document/control with any non-trivial application. Godot has no encapsulation or tracking support, allowing all modules to hook to any event leads to spaghett, which you learn when working with large projects in various languages (JS et al).
Godot could have built on Python, but they would have had to also include a language server (and maybe ipython or jupyter or something) to get the full seamless experience that GDScript gives. Including all that seems a bit much.
So, like you, I appreciate GDScript and have sympathy for why it was created.
Also, GDScript hasn't done anything like implicit type coercions (see JavaScript) and so GDScript can improve without breaking backward compatibility. If needed, breaking backwards compatibility in GDScript won't be as bad as breaking backward compatibility in a real programming language, so they can steer it where it needs to go for the benefit of Godot.
Having gotten into Godot with v4, it was a huge breath of fresh air coming from Unity and Unreal (which isn't really hobby friendly).
Composition of nodes is quick, easy to compartmentalize, and having signals as an interface makes building them very, very quick. Yes, the debugging story on Godot isn't quite there yet, but I genuinely doubt I'll ever touch Unity again unless I have to for a job.
https://github.com/ensisoft/detonator
It's a (2D only) game engine I've been putting together for years and obviously not yet at a level comparable to Godot, maybe more like haxe or lowe2d.
The target is simple single player, single developer "weekend" games.
Can you expand a bit about why this was messy or comolicated? I found the paradigm leads to pretty well organised code (sometimes you get the odd large system, but it can be broken down into smaller systems, sub systems or composed out of smaller functions).
There are two issues:
1. The fundamental issue is that the ECS model has independent subsystems communicating via a relational database. This breaks the connection between function callers and callees, makes control flow incredibly hard to trace, and means the type system can give you very little assistance.
2. Bevy also does not leverage Rust's type system in other ways. E.g. you can use resources that you forget to create and it will only crash at runtime instead of giving a compile time error.
I think you can create a good game in Bevy, and if you come from a C/C++ world you probably won't notice the lack of type safety. It didn't meet my goals, however.
Would something else even be possible in Rust? My understanding is that you cannot really add type safety in the way of "This should be a i64 and between 32 and 128, otherwise fail to compile", so not sure how it could be addressed by the language.
Or taken to the extreme "Fail to compile if the user creates an instance of this but doesn't call function F with that newly created instance"
Plugins are the main abstraction in Bevy. A plugin has two parts: build and run. Build creates stuff, and run uses stuff created by build and created by the build of other plugins running at the same time.
Build is pure side-effects, so the result type of build tells you nothing about what it builds. Therefore there are no types that can constrain what resources run uses, and therefore failing to create a resource that is used in run is a run-time, not compile-time error.
The alternative is the build returns a type representing the collection of resources it creates, and run's type is a collection of resources it uses. This requires some type level programming (a type level heterogeneous set). This is some of the simplest type level programming, but type level programming itself is quite foreign to most programmers. I assume this is why the Bevy developers went for the easier to write solution that doesn't enforce constraints at compile-time.
More generally, just like in regular programming some things are easier and some are harder to do in common type systems.
Your first example (integer constrained to a range) is harder because you need to solve linear inequations at compile-time, which is not a feature of most type systems (though see refined types).
You second example (must call a method) is relatively easy with linear types, as they express "must do something with this value".
Interesting, could you possibly share an example on how that would look like in Rust? Haven't come across it yet, and would certainly help with some things.
Lets say we want to make sure if "MyStruct" is ever defined + created, we want to make sure the program somewhere calls "register_struct" with an instance of that struct.
You can do a dynamic check to encode this, but that's not super popular. You can also issue a warning, and in theory turn that warning into an error, but it may also trigger on code unrelated to the specific struct you want it to, so I don't think that's a full solution either, and others may use your code without the warning, getting less guarantees.
For this reason I agree - developing games using an ECS design requires more discipline to manage complexiy, compared to an imperative one.
With regards to the chaos: I think it can be avoided, but like you said it requires a bit of discipline. I don't feel like it required that much more than normal software engineering (but I'm also the type of person that documents and tests everything even on personal projects lol). The plug-in system makes it easy to help bring order too.
This is all through a bevy-tinted lens, since I've done very little game dev (dabbled with UE and Godot) outside of bevy, though!
Easily grokable filenames and file structure are very important, and bevy specifically has a pretty nice plugin system which lets you really clearly 100% isolate groups of state/logic into more sensible sections instead of ultimately having some root level game loop that's directly setting up your 100 tiny little poorly named things.
I view 3 users 1. Complete Novice 2. Engineer dabbling in games 3. Professional game designer.
For #2, they are more likely to prefer C# as they probably already have experience with it, or otherwise will be familiar with the similar Java language. Also it's a nice resume boost to say you've used C#
For #3, I can't imagine the godot language is better for large scale games than any custom language. C# just has way more resources put behind it
For #1, I kinda see it. But they would probably be better learning a language with more tutorials available. Or if they're struggling, pygame is probably a better place to start.
https://github.com/godotengine/godot/issues/70796#issuecomme...
And despite my best efforts to statically type everything in GDScript, the language is full of holes that lose all the safety.
Let's say I'm not a big fan of the language. Why the hell they decided to not implement normal for loops, was just googling how to iterate an array backwards and most people were like "just invert the array and iterate over it, bro"
They should have just used Typescript, it's a sweet spot between safety and productivity.
https://docs.godotengine.org/en/stable/classes/class_@gdscri...
var array = [3, 6, 9]
for i in range(array.size() - 1, -1, -1):
print(array[i])
Admittedly not very pretty but it certainly works."why god why can't they just have for loops!?!?" and the problem was just ... knowing how to foreach over a range correctly? the idiom and language syntactical preference that python, a language older than java, has done for decades...?
Really trivializes every complaint and the assumed skill level of every person that I see in this thread complaining about gdscript to the absolute lowest level. Thanks for the post!
The doc states that range function returns an Array, so it looks like to iterate backwards you basically allocate array of indices and use those indices to get values from an original array. Not much better than reverting original array, if you will ask me.
Maybe there is some optimization for trivial scenarios, but the referred doc doesn’t mention it.
It really looks like python 2 case when you needed to remember that dict.items() returns copy and most of the time you needed iteritems().
I would imagine for most games the performance impact from this won’t matter much.
And to me it looks like pure language/stdlib problem. Like for me, the proposed solution looks ugly both from syntax and what is going on behind curtains perspective.
I would rather not to code in a language that makes/tolerates decisions like that.
Personally I’d just reverse the array and then iterate it. It’s going to make about zero difference.
Every language has its sharp edges.
I've used C# for my day job for years, but never felt the need to stop using GDScript for any of my projects.
Unreal Engine started out that way.
The "so, you have a choice of c++ or drawing lines between boxes" is missing a lot of middle ground :)
Signals are basically just event subscriptions. In fact, if you use C# with Godot you can actually just use C# native delegates/events.
Can someone explain?
Core is an experimental tool that simplifies the process of creating Action Role-Playing Games (Action-RPGs) by providing a unified set of tools and a streamlined approach to game development. It represents game elements (entities) and their properties (components) as simple data structures, allowing for greater flexibility and easier modification. The entire game state is stored in a single container (app/state), making it easier to manage and update the game's data. Core also provides a graphical user interface (GUI) for editing game content stored in a single file (resources/properties.edn), making the development process more accessible to non-programmers. By using Malli schemas for data validation, Core ensures that the game content is consistent and error-free, reducing development time and improving the overall quality of the game.
There are a few games like suduko that are about that are simple and yet have high replay ability. If you can come up with another game on these lines great, but such games tend to be very different from the things. Good luck in making an exception.
Clojure vectors are just lists, basically.
"Atoms" are mutable references to immutable datastructures (Clojure is immutable-by-default). You can kinda think of them as pointers, but with specific update semantics.
Transactions are similar to database transactions: mutate several datastructures simultaneously, but only 'commit' the changes if all operations succeed. Roll back and (optionally) retry if any part fails.
Malli schemas are just a way of doing typechecking in a dynamically-typed language.
Datomic is a bigger topic. It's an implementation of a non-SQL database system based on immutable datastructures, in which all changes are appends rather than being destructive, allowing you to 'rewind' the database and view it at any point in the past.
I don't think gamedev was ever simple, but I do believe the process can be streamlined. From my experience the biggest choke point (outside of keeping everyone aligned properly) is asset production. Arguably the most important aspect to make games sell, but the 3d asset pipeline has only gotten more complex.
If you can streamline on that (and stay lean as a team) I imagine you can dramatically shorten development.
I am using them to construct side effects which I call 'transactions' (similar to datomic) [:tx/foo 3] where :tx/foo is a keyword and uniquely identifies the component behaviour.
array / vector
> construct side effects which I call 'transactions'
setting a variable
> where :tx/foo is a keyword
variable or hashmap
> uniquely identifies the component behaviour
running a function
Of course it has a component system. I just hope no one sees this mess and thinks that if THIS is considered simple, videogame development isn't for them.
And I'm not even talking some fancy 3d title. How much would I fight against the framework if I wanted to try and recreate Thomas was Alone or Baba is You? Seemingly simple games but ones with very involved systems and state management.If it can truly handle all those edge cases and saves me times after rampup, I can concede it as simple.
A clojure vector is just a vector. Like a Java vector or C++ vector.
The rest seem to be Clojure concepts or libraries. It's a bit disorienting because the language isn't capitalized in the link.
Of course I'd need benchmarks to make a real judgement. The above is my gut reaction.
The main problem is total lack of specification - because I didn't come up with a story for the game or I think games maybe don't need stories. So I just coded like a maniac because it's just fun to code in clojure
Kudos for trying something cool, this is a space a lot of people are interested in. Thanks for sharing it.
I can think of a couple games that sprang from odd academic navel gazing like this. A sibling comment mentioned Jonathan Blow; when I read about this project, it immediately reminded me of Braid. I remember when procedural generation was an ivory tower topic. Hell, every development in 3d graphics started life as a totally impractical paper at a conference. There's a lot of things that are mainstream in games now that were once niche academic notions.
I don't understand the hostility.
Braid features actual novelty in game design, enabled exactly by not using an engine with a fixed view on how a game works. I don't see how this compares.
What style of game is that? I guess RPG? I think that's just because it was a convenient way to demo the concept.
The two interesting things about this, AFAICT, are that it enables mutable state during development in an interesting way, possibly allowing for repl-driven development of running games. That's neat. Like, play the game, get to a point where (for example) the game balance isn't right, and pop into a REPL to make adjustments. And possibly, rewind and replay the scenario in the process to try alternatives, which is related to point 2:
If this is using a datomic-style model, it's presumably keeping an immutable history, allowing for both an interesting development environment (where you can play, rewind, adjust, replay, etc) and interesting new gameplay possibilities.
I don't think anybody is suggesting that game devs should immediately jump on board and start developing on this platform. Again: I don't get the hostility. "Hey, here's a neat little game engine based on unfamiliar concepts." "That's dumb, nobody could develop a AAA game on that today, you should be ashamed for posting it!!" Just...chill out a smidge.
Saying this while telling me this is the wrong site for me. Nice.
My comment isn't hostile. My opinion on this github has value and I am not alone. I could have worded it 'nicely' but if you find every brutally honest comment to be hostile, then maybe this site isnt for you.
And I'm not offended by your 'brutal honestly'. I'm just mystified. You could comment "this is neither production-ready nor industry standard!" on half the posts on this site. Personally, I like being exposed to quirky new ideas, even if they don't always pay off. If I found them actively offensive, I'd have to question why I was wasting my time here.
I’ll also be posting a blog post about the journey soon!
Here are some of my favorite blog entries related to functional game development:
https://prog21.dadgum.com/228.html
https://prog21.dadgum.com/23.html
https://prog21.dadgum.com/24.html
Functional is all about transformation of data structures, and a game is nothing more than a function that takes {state, mouse, keyboard} as input and returns {new_state, output} where output is a set of Vulkan commands, or pixels that you bitblt to screen. Rinse and repeat in an vsynced infinite loop.
I think the linked articles above betray the fact that they were written 15 years ago when functional programming was a niche quasi-academic idea and no one was used to building stateful programs with it. 15 years ago it was all about Java and C++. Lisp was as forgotten as it is today. In 2024 most above average programmers have experience in functional logic, and it is not that arcane of an idea. The reason that it is not widely adopted is that functional programming is not as performant as imperative semantics, and you need all the speed you can get. On the other hand, imperative often means buggy mess as game complexity grows and painful debugging session trying to understand who and why changed this state variable.
But not all games are AAA FPS that require ingenious optimized codepaths to perform well, not in this day and age, so this is why you see commercial games running on "slower" abstractions such as C# (AOT compilation doesn't make it less of an abstraction layer), so you can very well design a commercial game in Haskell or Scheme or Lisp or Clojure if you wish. Nothing stops you, apart from the lack of serious game dev frameworks built in those languages.
It all depends on the compiler, really, and it is asymptotically hard to compile functional languages so they perform as fast as C for example. There is no market for "high performance Haskell or Clojure", so there is no compiler that good either.
JVM languages have a huge gap* in low-level capabilities where-as C# sits next to C and Rust in many of the features that it offers, even if the syntax is different. JVM implementations also come with significantly higher FFI cost. This makes them an overall poor choice for game development. Your experience of writing a game engine in pure C#, calling out to rendering and other device APIs will be massively better than doing so in Java/Kotlin/Clojure/etc, because of both runtime capabilities and ecosystem of interop libraries.
Also, C# has zero-cost abstractions in the form of struct generics which are monomorphized like in Rust, and performance-sensitive code relies on this where applicable in "modern" codebases.
* Projects like https://github.com/bepu/bepuphysics2 are impossible to implement on top of JVM without calling out to native components. This might change once the incubating Panama vectors improve upon their API and what they compile to.
The "sufficiently smart compilers" turn out to either not exist, or be beyond the ability of even the smartest humans.
This is not celebration of that, or condemnation that anyone tried. It's a major bummer, actually, and I am suitably bummed. I'd love to have the Sufficiently Smart Compiler. But wanting doesn't count for much. At this point if someone wants to argue that something at a Haskell level of "functional programming" can run at C speed routinely, they need to produce the compiler; we ran the gamut on mere theories.
(I have to qualify it that way because we do have a lot of evidence that you can have "functional flavored" languages that run much more quickly, like O'Caml (at least in single thread) and Rust, if you consider that "functional flavored". But straight-up Haskell does not appear to be able to "just" get transformed to C-speed code reliably.)
A lot of effort has gone into optimizing C compilers, Haskell is easier to optimize in theory, but in practice it isn't enough easier as to overcome the massively larger amount of effort put in C.
In the best case for both the code will be roughly the same speed. However the best case for both can look very different and any comparison is suspect as it is likely that whoever wrote the code wasn't as good at one as the other and so wrote bad code.
High-level languages like Haskell can and do approach the performance of handwritten C if you encode enough information to get the optimizations for free:
https://stackoverflow.com/questions/35027952/why-is-haskell-...
but that's a completely convoluted approach to identity in a model for a videogame. The reason Rich Hickey took that approach in Clojure to state and identity is because in the domains he cared about he wanted to prevent the destruction of past state. (he wanted to avoid what he called "place based programming" IIRC).
If you want to implement a git like versioning history say, you really care about any change to state as a collection of individually immutable snapshots. But in a videogame that's completely artificial. Nobody thinks about a persistent entity in a game as a collection of states at a million points in time. It's much more natural and performant to think of your entities as persistent and mutable and you basically only care about where they are now.
You care about what they are doing now, and what they should do on next render based on the rules of the game and the player’s input. To me, that looks a lot like (state, actions) => newState.
I’m not sure how much of a difference there really is between having objects track their own state vs having them pull their state from somewhere in a single State tree. The advantage to the latter approach IMO is that it simplifies cross-cutting concerns (“player deals bonus damage when all enemies are affected by poison”), and it helps immensely with debugging to be able to query the exact, full game state whenever it’s needed.
My brain has been rewired to find FP easier to reason about than OOP. This won’t be true for everyone, and it isn’t always the right tool. I think it works well for game dev but can be held back by performance concerns.
It's a costly business mistake to build your tech stack using any of the above languages. The trade off simply is not significant enough to matter vs using mainstream languages with 10,000x the number of mindshare.
Rust is starting to look like it will make the jump to likely to be around for the foreseeable future, but only time will tell.
Of course just because you can build it doesn't mean it will work. I know of an embedded system where the 16 bit CPU went obsolete and they discovered that the C code was not 32 bit safe and worse it relied on the timing of the one CPU it was written for (though not so bad as to have to turn off compiler optimizations). I know of a product written for X11 that is porting to wayland. Keeping code running for decades is a hard problem - and one that many fail to understand. (nor do they need to - the web site you do today will need a major rewrite to fit the latest UI fad no matter what you do)
Clojure won’t necessarily live as long as the JVM does, in that the language could someday be abandoned, but support for its hypothetical last language version won’t be somehow removed from the JVM.
Why not? Python2 is a good example - if they make a JVM2 without the cruft and then a transition they will leave behind those that don't transition. Of course that is the worst case and I'll admit unlikely.
(also the JVM isn't very relevant to me because I work in embedded systems without a JVM)
> If you write in something like C++ or Java running on Linux or Windows I'm confident that in 20 years you will find a tool that can build your code for the latest computers
What I wrote was based on your confidence in Java (the language) being around in 20 years. One of Java’s core features is backwards compatibility. Clojure’s implementation will continue to work as long as Java (the language) itself exists. There’s too much business depending on old Java software for the language to break like Python3 did.
Clojure is also a hosted language by design, and has been ported to JS, .NET, and BEAM (though maybe not completely on that one). If JVM2 were to come out, and if it supported garbage collection, it’s likely that porting it will be easy enough for someone to handle the task of transitioning the JVM1 build to JVM2. Implementing a lisp is not a rare hobby, and IMO Clojure’s language design makes it a particularly tasty flavor of lisp.
you won't be able to find them in enough numbers and it would be tough to gauge their proficiency too
unless you are purely interested in it for academic purposes, its best to avoid clojure and any sort of esoteric languages. Even Rust development is riddled with false roads and mirages.
i just want to save anyone reading this 5 years of their time. You don't get better when you are constantly having to re-invent the wheel for essentially shaving off roughly 20~30% lines of code you'd write in python, php, ts. It's hardly a fair trade off
But there is also a peak performance achieved by using tools for decades that is not transferable. C experts didn’t switch to Java, they found different jobs.
For your core technology you want a few of those 5-10+ year guys.
Combined with clojures way of handling immutable datastructures so well & the excellent protocol system (https://www.freshcodeit.com/blog/clojure-protocols-and-the-e...) I could separate the whole game easily into separate components.
Of course, the Clojure approach is great for a lot of use cases, but video games traditionally do a lot of mutable changes to components. That doesn't mean, of course, that it cannot be done any other way, but it would certainly be a different approach.
In my experience, it slightly favors wide rather than deep game state because wide game state implies fewer nodes that need to be re-created when creating a new state. Since the author is using ECS, it's probably wide enough already.
A bit more in the weeds and if one was using a deep game state, careful structuring of assoc-in and update-in calls might be warranted. Ideally each node would only be copied once to arrive at the next game state. Sometimes it can be more efficient to build a list of changes and then property sequence the application of the changes to the state.
At the end of the day, people don't have to use a single atom like the author either. A game state can consist of multiple mutable data structures. It's not like the Clojure-police are going to arrest anyone for it.
Also Clojure has better performance prospects than Ruby and Python, both have seen "real" usage in commercial indie games.
Personally, I think that FP could be a great fit, but we first need to come up with architectures that solve real game development problems. We have to do this with small scale experiments first (game jams are perfect for this) and then scale up only if they succeed.
This project is exactly that - kudos to the author.
They aren't using them because they aren't a good choice for delivering games that need to run fast and consistently in real time.
Immutable data structures and garbage collection might be nice for people writing something, but that isn't what someone buying software wants, they want smooth and fast.
Also most of the sprite rendering is the main problem, which an atlas texture could also improve even more. (Right now all creature animations are separate texture files).
And you can always step down a level to java if the need arises!
C# tends to be a bit more forgiving about when it triggers GC and how. The generational garbage collector in C# will tend to be more reliable or at least I never ran into super huge issues with the places I've used C# for game dev.
The JVM GC has this unfortunate effect of having very bad pauses occasionally. And appears to do so regardless of the type of GC you are using.
There are some techniques you can use to get around this -> re-using entities. Using C# structs. Not doing allocations/deallocations inside the main game loop if you can.
For small enough games it is irrelevant but as soon as you start to get a larger game with lots of memory allocations/deallocations it really crushes performance.
Notch surely isn't sorry for having coded it in Java.
Too much is wasted on what language, or engine to use, instead of what actually make as a game.
And even when everything is done right, it is a drop in the ocean of daily released titles.
As a game developer, I expect to see a log curve of diminishing returns of novel games given any simple templating/engine system.
In other words, the better you make your cookie cutting machine, the less variance your cookies will have.
I don’t know clojure. Is this normal terminology, ie to use “atom” this way? Seems like a bad name for the concept since the whole idea of “atoms” is that they’re indivisible (back when physics thought they were indivisible).
Also, how about clojurescript so you could run this in browsers?
My user test: https://www.youtube.com/watch?v=gcMBaQI7d-c
I've seen this story of "I want to make a game" [proceeds to make a game engine instead] happen in my own life (my engines were never any good or complete though), and in countless other programmers lives.
It may be the trap of thinking that "If I get the hard part out of the way first (which is writing the engine code, right? Right? Anyone?), then the rest of the game making process will be easy" that gets me.
Or maybe it's finding out along the way that it was more fun to make the engine than the game itself: "check it out, I completely redid the particle effects and I can now do 100x more particles at 60fps, how cool is that?"
There's way more easier-to-see improvements in the making of the engine, than in the making of the game itself, and so we (ok, I) keep optimizing the engine because those are quick dopamine payoffs compared to the slower payoff of having a polished game that's actually fun for the target audience to play. Sure, I might tell myself that the game I want is only possible once I have the engine first, so I'd better concentrate on that before making the actual game, and there's some logic to it. But without a clear idea of what the game will actually be, it's easy to fall into the trap of endlessly adding and refining features, rather than actually try and use those features in anything beyond a slick demo.
To combat the tendency of only making an engine rather than a game in my latest hobby project, I picked an already existing engine (Phaser js) and tried to get something interactive on the screen ASAP "with the stupidest, least designed code possible", and it mostly worked to get me a playable (ish) game! Granted, it's a knockoff puzzle game but hey, I sometimes find myself "playtesting" it instead of what I should really be doing, which is refactoring the code for what I'd like to have it do next, so I'm marking it as a win.
I am learning Clojure and would love to use it for some hobby game-dev, but I have not found a way to compile to html so I am using Godot instead. Not really in awe of the OOP approach though.
This is a libgdx backend for web. Should be possible to use with clojure but haven't tried. This is actually the most interesting next step for the engine I think - would let anyone try the game from the browser!
Even if it's would be hard on performance o think it would be worth it - I would just make the game turn based then
absolutely not recommended even for solo
i would not recommend it for any sort of web app either
clojure/atomic is ovverated
jesus wept. sweep. c'mon.
They (you?) should change the name given the obvious trademark and general confusion issue.
It is (was) marketing failure and an unnecessary legal risk if this gets bigger and comes up on Enterbrain's radar.
You meant trademark, not copyright. Otherwise, your point still stands.
As for names, maybe something cute like ClojRPG?
For example side effects are just vectors of `[:tx/foo param]`.
But I highly recommend changing the capitalization of Maker to maker to avoid being mixed up with the product RPG Maker. Adding "an" helps signal that it's a descriptor instead of a name too.
Core: An RPG maker and engine for Clojure.
CrystalCore - because RPGs must have some sort of magic crystal, it's the law
CreataCore - why limit the name to RPG theme in case it develops into something larger?
Just a few quick name suggestions for OP.
Proper grammar would be "an RPG making tool".
Additionally, you deliberately wrote "RPG Maker" rather than "RPG maker". Capitalization is important, kind of like how "US bank" and "US Bank" mean completely different things (former is a generic reference to an American bank, latter is the name of an American bank).
So yes, I would change the name if I were you (and you have from what I can tell, good job) because it's infringing upon the RPG Maker brand and trademark but most importantly because it's just confusing.
I think HN automatically converts post titles to title case. (There's a short window of time to manually edit the post title to fix the capitalization.)
I really don't think it's unreasonable to assume this had something to do with RPG Maker when it was written like that.
[1]: https://github.com/damn/core/commit/72682f512343c596bce84f0f...