Jump to content


Photo

Deformable grid optimization


  • Please log in to reply
4 replies to this topic

#1 lolmister

lolmister

    GMC Member

  • New Member
  • 4 posts
  • Version:Mac

Posted 22 February 2012 - 04:22 AM

I have been trying to create a geometry wars style grid in game maker, and I have mostly been successful. I have some problems, however, with frame rate. If someone could show me a way to get the same effect more efficiently I would be very grateful.

Here is a screenshot of it so far:
Posted Image
just so you know, the doughnut looking things attract the grid, everything else repels it slightly.

The way I have attempted to simulate this grid is by defining the vertexes where two lines on the grid cross, and storing their x and y coordinates in two different arrays, gridx, and gridy. I also store their momentum in two other arrays called gox and goy. This is all done in the create event, shown here:
for(i=0;i<ceil(room_width/size)+3;i+=1) // the +3 is just so that you cannot see the edge of the grid
for(n=0;n<ceil(room_height/size)+3;n+=1) // size is the distance between each point
{
 gridx[i,n]=size*i
 gridy[i,n]=size*n
 gox[i,n]=0
 goy[i,n]=0
}  
To render this grid I simply draw a line in between these vertexes. I also draw and the average between vertexes the same way so that the grid can appear smaller without wasting cpu power. This is all done in the draw event code, shown here:
for(i=0;i<ceil(room_width/size)+3;i+=1) //drawing the vertical lines
for(n=0;n<ceil(room_height/size-1)+3;n+=1)
{
 draw_line(gridx[i,n],gridy[i,n],gridx[i,n+1],gridy[i,n+1]) 
 if(i<ceil(room_width/size)+2  ) //checking to make sure that there is a line after this to average with
 draw_line((gridx[i,n]+gridx[i+1,n])/2,(gridy[i,n]+gridy[i+1,n])/2,(gridx[i,n+1]+gridx[i+1,n+1])/2,(gridy[i,n+1]+gridy[i+1,n+1])/2) //drawing the average line
}
for(i=0;i<ceil(room_width/size)+2;i+=1)
for(n=0;n<ceil(room_height/size)+2;n+=1)
{
 draw_line(gridx[i,n],gridy[i,n],gridx[i+1,n],gridy[i+1,n])
 if(n<ceil(room_height/size)+2) //checking to make sure that there is a line after this to average with
 draw_line((gridx[i,n]+gridx[i,n+1])/2,(gridy[i,n]+gridy[i,n+1])/2,(gridx[i+1,n]+gridx[i+1,n+1])/2,(gridy[i+1,n]+gridy[i+1,n+1])/2) //drawing the average line
}          

I do not think that I have any code here so far that could be improved, I just included it just in case I missed something. This is what I really need help with, my step event where I simulate the grid.
Here it is:
for(i=1;i<ceil(room_width/size)+2;i+=1)
for(n=1;n<ceil(room_height/size)+2;n+=1)
{
 gox[i,n]=gox[i,n]/fric //Friction on the momentum, fric is a variable I define elsewhere so that I can tweak it.
goy[i,n]=goy[i,n]/fric
 spring(0,-1) //Spring is a code that I have also posted below, it adds the force of a spring in between each point to gox and goy
 spring(0,1)
 spring(-1,0)
 spring(1,0)
}

for(z=0;z<instance_count;z+=1) //this is where I go around to each instance, and check how it affects the grid
if(instance_exists(instance_id[z]))
{

  xx=round(instance_id[z].x/size)
  xxx=instance_id[z].x
  yy=round(instance_id[z].y/size)
  yyy=instance_id[z].y
  frce=instance_id[z].force //each object has a force, which is the amount of force it puts on the grid
  rng=instance_id[z].range // each instance has a range, which is the radius of its effect on the grid

  for(i=xx-rng/size;i<xx+rng/size;i+=1)
  for(n=yy-rng/size;n<yy+rng/size;n+=1) //I go to each point on the grid within the range of the instance, and affect it accordingly
  {
  if(i>0 && i<ceil(room_width/size)+2 && n>0 && n<ceil(room_height/size)+2) //making sure that the point im affecting is actually on the grid
  {
    eff=rng-point_distance(xxx,yyy,gridx[i,n],gridy[i,n])
    if(eff>0)
    {
    dir=point_direction(xxx,yyy,gridx[i,n],gridy[i,n])
    gox[i,n]+=cos(dir/180*pi)*eff*frce
    goy[i,n]-=sin(dir/180*pi)*eff*frce
    }
  }
  }
}
for(i=1;i<ceil(room_width/size)+2;i+=1)
for(n=1;n<ceil(room_height/size)+2;n+=1) //adding the movement that has been calculated to each point
{
 gridx[i,n]+=gox[i,n]
 gridy[i,n]+=goy[i,n]
}

