Pages: « 1 2
  Print  
Author Topic: ENIGMA Entity-Component-System?  (Read 6727 times)
Offline (Male) Josh @ Dreamland
Reply #15 Posted on: November 03, 2013, 09:35:06 PM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

View Profile Email
Yes, where M is a small constant. Using a bit set, it drops to O(N × M/64) = O(N × M), assuming you can compact all the combinations together in one word. I'm not fundamentally opposed to a bitset, but I don't particularly care for RTTI.

Using queues trades checks for memory. Instead of iterating the smallest queue of objects and checking that (A) all component bits are set or (B) the entity is in all the correct queues, we just iterate the queue with the correct combination. This is good when the number of components needed in a single combination is large, but the number of necessary unique combinations is small.

In the general case, it's terrible, as the number of combinations grows exponentially in the number of behaviors. You'd want to use queues when you need to iterate all tanks which use tank logic and have tank physics and a position, and all ninjas which use ninja logic and have ninja physics and a position, but no other combinations. In this case, you'd have as many as four checks depending on which bits were assigned to which component, but you'd only need two additional queues to which such tanks and ninjas could add themselves, thus saving all checks and iterating in O(N), N being the number of matches.

Again, these queues are only possible when this information is known at compile time. It's fine if the tank and ninja objects can remove these behaviors at runtime, as long as we can create the checks to manage those queues when this happens at compile time.

Knowing combinations at compile time helps in the completely dynamic case, too, as it enables you to reduce the number of checks to O(N × M/64), where M is the number of behaviors in your combination instead of the total number of behaviors.
« Last Edit: November 03, 2013, 09:41:35 PM by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) Ideka
Reply #16 Posted on: November 05, 2013, 06:03:44 PM

Member
Joined: Apr 2011
Posts: 85

View Profile
How is M a small constant? It depends on how many components each system needs (if anything, the maximum possible M is a constant).
Also how does it drop to O(N * M) using a bitset? Wouldn't the check just be be entity.components | system.required_components, O(1)?
Logged
Offline (Male) Josh @ Dreamland
Reply #17 Posted on: November 06, 2013, 07:48:35 PM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

View Profile Email
In a dynamic bitset, entity.components | system.required_components is O(N). One OR for each 64 bits. So only one OR is required if you have less than 65 components.

Typically the number of components you need in a combination will be small. If not, you might want to rethink how you're developing your system. A function depending directly on some thirty classes isn't very attractive, to say the least.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) Ideka
Reply #18 Posted on: November 29, 2013, 12:44:45 AM

Member
Joined: Apr 2011
Posts: 85

View Profile
I don't know, one OR for each 64 bits sounds good to me.

By the way what did you mean by this?
The point was that his system is no more of a revolution to me than Java people constantly spouting if (entity instanceof SomeComponent) or C# people doing the same with if (entity is SomeComponent). I get that you're attached to this idea; I don't get why you don't see the remarkable similarities between it and multiple inheritance. You're looking at the small picture of what it allows; the big picture is this:

Code: [Select]
Operation X
  Subtype A
  ---Operation 1
  ---Operation 2
  ---Operation 3
  Subtype B
  ---Operation 1
  ---Operation 2
  ---Operation 3
  Subtype C
  ---Operation 1
  ---Operation 2
  ---Operation 3
Operation Y
  Subtype A, as well
  Subtype D
  ---Operation 1
  ---Operation 2
  ---Operation 3
Operation Z
  Subtype B, as well
  Subtype E
  ---Operation 1
  ---Operation 2
  ---Operation 3
  Subtype F
  ---Operation 1
  ---Operation 2
  ---Operation 3
I didn't get what you meant at the time and forgot to ask.
Logged
Offline (Male) Josh @ Dreamland
Reply #19 Posted on: November 29, 2013, 10:35:17 AM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

View Profile Email
I was pointing out that using multiple inheritance does not stop you from constructing methods that work with instances of each "component" class. You were showing that inheritance is not what you want by pointing out that class have functions instead of functions working with classes. It works either way. Java functions take advantage of functions requiring some interface all the time, and it doesn't matter what you hand the function as long as it implements that interface. Yes, an interface will have functions, but that doesn't mean it can't work like the component system.

In other words, while it's more correct to put the doTankAI method in the tank interface, there's nothing stopping you from putting it in a non-member function, which is necessary if you want a doNinjaTankAI method.

So in that outline, Operation Y might be doNinjaTankAI, Subtype A might be Tank, Subtype D might be Ninja, and their operations 1-3 might be getTankHealth, getNinjaHealth, fireCannon, throwStars, whatever.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) Ideka
Reply #20 Posted on: December 01, 2013, 01:46:07 AM

Member
Joined: Apr 2011
Posts: 85

View Profile
Oh, yeah, I knew that.
What I was pointing out was the fact that each operation runs looped in an ECS.
i.e., instead of
Code: [Select]
foreach (entity in entities) {
    entity.run_operations();
}
it's:
Code: [Select]
foreach (operation in operations) {
    operation.process_entities();
}
Logged
Offline (Male) Josh @ Dreamland
Reply #21 Posted on: December 12, 2013, 11:00:46 AM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2956

View Profile Email
That doesn't really concern ENIGMA's implementation, as the expectation would be that ENIGMA handles it for you.

I'll point out that ENIGMA's event system, which is not component-based, functions the same way.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Pages: « 1 2
  Print