Component Entity Design

Started by
11 comments, last by Hodgman 5 years, 4 months ago

Hello, 

Im new here but am finally trying to switch from Inheritance Based Game design to Component/Entity System Design. 

Im starting off with a simple Checkers game and can't seem to figure out how to design this game.

I know I have the Board and Checker Pieces for the Entities. I know I'll need a Visual Component, Move Component and an AI Component. Is this right?

Im not sure how to layout this type of game. I don't know if the Board should be an entity or not. Im not sure where the drawing of the board should be taking place and where the majority of the game logic would go.

In case it matters, Im programming in Swift.

 

Thank you in Advance for all your help.

 

Advertisement
1 hour ago, Airtower said:

...Im programming...

Moving this to an appropriate forum.

-- Tom Sloper -- sloperama.com

1 hour ago, Airtower said:

Im new here but am finally trying to switch from Inheritance Based Game design to Component/Entity System Design.

If you've got an existing inheritance based design, start by replacing all of your is-a relationships with has-a relationships.
e.g. instead of Monster is a Sprite, use Monster has a Sprite.

IMHO, it's worth studying some basic OOP design theory as it's supposed to answer these questions. Building software out of components isn't new - the composite reuse principle was coined in the early 90's to warn people off of an over-use of inheritance ?

I see.

Yea, I know it isn't new but it is something Ive just recently decided to change my thinking when approaching design.

Thank you for your help and hopefully this will help enough to get me going.

 

Ok, 

Ive been reading more articles on Composite Reuse Principles and still can't come to a solution. I don't have a checkers game to change from OOP to Composite Reuse design. I am only doing this to learn how to use this (new to me) design pattern. 

Mainly, I am having problems with the Board Entity. Here is my setup...

I have 2 entities, a GameBoard and a Checker. 

I have 3 Components, Sprite(visual), MoveCompont and the Artificial Intelligence Component. 

All 3 components connect to the Checker piece but I can't determine how to fit the GameBoard into this design. I know it should draw the board on the screen, keep track of each square but I can't figure out if I should have a manager to keep track of all of the pieces and check the logic to allow a move or check for wins and so on.

 

Thank you

There's probably no one right answer here, but my initial thought is that a 'piece' entity is the wrong place for a 'movement' or 'AI' component (with the possible exception of a 'movement' component that handles cosmetic animation effects).

I think for something like checkers, things like AI and movement - in fact perhaps all game logic - might better be made the responsibility of a single module that has a "bird's-eye" view of the game. Individual pieces don't have this bird's-eye view (conceptually speaking), and so are probably not the best place for this functionality.

Here's an idea of how you might arrange this in an entity-component system (I'll stick with a strict entity-component description here, since that's what you're using, although other terminology or levels of granularity can be used as well):

- A 'game logic' component (and associated container entity) that does the bulk of the work (AI, movement, etc.). This would include a grid representation of the board (separate from any world-space visual representation) that's used to track game state.

- A 'board' entity. Just a visual element with no behavior.

- The 'piece' entities. These would also just be visual elements, more or less. The 'game logic' component would have access to the transforms of these entities in order to move them. (Animated movement could also be handled by a per-piece component, as mentioned earlier.)

Rendering can be handled in different ways, but a simple approach is to have 'renderable' components (these would likely be the 'Sprite' components in your system), and (one way or another) to iterate over these and render them individually each frame. Here, the 'board' and 'piece' entities would each have a renderable component. (Note that this is just one, fairly simple approach, and that pursuit of things like elegance and efficiency could take you in other directions. But for many games I think this simple approach should be sufficient.)

I think you hit on some of these ideas in your post, but maybe the above suggestions will help clarify things a bit.

Note that these are just my thoughts on the matter (others might recommend something completely different).

4 hours ago, Zakwayda said:

- A 'game logic' component (and associated container entity) that does the bulk of the work (AI, movement, etc.). This would include a grid representation of the board (separate from any world-space visual representation) that's used to track game state.

I don't think you need an entity for the game logic. Also, game logic doesn't have to be a component. You can put the game logic into main(). Process the input, update the placement of units according to game rules, and then render them at their positions.

 

Also, a bit of a rant and personal opinion here, i think ECS is overkill for something like a checkers game. The ECS style architecture would be better suited when you have so many entities it becomes unwieldy to handle each of their behaviours individually (because you either duplicate a lot of code, or make large inheritance hierarchies where you can't reason about the code quickly anymore), so you split them into a smaller subset of pieces which you can easily [reason about it's] process/update, and compose the higher concept entities from those pieces, relying on standardized piece-wise functionality. And you can even continue the process further, and split any of those pieces (L1 pieces?) into another subset of pieces (L2 pieces) with their own update procedures, in order to compose the higher level piece, out of which you compose the entities. This is what you'd be doing anyway when you're coding for the first time, or not following ECS rules: embedding structs into structs into structs until you have a good data organization scheme that you can easily follow.

