Add support for map objects

This commit is contained in:
Camden Dixie O'Brien 2025-01-01 16:50:51 +00:00
parent 12751a49f8
commit cbb4b7884c

View File

@ -48,6 +48,9 @@
#define BASEANIMPERIOD 100 #define BASEANIMPERIOD 100
#define MAXOBJTYPES 8
#define INITOBJCOLCAP 16
#define NELEMS(a) (sizeof(a) / sizeof(a[0])) #define NELEMS(a) (sizeof(a) / sizeof(a[0]))
typedef enum { typedef enum {
@ -85,6 +88,22 @@ typedef struct {
SDL_Rect src; SDL_Rect src;
} entity_t; } entity_t;
typedef struct {
unsigned animframes;
SDL_Rect src;
SDL_Texture *tex;
} objtype_t;
typedef struct {
unsigned type;
ivec_t pos;
} obj_t;
typedef struct {
size_t n, cap;
obj_t *buf;
} objcol_t;
static const char *assetdir; static const char *assetdir;
static SDL_Window *window; static SDL_Window *window;
static SDL_Renderer *renderer; static SDL_Renderer *renderer;
@ -96,6 +115,8 @@ static const unsigned impassable[] = {
284, 485, 486, 525, 527, 566, 567, 731, 284, 485, 486, 525, 527, 566, 567, 731,
768, 770, 771, 804, 805, 806, 808, 845, 768, 770, 771, 804, 805, 806, 808, 845,
}; };
static objtype_t objtypes[MAXOBJTYPES];
static objcol_t objcol;
static inline double mag(dvec_t v) static inline double mag(dvec_t v)
{ {
@ -188,6 +209,101 @@ static void maploadlayer(xmlNodePtr layernode, int layeridx)
} }
} }
static unsigned objtypeload(const char *templ)
{
static char buf[MAX_PATH_LEN];
assert(strlen(assetdir) + strlen(templ) + 1 < MAX_PATH_LEN);
strcpy(buf, assetdir);
strcat(buf, "/");
strcat(buf, templ);
// Identify object type ID
xmlDocPtr doc = xmlParseFile(buf);
assert(NULL != doc);
xmlNodePtr node = xmlDocGetRootElement(doc);
assert(NULL != node);
assert(xmlStrcmp(node->name, (const xmlChar *)"template") == 0);
node = node->xmlChildrenNode;
while (node != NULL
&& xmlStrcmp(node->name, (const xmlChar *)"object") != 0)
node = node->next;
assert(NULL != node);
unsigned id
= atoi((const char *)xmlGetProp(node, (const xmlChar *)"gid"));
assert(id < MAXOBJTYPES);
// Populate objtype struct if not already loaded
if (NULL == objtypes[id].tex) {
objtypes[id].src.x = 0;
objtypes[id].src.y = 0;
objtypes[id].src.w
= atoi((const char *)xmlGetProp(node, (const xmlChar *)"width"));
objtypes[id].src.h = atoi(
(const char *)xmlGetProp(node, (const xmlChar *)"height"));
node = node->xmlChildrenNode;
while (node != NULL
&& xmlStrcmp(node->name, (const xmlChar *)"properties") != 0)
node = node->next;
assert(NULL != node);
for (node = node->xmlChildrenNode; NULL != node; node = node->next) {
if (xmlStrcmp(node->name, (const xmlChar *)"property") != 0)
continue;
const char *key
= (const char *)xmlGetProp(node, (const xmlChar *)"name");
const char *val
= (const char *)xmlGetProp(node, (const xmlChar *)"value");
if (strcmp(key, "animframes") == 0) {
objtypes[id].animframes = atoi(val);
} else if (strcmp(key, "assetpath") == 0) {
assert(strlen(assetdir) + strlen(val) < MAX_PATH_LEN);
strcpy(buf, assetdir);
strcat(buf, val);
objtypes[id].tex = IMG_LoadTexture(renderer, buf);
assert(NULL != objtypes[id].tex);
} else {
assert(false);
}
}
}
return id;
}
static void maploadobjects(xmlNodePtr node)
{
objcol.n = 0;
objcol.cap = INITOBJCOLCAP;
objcol.buf = malloc(sizeof(obj_t) * objcol.cap);
assert(objcol.buf);
node = node->xmlChildrenNode;
assert(NULL != node);
do {
if (xmlStrcmp(node->name, (const xmlChar *)"object") != 0)
continue;
// Get slot for object, growing buffer if needed.
if (objcol.n == objcol.cap) {
objcol.cap *= 2;
objcol.buf = realloc(objcol.buf, sizeof(obj_t) * objcol.cap);
assert(objcol.buf);
}
obj_t *o = &objcol.buf[objcol.n++];
// Load object type
const xmlChar *templ = xmlGetProp(node, (const xmlChar *)"template");
assert(NULL != templ);
o->type = objtypeload((const char *)templ);
// Load object location and set size from objtype
o->pos.x
= atoi((const char *)xmlGetProp(node, (const xmlChar *)"x"));
o->pos.y
= atoi((const char *)xmlGetProp(node, (const xmlChar *)"y"));
} while ((node = node->next) != NULL);
}
static void mapload(const char *path) static void mapload(const char *path)
{ {
xmlDocPtr doc; xmlDocPtr doc;
@ -197,14 +313,14 @@ static void mapload(const char *path)
node = xmlDocGetRootElement(doc); node = xmlDocGetRootElement(doc);
assert(0 == xmlStrcmp(node->name, (const xmlChar *)"map")); assert(0 == xmlStrcmp(node->name, (const xmlChar *)"map"));
node = node->xmlChildrenNode; node = node->xmlChildrenNode;
for (int l = 0; l < MAPNLAYERS; ++l) { int layer = 0;
do
node = node->next;
while (NULL != node
&& xmlStrcmp(node->name, (const xmlChar *)"layer") != 0);
assert(NULL != node); assert(NULL != node);
maploadlayer(node, l); do {
} if (xmlStrcmp(node->name, (const xmlChar *)"layer") == 0)
maploadlayer(node, layer++);
else if (xmlStrcmp(node->name, (const xmlChar *)"objectgroup") == 0)
maploadobjects(node);
} while ((node = node->next) != NULL);
} }
static void mapdraw(void) static void mapdraw(void)
@ -279,14 +395,33 @@ static void entitydraw(entity_t *e, uint64_t t)
e->src.x = e->animstep.x * frame + e->svarstep.x * e->svar; e->src.x = e->animstep.x * frame + e->svarstep.x * e->svar;
e->src.y = e->animstep.y * frame + e->svarstep.y * e->svar; e->src.y = e->animstep.y * frame + e->svarstep.y * e->svar;
SDL_Rect dest = { SDL_Rect dest = {
.x = SCALE * (int)(e->pos.x - vpos.x - e->src.w / 2), .x = SCALE * (e->pos.x - vpos.x - e->src.w / 2),
.y = SCALE * (int)(e->pos.y - vpos.y - e->src.h / 2), .y = SCALE * (e->pos.y - vpos.y - e->src.h / 2),
.w = SCALE * e->src.w, .w = SCALE * e->src.w,
.h = SCALE * e->src.h, .h = SCALE * e->src.h,
}; };
SDL_RenderCopy(renderer, e->tex, &e->src, &dest); SDL_RenderCopy(renderer, e->tex, &e->src, &dest);
} }
static void objsdraw(uint64_t t)
{
for (unsigned i = 0; i < objcol.n; ++i) {
const obj_t *obj = &objcol.buf[i];
assert(obj->type < MAXOBJTYPES);
const objtype_t *type = &objtypes[obj->type];
assert(NULL != type->tex);
SDL_Rect src = type->src;
src.x += type->src.w * ((t / BASEANIMPERIOD) % type->animframes);
SDL_Rect dest = {
.x = SCALE * (obj->pos.x - vpos.x),
.y = SCALE * (obj->pos.y - vpos.y - type->src.h),
.w = SCALE * type->src.w,
.h = SCALE * type->src.h,
};
SDL_RenderCopy(renderer, type->tex, &src, &dest);
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char path[MAX_PATH_LEN]; char path[MAX_PATH_LEN];
@ -436,6 +571,7 @@ int main(int argc, char *argv[])
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
mapdraw(); mapdraw();
objsdraw(t);
entitydraw(&p, t); entitydraw(&p, t);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }