What is the difference between "Entity" and "Sprite"?

Started by
21 comments, last by Daaark 11 years, 2 months ago

If you are writing a simple game, they might not know about each other at all. Your rendering code will just loop through the list of things you want to draw, and hardcode everything.

Yes I'm writing a simple game: on the one hand, I have an entity (i.e. a spaceship) in which I've already coded all it logic (moving forward, backward, rotating to a direction). By the other hand, I have a spaceship sprite which contains a 2D image and a render function.

I could have in a Game class a list of sprites where each one of those has a relation with a entity. So, when I want to update the screen, I would do the following:


def updateScreen(game, screen):
  for sprite in game.sprites:
    sprite.render(screen)

But, what if I wanted to update the game state?


def updateState(game):
  for sprite in game.sprites:
    sprite.entity.update() #Something like this could be fine?

Or would be better to mantain two lists (sprites, entities) and manage them separatly?

Thanks

Advertisement

As we see, the general consensus is that an entity represents a distinct thing or actor in the game, and sprite represents its graphical representation -- but, every engine is different and you can split hairs 6 ways from Sunday.

The important thing is that your design is functionally decomposed -- that's just another way of saying, "uphold the single responsibility principle". At some level you have a thing that participates in the world in some way, and that thing may or may not have a visual component. At another level, you have a graphical representation, or appearance, which could be a 2-D image or a 3-D model, which is used to represent certain things within the game visually. Usually, many things might share this appearance, so its more optimal for visually similar things to share a single appearance, than for every thing to have its own, distinct appearance. If animation is involved, then the appearance will often know that it supports animation, and the animation state for each thing is stored separately, either as part of the thing, or in an object dedicated to storing animation state, which is referenced by each thing.

This separation, of thing and appearance, with animation somewhere in between, usually suffices for simple graphics. But you can introduce additional variables to affect the basic appearance in subtle ways -- for example, a variable might control whether a particular enemy slime is green, blue, or red, without having a wholly different appearance object than other slimes of different colors. In that case, this color variable would, like animation state, either be part of thing, or in an object that thing references.

I've used thing, and appearance here to sidestep any preconception about what these terms mean, but for my money they're synonymous with entity and sprite (or model, for 3-D). You should use names that make sense, but at the end of the day its the organization of and relationships between objects that make things "right" or not. Concern yourself first with a structure that makes sense and is properly decoupled. In isolation, having the right names on the wrong solutions won't make your code any more usable.

throw table_exception("(? ???)? ? ???");

It's also worth mentioning that component-based design largely sidesteps the subtle hair-splitting that occurs around wishy-washy notions like entities (and their properties like sprites) in all their permutations. Its more complicated to get running, but its very flexible thereafter. Component-based design essentially does away with such hair-splitting by accepting and embracing it as a natural consequence of trying to put so many slightly different things in a single bucket.

throw table_exception("(? ???)? ? ???");


I'll go back to the pong example here.

The GAME code doesn't need to know anything about the graphical side. While it's very important that game be DESIGNED with all subsystems in mind, working in harmony, the actual coded sub-systems don't need to know or care about each other most of the time.

The paddle entities move back and forth either on player input, or a AI tick. The ball entity will move according to it's velocity, and will check other entities for collision. It doesn't need to know or care about resolutions, or sprites, or anything else.

The renderer will take the current state of the game and create an image that represents it. It will loop through the entities and render the proper sprite at the proper position for each one. The sprites don't need to know about anything except maybe how many unique objects are referencing them.

You can even replace the 2D renderer with a 3D one, and the gamestate and it's entities don't have to know, or even change, because of their single responsibility (as Ravyne puts it).

The renderer will take the current state of the game and create an image that represents it. It will loop through the entities and render the proper sprite at the proper position for each one. The sprites don't need to know about anything except maybe how many unique objects are referencing them.

You can even replace the 2D renderer with a 3D one, and the gamestate and it's entities don't have to know, or even change, because of their single responsibility (as Ravyne puts it).

