Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1075932 Posts in 44152 Topics- by 36119 Members - Latest Member: Royalhandstudios

December 29, 2014, 04:14:56 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Optimizing some complex code!
Pages: [1]
Print
Author Topic: Optimizing some complex code!  (Read 575 times)
Glyph
Level 9
****


Relax! It's all a dream! It HAS to be!


View Profile
« on: September 07, 2013, 06:08:19 PM »

So, here's some background. Recently I made a dungeon-generating script that worked pretty well. It infinitely generates a dungeon with pieces made from text files, and then it tiles them. The only problem is that last part -- the tiling script was way too slow. I called for some help on the Game Maker forum but to little success. I gave up on it for a while, but now I'm going to make one last stab at it.
I'm looking for some Game Maker Sage to offer insight into how I could optimize the script 'addtile' (it is definitely the source of the slowness). I'm not much one for optimization so I'm sure there's some big cuts that can be made here or there.

The file: (gm8, 20.6kb)
https://www.dropbox.com/s/t3vdpl3uxblomz9/Generate.zip
Use the arrow keys to scroll through the map. After a certain distance, a new segment will be generated.

The script in question:
Code:
//adds tile to a room
g=0;
var temp,xa,ya;
xa=a.x; ya=a.y;
//udlr
temp[0]=position_meeting(xa,ya-16,o_blk)<<3|position_meeting(xa,ya+16,o_blk)<<2|position_meeting(xa-16,ya,o_blk)<<1|position_meeting(xa+16,ya,o_blk)
//topleft clockwise
if temp[0]=15 temp[1]=position_meeting(xa-16,ya-16,o_blk)<<3|position_meeting(xa+16,ya-16,o_blk)<<2|position_meeting(xa+16,ya+16,o_blk)<<1|position_meeting(xa-16,ya+16,o_blk)

switch(temp[0])
{
case 15:
//all+inner
if temp[1]!=15 {
if !(temp[1] & 2) {a.tiles[g]=tile_add(b_tiles_rock,80,0,16,16,xa,ya,10000);} else
if !(temp[1] & 1) {a.tiles[g]=tile_add(b_tiles_rock,96,0,16,16,xa,ya,10000);} else
if !(temp[1] & 8) {a.tiles[g]=tile_add(b_tiles_rock,96,16,16,16,xa,ya,10000);} else
if !(temp[1] & 4) {a.tiles[g]=tile_add(b_tiles_rock,80,16,16,16,xa,ya,10000);}} else
{a.tiles[g]=tile_add(b_tiles_rock,32,32,16,16,xa,ya,10000);} break;

//three (floors)
case 14: {/*r*/a.tiles[g]=tile_add(b_tiles_rock,48,32,32,16,xa,ya,10000);} break;
case 13: {/*l*/a.tiles[g]=tile_add(b_tiles_rock,0,32,32,16,xa-16,ya,10000);} break;
case 11: {/*d*/a.tiles[g]=tile_add(b_tiles_rock,32,48,16,32,xa,ya,10000);} break;
case 7: {/*u*/a.tiles[g]=tile_add(b_tiles_rock,32,0,16,32,xa,ya-16,10000);} break;

//two (corners & bars)
case 10: {/*r-d*/a.tiles[g]=tile_add(b_tiles_rock,48,48,32,32,xa,ya,10000);} break;
case 6: {/*r-u*/a.tiles[g]=tile_add(b_tiles_rock,48,0,32,32,xa,ya-16,10000);} break;
case 5: {/*l-u*/a.tiles[g]=tile_add(b_tiles_rock,0,0,32,32,xa-16,ya-16,10000);} break;
case 9: {/*l-d*/a.tiles[g]=tile_add(b_tiles_rock,0,48,32,32,xa-16,ya,10000);} break;
case 3: {/*u-d*/a.tiles[g]=tile_add(b_tiles_rock,80,32,16,16,xa,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,8,16,8,xa,ya-8,10000); g+=1 a.tiles[g]=tile_add(b_tiles_rock,32,64,16,8,xa,ya+16,10000);}; break;
case 12: {/*l-r*/a.tiles[g]=tile_add(b_tiles_rock,96,32,16,16,xa,ya,10000); g+=1 a.tiles[g]=tile_add(b_tiles_rock,8,32,8,16,xa-8,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,64,32,8,16,xa+16,ya,10000);} break;

//one (ends)
case 1: {/*r*/a.tiles[g]=tile_add(b_tiles_rock,112,64,16,16,xa,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,8,16,8,xa,ya-8,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,64,16,8,xa,ya+16,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,8,16,8,16,xa-8,ya,10000);}; break;
case 2: {/*l*/a.tiles[g]=tile_add(b_tiles_rock,112,48,16,16,xa,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,8,16,8,xa,ya-8,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,64,16,8,xa,ya+16,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,64,16,8,16,xa+16,ya,10000);}; break;
case 4: {/*d*/a.tiles[g]=tile_add(b_tiles_rock,112,32,16,16,xa,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,8,16,8,xa,ya-8,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,8,16,8,16,xa-8,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,64,16,8,16,xa+16,ya,10000);}; break;
case 8: {/*u*/a.tiles[g]=tile_add(b_tiles_rock,112,16,16,16,xa,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,32,64,16,8,xa,ya+16,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,8,48,8,16,xa-8,ya,10000); g+=1; a.tiles[g]=tile_add(b_tiles_rock,64,48,8,16,xa+16,ya,10000);} break;

//none
case 0:
a.tiles[g]=tile_add(b_tiles_rock,112,0,16,16,xa,ya,10000);
break;
};
a.maxtiles=g+1;
Just for a reference point, on my computer, it takes 14-20 seconds to get out of the load dialog, and the script is run ~8000 times per generation. I would like to cut the time down A LOT, and I'm sure there's a way lying out there somewhere.
Logged

    
Try out my games!
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1 on: September 08, 2013, 01:32:55 AM »

