At this point, the foundation of the game has mostly been established. Before going deeper to implement more mechanics of the original game, an asset management system is implemented. This is one of the system that I thought would be a challenge to implement. Furthermore, this system would be iterated upon as the game develops. Thus having an early basic version would be desirable. With the system in place, I could also start developing graphics for the game, which would be fun and serve as a nice distraction from the usual coding.
There are 4 main type of assets as far as I am aware of:
- Texture
- Sound
- Font
- Sprites
There may be more types of asset in the future, but these are the 4 I'm going to focus on.
Texture, Sound, Font Management
In my eyes, these three are foundational assets for a game. Any other assets would most likely be building on top of them. An asset manager is written to deal with them. The manager will be responsible to add/query/delete the assets on demand. The data structure to store has already been implemented by Raylib. There isn't much to write about here as the procedure is largely similar to the memory pool manager that I've written before.
Sprite
Asset
Sprite is an interesting asset. Fundamentally, a game will use a sprite to visually present an Entity. In this engine, a sprite is derived from a texture. A texture can contain all the images required to represent an Entity and it is up to the Sprite to interpret it correctly and draw it. This allows the usage of a spritesheet down the line. A sprite can be animated as well. In this game engine, I will be using traditional frame-by-frame animation as it is much easier to deal with.
Sprite animation can be seen as moving a rectangular frame across a texture, changing the sprite image every so often based on some speed. As such, the Sprite is created as such:
typedef struct Sprite {
Texture2D* texture;
Vector frame_size;
Vector2 origin;
int frame_count;
int current_frame;
int elapsed;
int speed;
char* name;
} Sprite_t;
This implementation does have a limitation for now: Animated sprite frames must be placed sequentially in an horizontal manner.
Component
This struct will merely hold the data for a sprite. To properly use it, a Sprite component is implemented (henceforth will now be referred as CSprite to avoid confusion with the sprite asset). A Csprite will hold multiple sprites related to that entity and deal with the sprite transition logic. The sprites are held in an array and the transition function will return the index of the sprite to transit into.
typedef unsigned int (*sprite_transition_func_t)(Entity* ent);
typedef struct _CSprite_t {
const char** sprites_map;
sprite_transition_func_t transition_func;
Vector2 offset;
unsigned int current_idx;
};
The sprite transition function requires information from the Entity, in general, to perform the logic. Thus, the pointer to the Entity is passed in instead of any selected component.
System
A sprite animation system is implemented to determine the sprite to be drawn at that particular frame. This system will deal with any entity with the CSprite component. There are simply two step to the animation system:
- Run the sprite transition logic to determine the sprite to draw
- Update the sprite frame index
The drawing system is updated to draw a sprite based on the sprite asset struct.