2010-03-16 52 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