Great. You're suggesting that a GAME hasn't any reference to render code; instead, it might have a renderer subsystem that cares about it (which could be 2D or 3D, it won't affect the game logic). But then, how can I know how a entity could be rendered (or how can i bind it a sprite ) without have any "graphic" information on it?

Newly thanks to all

Typically, there's some kind of abstract (by which I mean the general meaning of, not 'abstract' in the C++ sense) 'marker' which is system-neutral.

An object has some marker which says its a ball, or a paddle, or a zombie, or whatever, and so the game logic looks at it and makes it behave like a ball and, independently, the renderer looks at the same object and makes it look like a ball. The game logic has some mechanism for updating all the stuff it needs to update, and the renderer likewise has some mechanism for looping over all the stuff it needs to draw -- this might be a scene graph, or some list of entities that need to be drawn, often involving the visitor pattern. But the key point here is that, as far as the game logic is concerned, a ball only has to behave like a ball--it couldn't care less what a ball looks like--and likewise, the renderer only needs enough information to draw the ball--it couldn't care less about the direction, mass, or velocity of the ball, or whether its controlled by a human or AI player.

Note that this doesn't mean that the two systems don't have to agree for best results. Your pong game is going to behave rather oddly if the game logic thinks that the ball has radius 5, but the renderer draws it as if it has radius 7. So, at some point, usually either by convention or at construction, these systems come to agree on certain properties of the object, but the game logic never *directly* influences the renderer, nor vice versa.

throw table_exception("(? ???)? ? ???");

By the way, all this talk about component-based systems and having game logic and graphics rendering so completely decoupled is sort of the "industrial strength" solutions.

Are these solutions better practice than less-general, more-coupled code? Absolutely. But it's also not strictly necessary for lighter-weight situations. It really comes down to whether the weight of your needs is sufficient to pay the cost of admission for decreased coupling. It's also a spectrum of solutions -- I'd still keep a separation between thing, animation, and appearance, in all cases, but would I go full-bore, mega-scene-graph, abstract-renderer for Pong, or Tetris? Probably not, unless there were real plans to support multiple ways of viewing the game.

throw table_exception("(? ???)? ? ???");

Great. You're suggesting that a GAME hasn't any reference to render code; instead, it might have a renderer subsystem that cares about it (which could be 2D or 3D, it won't affect the game logic). But then, how can I know how a entity could be rendered (or how can i bind it a sprite ) without have any "graphic" information on it?

Newly thanks to all

Beginners tend to mix all their game logic, rendering code, and input into one big mess.

A Game of course will have references to everything. But every component that a game is made up of only needs to know about itself. This is no different than a real machine.

I just made a cup of coffee in a single cup coffee maker. It is composed of a few subsystems that don't know about each other, but work together to solve the problem.

When I turn the unit on the main part asks the water tank if there is enough water. If it says yes, it turns on the heater for about 30 seconds. Then it says 'ready'.

This means I put my cup on the tray, and a coffee cartridge in the holder and close it. Then I press one of the brew buttons.

The machine sucks the water out of the tube and sends it to a little heater. Then it shoots it through the cartridge and out a hole. Then that drop of coffee lands in my cup.

All those little components do their job independently and don't know about each other. The tank heats on command and reports water level. The tube moves the water from point A to B. And finally the little nozzle thing heats that one drop to boiling point and shoots it through the cartridge and out of the machine.

The machine doesn't even know if there is a cup on the tray, or a cartridge in the slot! That's out of it's scope of responsibility. Just like any component in the machine, that's my single area of responsibility in the equation.

So, you can combine several types of things into a higher level thing.

class GameObject
{
Entity entity;
Sprite* sprite;
WhateverElse we;
}

Also, another example would be a resource loader. It just passes pointers to loaded objects, and doesn't know anything else about them.

When you create a gameobject you need to assign a sprite. You get it from the resource loader.

GameObject Paddle1;
Paddle1.sprite = ReourceLoader.GetSprite(".../Paddle.dds");

The GetSprite() will scan over it's list of loaded assets. If it finds ".../Paddle.dds" has already been loaded, it will simply return a pointer to it, and add 1 to the reference count. If it's not loaded, it will load the image, add it to the list of loaded images, add 1 to the reference count, and then return the pointer.

When you are done with your objects, you call ResourceLoader.KillSprite(".../Paddle.dds"), and that will simply decrease the reference count on ".../Paddle.dds". If the reference count reaches 0, it will be deleted from memory (or marked as free so another can be loaded on top of it).

The ResourceLoader knows nothing about the game or anything else outside of it's realm of responsibility. It just counts, loads, and passes out pointers to loaded assets on request.

So, you can combine several types of things into a higher level thing.

class GameObject
{
Entity entity;
Sprite* sprite;
WhateverElse we;
}

OK, and who is responsible of listening events? A game object? Or an entity? Thanks
The game logic will update all the data on the GameObject.Entity objects, and then the renderer will loop through those GameObject.Entity objects to use their positions and sizes, and it will draw them using the GameObject.Sprite data they are pointing to.

This topic is closed to new replies.

Advertisement