Exactly, Enemy for instance, is a specific Object, and any Object own a reference on a Sprite structure (which deal about handling the visual part).
For instance in SGDK the Sprite structure is just about displaying (meta) sprite, and so dealing about VRAM / hard sprite allocation / handling animation etc... but in my view in any game, we should have a more generic Object structure / class which allow to handle IA, logic, ... stuff and this Object structure own a reference on a Sprite internally which handle the display.
Here's the Sprite (and dependencies) structure of SGDK :
Code:
/**
* \brief
* VDP sprite info structure for sprite resource definition.
*
* \param y
* Y offset for this VDP sprite relative to global Sprite position plus 0x80 (0x80 = 0 = no offset)
* \param size
* sprite size (see SPRITE_SIZE macro)
* \param numTile
* number of tile for this VDP sprite (should be coherent with the given size field)
* \param x
* X offset for this VDP sprite relative to global Sprite position plus 0x80 (0x80 = 0 = no offset)
*/
typedef struct
{
s16 y; // respect VDP sprite field order
u16 size;
s16 x;
u16 numTile;
} VDPSpriteInf;
/**
* \brief
* Sprite animation frame structure.
*
* \param numSprite
* number of VDP sprite which compose this frame
* \param vdpSpritesInf
* pointer to an array of VDP sprites info composing the frame (followed by H/V/HV flipped versions)
* \param collision
* collision structure
* \param tileset
* tileset containing tiles for this animation frame (ordered for sprite)
* \param w
* frame width in pixel
* \param h
* frame height in pixel
* \param timer
* active time for this frame (in 1/60 of second)
*/
typedef struct
{
u16 numSprite;
VDPSpriteInf **vdpSpritesInf;
Collision *collision;
TileSet *tileset;
s16 w;
s16 h;
u16 timer;
} AnimationFrame;
/**
* \brief
* Sprite animation structure.
*
* \param numFrame
* number of different frame for this animation
* \param frames
* frames composing the animation
* \param length
* animation sequence length
* \param sequence
* frame sequence animation (for instance: 0-1-2-2-1-2-3-4..)
* \param loop
* frame sequence index for loop (last index if no loop)
*/
typedef struct
{
u16 numFrame;
AnimationFrame **frames;
u16 length;
u8 *sequence;
s16 loop;
} Animation;
/**
* \brief
* Sprite definition structure.
*
* \param palette
* Default palette data
* \param numAnimation
* number of animation for this sprite
* \param animations
* animation definitions
* \param maxNumTile
* maximum number of tile used by a single animation frame (used for VRAM tile space allocation)
* \param maxNumSprite
* maximum number of VDP sprite used by a single animation frame (used for VDP sprite allocation)
*
* Contains all animations for a Sprite and internal informations.
*/
typedef struct
{
Palette *palette;
u16 numAnimation;
Animation **animations;
u16 maxNumTile;
u16 maxNumSprite;
} SpriteDefinition;
/**
* \brief
* Sprite structure used by the Sprite Engine to store state for a sprite.<br>
* WARNING: always use the #SPR_addSprite(..) method to allocate Sprite object.<br>
*
* \param status
* Internal state and automatic allocation information (internal)
* \param spriteDef
* Sprite definition pointer
* \param animation
* Animation pointer cache (internal)
* \param frame
* AnimationFrame pointer cache (internal)
* \param animInd
* current animation index (internal)
* \param frameInd
* current frame animation index (internal)
* \param seqInd
* current frame animation sequence index (internal)
* \param timer
* timer for current frame (internal)
* \param x
* current sprite X position on screen
* \param y
* current sprite Y position on screen
* \param depth
* current sprite depth (Z) position used for Z sorting
* \param attribut
* sprite specific attribut and allocated VRAM tile index (see TILE_ATTR_FULL() macro)
* \param visibility
* visibility information of current frame for each VDP sprite (max = 16)
* \param VDPSpriteIndex
* index of first allocated VDP sprite (0 when no yet allocated)<br>
* Number of allocated VDP sprite is defined by definition->maxNumSprite
* \param frameNumSprite
* the number of VDP sprite used by the current frame (internal)
* \param lastVDPSprite
* Pointer to last VDP sprite used by this Sprite (used internally to update link between sprite)
* \param data
* this is a free field for user data, use it for whatever you want (flags, pointer...)
* \param prev
* pointer on previous Sprite in list
* \param next
* pointer on next Sprite in list
*
* Used to manage an active sprite in game condition.
*/
typedef struct _Sprite
{
u16 status;
u16 visibility;
const SpriteDefinition *definition;
Animation *animation;
AnimationFrame *frame;
s16 animInd;
s16 frameInd;
s16 seqInd;
u16 timer;
s16 x;
s16 y;
s16 depth;
u16 attribut;
u16 VDPSpriteIndex;
u16 frameNumSprite;
VDPSprite *lastVDPSprite;
u32 data;
struct _Sprite *prev;
struct _Sprite *next;
} Sprite;
As you can see, it's already quite a beast but here you have the "live" Sprite structure as well as the sprite definition structure (the one that should stay in ROM, to define a sprite with its animations and frames).
Still that sprite structure just handle the sprite display, nothing else. I think it's better to separate both so you can minimize your Sprite size object for your sprites functions.