1
\$\begingroup\$

I'm writing sort of a 2D game engine for making the process of creating games easier. It has two classes, Actor and Sprite. Actor is used for interactive elements (the player, enemies, bullets, a menu, an invisible instance that controls score, etc) and Sprite is used for animated (or not) images with transparency (or not).

The actor may have an assigned sprite that represents it on the screen, which may change during the game. E.g. in a top-down action game you may have an actor with a sprite of a little guy that changes when attacking, walking, and facing different directions, etc.

Currently the actor has x and y properties (its coordinates in the screen), while the sprite has an index property (the number of the frame currently being shown by the sprite).
Since the sprite doesn't know which actor it belongs to (or if it belongs to an actor at all), the actor must pass its x and y coordinates when drawing the sprite.
Also, since a actors may reset its sprite each frame (and usually do), the sprite's index property must be passed from the old to the new sprite like so (pseudocode):

function change_sprite(new_sprite)
    old_index = my.sprite.index
    my.sprite = new_sprite()
    my.sprite.index = old_index % my.sprite.frames
end

I always thought this was kind of cumbersome, but it never was a big problem.

Now I decided to add support for more properties. Namely a property to draw the sprite rotated, a property to draw it flipped, it a property draw it stretched, etc. These should probably belong to the sprite and not the actor, but if they do, the actor would have to pass them from the old to the new sprite each time it changes... On the other hand, if they belonged to the actor, the actor would have to pass each property to the sprite when drawing it (since the sprite doesn't know which actor it belongs to, and it shouldn't, since sprites aren't just meant to be used by actors, really). Another option I thought of would be having an extra class that owns all these properties (plus index, x and y) and links an actor with a sprite, but that doesn't come without drawbacks.

So, what should I do with all these properties?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ A small addition to some excellent answers below: I'd consider separating the drawing of sprites from the Sprite class. Then, Sprite becomes just a container/manager of the current frame, and a separate Renderer would be responsible for drawing. \$\endgroup\$
    – Torious
    Oct 29, 2012 at 0:47
  • \$\begingroup\$ @Torious Hmm... currently a Sprite is, in essence, just a bunch of Images. Sprite.draw just calls the draw method of the image currently being shown in the animation (as determined by index). Is that what you mean? \$\endgroup\$ Oct 30, 2012 at 0:43

4 Answers 4

1
\$\begingroup\$

A common way to deal with the problem you're describing is to do this:

class Transform
{
   public int x;
   public int y;
   public float rotation;
}
class Actor
{
   public Sprite s;
   public Transform t;
}
class Sprite
{
   public Transform t;
}

Now your data is encapsulated in one class ref'd by both Actor and Sprite. As for that separation, yes I think that's a good idea as the actor is essentially game logic, and the sprite is a view -- they are in this sense completely decoupled for cleaner code.

So you can take that as a more general, "yes" to your final suggestion. Push things out into intermediary classes where appropriate.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ That circular reference is undesirable. The asker specified, correctly, that the sprite should not know about the actor. The sprite is a lower level rendering utility, and should not have a reference to a higher level complex game object. \$\endgroup\$ Oct 29, 2012 at 0:16
  • \$\begingroup\$ @ktodisco True, that was just carelessness. Removed. \$\endgroup\$
    – Engineer
    Oct 29, 2012 at 8:44
  • \$\begingroup\$ Guess I'm gonna go with this. For now, at least. A big thanks to everyone who tried to help! \$\endgroup\$ Nov 1, 2012 at 1:26
2
\$\begingroup\$

Each object should own its own properties. If other objects need to know those properties, let them query for them.

Your sprites probably don't have an intrinsic position, and they don't know how to get a position to be rendered because they may have to get that information from more than just Actors. So, you need a class that mediates between them. You might have an ActorView that holds a reference to the Actor and contains an instance of Sprite. When the Actor moves, ActorView is notified, and knows where to draw the sprite. The ActorView could also hold the current frame of animation, etc.

\$\endgroup\$
1
\$\begingroup\$

Classes and objects are just bundled functionality, nothing more. And that way you should work with them.
Ideally you should build your classes around composition. The more advanced object should consist out of multiple smaller objects, and do all the communication needed between the smaller objects. The smaller objects should do nothing on their own and should know nothing about their parent. They just should do what is wanted from them.
In the case of this question that would look like this:

class Actor
{
  Sprite sprite;
  int x, y;
  float rotation;
  [...]
  void draw()
  {
    sprite.draw(x, y, rotation);
  };
  void update(dTime)
  {
    sprite.advanceAnimation(dTime);
    [...]
  };
  [...]
}
\$\endgroup\$
6
  • \$\begingroup\$ Well, you are pretty much describing how my system currently looks like. How do you suggest I solve the problem? Thanks. \$\endgroup\$ Oct 29, 2012 at 20:04
  • \$\begingroup\$ Well, either you adapt the sprite class to what you need or you make a global Renderer class and you adapt that. In my personal project I use the Renderer approach as it's more flexible. \$\endgroup\$
    – API-Beast
    Oct 29, 2012 at 20:07
  • \$\begingroup\$ It's more flexible because I can apply those transformations to any Drawable class not just Sprites. \$\endgroup\$
    – API-Beast
    Oct 29, 2012 at 20:15
  • \$\begingroup\$ I'm sorry, but what you said souds very ambiguous. "adapt the sprite class to what you need"? "make a global Renderer class and you adapt that"? \$\endgroup\$ Oct 30, 2012 at 0:39
  • \$\begingroup\$ @GerardoMarset Well you need to implement the feature "somewhere", that's what I meant with adapt. Where you implement it really depends on how your engine looks like. For example if all you'll ever need is your sprite class you can implement it there. But if you need more control about the rendering you should implement a class for the Renderer. \$\endgroup\$
    – API-Beast
    Oct 31, 2012 at 12:24
0
\$\begingroup\$

Whenever you encounter a situation like this, there are a couple of questions you can ask yourself to determine the what the best structure is going forward:

  • Is one class a more complex version of the other class?
  • Should one class know about the other?
  • What overall purpose is the class supposed to serve?
  • Is one class a utility to be used by more complex class?

If you answer yes to the first question, then inheritance is what you're looking for. For example, a regular sprite, or a sprite that supports multitexturing. In the case you're describing, the answer is probably no, an Actor is not a more complex Sprite. I think you are right that the Sprite class should not know about the Actor class, because, tying into the fourth question, the Sprite class is really a rendering utility for the Actor class; the Actor class relies on the Sprite class to draw itself on screen.

So, the Actor class should contain an instance of the Sprite class, in the same way that a GameObject in a 3D engine would have a Model to represent itself in the world.

To get to the specifics of your question, it seems like the root of your problem is your concern in how much maintenance the Actor class is going to have to handle for its Sprite. You mentioned that the Sprite instance often changes every frame, and the Actor would have to be responsible for updating it (I'm guessing this is for 2D animation?). I think this is where your structure goes wrong. What I would suggest is to create an AnimatedSprite class, which is responsible for the update of it's current on-screen sprite, and would store the 'index' of its animation. It's API could include functions such as animate, stop, etc; everything you might want an animated sprite to do. For position, your Sprite class' draw-call should take in the position where it is to be drawn.

What's most important is that a whole class instance inside of your Actor class should not have to be reconstructed every frame. If that becomes necessary, you should probably look for areas of improvement in your architecture.

\$\endgroup\$
8
  • \$\begingroup\$ It's preferred when an answer is downvoted that an explanation is provided. I'd like to know how I could improve my answer. \$\endgroup\$ Oct 29, 2012 at 16:34
  • \$\begingroup\$ Sprites handle animation already. The Sprite isn't likely to be changed every frame, but to be re-set every frame. Something like if not occupied then set_sprite(SpriteIdle) in a method that is called every frame is common. That's what I meant. (It wasn't me who downvoted you, by the way.) \$\endgroup\$ Oct 29, 2012 at 20:00
  • \$\begingroup\$ @GerardoMarset Hmm.. I guess I'm just confused about why the Actor needs to perform maintenance on the Sprite every frame. That paradigm just doesn't seem clean to me. \$\endgroup\$ Oct 29, 2012 at 20:47
  • \$\begingroup\$ Since the sprite is usually set every frame, and the sprite owns index, index would be reset to 0 every frame if the actor didn't pass it from the old sprite to the new one. \$\endgroup\$ Oct 29, 2012 at 20:53
  • \$\begingroup\$ @GerardoMarset But what does setting the sprite every frame accomplish? What specifically does 'resetting' the sprite do? \$\endgroup\$ Oct 29, 2012 at 21:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .