Sign in to follow this  
KellerHood

SDL tilemap overlapping player

Recommended Posts

I'm using SDL for an RPG I am making, and it seems that the tilemap I am rendering is overlapping the player object. Even though I am drawing the player after the tiles. And only some tiles will overlap him.
Take this diagram ([O] being a tile that would not overlap the player, [P] being the player, and [X ] being a tile that overlaps the player):
[O][O][O][O][O]
[O][O][O][O][O]
[O][O][P][X ][X ]
[X ][X ][X ][X ][X ]
[X ][X ][X ][X ][X ]

All tiles that are both below the player and to his right overlap him. But not any of the others.
I have a tilemap struct and a sprite struct. The tilemap has an array of tiles and an array of entities.
Written in plain C, here is tilemap.h:
[code]

#ifndef TILEMAP_H
#define TILEMAP_H

/*TODO: Change the entities array to only one dimension*/

/*
Tilemaps have two layers: An image layer and an entity layer.
Images do not move. They cannot destroyed in any way.
Entities can move, and can be destroyed. Entities also have underlying images upon creation.
*/
#include "sprite.h"
#include "player.h"
typedef struct
{
int** tiles; /*numeric index for each tile*/
sprite*** images; /*array of sprites to draw*/
sprite*** entities; /*array of entities to maintain and draw*/
int w, h;
} tilemap;

tilemap* new_tilemap(int w, int h, const char* filename)
{
tilemap* tm = malloc(sizeof(tilemap));
tm->w = w;
tm->h = h;
tm->tiles = malloc(sizeof(int*) * h);
int i;
for (i = 0; i < h; ++i)
{
tm->tiles[i] = malloc(sizeof(int) * w);
}

tm->entities = malloc(sizeof(sprite**) * h);
for (i = 0; i < h; ++i)
{
tm->entities[i] = malloc(sizeof(sprite*) * w);
}

FILE* file = fopen (filename, "rb");
if (file == NULL)
{
printf("Failed to open map %s\n", filename);
}
int j;
for (j = 0; j < h; ++j)
{
for (i = 0; i < w; ++i)
{
fscanf(file, "%d", &(tm->tiles[j][i]));
}
}
fclose(file);

tm->images = malloc(sizeof(sprite**) * h);
for (i = 0; i < h; ++i)
{
tm->images[i] = malloc(sizeof(sprite*) * w);
}
for (j = 0; j < h; ++j)
{
for (i = 0; i < w; ++i)
{
switch (tm->tiles[j][i])
{
case 0:
tm->images[j][i] = new_sprite_file("dat/tiles/0.bmp", 1);
tm->entities[j][i] = NULL;
break;
case 1:
tm->images[j][i] = new_sprite_file("dat/tiles/1.bmp", 2);
tm->entities[j][i] = NULL;
break;
case 2:
tm->images[j][i] = new_sprite_file("dat/tiles/0.bmp", 1);
tm->tiles[j][i] = 0;
tm->entities[j][i] = new_player();
break;
default:
tm->images[j][i] = NULL;
tm->entities[j][i] = NULL;
break;
}
tm->images[j][i]->x = i*tm->images[j][i]->w;
tm->images[j][i]->y = j*tm->images[j][i]->h;
if(tm->entities[j][i] != NULL)
{
tm->entities[j][i]->x = i*tm->entities[j][i]->w;
tm->entities[j][i]->y = j*tm->entities[j][i]->h;
}
}
}
return tm;
}

/*DRAWING CODE FOR THE TILEMAP HERE*/
void render_tilemap(tilemap* tm, SDL_Surface* dest)
{
int i, j;
for (j = 0; j < tm->h; ++j)
{
for (i = 0; i < tm->w; ++i)
{
sprite* img = tm->images[j][i];
if (img != NULL)
{
img->update(img);
render_sprite(img, dest);
}
sprite* ent = tm->entities[j][i];
if (ent != NULL)
{
ent->update(ent);
render_sprite(ent, dest);
}
}
}
}

void free_tilemap(tilemap* tm)
{
int i, j;
for (i = 0; i < tm->h; ++i)
{
free(tm->tiles[i]);
}
free(tm->tiles);

for (j = 0; j < tm->h; ++j)
{
for (i = 0; i < tm->w; ++i)
{
SDL_FreeSurface(tm->images[j][i]->image);
free(tm->images[j][i]);
}
}
for (i = 0; i < tm->h; ++i)
{
free(tm->images[i]);
}
free(tm->images);

for (j = 0; j < tm->h; ++j)
{
for (i = 0; i < tm->w; ++i)
{
if(tm->entities[j][i] != NULL)
{
SDL_FreeSurface(tm->entities[j][i]->image);
free(tm->entities[j][i]);
}
}
}
for (i = 0; i < tm->h; ++i)
{
free(tm->entities[i]);
}
free(tm->entities);
free(tm);
}
#endif
[/code]