finally I have the spring code, which i use in the step event.
dist=point_distance(gridx[i,n],gridy[i,n],gridx[i+argument0,n+argument1],gridy[i+argument0,n+argument1])-size
dir=point_direction(gridx[i,n],gridy[i,n],gridx[i+argument0,n+argument1],gridy[i+argument0,n+argument1])

gox[i,n]+=cos(dir/180*pi)*-springforce*dist
goy[i,n]-=sin(dir/180*pi)*-springforce*dist

I would post my entire project, but I have GM for mac, so not many people would be able to see it. if anyone with a mac wants me to post it I will though.
I would appreciate any help, and if anything is unclear then just ask. THANKS!!!

Edited by lolmister, 22 February 2012 - 05:32 AM.

  • 0

#2 kibblesbob

kibblesbob

    "Xarrot Studios"

  • GMC Member
  • 212 posts
  • Version:GM:Studio

Posted 22 February 2012 - 04:30 AM

- for statements take longer than repeat statements, so you could switch them out and replace them all with 'repeat's

- inside of your for statements, you are doing:

if(instance_exists(instance_id[z]))
    {
    xx=round(instance_id[z].x/size)
    xxx=instance_id[z].x
    yy=round(instance_id[z].y/size)
    yyy=instance_id[z].y
    frce=instance_id[z].force //each object has a force, which is the amount of force it puts on the grid
    rng=instance_id[z].range // each instance has a range, which is the radius of its effect on the grid
    }

You are calculating EACH and EVERY SINGLE TIME,
instance_id[z]
and this is quite slow, I suggest making a variable for it like:
inst_id = instance_id[z]


These improvements should help a bit, especially if this is your draw/step code.

Edited by kibblesbob, 22 February 2012 - 04:31 AM.

  • 1

#3 lolmister

lolmister

    GMC Member

  • New Member
  • 4 posts
  • Version:Mac

Posted 22 February 2012 - 04:41 AM

Thanks kibblesbob, I put in those changes and the fps went up, not tremendously, but about 10-11 frames per second up from 5-6 when I make the grid small. Though, I still need to find a way to do this more effectively, I read somewhere that geometry wars simulates upwards of 6,000 points, and right now the best i can do at a stable frame rate is about 67. I also just realized that I simulate each connection between points twice, so if anyone else has suggestions i would be very gratefull

Edited by lolmister, 22 February 2012 - 05:20 AM.

  • 0

#4 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • Retired Staff
  • 15415 posts
  • Version:GM:Studio

Posted 22 February 2012 - 07:02 AM

instead of draw line, use primitives

The following functions exist for drawing primitives


draw_primitive_begin(kind) Start a primitive of the indicated kind.
draw_vertex(x,y) Add vertex (x,y) to the primitive, using the color and alpha value set before.
draw_vertex_color(x,y,col,alpha) Add vertex (x,y) to the primitive, with its own color and alpha value. This allows you to create primitives with smoothly changing color and alpha values.
draw_primitive_end() End the description of the primitive. This function actually draws it.

that should make is much faster than doing individual draw_lines. You can use a d3d model too.

Also note playing with UVs with a proper texture instead of the position of the line points could allow the effect with less data points.
http://www.gmlscript...pic.php?id=1688

Finally. if you want to really dive in. You can move your grid modification and d3d model generator in a dll using the gmapi library (if in gm7 or 8)
  • 0

#5 xot

xot

    GMC Dismember

  • Retired Staff
  • 4772 posts
  • Version:GM:Studio

Posted 22 February 2012 - 09:16 PM

Your spring code is pretty costly. I think you could achieve the same results with something along the lines of:

ii = i+argument0;
nn = n+argument1;
gox[i,n] += (gridx[i,n] - gridx[ii,nn]) * springforce;
goy[i,n] += (gridy[i,n] - gridy[ii,nn]) * springforce;

I didn't test that. I might have gotten the grid terms backwards.

I see some similar code in your step event.

General advice:

I see a few places where you are performing checks inside loops before doing something. See if you can restructure your code and system so that these checks aren't necessary, or can be performed outside of the loop, or can be solved with redundant data.

Reduce function/script calls as much as possible. There is a pretty large speed penalty for simply calling a script, regardless of what it does.

Any time I'm doing something that requires a lot of math on a grid structure, I see if I can solve the problem using the ds_grid math functions. They can perform operations on entire grids with one function call and can produce exceptional speed gains in many situations.
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users