Please don't put ECS into your game engine

I can't think of any reason whatsoever why GoL would have to be this complicated, or why you'd need more than one behavior at all. (Maybe if you wanted to do some kind of extremely fancy animation...?)

I imagine if you think about it for a while, you could figure out how to do it a lot more simply... :slight_smile:

I did not meant to say that ECS needs a substitute or an alternative. I definitely agree completely that ECS, as it stands, has, at the moment, no alternative.

What I'm saying all along, in one way or another, is that making ECS the root of all state management makes development awkward and uncomfortable. Things that should, at least semantically, be structurally overarching the rest of the game, end up being in the scene embodied by components on some entity and the usual unity ad-hoc bingo begins.

And I'm definitely not asking everyone to stop putting ECSs into their engine (pardon the provocative title).

My request (actually a plea) is just about letting users manage their own state. Then users would be able to make exactly what they need. And if they need an ECS -- they would embed it into their state.

That, of course, implies that engine should then be able to work without ECS. But the engine already does that (correct me if I'm wrong), the API is just not exposed.

It depends on how the engine is designed. In a 2D engine, for example, it's possible that the rendering engine is relying on the entity system to do efficient culling and iteration of the sprites that are visible in the current camera view: You don't want to be translating data from one form to another in time-sensitive code like the graphics pipeline.

That certainly doesn't preclude a game from using its own state management and treating the ECS as part of the graphics API.

That is true.

But I would like to note, however, that if user doesn't use ECS, then one is probably not on the hunt for performance in general. Or, at least, not at that exact moment.

But if engine requires use of ECS (and, suppose, the state is not ECS-friendly), then rebuilding the entire ECS-dataset is the easiest solution. And if engine doesn't allow for that (or if we're avoiding that), then there are two options left -- either update stale entities "by had", which is really ad-hoc-y and error-prone (in my experience), or do something akin to VirtualDOM, which could be even more error-prone, will definitely be more ad-hoc-y (because entities are typed structs and not heterogeneous data-structures), will definitely be, performance-wise, even worse than rebuilding.

If engine could expose some more primitive APIs (that could as well be used internally by ECS-aware render, sound-engine, etc) that would, hypothetically, be a win for everyone.

Somewhat off topic, but I remember John Carmack mentioning an interesting purely functional architecture to solve this problem, which I don't think I saw implemented in Rust (but not that I keep a close eye on this).

Basically, we write update as State -> Input -> State. Then, we arrange memory such that State is just a single contiguous chunk of bytes. Then we re-use the State's memory between updates. In a sense, we've just implement a semi-space garbage collector which, on every frame, copies live objects from old half of the heap to the new half of the heap, with a slight tweak that objects are updated according to the game rules during evacuation.

2 Likes

As a game developer with over 25 years of experience, let me assure you that Entity Component Systems exist and are popular for good reasons. Performance is one key benefit, but also an ECS achieves a kind of data normalization similar to SQL databases. This relational model affords flexibility that is difficult to maintain in OO systems.

I'd take a Rust ECS over a Love2D engine any day. With the freedom and speed of unopinionated Lua development, most developers (self included) will quickly paint themselves into a corner. Change will become difficult because the engine does exactly what you tell it to do, and you will contradict yourself as requirements and implementations change. The ECS will, of course, do what you tell it to do also -- but it will do so in a manner that is structurally consistent. Your way of telling it what to do is far more organized than evolved imperative code. This gives you greater control, makes change easier and more predictable.

Don't worry about Conway's Game of Life. It doesn't discourage ECS any more than it discourages a class hierarchy. Think clearly about what the evolution of state actually involves: a previous state, an action, and a new state. If you've seen implementations that make use of already-updated state as if it were previous-state, then those were simply naΓ―ve implementations. You can easily achieve correct updates by flip-flopping between two full states, but in some cases like Life where change depends only on local previous state, you can fill and use a small cache as you go along, using only a margin more than one full state.

7 Likes

As I have said

The issue I am talking about is just that

