我正在为我的小型项目开发纹理管理和动画解决方案。虽然该项目使用Allegro进行渲染和输入,但我的问题主要围绕C和内存管理。我想在这里发布它以获得对方法的想法和见解,因为当涉及指针时我很糟糕。
基本上我要做的是将所有纹理资源加载到中央管理器(textureManager)中 - 这实际上是一个包含ALLEGRO_BITMAP对象的结构数组。存储在textureManager中的纹理大多是完整的精灵表。
从那里开始,我有一个anim(ation)结构,它包含特定于动画的信息(以及指向textureManager中相应纹理的指针)。
为了给你一个想法,这是我如何设置和播放玩家的步行动画:
createAnimation(&player.animations[0], "media/characters/player/walk.png", player.w, player.h);
playAnimation(&player.animations[0], 10);
渲染动画当前帧只是blitting存储在textureManager中的精灵表的特定区域的情况。
供参考,这是anim.h和anim.c的代码。我很确定我在这里所做的事情可能是一种可怕的方法,原因有很多。我想听听他们的消息!我是否愿意接受任何陷阱?这会像我希望的那样起作用吗?
anim.h
#ifndef ANIM_H
#define ANIM_H
#define ANIM_MAX_FRAMES 10
#define MAX_TEXTURES 50
struct texture {
bool active;
ALLEGRO_BITMAP *bmp;
};
struct texture textureManager[MAX_TEXTURES];
typedef struct tAnim {
ALLEGRO_BITMAP **sprite;
int w, h;
int curFrame, numFrames, frameCount;
float delay;
} anim;
void setupTextureManager(void);
int addTexture(char *filename);
int createAnimation(anim *a, char *filename, int w, int h);
void playAnimation(anim *a, float delay);
void updateAnimation(anim *a);
#endif
anim.c
void setupTextureManager() {
int i = 0;
for(i = 0; i < MAX_TEXTURES; i++) {
textureManager[i].active = false;
}
}
int addTextureToManager(char *filename) {
int i = 0;
for(i = 0; i < MAX_TEXTURES; i++) {
if(!textureManager[i].active) {
textureManager[i].bmp = al_load_bitmap(filename);
textureManager[i].active = true;
if(!textureManager[i].bmp) {
printf("Error loading texture: %s", filename);
return -1;
}
return i;
}
}
return -1;
}
int createAnimation(anim *a, char *filename, int w, int h) {
int textureId = addTextureToManager(filename);
if(textureId > -1) {
a->sprite = textureManager[textureId].bmp;
a->w = w;
a->h = h;
a->numFrames = al_get_bitmap_width(a->sprite) / w;
printf("Animation loaded with %i frames, given resource id: %i\n", a->numFrames, textureId);
} else {
printf("Texture manager full\n");
return 1;
}
return 0;
}
void playAnimation(anim *a, float delay) {
a->curFrame = 0;
a->frameCount = 0;
a->delay = delay;
}
void updateAnimation(anim *a) {
a->frameCount ++;
if(a->frameCount >= a->delay) {
a->frameCount = 0;
a->curFrame ++;
if(a->curFrame >= a->numFrames) {
a->curFrame = 0;
}
}
}
答案 0 :(得分:0)
您确定需要指向ALLEGRO_BITMAP **sprite;
中anim
指针的指针吗?
IIRC Allegro BITMAP句柄已经是指针,所以不需要双引用它们,因为你似乎只想为每个动画存储一个Bitmap。
您应该在ALLEGRO_BITMAP *sprite;
中使用anim
。
我的代码没有看到任何其他问题。
答案 1 :(得分:0)
您可能需要考虑一个包含Frame结构数组的更灵活的Animation结构。每个帧结构可以包含帧延迟,x / y热点偏移等。这样,相同动画的不同帧可以是不同的大小和延迟。但如果你不需要这些功能,那么你正在做的事情很好。
我假设您将以固定的帧速率运行逻辑(每秒逻辑帧的常数)?如果是这样,那么延迟参数应该很好。
关于您的代码的快速评论:
textureManager[i].active = true;
在检查位图是否已加载之前,您可能不应将其标记为有效。
另请注意,Allegro 4.9 / 5.0完全由OpenGL或D3D纹理支持,因此,大型位图无法在某些视频卡上加载!如果要生成大型精灵表,这可能是一个问题。截至当前版本,您必须自己解决。
您可以执行以下操作:
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
ALLEGRO_BITMAP *sprite_sheet = al_load_bitmap("sprites.png");
al_set_new_bitmap_flags(0);
if (!sprite_sheet) return -1; // error
// loop over sprite sheet, creating new video bitmaps for each frame
for (i = 0; i < num_sprites; ++i)
{
animation.frame[i].bmp = al_create_bitmap( ... );
al_set_target_bitmap(animation.frame[i].bmp);
al_draw_bitmap_region( sprite_sheet, ... );
}
al_destroy_bitmap(sprite_sheet);
al_set_target_bitmap(al_get_backbuffer());
要明确:这是视频卡限制。因此,大型精灵表可能会在您的计算机上运行,但无法加载到另一台计算机上。上面的方法将精灵表加载到内存位图(基本上保证成功),然后每帧创建一个新的,更小的硬件加速视频位图。