Your code looks reasonably tight to me.

My guess (though I don't know GM well), is that those calls to position_meeting are slowing you down. You should verify this before proceeding. What is o_blk? If you know more about its shape, I'm sure you can replace those calls with some logic instead. Could it be an array of numbers instead of a GM object.
Logged
motorherp
Level 2
**



View Profile WWW Email
« Reply #2 on: September 08, 2013, 02:41:26 AM »

Hard to say without knowing more about your project.  Looks like the real problem however is that you're calling this function 8000 times.  The fastest code is always the code that doesn't run.  Is there not a way you can split this up such as only generating tiles when they become visible to the player instead of generating everything at the start?
Logged

Glyph
Level 9
****


Relax! It's all a dream! It HAS to be!


View Profile
« Reply #3 on: September 08, 2013, 05:57:15 PM »

@BorisTheBrave: the position_meeting is definitely the slow part. I'd like to look into some way to make it faster - perhaps a different function?

@motorherp: I have tested something in that vein of reasoning before: rooms used to be tiled as they were needed, before moving into the view. The slowdown was still somewhat noticeable and I deemed it too costly to be run at all times during the game (I want to have some wiggle room without that performance worry hovering over my head, hence the loading thing).

Thanks for the help, and I will continue looking into it.
Logged

    
Try out my games!
Evan Balster
Level 10
*****


I live in this head.


View Profile WWW Email
« Reply #4 on: September 08, 2013, 08:06:01 PM »

Place_meeting is going to run in O(N) where N is the number of candidate objects.  Much, much simpler would be to simply fill a ds_grid with information on which grid-spaces contain or do not contain a tile, and perform all autotiling using that.

Also, since when did bitwise & ever work in Game Maker?  All of its numbers are doubles.  I refuse to believe that's doing what it looks like...
Logged

Creativity births expression.  Curiosity births exploration.
Our work is as soil to these seeds; our art is what grows from them...


Wreath, SoundSelf, Infinite Blank, Cave Story+, <plaid/audio>
mokesmoe
Level 10
*****



View Profile WWW Email
« Reply #5 on: September 08, 2013, 09:12:54 PM »

Make sure you aren't using precise collision checking.

ds_grid might not work well with infinite generation or going in all directions.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic