Thank you for posting this, Bambo! I was curious why we were seeing 10s of new stars all of a sudden and trying to figure out where the GitHubbers were coming from.
Grid Engine 9 is now the largest pure-Lua game engine on GitHub. As s_y_n_t_a_x has mentioned in this thread, I built the Grid Engine on top of LÖVE.
I came from the hlcoders world, having used the Source Engine for several years, and was upset the 2D world didn't have sophisticated game engine technology like the 3D solutions in the field.
There's tons of great game software out there! But to me, a game engine isn't just a load, update, draw framework. There's a lot of hard work involved past binding libraries together.
A game engine needs an architecture, it needs to do multiplayer serialization for you, and give you a meaningful way to load maps out-of-the-box, and so much more.
Too many hobbyists are rolling this themselves, and I hope to continue to bring rich game development features OOTB to other hobbyists like myself.
If you're interested in Grid, but don't find something quite right with it, could you tell me? I've worked on this project for at least the past 6 years from what my logs tell me, but it only continues to get better thanks to people like you all reading posts like this and giving me feedback over the years.
A few casual notes, though I could continue to expand on this:
lgameframework is a project I took on some time ago to provide a LuaJIT FFI alternative to LÖVE. It helped educate me on what was necessary to interact directly with the OpenGL layer, and understand what challenges the LÖVE developers will have in the distant future with OpenGL being deprecated on macOS. (Will they move to bgfx? Or Vulkan/MoltenVK? Who knows. Ask Alex, I suppose.)
As an interesting side note, it does things LÖVE doesn't, which may or may not be interesting depending on whether or not you think first-party 3D features, PBR, VR (See also LÖVR) are desirable in a pure Lua project.
It also serves as a hatch door project I hope I never have to use. Valve broke Source for modders somewhere between the 2007 and 2013 engine branches with SteamPipe, and the idea that you could spend literal years on a project and have some developer break your work in Bellevue was scary to me. They don't have the same respect for the modding community today that they did maybe 15 or so years back. I don't think that's going to change, unfortunately, but I'm digressing.
I trust the LÖVE team, and appreciate that it's FOSS software, but I need full control over the stack I present to developers using the Grid Engine, and I need to respect users by not breaking things.
In the event LÖVE breaks things, the Grid Engine needs to be patched to account for those changes, and Grid has been around long enough to see this happen a small number of times. I think the changes have been reasonable so far, but mature projects will inevitably end up with deprecation notices and backwards compat patches, and that's where we are now.
lgameframework is defensive software, but I'd rather continue to promote LÖVE. The only issue I see with this, and cannot condone however, are the libraries that have come out of the community with inappropriate names.
Edit: I apologize that all of this sounds a bit dark, that's not my intention, but a lot of people's hard work can be at stake. Implementors of such software need to defend their users. The LÖVE developers have created something wonderful, and I must reiterate this.
I plan on Grid being around for years to come, which means you have to start thinking about protecting that mote. Planimeter projects have been in the works since 2010. I work in a narrow subset of the gamedev space, and don't plan on stopping any time soon. It will be my life's work.
Hey I know you mentioned it here and it is shown on the getting started tutorial, but may be useful to mention it on the front page too: the engine is built upon Love 2D.
I love the idea of a game engine with multiplayer built in from the start. It reminds me a bit of MUD engines for text-based games back in the day. Interested to see where this goes!
Thank you. I think it's particularly important that features like this come standard these days. In the last two decades a lot of work in client-side prediction has taken place, but not a lot of it has been working itself back to hobbyists.
Quite an impressive project! I'm curious how the authors went about their strategy for hot reloading in particular.
In Grid, I extend the package library, and utilize the implementation details of `module` which allow one to override or set new keys on subsequent loads of the same file.
It's one of the reasons I don't think I can use the newer module patterns beyond Lua 5.1.5, because as far as I understand, they require one to completely replace what's stored in `package.loaded` versus merging to any existing table.
I had also not given much thought to static typing with Lua until the last year or so working with Lua only because it makes generating documentation harder. Otherwise, I tend to share Roberto Ierusalimschy's opinions of dynamic typing.
I would read his most recent interview from Moscow in 2019. I think he's a very interesting person.
Yes, primarily. But the real answer is because of Lua from Garry's Mod, and the design of the engine is heavily inspired by Source and QuakeWorld. Even today, I still believe Quake is one of the most elegantly designed game codebases in existence.
Planimeter was formerly called Team Sandbox, and we were a group of developers working on a game called Half-Life 2: Sandbox, which was a FOSS alternative to Garry's Mod that stayed Half-Life themed.
The team is comprised of mostly different volunteers now.
Lua is a little confusing language for me because you need to throw out most of the things you know because it has its own way of doing things, it is not necessarily a bad thing but it is confusing. Luckily, it is a very small language so it wouldn't take that long to grasp it all. The most confusing thing was the fact that (almost) everything seems like a hashtable.
Ignoring metatable weirdness, I think "you need to throw out most of what you know" is quite wrong.
The main thing you need to know is that Lua's table type can be numerically iterated between index 1 and the first gap where numeric index has nil value using the ipairs iterator in addition to the non-exclusively-numeric unordered pairs iterator. A common pitfall with sparse tables is that the length shortcut # returns seemingly the wrong result if you aren't aware of that first part.
Most of the difficulty writing in Lua comes from the fact that there's no first class support for OO-style Classes, so you have to fake them, and there's no standard library so you end up reinventing a lot.
But other than that, it's a dead simple language with few features.
Lua's lack of integer support caused me some issues. Using floor() around everything wasn't really an ideal solution and I ended up changing languages for that project.
Metatables are cool, but have some weirdness to them. For OOP i ended up using metatables to make a simple prototype(rather than class) based system, but it was hacky at best.
Tables themselves are pretty awesome and powerful, but I have to admit, working with them gets a bit tiresome in ways working with dedicated arrays and hash maps don't. You have to remember exactly what kind of data is in your tables and looping through them can be a pain.
Overall though, I still love lua, it's the language that helped me 'get' programming and I wouldn't actually appreciate dedicated data structures and typed variables so much if I hadn't had the experience of starting with a more free, loose and simple language like lua. Also, its ability to easily interface with C and be easily embedded has made it appear in so many different and sometimes strange and just downright cool applications.
I've been playing with the solarus engine lately, it uses lua for its scripting, it's the first time I've written any lua in a while, but i've been enjoying it as I rediscover all the little cool things I like about it and i still think it makes a good first or second language for people.
Having the reinvent the wheel isn't necessarily a bad thing when you're learning. That hacky prototype system I made helped me understand OOP far better than just using classes in other languages had. Even if it didn't really work all that well in the end. It really made me appreciate what a built in class system actually gives you.
Integer support was added in Lua 5.3 (released in January 2015). It also added binary operators, rendering the bitop module obsolete.
One thing I never understood is the mania for OO programming---I regularly see people announce Yet Another OO Module for Lua on the mailing list, and I have to ask myself, "Why?" Is OO the only thing taught these days in school? There are other ways of organizing code than OO.
Serious question: How do you organize your data in a semantically meaningful way without something like an object/struct (in a strong type system preferably). I get functional programming and all, but structs just seem like a natural way to organize data.
Structs are a natural way to organize data, but that doesn't necessarily make it "OO". In Lua, a module is typically a table (associative array really) of functions. All of the standard modules that come with Lua are just collections of functions that don't have a concept of "this" (like math or os).
Now, an object in Lua can have functions that assume a "this" parameter (Lua calls it "self") and thus, it can be viewed as an object qua OO, for example, an open file:
file = io.open("foo.txt","r")
file:setvbuf('no') -- no buffering
file:seek('set',10) -- seek to byte 10 in file
data = file:read(8) -- read 8 bytes
file:close() -- close file
but Lua lacks typical OO features like inheritance, a "class" function or method, which are what the OO modules in Lua always add. It's this mentality, that OO is missing if you don't have inheritance.
> Lua can have functions that assume a "this" parameter (Lua calls it "self")
Even Lua's assumed "self" via the thing:funcname(...) call is just a charade and is secretly just thing.funcname(thing, ...). The split between . and : calling, IME as an informal Lua teacher, is confusing to programming newbies when they first encounter it and I kinda wish the language hadn't chosen _that_ as the thing to spend time implementing.
To second the use of structs, mostly this. Typically i use structs for most numeric types or anything that doesn't need a method and classes for any reference type with methods. Though, i'll stick to structs/stack allocated data as much as possible.
I try to make a clear distinction between stack and heap stuff and use one or the other where appropriate.
From lua i moved to D for a lot of my heavier projects. I like the way D separates types and uses appropriate reference and copy semantics. Being able to specifically separate heap and stack data and essentially use structs and classes as either copy or reference data just seems fairly straightforward to me.
A struct is just a bunch of stuff of different types grouped up in memory, while a class is essentially a pointer that can be moved to some places in memory and can point to data or functions, use each appropriately and where necessary.
Object orientation is not really about making use of structs - many (most?) functional languages also use structs; it's just a grouping of related data.
Object-orientation is about grouping together functionality and data. I.e., an object consists of both a struct, and the functions that act on that struct, known as methods.
In OO, your type additionally refers to the functions called on the data, not just on the data. E.g. you might have a car and a boat and they both only have a position and velocity as data, but the boat has a "sink" method the car doesn't.
For games programming in particular, there is a paradigm known as ECS or Entity Component System. (Depending on your view you might call this a sub-paradigm of object orientation, but I think it's much more accurately described as an alternative.) As the Wikipedia article states:
> An entity only consists of an ID and a container of components. The idea is to have no game methods embedded in the entity.
EDIT: There's also the very interesting paradigm that e.g. Julia uses known as "Multiple Dispatch". This is kind of like defining methods on objects, except that the method is defined on a collection of objects instead of a single one.
E.g., in traditional OO, you might have a vehicle#crash method. And it might take another vehicle as argument, e.g. car.crash(truck). But in multiple dispatch you define a function crash that takes in two vehicles, and then depending on the type of the vehicles given, it changes its behaviour so that crash(car, truck) is different from crash(car, car).
In a sense, the function is not thought of as belonging to either the car or the truck, but as belonging to the pair of them, so conceptually this is different to OO.
I'm not particularly familiar with the paradigm so I'm sure I'm not doing it justice, but you can read further on Wikipedia and in the Julia docs, or the given video:
You talking about Solarus Engine rang a bell for me as I wondered if it had anything to do with Zelda Solarus, a fan game I played fifteen years ago and what introduced me to RPG Maker. And it does ! It's really heart warming to see people follow through with their own projects for so long, Thanks for the throwback !
Solarus is such an interesting engine in that it's almost certainly more powerful than Defold, but its focus on making a Zelda-like game engine probably makes it harder for users to see how it can be reused for other works.
Even the OO shortcomings of Lua aren't very different from the Javascript of the recent past. The two languages are quite similar, save that Lua indices are 1-based and JS comparators are nightmare fuel.
My pet peeve is that it's somewhat verbose in using keywords rather than single-character punctuation to mark blocks and clauses.
I will prioritize this immediately. I believe one should be able to understand all of the concepts the engine offers within short order, and clearly I need documentation to back that belief.
Everything is there to get started in just minutes, reducing any installation friction typically found with larger game engines, but I agree that documentation should be able to reduce the cognitive friction such that one can get started faster.
Thank you for pointing this out. If you're so inclined, sample game code comes with the engine for the time being to understand how it works. I realize this isn't completely ideal, but feedback like this is critical to the direction I take.
Regarding Grid, personally I always like to look at example applications built with framework/library/engine so seeing a list of projects that utilize Grid would be nice.
Apparently the developers are reading this thread, so I have a request: Please reduce your website's dependence on javascript. Doesn't leave a great impression when I need to fiddle with noscript before seeing static text.
I would do more of this if I had a simpler way of pulling documentation from the GitHub Wiki repo.
I’m sorry the experience was poor, and I’ll consider this feedback as I make improvements to our documentation and marketing collateral to make it nicer to use. My apologies. I work hard to win over developers, many times one at a time, and so your feedback isn’t lost on me.
1. Embeddability. You can create a game engine in a performant systems language like c++ and embed lua in it for the scripting.
2. Speed. The lua interpreter is much faster than python in general. When you throw luajit into the fix, they are not really comparable at all.
3. simplicity: lua is tiny. and one of the easier languages for non coders (game designers, artists) to get started with.
4. Effortless C interop. You can make lua bindings for anything written in c with minimal effort.
Now to this specific engine. lua has one of the simplest and most beloved game frameworks out there - Love2d. its almost a foundational game framework for so many people (like pygame in python, XNA etc), including yours truly. Its been a beginners choice for over a decade now. Grid is built on top of Love2d.
btw, just in case you are interested in a python game engine, you should try out Arcade. Its pretty feature rich and aimed at beginners.
You could make the same 4 points about Pawn, I don't know why nobody uses it. Pawn has all of lua's strengths without any of its quirks and weaknesses.
The only benchmarks I could find claims that it is significantly slower than Luajit. The official docs claim that the fastest implementation is available on fewer platforms than Luajit.
Regarding the lack of structs, the official docs say "pawn has no "struct"s, but it extends arrays so that it can mimic light-weight structures with arrays; as an example of those extensions, pawn supports array assignment and array indices can be assigned an individual "identify" (or "purpose") and even form a sub-array." but the manual's mentions of array assignment make it seem like that's just memcpy. One could imagine having bullet objects and declaring BULLET_X=0, BULLET_Y=1, BULLET_SPRITE_IDX=2, and so on, just so that when one has a bullet object and they would like to draw it at the right location they could avoid writing draw(b[2], b[0], b[1]). Having an array of untyped cells and memcpy isn't really the same as having a struct with named members. Please correct me if I'm wrong.
A lot of useful patterns become less possible when one does not have a map or set type and when one does not have coroutines. It seems like instead of coroutines Pawn includes a syntactic sugar for a switch statement that depends on a single global state variable, in which the cases can be declared like functions. This is interesting but not particularly helpful. Why can one not have multiple different state machines, multiple instances of a state machine, and so on?
Because Lua is much simpler than Python, but not in a way that makes it less powerful. You can grasp the entirety of Lua in your head, with all its semantics and behaviour, which is less easily done with Python (in my opinion).
LuaJIT is much faster than Python, directly interfaces with C, incredibly small,and the language itself is very simple. This is also built on top of LOVE2D which is written in Lua and is arguably one of the best game frameworks out there.
Seriously asking or just trolling? This statement could be made for almost any language. Why did we start with Python when there was Perl? Why did we start with Perl when we could use shell and awk? Why did we start writing something like awk when we could just have dedicated C programs? Why C when we had BCPL/Algol? Why Algol when we had... okay, granted, there's a limit.
Regarding the specifics: Lua is very simple, you can keep the whole language in your head easily, the table mechanism is very powerful, and the whole thing is easy to embed. Which is why it was used in commercial games and thus is industry/genre-relevant.
Years of being extremely difficult to run on a Mac (no pip install), horrible website update (the old one was bad, but at least it was cool & functional), and on-going issues like this: https://github.com/pygame/pygame/issues/555
There's not even a note on the website that it's entirely broken in Mojave. It's just _always_ something.
Compared to LOVE and numerous other projects which just worked right out of the box. I'm a total Python guy, but Pygame has always been frustrating.
Lua has significantly better performance than Python, but the big reason is that Lua has a very nice C/C++ API that makes it easy to integrate with other programs. Combined with a 20k LoC source code, and you have a programming language that is cheap and easy to embed, fast, and simple. Batteries are not included, so it’s very light weight.
Another reason for using Lua in games is that its garbage collection strategy is well-suited for the task.
Python uses reference counting (which has a predictable performance profile but can lead to long pauses if a large object graph is deallocated at once) and stop-the-world GC for reference cycles.
Have you ever tried to embed a python interpreter?
Lua is both easier to embed and allows you to have a strict interface. Look up the history of bastion/rexec in Python - with python there's no possibility of controlling untrusted code.
I liked the speed and the power of tables. It's also an incredibly simple language. I learned the ins and outs in a couple of days and was able to get right to work on making a game. Almost never did I have to reference documentation after that--it all fit in my head without even really trying to memorize it. Python, on the other hand, has loads of features, but that results in me often looking up the right way to do something since there are so many layers to it. What Lua provides is rather bare, yet powerful and incredibly easy to jump right into.
Much like many people turn to Python for scientific scripting, for example, Lua has gained a reputation for being easy to use in the game development world.
Grid Engine 9 is now the largest pure-Lua game engine on GitHub. As s_y_n_t_a_x has mentioned in this thread, I built the Grid Engine on top of LÖVE.
I came from the hlcoders world, having used the Source Engine for several years, and was upset the 2D world didn't have sophisticated game engine technology like the 3D solutions in the field.
There's tons of great game software out there! But to me, a game engine isn't just a load, update, draw framework. There's a lot of hard work involved past binding libraries together.
A game engine needs an architecture, it needs to do multiplayer serialization for you, and give you a meaningful way to load maps out-of-the-box, and so much more.
Too many hobbyists are rolling this themselves, and I hope to continue to bring rich game development features OOTB to other hobbyists like myself.
If you're interested in Grid, but don't find something quite right with it, could you tell me? I've worked on this project for at least the past 6 years from what my logs tell me, but it only continues to get better thanks to people like you all reading posts like this and giving me feedback over the years.
Thanks again, Andrew