c - 纹理管理/指针问题

标签 c memory-management pointers allegro

我正在为我的一个小型副项目开发纹理管理和动画解决方案。虽然该项目使用 Allegro 进行渲染和输入,但我的问题主要围绕 C 和内存管理。我想把它贴在这里以获取对方法的想法和洞察力,因为在指针方面我很糟糕。

本质上,我要做的是将我所有的纹理资源加载到一个中央管理器 (textureManager) 中——它本质上是一个包含 ALLEGRO_BITMAP 对象的结构数组。存储在 textureManager 中的纹理大部分是完整的 Sprite 表。

从那里,我有一个 anim(ation) 结构,它包含特定于动画的信息(以及指向 textureManager 中相应纹理的指针)。

为了给你一个想法,下面是我设置和播放玩家“行走”动画的方式:

createAnimation(&player.animations[0], "media/characters/player/walk.png", player.w, player.h);
playAnimation(&player.animations[0], 10);

渲染当前帧的动画只是 blitting 存储在 textureManager 中的 Sprite 表的特定区域的情况。

作为引用,这里是 anim.h 和 anim.c 的代码。我敢肯定,出于多种原因,我在这里所做的可能是一种糟糕的方法。我想听听他们的事!我是否让自己陷入任何陷阱?这会像我希望的那样工作吗?

动画.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

动画.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;
        }
    }
}

最佳答案

您可能需要考虑一个更灵活的动画结构,它包含一个帧结构数组。每个帧结构都可以包含帧延迟、x/y 热点偏移等。这样,同一动画的不同帧可以有不同的大小和延迟。但是,如果您不需要这些功能,那么您正在做的事情就很好。

我假设您将以固定帧速率(每秒恒定的逻辑帧数)运行逻辑?如果是这样,那么延迟参数应该运行良好。

关于您的代码的快速评论:

textureManager[i].active = true;

在检查位图是否已加载之前,您可能不应该将其标记为事件状态。

另请注意,Allegro 4.9/5.0 完全受 OpenGL 或 D3D 纹理支持,因此,大型位图将无法在某些视频卡上加载!如果您要生成大型 sprite 表,这可能是个问题。从当前版本开始,您必须自己解决它。

你可以这样做:

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());

需要说明的是:这是视频卡的限制。因此,一个大的 sprite 表可能在您的计算机上工作,但无法在另一台计算机上加载。上述方法将 sprite 表加载到内存位图中(基本上保证成功),然后每帧创建一个新的、更小的硬件加速视频位图。

关于c - 纹理管理/指针问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2452835/

相关文章:

c++ - 将结构的地址分配给另一个结构的指针

c++ - 无法从数组或指针 vector 内部访问指向对象的成员

c - Scanf 似乎工作不正常,或者我做错了什么

c - 什么是总线错误?它与段错误有什么不同吗?

c - 保留内存等于共享内存,但内存从未被保留

java - 没有找到足够的连续内存会导致 OOM 吗?

c++ - 在给定指向该元素的指针的情况下获取双端队列中元素的索引?

c - ARM汇编跳转到地址

c - 我怎样才能订阅一个 channel ,然后在不阻塞的情况下做其他事情?

ios - 使用 View Controller 的更好方法是什么?