Hey Shawn sorry for this late reply, I've been trying to figure out how to properly do that (Never used ds_maps before or tried saving tiles) was wondering if you could help me out a bit if possible, no tutorials online seem to show how to do this and nothing I do seem to save the tile and then load it, I tried pretty much reusing the script I used initially but adding the map to it but I can't seem to get it to work. I think the answer is yes to this but I'm gonna ask anyway, can this be saved globally and then called? Or does it have to be in the room? Thanks for the help so far.
Because I am still in the learning stages of GML, I am not sure if my solution qualifies for "Properly do that" definition but it seems to work for me. In my solution the world can be somewhat infinite, not limited to memory (currently it runs at 112MB of ram) but only by hard drive space; my concept came from Minecraft world generation, chunking and loading.
Explanation:
Tilemap is 2048 x 2048 px containing 64 x 64 32px tiles
Biome size is 64 x 64 tiles
Main room is 2 x 2 Biomes and the tiles are held in a ds_grid (128 x 128 tiles) that is updated based on the player's location in the world.
The room wraps vertically and horizontally; I have a little issue I am trying to work out that when the player wraps the room it flickers once during transition to the other side of the room, but otherwise it is pretty clean.
The biomes are saved in binary files with the x_y of the biome that it belongs to as the name (biome_0_0.dsg) for example, with each 16 bit entry holding the tile location of the tilemap 8 bits for x coordinate and the last 8 for y with a capability of 256 x 256 tilemap grid, starting at the 0,0 and wrapping too 64, 64 which is 64 * 64 * 2 bytes with the file size being 8192; you can add whatever you like as far as other data too and just increase the byte count.
The meat and potatoes:
In this example I created the whole world in a ds_grid of tiles because I was playing with and learning cellular automata to create a random world with water and sand on a grass generated world.
Because this example takes 1GB of ram and 2 minutes to save the world to biome files for 128 x 128 biomes, I have started working on a smaller approach that is generated while playing the game, getting even closer to the Minecraft concept.
Also, some of the value are still hard coded or as GMWolf likes to refer as "Magic Numbers", later on a config file will be created/used based on user preferences; it is very incomplete, because I have only been working on this a little over a month with a 40-60hr per week regular job taking up most of my time.
Creating/Saving the world
Code:
//create world grid with grass tiles
var grid = ds_grid_create(8192, 8192); //grid is created and destroyed in this script to prevent memory leaks.
var val = 17 + (18 << 8); //grass tile at tilemap grid 17,18
ds_grid_set_region(grid, 0, 0, 8192, 8192, val);
//use cellular automata to add water, sand, etc based on biome types.
//save world to files
var worldBiomes_1d = global.worldBiomes_1d;
var biomeTiles_1d = global.biomeTiles_1d;
var biomeTiles_2d = power(biomeTiles_1d, 2) * 2;
var bfr = buffer_create(biomeTiles_2d, buffer_fixed, 2);
for (var by = 0; by < worldBiomes_1d; by++)
{
for (var bx = 0; bx < worldBiomes_1d; bx++)
{
buffer_seek(bfr, buffer_seek_start, 0);
for (var ty = 0; ty < biomeTiles_1d; ty++)
{
for (var tx = 0; tx < biomeTiles_1d; tx++)
{
buffer_write(bfr, buffer_u16, ds_grid_get(grid, tx + (bx * biomeTiles_1d), ty + (by * biomeTiles_1d)));
}
}
var fn = "biomes/biome_" + string(bx) + "_" + string(by) + ".dsg";
buffer_save(bfr, fn);
}
}
buffer_delete(bfr);
ds_grid_destroy(grid);
Loading/drawing the world
terrain object, you can put this in the player obj and save on some processor time for global variable accessing but I like to split things up as my player obj is pretty hefty in itself.
Create Event
Code:
bmTls_1d = global.biomeTiles_1d;
tl_px_1d = global.tileSize_px_1d;
bfrDataBytes = global.bufferDataSizeBytes;
terrain_spr = global.terrain_sprMap;
plyr_x = global.player_x; //updated in obj_player
plyr_y = global.player_y; //updated in obj_player
gridTiles = bmTls_1d * 2;
roomGrid = ds_grid_create(gridTiles, gridTiles);
bufSize = power(bmTls_1d, 2) * bfrDataBytes;
step = 0;
Step event
Code:
if (alarm[0] == -1)
{
alarm[0] = room_speed;
var h = step >> 1;
var w = step & 1;
// the room size is 2x squared biome chunks
var bx = global.biome_x + w; //set in obj_player
var by = global.biome_y + h; //set in obj_player
var fn = "biomes/biome_" + string(bx) + "_" + string(by) + ".dsg";
if (file_exists(fn))
{
var buffer = buffer_load(fn);
if (buffer_get_size(buffer) == bufSize)
{
//loop thru buffer and pop room tile grid
for (var i = 0; i < (bufSize / 2); i++)
{
var tile = buffer_read(buffer, buffer_u16);
ds_grid_set(roomGrid, (i % 64) + (w * 64), (i div 64) + (h * 64), tile);
}
}
buffer_delete(buffer);
}
step = (step >= 3) ? 0 : step + 1;
}
Draw event
Code:
plyr_x = global.player_x;
plyr_y = global.player_y;
var plyr_tile_x = plyr_x div 32;
var plyr_tile_y = plyr_y div 32;
//draw 2 tiles around the camera as buffer
var draw_tiles_width = (cam_w div tl_px_1d) + 4;
var draw_tiles_height = (cam_h div tl_px_1d) + 4;
var px_x = (plyr_tile_x * tl_px_1d) - (cam_w div 2) - (tl_px_1d * 2);
var px_y = (plyr_tile_y * tl_px_1d) - (cam_h div 2) - (tl_px_1d * 2);
var tx = px_x div tl_px_1d;
var ty = px_y div tl_px_1d;
for (var i = 0; i < draw_tiles_height; i++)
for (var j = 0; j < draw_tiles_width; j++)
{
var val = ds_grid_get(roomGrid, tx + j, ty + i);
var tpx_x = (val & $00FF) * tl_px_1d;
var tpx_y = (val >> 8) * tl_px_1d;
draw_sprite_part(terrain_spr, 0, tpx_x, tpx_y, tl_px_1d, tl_px_1d, px_x + (j * tl_px_1d), px_y + (i * tl_px_1d));
}
This all works well but plenty of room for optimization and clean up; like I said I am just learning GML and getting use to it's library and doing a lot of playing with ideas so you will see a lot of inconsistencies but hopefully you get the fundamental idea on how I did it.
EDIT:
As an after thought, the ds_grids could easily be replaced with 2d arrays and then you not need to worry about the global issue with ds_grid and memory leaks; like I said optimization is needed.