And my proposal does not actually goes against ECS in any way (or at least I don't see how it could)

There are just too many advantages not to choose a ECS to be one of the main components of a fully fladged new game engine aimed at building (up to) complex and very features rich games. And these advantages, as @voidshine and others already mentioned, go from performance to the fact that a data oriented architecture also helps with how games are usually structured, as well as keeping your dependency graph simpler.

On the other hand, I also think that the vast majority of games out there (which are not AAA) do not exactly need the complexity that comes with ECS (be aware that other complexities exists without), and they do not need the performance that is achievable with ECS.

There are alternatives, there are other simpler engines that have analogies but may be restricted to smaller problem set (shameless plug https://gliderkite.github.io/posts/semeion), but in the end ECS is just another tool that may fit very well some architecture or just be overkill.

Yeah ECS is great but when you have to make an entity to hold global game state (like score, etc) -- that, to me, seems awfully repulsive. As if people building engines refuse to acknowledge existence of things other than primary game loop. All the Rust game engines that currently exist (that I am aware of, that aren't piston, that aren't a tiny project) basically unsuited to build anything except single game loop.

Scale and performance?
Sure, they provide, they deliver.

Nested game loops?
You're on your own with fragile stateful scaffolding of ad-hoc entities.

What's a nested game loop

1 Like

It, due to state of affairs, is a purely semantical thing (although there's coroutines in Unity, that do something akin to that).

Allow me to introduce an example.

Competitive game of Counter Strike could be described as multiple nested game loops.

  • Wait for players to connect for 5 minutes + 1 minute warmup
    • Action
  • Rounds repeat until one team wins 16 rounds or total of 30 rounds is played
    • Action
  • Final Screen

So that we could, hypothetically, model the game as a nested series of loops

while (session) {
    while (wait_or_warmup) {
        action(); // with all the actual ECS business
    }
    while(repeat_rounds) {
        reset();
        while (round) {
            action(); // with all the actual ECS business
        }
    }
    final_screen();
}

Or, as a state machine, which would be more suited for Rust (because Rust does not have coroutines).

Ah I see, in my opinion that kind of thing would best solved outside of the ECS. When I saw Amethyst's state stack architecture I thought it looked like a nice way of handling it :slight_smile:

(not that this conversation has anything to do with amethyst, just that amethyst was where I first saw the idea)

I'm glad you brought up Amethyst. I was looking at it myself just today.

That would be State Manager, right? That's a good example of how an engine could have something other than ECS at the base of it's state management.

Although I would prefer if it let me fill that space with my own logic, that is still at least a single a step in the right direction.

What is stopping you? Amethyst's state stack is like a page of trivial code, and you could probably replace it with whatever you like in an evening.

Have you ever written a game using an ECS? Judging by the things you're saying about it in this thread, you're punching at ghosts. They don't have the problems you say they have, and they're not even used in the way you seem to be assuming they're being used. ECSs hold entities and process them. That's all they do. They don't hold all game state. They're just a database of game objects. An ECS isn't a game engine, it is just a small part of one. Any part of your game that you don't want in an ECS can be placed outside of the ECS. An ECS does not constrain the design of your game in any fashion.

You may as well be arguing that webservers shouldn't use RDBMs just because they're not conducive to handling user input and displaying content. An ECS is not a game engine. It's not even an architecture for a game engine. It's just a way of pooling and accessing resources.

4 Likes

Huge pile of dependent code with all the borrowed references and trait bounds (and most of those traits are private).

I am not talking about ECS, I am talking about game engines.

I am not assuming, this is actually the way they are being used, I've seen it many times.

Even the Amethyst's pong tutorial stores scores on the actual scoreboard entity. Because there is no better option, it seems, because they made ECS, and made it mandatory.

ECS does not, the game engine could, however. The best option I see, with, say, Bevy or Amethyst, is using global lazy-static variable. Could be better.

It's a TUTORIAL. It's not an example of how to design a game, it's an example of how to use the APIs. You are not required to do what it does. There are better options, but pointing them out in a tutorial is not conducive to making a concise and informative tutorial.

The basis of a good argument is establishing credibility and presenting compelling arguments. All you're presenting here is "I personally can't do it right" and "trust me." You can do better than that. For starters, show the code you've written. Link to the code that you're seeing problems in. Show me how your conclusions are necessitated by a specific design. (I personally have made games in Amethyst, and I know for a fact that you do not need to put scores in the ECS as entities. There's nothing you can say to convince me otherwise. Do you see why this is? What is your problem with resources?)

Because my experiences are completely contradictory to yours, and there's no point in playing "he said she said" by comparing opinions about unobserved data.

1 Like

[Moderator note: Please tone it down a bit, folks.]

6 Likes

The resources are nice and I like that they're there. It even states it in the Amethyst book, even about "score of a pong" specifically (sorry, I missed that).

The issue for me is, though, that it's hard to make hierarchical structures out of just flat sets of components and systems (take, for instance, my example of nested game loops). That whole deal is, essentially, procedural programming with a lot of global variables, except order in which procedures are called is not guaranteed. As a result, as it seems to me, a fragile stateful system appears, with a lot of, as Rich Hickey put it, "I will put the acorn behind this tree, and you come by later and find it behind the tree" logc.

Though it's not a game engine, I've been working on the cala crate which can be used to make 2D and 3D video games, as well as GUI applications. It's not complete by any means, since graphics currently only work on Linux (other features are cross-platform). Maybe it'd work for you? If you do try it, I'd like feedback. There's no ECS involved in it, but rather shared and private contexts for asynchronous tasks (similar to the design of the Tide webserver). I eventually plan to build a game engine depending it (which will mostly be physics functions).

This is almost certainly not intended to be implemented with multiple isolated event loops. And if it was actually done this way in CS, they probably had a bad reason, like cutting corners to meet some arbitrary deadline? These states are actually handled by a ...

You said it yourself. You're not confusing ECS for FSM, but I still can't figure out why you're do hung up on a crusade against ECS? The irony that ECS manages game state and state machines manage state transitions is not lost on me, but these are also very distinct responsibilities, so there should be little confusion with that as well.

This is that confusion showing up. Nothing intrinsically prevents you from structuring your game state with a hierarchy. The ECS may query a flat list of entities, but this can also be seen as a flat list of root nodes. If you want to make state transitions like main menu -> play a match -> results screen, you don't do that in ECS.

3 Likes