• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Creating from ds_grid coords produces weird issue (Plz help)

H

Haulidaie

Guest
Hi, first thread. I usually don't post to forums so go easy on me.

I'm using a ds_grid (whose data is written within a ds_map) to store positions of objects in my room. I've got a save script that looks like this:
Code:
///@description Save the room's objects to a grid, and then store in ds_map

with(obj_room_manager) {
    var
    rName = room_get_name(room),
    hCells = room_width div global.cellSize,
    vCells = room_height div global.cellSize,
    grid = ds_grid_create(hCells+1, vCells+1);
    
    //Loop through every cell
    for(var v = 0; v < vCells; v++) {
        for(var h = 0; h < hCells; h++) {
            //Get instance in cell (if there is one)
            var inst = instance_position(h*global.cellSize, v*global.cellSize, obj_parent_solid);
            if(inst != noone and grid[# h, v] != "0") {
                //Handle large grid objects
                if(inst.sprite_width > global.cellSize or inst.sprite_height > global.cellSize) {
                    ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v+(inst.sprite_height/global.cellSize)-1, "0");
                }
                grid[# h, v] = inst.object_index;
            } else {
                grid[# h, v] = "0";
            }
        }
    }
    
    //Save grid, and tidy
    global.sRooms[? rName] = ds_grid_write(grid);
    ds_grid_destroy(grid);
    show_message("Saved!");
}
And I've got a load script that looks like this:
Code:
///@description Load room objects from saved grid

with(obj_room_manager) {
    var
    rName = room_get_name(room),
    hCells = room_width div global.cellSize,
    vCells = room_width div global.cellSize,
    grid = ds_grid_create(hCells+1, vCells+1);
    
    //Check if the room has a saved grid
    if(global.sRooms[? rName] = undefined) {
        ds_grid_destroy(grid);
        return(false);
    } else {
        ds_grid_read(grid, global.sRooms[? rName]);
    }
    
    //Loop through every cell
    for(var v = 0; v < vCells; v++) {
        for(var h = 0; h < hCells; h++) {
            var inst = real(grid[# h, v]);
            //Add saved grid data to room
            if(inst > 0) {
                instance_create_layer(h*global.cellSize, v*global.cellSize, "Instances", inst);
            }
        }
    }
    
    //Tidy
    ds_grid_destroy(grid);
    show_message("Loaded!");
    return(true);
}
So my actual problem is that my global.cellSize, and most objects are 16*16, but some objects (buildings) are 32*32. For all of the smaller objects, these scripts work fine. Everything is saved were it's meant to, and everything is spawned in the right place upon loading.

However
, the 32*32 (or larger) objects always spawn one cell (16 pixels) further down the room than where they originally were.

Now I've tested, and messed around with it for hours, and the size of the object doesn't change how far down it moves. Also, I've become pretty sure that it's the load script, specifically, the instance creation itself that's the issue. But I just can't prove it.

What's even more confusing, is when I tried to just jump around the issue with this code:
Code:
//Load script instance creation replacement
if(inst.sprite_height > global.cellSize) {
    instance_create_layer(h*global.cellSize, (v-1)*global.cellSize, "Instances", inst);
} else {
    instance_create_layer(h*global.cellSize, v*global.cellSize, "Instances", inst);
}
It didn't work! The same thing happened!

Now I'm probably just being an idiot, or missed something stupidly small, but I am well and truly stumped. Any help would be greatly appreciated. I'm using the latest version of GMS 2.
 
H

Haulidaie

Guest
So I've just fixed it by changing the sprite origin of my buildings from top-left (like all my other object) to middle-left. Works perfectly. Annoying. Put works perfectly.

I'd still love to know what the hell was happening. But I guess it no longer matters.
 
I think I might know why - but bear with me...

EDIT:
Doesn't this

ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v+(inst.sprite_height/global.cellSize)-1

h+ (sprite_width / global.cellsize) -1
v+(inst.sprite_height/global.cellSize)-1

amount to:

h + (2) -1?
v + (2) -1?

So it's adding 1 to the h & v amount, and having a 0,0 origin is pushing it 1 right & down?

I could be wrong (most likely am) but this might fix it with your original origin:

ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v, "0");
 
Last edited:
H

Haulidaie

Guest
I think I might know why - but bear with me...

EDIT:
Doesn't this

ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v+(inst.sprite_height/global.cellSize)-1

h+ (sprite_width / global.cellsize) -1
v+(inst.sprite_height/global.cellSize)-1

amount to:

h + (2) -1?
v + (2) -1?

So it's adding 1 to the h & v amount, and having a 0,0 origin is pushing it 1 right & down?

I could be wrong (most likely am) but this might fix it with your original origin:

ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v, "0");
Thanks for your reply!

So the reason I'm doing that is since I don't want other objects to spawn inside my building, I'm making sure all cells that the building occupies (aside from the top left) contains a null ("0") id.

I did apply your fix, but I found that the same thing still happened. :/

Update: It's super annoying having the origin middle-left, because I have to pad everything differently. Any fixes, or even pure speculation is appreciated.
 
Last edited by a moderator:
Sorry about that - it was quite late, and I misunderstood a bit of your code.

Code:
var inst = instance_position(h*global.cellSize, v*global.cellSize, obj_parent_solid);
            if(inst != noone and grid[# h, v] != "0") {
                //Handle large grid objects
                if(inst.sprite_width > global.cellSize or inst.sprite_height > global.cellSize) {
                    ds_grid_set_region(grid, h, v, h+(inst.sprite_width/global.cellSize)-1, v+(inst.sprite_height/global.cellSize)-1, "0");
                }
                grid[# h, v] = inst.object_index;
If I understand this part of the code correctly:

You are testing through an approximation of the ds_grid dimensions, and seeing if there is a collision at an actual physical point with instance_position.

If it's a 32 /32 object then "ds_grid_set_region" is doing four squares of the grid as "0" - the current grid approximation, one below, one to the right, and one down right.

Code:
grid[# h, v] = inst.object_index
then sets the current ds_grid position as the object_index. It is overwriting the first grid position as a new number (the object_index)

Further loops through the grid approximations will pick up this object again (since you will hit it 4 times? with instance_position if its 32 /32 ) but because those remaining three squares will be set to a value of "0" (a string, rather than real) it won't be added into the grid upon further collisions. As governed by this bit of the code:

Code:
 if(inst != noone and grid[# h, v] != "0")
Am I understanding it correctly so far?

EDIT:
While I won't claim to have figured out the current issue, this method may be a bit excessive...??

Using two for loops to go through the grid approximations, and checking instance_position for each one.

My simplification would be to give all those objects the same parent, and have them do it.

Code:
with (whatever_parent_object)
{grid_x =  x / sprite_width;
grid_y = y / sprite_height;
global.grid[# grid_x, grid_y] = object_index}
I think that would be much less effort for the computer to do...no for loops required, and no collision checks either. But I am a noob / idiot... :)
 
Last edited:
Top