Sign in to follow this  

map loading help

This topic is 3590 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've attempted to get this working for so long I'm near giving up :(. For now I've created a hard coded map. char map[3][3] = {0,0,0, 0,0,0, 0,0,0}; My code was working at one point but it made the game freeze.. And my current code only displays one tile. Since alot of things are probably done wrong I'll go back to where the start of the problems may be. --- I have a field class which is a map, it stores the needed tiles, what would be a good way of creating a tile array? at the moment its Tile _tiles[9]; But obviously then it all maps would have to be that size... -- Second question here is my current map loading code, what would be a better way of doing it?
void Field::Init(int width, int height)
{
	_width = width;
	_height = height;
	_maxTiles = _width * _height;
	int type = 0;
	for(int i = 0; i < _maxTiles; i++)
	{
		for(int y = 0; y < _height; y++)
		{
			for(int x = 0; x < _width; x++)
			{
				_tiles[i].Init(x*32, y*32, type, Gfx::GetImage("tile1.png"));
			}
		}
	}
}

And the map drawing code
void Field::Draw(SDL_Surface* screen)
{
	for(int i = 0; i < _maxTiles; i++)
	{
		Gfx::ApplySurface(_tiles[i].GetBox().x, _tiles[i].GetBox().y, _tiles[i].GetImage(), screen);
	}
}

This is being done with C++ and SDL. Any and all advice is welcome but if you find a fault(I garuntee it) can you explain a better alternative -regards Namingway

Share this post


Link to post
Share on other sites
Namingway, i could post you my Tile loading and Config loading system if you just want it to work ;).

And also, what type of tilesystem is it? (Platform, Topdown game?)

Share this post


Link to post
Share on other sites
Quote:
for(int i = 0; i < _maxTiles; i++)
{
for(int y = 0; y < _height; y++)
{
for(int x = 0; x < _width; x++)
{
_tiles[i].Init(x*32, y*32, type, Gfx::GetImage("tile1.png"));
}
}
}


Do you know what this code really does?

Share this post


Link to post
Share on other sites
Quote:
Original post by ChJees
Namingway, i could post you my Tile loading and Config loading system if you just want it to work ;).

And also, what type of tilesystem is it? (Platform, Topdown game?)


Topdown. Scanning someone elses map code might be useful :D
Init code

void Tile::Init(int x, int y, int type, SDL_Surface* img)
{
_box.x = x;
_box.y = y;
_box.w = TILE_WIDTH;
_box.h = TILE_HEIGHT;
_type = type;
_image = img;
}




and ToohrVyk I'm not quite sure i know what you mean

Share this post


Link to post
Share on other sites
Thoorvyk pointed out a rather obvious problem: you're initializing every tile _height * _width times. Every tile will end up having the same coordinates: (_height * 32, _width * 32), because that's what they're initialized with the last time. Rework that logic so tiles are initialized properly and only once.

Share this post


Link to post
Share on other sites
A changed a few things and now its working okay, however when I close the program it seems the stack gets corrupted!!

Changes:-

void Field::Init(int width, int height)
{
_width = width;
_height = height;
_maxTiles = _width * _height;
}

void Field::InitTiles()
{
int type = 0;
int i = 0;
for(int y = 0; y < _height; y++)
{
for(int x = 0; x < _width; x++)
{
_tiles[i++].Init(x*TILE_WIDTH, y*TILE_HEIGHT, type, Gfx::GetImage("tile1.png"));
}
}
}

void Field::Draw(SDL_Surface* screen)
{
for(int i = 0; i < _maxTiles; i++)
{
Gfx::ApplySurface(_tiles[i].GetBox().x, _tiles[i].GetBox().y, _tiles[i].GetImage(), screen);
}
}



I've never run into this problem before so don't really know how to fix it, or what caused it.

Edit: No its not working, if I set the width and height of the map over 8 it corrupts... I can never get this right :(

Share this post


Link to post
Share on other sites
What do you mean with 'the stack gets corrupted'? What is actually happening?

Anyway, you haven't forgotten about _tiles size, right? Your current approach requires you to hardcode the maximum number of tiles, which, in your first post, was set as 9. Personally, I'd go with a std::vector, or I'd look into boost::multi_array, since both are resizable and more flexible to work with than low-level arrays.

Share this post


Link to post
Share on other sites
I will post how i solved my tile system here :P.

And note that i use SDL and SDL_image for this.

Globals and how to render the layers
vector<_tile_> thelevel;
SDL_Rect loadedtiles[100];
SDL_Surface *tileset;

//The rendering part, put this into your gameloop
for( short int l = 0; l < 9; l++ )
{
for( int i = 0; i < thelevel.size(); i++ )
{
//_tile_ &temp;
if (thelevel[i].get_layer() == l)
{
thelevel[i].render();
}
/*_tile_ *temp;
temp = &thelevel[i];
temp->render();*/

}
}




Tileset.h
#ifndef _TILESET_
#define _TILESET_
class _tile_
{
public:
void render();
int check_collision();
void set_layer(int layer);
short int get_layer();
void set_graphic(SDL_Rect surface);
void set_position(int x, int y); //Self-explanatory
void set_collisionmode(bool col);

private:
bool collision;
int x, y; //Position
short int layer; //Render layer
SDL_Rect graphic; //The graphic
bool is_visible(); //Self-explanatory
};
void LoadTiles();
#endif





Tileset.cpp
#include "Tileset.h"
/* Tile System & Level System */
//SDL_Surface extern *screen;

void _tile_::render()
{
apply_surface( x, y, tileset, screen, &graphic );
}
int _tile_::check_collision()
{}
void _tile_::set_layer(int newlayer)
{
layer = newlayer;
}
void _tile_::set_graphic(SDL_Rect surface)
{
graphic.x = surface.x;
graphic.y = surface.y;
graphic.w = surface.w;
graphic.h = surface.h;
}
void _tile_::set_position(int newx, int newy)
{
x = newx;
y = newy;
}
void _tile_::set_collisionmode(bool col)
{
collision = col;
}
short int _tile_::get_layer()
{
return layer;
}

void LoadTiles()
{
fprintf(stdout,"Loading tilesheet...\n");
int loop = 0;
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
int rx,ry,rw,rh; //Vars
SDL_Rect rect; //Rect
//Calculate the crap:
rx = x * 32;
ry = y * 32;
rw = rx;
rh = ry;

rect.x = rx;
rect.y = ry;
rect.w = 32;
rect.h = 32;

//Apply the whole crap:
int arrayloc = loop;
loadedtiles[arrayloc].x = rect.x;
loadedtiles[arrayloc].y = rect.y;
loadedtiles[arrayloc].w = rect.w;
loadedtiles[arrayloc].h = rect.h;

fprintf(stdout,"Tile: X %i Y %i, W %i H %i. al: %i\n", rect.x, rect.y, rect.w, rect.h, arrayloc);
loop++;
}
}
fprintf(stdout,"Finished loading tilesheet.\n");

}




You should be able to figure out how it works from my code, Copy and pasting this code will most likely not work without extensive rewiring (recoding) :P.

All bugs are flattened out in my Tilesystem that are problematic.

Share this post


Link to post
Share on other sites
Quote:
Original post by namingway
I have a field class which is a map, it stores the needed tiles, what would be a good way of creating a tile array? at the moment its Tile _tiles[9];
But obviously then it all maps would have to be that size...


Boost::multi_array.

Quote:
Second question here is my current map loading code, what would be a better way of doing it?


Don't write Init() functions. Use constructors.

Also, your loop is wrong: currently you try to set *each* tile to *every* (x, y) location combination, and they all end up in the bottom-right. What you want to do is just have the x and y loops, and increment i in the inner loop.

Try to avoid redundant information, too. Doesn't the image to use depend exactly on the "type" of the tile? So just remember the type inside the Tile, and when it comes time to draw, look up the appropriate SDL_Surface* using that type value. In fact, you don't need to calculate and store the x and y positions of tiles ahead of time; when you're iterating through to draw them, you can recalculate the values. Meanwhile, the Field doesn't need to remember the "maxTiles"; it can calculate that as just height * width. Although, if you use something nice like boost::multi_array, it will remember the dimensions for you, too :)

Quote:
And the map drawing code
*** Source Snippet Removed ***


Don't "ask" a class for its data. "Tell" the class to do something, and have it "tell" its data to others, as needed. In general, give tasks to those objects which have the best access to the information required for those tasks.




Putting those hints together, we get something like:


// where '_tiles' is declared as boost::multi_array<Tile, 2>

Field::Field(int width, int height): _tiles(boost::extents[width][height])
{
for (boost::multi_array<Tile, 2>::iterator it = _tiles.begin();
it != tiles.end(); ++it)
{
// TODO: get a different "type" for each tile somehow (maybe
// read from a file?)
// Of course, you could set 0 as the default parameter for the
// Tile constructor, too...
*it = Tile(0);
}
}

// Notice I add some flexibility here, to draw the field at some given screen
// location instead of just the origin. You will probably appreciate this later
// ;) Notice how, by not storing the tile locations within the tiles, we can
// draw the field anywhere we like without updating any tile contents.
void Field::Draw(int xpos, int ypos, SDL_Surface* screen)
{
int height = _tiles.shape()[0];
int width = _tiles.shape()[1];
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
_tiles[x][y].Draw(x * 32 + xpos, y * 32 + ypos, screen);
}
}
}

void Tile::Draw(int xpos, int ypos, SDL_Surface* screen)
{
Gfx::ApplySurface(xpos, ypos, Gfx::ImageForTileType(_type), screen);
}


Share this post


Link to post
Share on other sites
Thanks to everyone helping out, btw the type was remaining at 0 for the time being as I just wanted to get the code done to draw the tiles and i'll sort out the type later, also I don't actually know how to use a class constructor when its inside another class...

Share this post


Link to post
Share on other sites

This topic is 3590 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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