2010-03-16 54 views
1

我正在为我的一个小型项目制作纹理管理和动画解决方案。尽管该项目使用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); 

渲染动画当前帧仅仅是块传输存储在精灵表的特定区域的情况下, 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

您可能想要考虑一个更灵活的Animation结构,其中包含一个Frame结构数组。每个帧结构可以包含帧延迟,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()); 

需要明确的是:这是一个视频卡的限制。所以一个大的精灵表可能在你的电脑上工作,但无法加载到另一个表上。上面的方法将精灵表加载到内存位图(本质上保证成功),然后每帧创建一个新的,更小的硬件加速视频位图。

0

你确定你需要一个指针anim到指针ALLEGRO_BITMAP **sprite;

IIRC Allegro BITMAP-句柄已经是指针了,所以不需要双引用它们,因为你似乎只想为每个动画存储一个Bitmap。

您应该在anim中使用ALLEGRO_BITMAP *sprite;

我看不到您的代码有任何其他问题。

+0

ALLEGRO_BITMAP不是一个指针,但你是正确的。由于他使用的是精灵表(一个包含多个图片的位图),因此他只需要一个指向单个位图的指针。 – Matthew 2010-03-16 17:35:43