And here is sprite.h:
[code]

#ifndef SPRITE_H
#define SPRITE_H
#include <stdlib.h>
#include <SDL/SDL.h>

typedef struct sprite sprite;

struct sprite
{
SDL_Surface* image;
SDL_Rect bbox;
float x;
float y;
int w;
int h;
float frame;
int framenumber;
float speed;
int frames;
void(*update)(sprite* this); /*To be overidden by subtypes*/
};
void sprite_update(sprite* this)
{
this->bbox.x = this->x;
this->bbox.y = this->y;
if (this->frames > 1) /*If there is even an animation to play*/
{
if (this->frame > this->frames-0.5f)
this->frame = 0;
else
this->frame+=this->speed;
this->framenumber = (int)(this->frame);
}
}

sprite* new_sprite() /*to be overidden by subtypes*/
{
sprite* s = malloc(sizeof(sprite));
SDL_Surface* image = SDL_LoadBMP("dat/defaults.bmp");
SDL_Surface* opimage = SDL_DisplayFormat(image);
SDL_FreeSurface(image);
*s = (const sprite)
{
.image = opimage,
.x = 0,
.y = 0,
.frame = 0,
.speed = 0.0f,
.frames = 1,
.framenumber = 0,
.update = *sprite_update
};
s->w = s->image->w/s->frames;
s->h = s->image->h;
s->bbox = (const SDL_Rect){.x = s->x, .y = s->y, .w = s->w, .h = s->h};

Uint32 colorkey=SDL_MapRGB(s->image->format, 255, 0, 255);
SDL_SetColorKey(s->image, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey);

return s;
}
sprite* new_sprite_file(const char* filename, int frames) /*to be overidden by subtypes*/
{
sprite* s = malloc(sizeof(sprite));
SDL_Surface* image = SDL_LoadBMP(filename);
SDL_Surface* opimage = SDL_DisplayFormat(image);
SDL_FreeSurface(image);
*s = (const sprite)
{
.image = opimage,
.x = 0,
.y = 0,
.frame = 0,
.speed = 0.125f,
.frames = frames,
.framenumber = 0,
.update = *sprite_update
};
s->w = s->image->w/s->frames;
s->h = s->image->h;
s->bbox = (const SDL_Rect){.x = s->x, .y = s->y, .w = s->w, .h = s->h};

Uint32 colorkey=SDL_MapRGB(s->image->format, 255, 0, 255);
SDL_SetColorKey(s->image, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey);

return s;
}

void render_sprite(sprite* s, SDL_Surface* dest)
{
SDL_Rect currentframe;
currentframe = (const SDL_Rect){.x = s->framenumber * s->w, .y = 0, .w = s->w, .h = s->h};
SDL_BlitSurface(s->image, &currentframe, dest, &(s->bbox));
}
#endif
[/code]

And finally, player.h:
[code]

/*'player' subtype of the 'sprite' class*/
#ifndef PLAYER_H
#define PLAYER_H
#include "sprite.h"

extern int g_key[321];

void player_update(sprite* this)
{
this->bbox.x = this->x;
this->bbox.y = this->y;
if (this->frames > 1) /*If there is even an animation to play*/
{
if (this->frame > this->frames-0.5f)
this->frame = 0;
else
this->frame+=this->speed;
this->framenumber = (int)(this->frame);
}
if (g_key[SDLK_LEFT])
if(this->x > 0)
this->x -= 1;
if (g_key[SDLK_RIGHT])
if (this->x+this->w < 160)
this->x += 1;
if (g_key[SDLK_UP])
if (this->y > 0)
this->y -= 1;
if (g_key[SDLK_DOWN])
if (this->y+this->h < 144)
this->y += 1;
}

sprite* new_player()
{
sprite* s = malloc(sizeof(sprite));
SDL_Surface* image = SDL_LoadBMP("dat/linkwalkd.bmp");
SDL_Surface* opimage = SDL_DisplayFormat(image);
SDL_FreeSurface(image);
*s = (const sprite)
{
.image = opimage,
.x = 0,
.y = 0,
.frame = 0,
.speed = 0.125f,
.frames = 2,
.framenumber = 0,
.update = *player_update
};
s->w = s->image->w/s->frames;
s->h = s->image->h;
s->bbox = (const SDL_Rect){.x = s->x, .y = s->y, .w = s->w, .h = s->h};

Uint32 colorkey=SDL_MapRGB(s->image->format, 255, 0, 255);
SDL_SetColorKey(s->image, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey);

return s;
}

#endif
[/code]

I think the error may have something to do with the bbox member of the player, but I'm not sure. I can't see where this problem is coming from, and if it's SDL related or related to my own logic.

EDIT: Never mind. Simply separated the drawing of the entities and the drawing of the tiles to two separate loops.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this