Tile Colisions?

S

seanm

Guest
Maybe you can make a grid collision system that works with moving walls, but I can't imagine it would be more efficient that the alternatives. Plus your movement resolution would be the size of the cells? Maybe I'm just not understanding but it doesn't seem like a great idea.

If you have a lot of tiles you need to delete the extra ones if you are calling any tile functions. The tile functions will just freeze your game for a bit if you have too many tiles loaded.
 
J

jackhigh24

Guest
i use ds_grid for all my collision moving or not and it many times quicker than any other way, i never use tile collision any more there to slow when compared to a ds_grid, but still there faster than using invisible object what dumb idea who ever said that LOL.
 
A

anomalous

Guest
How do you test LOS/raycasting with your ds_grid collision?

I tried a wide range of Bresenham type solutions and the absolute best performed horribly compared to collision_line on masks.
This made only ds_grid not an option (I still use it for basic movement).

Also, are you sure about this tile advice? My actual implementation 2+ years ago clearly showed large numbers of tiles slowed the engine down, it specifically showed up in the debugger under the Room Handling time (black boxed in there), and tile functions were not in use. Further, I suspect if tile function speed does increase, that shows up in the GML profiler as an increase in the time of the actual tile functions, easy to see right? I found no workable solution other than to add/remove tiles broken up per step (performs very fast, entirely workable)

@seanm didn't you also implement large tile maps and found similar results?
 
S

seanm

Guest
I suspect that collision masks and box casting are far more optimized internally than anything you could write yourself. I myself found any kind of boxcasting for rotated sprites was at the very least incredibly annoying, and felt super slow.

That being said, raycasting a line should still work well if you are using the YYC. Any kind of loop is much more optimized in the native compiler.

And yes, the more tiles I had the more my framerate suffered if I tried to do anything with tiles. I can't remember if they hurt my performance if I didn't touch them after they were created though; but I did have ~1million tiles loaded at once and I was able to keep a steady 60fps. So I don't think performance is hurt too badly if at all. But again, with that many tiles, any of the tile functions would freeze my game for a second or two.

@anomalous
 
J

jackhigh24

Guest
ye i have no experience with LOS/raycasting so cant say anything about that, but the reason i use ds_grid now is with tiles its the tile checking for collisions that kills it based on how many tiles you have, much faster with a ds_grid but like i said iv no idea about LOS/raycasting, might look it up later though and see if it can be applied.
 
S

seanm

Guest
Yes just store the tiles collision info into a grid and use a grid lookup instead of the tile_find function
 

TheouAegis

Member
When we're talking about terrain that moves, do we mean moving relative to the view or relative to the game world? Things like moving platforms were separate objects in a lot of games. But as for the position of the tiles in the view/room due to just walking, you'd just keep track of how far the tiles have been offset in the view and add that to the position you're checking.
 
S

seanm

Guest
@TheouAegis I have no idea what people are talking about anymore.

But I went and tested object deactivation.

10000 objects

spacebar event in controller object
Code:
instance_deactivate_region(view_xview[0]-20,view_yview[0]-20,view_wview[0]+40,view_hview[0]+40,false,true)
instance_activate_region(view_xview[0]-20,view_yview[0]-20,view_wview[0]+40,view_hview[0]+40,true)

//This is the killer
instance_activate_object(objControl)

The default fps_real is: 400
Spacebar code, without instace_activate_object(objControl): 600
Spacebar code, with instace_activate_object(objControl): 120


so instance_activate_object destroys framerates, which is unfortunate because its great at keeping something active if it happens to slip out of the view.
 
S

seanm

Guest
It is still slower to use, but
calling instance_activate_object(-1) to reference the objects id, instead of its object index
holds the fps_real around 560

@TheouAegis
 

TheouAegis

Member
What if you tried to reference another object and not the controller itself (which seemed kinda pointless in your code, if your code was in objControl and that was what you were activating) via its numerical object_index? Using -1 should be faster than an object_index because GM would in theory not even bother scanning through all the objects at that point, since -1 isn't an object_index.
 
S

seanm

Guest
If I use a different object_index:
Code:
instance_activate_object(objOther)
the framerate still drops to ~120

---

If I use 0 (the objects index):
Code:
instance_activate_object(0)
the framerate still drops to ~120

---

If I catch the other objects id:
Code:
obj=instance_create(x,y,objOther)
then use that
Code:
instance_activate_object(obj)
the framerate stays ~560
 
B

bojack29

Guest
Raycasting in a grid is actually pretty easy. Depending on what your looking for you simply find the smaller of the two sides of the object. Rotated objects have a maximum width and height, so you simply check for the smaller of the two.

