Управление текстурой / вопрос указателя - PullRequest
1 голос
/ 16 марта 2010

Я работаю над решением для управления текстурой и анимацией для небольшого побочного проекта. Хотя проект использует 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;
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 16 марта 2010

Возможно, вы захотите рассмотреть более гибкую структуру анимации, которая содержит массив структур 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 голосов
/ 16 марта 2010

Вы уверены, что вам нужен указатель на указатель для ALLEGRO_BITMAP **sprite; в anim?

IIRC-маркеры Allegro BITMAP уже являются указателями, поэтому нет необходимости в двойных ссылках на них, так как вы, похоже, хотите хранить только одну битовую карту на анимацию.

Вы должны использовать ALLEGRO_BITMAP *sprite; в anim.

Я не вижу других проблем с вашим кодом.

...