Anyway, to follow the thread question, what i would do is something like the following (pseudo code):


EMPTY = 0
RED = 1
BLACK = 2
board {
  Tiles[8][8] = {EMPTY}
  sprite BoardSprite
  sprite RedPiece
  sprite BlackPiece
}

int main() {
	// .. initialization of the window, device, state, whatever
    board Board
    GameRunning = true
    while(GameRunning) {
    	Input = grabInput(InputDevice)
        GameRunning = gameLogic(Input, Board)
        render(GraphicDevice, Board)
    }
}

"grabInput" returns a struct with the inputs you want to handle (either raw device input you're interested in, or remapped logical commands, whatever suits your needs or framework).

"gameLogic" receives the board and the input, and internally, checks if it's the red or black player turn, and either processes the user input into board actions, or lets the AI produce board actions, then executes the generated board actions for the active player (which at this point, the logic doesn't care if they were produced by the user or AI, you could use this to pit two AIs against each other).

"render" just draw the board and the pieces, taking the visuals from the board.

Since this is a very simple game, an ECS (as i said above) is overkill and too rigid in it's traditional definition. Chess expanded to 4 times the board size and piece count, with several new piece types, and done in real time, could maybe be a better candidate :P

devstropo.blogspot.com - Random stuff about my gamedev hobby

Quote

I don't think you need an entity for the game logic. Also, game logic doesn't have to be a component. You can put the game logic into main(). Process the input, update the placement of units according to game rules, and then render them at their positions.

My answer was offered in the context of a strict entity-component system where all behavior is implemented in terms of components contained in entities (this seems to be what the OP is doing, and I think Unity's system works that way as well, although I may be wrong about that). Obviously nothing 'needs' to be an entity or component, but I think it's fairly common in such systems to implement all behavior via components.

One argument for doing it this way is that a component system will likely already have all the needed architecture in place for updating, logic, and so forth. For example, there will likely already be a main loop implemented somewhere, with all behavioral components iterated over and given an opportunity to do their work. Behavioral components may also have environmental information (like time deltas and input events) passed in to the update function (although this of course can be handled in other ways).

My thinking is, as long as you have such architecture in place, why duplicate it by placing game logic somewhere else, such as in main()? Implementing the game logic as a component seems more sensible to me.

Of course there's the question of whether to use an entity-component system at all. Regarding that:

Quote

Also, a bit of a rant and personal opinion here, i think ECS is overkill for something like a checkers game.

I agree, more or less, but the OP specifically said:

Quote

I am only doing this to learn how to use this (new to me) design pattern.

Personally, I don't think there's anything wrong with using a relatively simple project as an opportunity to familiarize oneself with a specific design pattern, even if, strictly speaking, that pattern may be unnecessarily complex for the use case in question.

28 minutes ago, Zakwayda said:

I agree, more or less, but the OP specifically said:

Quote

I am only doing this to learn how to use this (new to me) design pattern.

Personally, I don't think there's anything wrong with using a relatively simple project as an opportunity to familiarize oneself with a specific design pattern, even if, strictly speaking, that pattern may be unnecessarily complex for the use case in question.

Using a design pattern as an exercise is the worst way to learn about it: it's guaranteed that one will misapply the pattern, deform it into something trivial and/or abnormal, damage the overall quality of the software with inappropriate (maybe knowingly inappropriate) design decisions, and fail to understand how and why it is useful (because in that context it isn't useful).

I strongly suggest finding issues of any kind with iteration N-1 of the checkers game (redundant and convoluted code, pointless complications, lack of needed flexibility, hacky special cases, unnatural names, inefficiencies...) and trying to do something different and better in iteration N.

Predicting what kind and what degree of Component-Entity orientation is best is a fool's errand; even Hodgman's wise recommendation to replace inheritance with ownership (and delegation) can have exceptions and should be regarded as a test to think about (would these specific classes be improved?).

Omae Wa Mou Shindeiru

Quote

Using a design pattern as an exercise is the worst way to learn about it: it's guaranteed that one will misapply the pattern, deform it into something trivial and/or abnormal, damage the overall quality of the software with inappropriate (maybe knowingly inappropriate) design decisions, and fail to understand how and why it is useful (because in that context it isn't useful).

If that's the case, then I suppose the OP's aim is misguided to begin with and a different strategy should be preferred. I was just responding to the question as stated, but I'm happy to defer to your view that the endeavor is ill-advised (I don't have strong feelings about it myself).

This topic is closed to new replies.

Advertisement