Heres a script that attempts to do that
Code:
scr_gridCollLine(sx, sy, gx, gy, cellSizeX, cellSizeY, grid_index, object, valueToCheck);

var a, b, c, d, e, sx, sy, gx, gy;

a = argument7;
b = min(a.boxbbox_right - a.bbox_left, a.bbox_bottom - a.bbox_top);

sx = argument0;
sy = argument1;

gx = argument2;
gy = argument3;

c = point_distance(sx, sy, gx, gy);
d = point_direction(sx, sy, gx, gy);

for(e = 0;e <= c;e += b){
  
     if (e > c){
          e = c;
     }

     sx += lengthdir_x(b, d);
     sy += lengthdir_y(b, d);

     if (argument6[# floor(sx / argument4) * argument4, floor(sy / argument5) * argument5] == argument8){
          return true;
     }
}
return false;
If you want the id you can simply run a reg collision line after. Or you can insert an instance position check where the return true area is
 
Last edited by a moderator:

Yal

🐧 *penguin noises*
GMC Elder
Interesting results about instance_activate_object()... an interesting side-effect is that its speed footprint should be roughly the same no matter the number of objects you would activate by that since it needs to loop through every instance either way, so it's much more efficient to have a single 'activate me' parent for all objects you want activated and there's no real penalty for activating objects that might as well be inactive with a little extra effort. I use deactivation a lot, so I'll find those results useful.
 

TheouAegis

Member
No, I mean 100000 or whatever is the breakpoint for instances. If the value is less than 100000 or whatever, then GM assumes it's an object_index, unless the value is less than 0, in which case GM assumes it's a special pointer.
....
Would be interesting to see what happens if you make 100000 objects in GM.
 

Yal

🐧 *penguin noises*
GMC Elder
Would be interesting to see what happens if you make 100000 objects in GM.
I've actually seen a guy who tried. (Or actually used the 'merge project' feature several times in pre-GMS; it changes all resource IDs to new ones to ensure they're unique and if you keep going long enough with a big project you hit that cap). Basically, more or less every function that treats instances and objects differently broke down completely because it assumed references to objects were actually instance IDs. I think they eventually managed to solve the problem by exporting the project as a GMRES and then loading it into an empty file since that resets the numbering from 0.
 

TheouAegis

Member
Ah good to know. I figured it'd glitch out the program if you actually got that high.

I tried using file_copy() but I can't get the damned function to work in Studio to automatically copy an object.gmx. I even set it as an included file and still couldn't get it to work. What the eff is up with file_copy() in Studio?

if file_exists("object2.object.gmx")
{
repeat 100000
file_copy("object2.object.gmx","object"+string(i++)+".object.gmx");
}

Ran through the loop, but nothing was created that I could find.
 

Yal

🐧 *penguin noises*
GMC Elder
I tried using file_copy() but I can't get the damned function to work in Studio to automatically copy an object.gmx. I even set it as an included file and still couldn't get it to work. What the eff is up with file_copy() in Studio?
It's sandboxed for a start, so make sure you're using it in the directory where the file actually is (by default, in LocalAppData). (Try adding an 'else' case that shows a debug message if the file isn't found). Also, AFAIK GMS also uses a list of all resources, so just copying the object file still doesn't mean the copies get added to the project.
upload_2016-7-17_11-4-21.png
Finally, you probably would want to edit the names of the objects as well (when adding to the .project file) to ensure you don't have to click through 100,000 "illegal name" errors when you load up the project.
 

TheouAegis

Member
I did a search of my hard drive. Figured out what happened.

So the file was dumped into the temp directory (working_directory). When the file was copied, it was copied into a project directory (different root than the working_directory).
 
S

SagyDemn

Guest
You'll need to use the tile_layer_find function:

ie:
Code:
var tmp_depth = 1000;
var tmp_tile = tile_layer_find(tmp_depth, x+32, y);

if(tmp_tile == -1)//no tile
{
x+=32;
}
Thnaks You so Much :p
 
S

Samurai

Guest
You'll need to use the tile_layer_find function:

ie:
Code:
var tmp_depth = 1000;
var tmp_tile = tile_layer_find(tmp_depth, x+32, y);

if(tmp_tile == -1)//no tile
{
x+=32;
}
Does this work if the tile is displayed as a background itself? Since backgrounds that are setup in the room without any tile grid setup. The tiles can go on continously horizontal and vertical.
 

TheouAegis

Member
If you used tile_layer_hide and not tile_layer_delete, then the tiles are still readable even if they aren't drawn.
 

Yal

🐧 *penguin noises*
GMC Elder
Does this work if the tile is displayed as a background itself? Since backgrounds that are setup in the room without any tile grid setup. The tiles can go on continously horizontal and vertical.
Nope, backgrounds and tiles are completely different things, and the background is supposed to only be a decorative image.
 

TheouAegis

Member
Oh. Haha, I didn't interpret his answer that way. I assumed he was talking about putting the tiles in the room, letting the room get drawn to a surface for one frame, then hiding/deleting the tiles, saving the surface to a background, and using that background.
 
T

Tofu Heavy Industries

Guest
At the start of the room (in the Room Creation Code), loop through every tile in the room. Based on the tile, store a value in an array relative to that tile's position that will denote what kind of properties that tile has. Then when you need to check for collisions, you find the relative position in the array of the coordinate to check and see what value exists in the array at that position.

http://gmvania.blogspot.com/2012/12/i-completed-my-tile-map-scripts.html
Ok, so I'm trying to use this as a tile collision system instead of using the functions everyone uses in GMS2. (cant afford it). But im not getting somethings..

#1 : He uses the variable "solid_count" in the second code snippet. But its previously undefined and I dont know where how hes actually identifying a tile as being solid during the first loop.

#2: He says :
Code:
The array solid_map in this example holds all the definitions. In this case, tile sheets would need to be arranged so that all tiles of the same type are together and located in the bottom-right section of the tile sheet.
I don't have the tile sheet for CV3 and cant find it, so I dont know how many tiles this "bottom right section" is that hes talking about. Is it up to us to define, and if so, how?

#3: Is the third code section on the page just the first 2 sections simplified?

#4: The last section, the map read; since I dont understand where/how a flag for solid was set, i dont understand how this works. Would this piece go into a step event of a moving object?


I am just really not putting all this together. I feel like id need a fully-coded complete functional example to get this working.
 

TheouAegis

Member
OMG This thread is so old, I forgot what my post had said. lol I had written up that guide for people who I had been discussing things with at the time, so yeah there are a lot of loose ends in it.

First off, the code was written for use with a Classic Castlevania clone, based on the code used in Castlevania III.

#1 : He uses the variable "solid_count" in the second code snippet. But its previously undefined and I dont know where how hes actually identifying a tile as being solid during the first loop.
The solid_count is how many TYPES of solids you'll have in the room. In most of the tutorials around the Game Maker community, people typically settle on 1 type of solid, so a tile is either solid or it's not solid. In Castlevania III, there were 8 types of solids because various tiles could affect how the player moved: Mud, Conveyor right, Conveyor left, Crumbling ledge, Ceiling Spike, Solid, and Floor Spike (same properties as a ceiling spike, but whatever). If you stood on a mud tile, you'd sink down. If you stood on a conveyor tile, you'd move left or right. If you stood on a crumbling ledge tile, it would gradually fall apart the longer you stood on it. If you touched a spike, you'd die.

#2: He says :
Code:
The array solid_map in this example holds all the definitions. In this case, tile sheets would need to be arranged so that all tiles of the same type are together and located in the bottom-right section of the tile sheet.
I don't have the tile sheet for CV3 and cant find it, so I dont know how many tiles this "bottom right section" is that hes talking about. Is it up to us to define, and if so, how?
The solid_map is an array specifying which tiles belong to each solid category. The way Castlevania had its tiles set up is all the decorative, non-solid tiles would be first, then tiles would be placed in the tile set in the same order as the types listed above - mud tiles first, then conveyor tiles, then crumbling ledge tiles (which was just the normal solid tile repeated), then the ceiling spike tile, then normal solid tiles, then a floor spike tile (which was actually somewhere else in the game's code, so it was always the last one). The solid_map would house the IDs of the last tile in each type of solidplus 1.

The way solid_map was used is you'd compare each tile's ID to each value in solid_map. If a tile had an ID less than the lowest entry in solid_map, the tile would be that type. As an example, let's say our solid_map was defined as [48,48,48,48,72,74,74,128]. If you had a tile with ID 32, then the tile would be type 0 (decorative) because it's not greater than solid_map[0]. If the tile had an ID of 52, then we check all the entries of solid_map until we find one that is higher than the tile ID. In this case, solid_map[4] is higher than the tile ID, so the tile is type 4 (crumbling ledge).

#3: Is the third code section on the page just the first 2 sections simplified?
The third code, if it's the one I'm thinking of, compresses the tile map. Instead of having each tile take up one variable, you can fit multiple tiles into one variable. In this case, it fits 2 tiles into one variable.

#4: The last section, the map read; since I dont understand where/how a flag for solid was set, i dont understand how this works. Would this piece go into a step event of a moving object?
The read code goes inside a script (hence the return calls in it). It would get the player's x and y coordinates, compress them to match the same layout as the tile map, then return (like a normal Game Maker function) the tile's type (0, 1, 2, 3, 4, 5, 6, or 7) so the game could then decide what to do with an instance walking on that tile.
 
Top