Jump to content


Photo
- - - - -

1000000 Instances! New (jan 12 2008)


  • Please log in to reply
30 replies to this topic

#1 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 12 January 2008 - 08:37 AM

  • Title: 1000000 Instances!!!!
  • Description: Using titled surfaces for blood splatter or other inanimate images
  • GM Version: :GM7:
  • Registered: yes
  • File Type: .gmk
  • File Size: 0.04MB
  • File Link: http://www.host-a.ne...owCostItems.zip
  • Required Extensions: none
  • Required DLLs: none
Summary


1000000 Instances!!!! Well, it looks like it... They are fake though.

This tutorial shows how to have numerous inanimate instances on the ground without taking too much CPU.

You may skip to the good stuff below if you know this…

The problem many people have when trying to leave dead bodies on the ground or bullet casings or tire marks is threefold.

1) People make the mistake of disabling code in the step event when an item is no longer “living”,
2) People realize that eventually this method (1) cause GM to slow down and try to limit the damage by giving a lifespan to the dead item… Fading it until it is no longer visible. This resolved some issues but, eventually the CPU will no longer be able to keep up at around 200-400 instances + living instances.
3) People usually forget that instances still draw when outside the room.

Let’s solve problem 3 first.

+++++++++++++++
edit... this fact is currently being debated here
http://gmc.yoyogames...opic=353363&hl=
In the draw event
if(bbox_bottom<view_yview[view_current]) exit;
if(bbox_right<view_xview[view_current]) exit;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) exit;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) exit;
draw_sprite_ext(sprite_index,-1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)

There… That will stop the instance from drawing itself. A faster solution is to disable the instance outside the room but this generic solution is the most viable for instance you wish to keep active… I realise this is a tutorial on how to alleviate CPU on dead instance… I’m just saying you should have this piece of code in all of your “on screen” object’s draw event, no matter what. You’ll see, in a large room, this is the difference between 20 FPS and 90.


edit... this fact is currently being debated here
http://gmc.yoyogames...opic=353363&hl=

I am now recomending not to do this unless you have code in the draw event (more than 5 lines).

It turns out I am about the only one so far that benefits from this check when only draw_sprite is called.

So, if you have a draw event because of other things like effects, please test if your code benefits from this check. It's simple... Just run the test bench in that thread. If you do not benefit from the check with the test bench, it means you are like 90% of the posters there, it means your PC is like most people...

It means you will truely see if the check improves perfomance in your case. Then add the check to your draw event and see if the performance increases.

If the test in that thread bench shows you get improvement from the simple check, your PC is not qualified to check your code... You will need to ask someone else to do it...

I do hope I worded all this correctly.

+++++++++++++++++

OK, now for the 1st item… How do I make an instance static… Disabling it without using code? Well, you clone it and destroy the original…

For that you need an object that will draw the image of the original and nothing else… It’s simple really, as long as all you need is to draw the image of the instance, all you need is pass along the state of the image to the clone.

Lets name the clone LowCostObj. It uses the draw event method mentioned above. That’s all it does… It’s a matter of setting it up.

Some "need to know" before "the good stuff"
Here is the script to clone an instance
When your instance dies, you call this script.

SCRIPT MakeLowCost
with(instance_create(x,y,LowCostObj))
{
   sprite_index = other.sprite_index;
   image_index = other.image_index;
   image_xscale = other.image_xscale;
   image_yscale = other.image_yscale;
   image_angle = other.image_angle;
   image_blend = other.image_blend;
   image_alpha = other.image_alpha;
}
instance_destroy();
So, instead of instance_destroy(), you call MakeLowCost() and presto, you have a clone of the instance… Killing the original…

But still, having too many of those will kill your CPU, so you need to handle 2)… Fading and destroying the clone

It’s good to leave the clone intact for some time then fade it out. The best method is to set an alarm when the clone is created, so the clone does nothing for a while. When the alarm is done, you start to fade… Doing so right in the alarm, not the step event.


On Create
alarm[0] = room_speed * 4;//4 seconds good enough

On alarm[0]
image_alpha -= 1/(room_speed*4) //4 seconds to fade

   alarm[0] = 1;

   if(image_alpha <=0) instance_destroy();

That’s it, this give it life span of four seconds with a four second fading… You could use image_alpha -= .1 and set alarm[0] to room_speed, giving a longer but less smooth fading over a longer period, so the CPU only does a little every second. You may remove the alarm entirely if you plan not to fade and destroy the clone… It will save on CPU cycles (if you plan on not having that many instances)… Me, I like the soft fading… Which we will not use anyway. That is right… We won’t… Having 1000 dead instance fading off (or staying inactive) will still kill your CPU.

The good stuff
We only implemented good solutions to problem 1, 2 and 3 but still, it does not fix the overall problem that is the goal of the tutorial; having numerous “dead” instances.

So, how do we solve this?

TILED SURFACES and freaky (but simple) coding.

The idea of surfaces is not new but most implementations try to draw a single surface to the entire view (not screen) which means if your view is 5000x5000, forget it…

We will tile a bunch of small(er) 256x256 surfaces that will capture the dead instances and remember them.

The basic logic is simple… tile a bunch of surface handling instances in the room, each having a surface to draw and each having the task of catching a dead instance. All along trying not to kill the CPU or video memory. So, the step event is off limits… Besides, the collision event is much better at catching things…

So, on collision, we catch the instance, draw it onto the surface and on paint, we draw the surface. Simple. But what instance do we catch? Some of you might have guessed already… We already have our cloning system… so all we need is to catch those clone (sounds like a game).

So, the logic is Catch the clone, copy it to the surface and kill the clone. Then draw the surface on draw. The impact is minimal since the number of clones will instantly drop to 0 each step.

Let call our surface handler LowLowCostObj… And set it’s MASK to a 256x256 square non transparent red sprite, no precision collision (it’s square) with x,y origins set to 0,0. That will make the collision happen and simplify our calculations…

Pseudo code
On create
Surface = create surface

On collision with clone
Draw clone on surface
Destroy the clone

On draw
If inside the view,
Draw the surface.

The only problem with that is if the clone is not fully on the surface, only a portion is caught. So we tile a bunch of surface handlers. Now the problem it that overlapping clones will be destroyed and the collision event of the other surface handler will not happen. So, we need to delay the destruction of the clone so all surface handlers have their way with it. A simple alarm in the clone set to 1 will delay the destruction to the beginning of the next step, allowing all the collision to be handled.

On collision with clone
Draw clone on surface
set clone alarm[1] to 1 (alarm[0] is taken already)

And in clone alarm[1]
Destroy self.

So that takes care of the system. The last issue if failure handling.

You can’t create the surface in the create event. The surface may become invalid. And you may not even need it for the handler if nothing happens over its position. So, you delay the creation of the surface to the collision event and check if it exists every time we draw (which is the proper method when using surfaces).

Another problem is if the computer cannot or can no longer create surfaces… Video memory is blown… We need to revert to the original handling (the fading) and stop trying to create surfaces if that happens.

So, the new create event is
surface = -100;
retrymax = 10;
retry = 0;

The collision with LowCostObj is
if(!surface_exists(surface))
{
   surface = surface_create(256,256);
   if(!surface_exists(surface))
   {
	   retry+=1;
	   if(retry>=retrymax)
	   {
		   instance_destroy();
	   }
	   exit;
   }
   retry = 0;
   surface_set_target(surface);
   draw_clear_alpha(c_black,0);
}

surface_set_target(surface);
with(other)
{
   draw_sprite_ext( sprite_index, -1, x-other.x, y-other.y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)
   alarm[1] = 1;
}
surface_reset_target();

And the draw is
if(bbox_bottom<view_yview[view_current]) exit;
if(bbox_right<view_xview[view_current]) exit;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) exit;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) exit;
if(!surface_exists(surface)) exit;

draw_surface(surface,x,y);

Oh, and to clean up
On Room End
if(!surface_exists(surface)) exit;

surface_free(surface);

So, now, when the object detects a clone, it tries to create the surface if it did not do it prior… It will try and fail a few times before committing suicide, leaving the clone to revert to its fading method.

All we need now is a tiling method. For that, we create a 3rd object that you will drop in the room. LowLowCostTileRoomObj

On Create
var i,j;
for(i = 0;i<room_width;i+=256)
   for(j = 0;j<room_height;j+=256)
	   instance_create(i,j,LowLowCostObj)
	   
instance_destroy();


Ok, lets recap…
You drop a “Tiler” object in the room. It tiles the room with the surface handlers…

The “surface handlers” do not draw until in view and until they actually have stuff to draw. They have a collision mask the size of the surface and capture any clones that collide with them (created over them)

The “clones” duplicate the look of the instance we destroyed using MakeLowCost(). And will fade away if they were not captured…

In your objects, you destroy the instance using MakeLowCost() and you are set…

Note, you can also create objects and set the parent to LowCostObj such as the tire marks in the example (Last Room)… If you need to have a damaged version of the instance that “died”, create a dead version, set the sprite to the dead looking sprite and set the parent to LowCostObj.

Now to create the dead looking inactive version of the instance, in the destroy event (which was called using instance_destroy() in this case, the code will look something like this…

with(instance_create(x,y,DeadLookingVersionObj))
   {
	   image_angle = other.image_angle;
   }
…copying over the proper state of the image, in this case only the image angle is relevant.


Note. All is not carved in stone, you may create a dead looking instance elsewhere than the destroy event… The tire thread in the example are created every step.

Also, even if this method handles large view, in reality, you may still have problems if the view requires 1000 surface handler instances each with its surface… that’s 1000 * 256 * 256 * 4… 256MB. Fortunately, the code self fixes itself to accommodate this issue but be aware that some video card may fail early.


So, I added a safeguard to the clones… They will destroy any other old clones when the limit is reached

On create
If(limit reached) destroy first clone in the clone list

Note the depth of the surface tiles is 1 and so are the clones. So make sure you don’t have anything under there or change the depth to match your game. You may implement the same system at different depths but be aware that each surface tile at each depth must be unique/different and handle it’s own clones besides the supplied example

By this I mean, if you want a LowLowCostDepth10000, you should have a LowCostObjDepth10000 so there is no conflict with overlapping surface handlers at different depths.

Also, if you set Interpolate Color Between Pixels in the game options you may have to call…
texture_set_interpolation(false)
//drawing to surface code in collision
//…
texture_set_interpolation(true)
…if you find odd differences between the original image and the fake one.

Finally, you can set the parent of any static “décor” objects to LowCostObj that you may want add in the room. Just add a (possibly empty) code box in the create event to disable the fading and setup the object. Be aware that if the system starts to fail during the game, and the surface is lost, you may loose valuable details.

Don’t let all these warnings scare you. They are all known issues using surfaces.

Have fun!
Icuurd12b42

Oh yeah, a little credit is always fun!

Edited by icuurd12b42, 22 July 2011 - 07:21 PM.

  • 4

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#2 WarriorArtiste

WarriorArtiste

    3d Creator

  • New Member
  • 1032 posts

Posted 12 January 2008 - 07:29 PM

Or you could just 1 instance draw everything and be a lot faster! :P
  • 0
Ultimate 3D 2.1 April 2, 2008!

-33% of the population are Zoogles, 34% of the population are Yoodles, and 100-(34+33)% of the population are noodles. If you put this in your signature, I'm alright with that, if not, that's fine too.

#3 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 14 January 2008 - 05:58 AM

Or you could just 1 instance draw everything and be a lot faster!  ;)

<{POST_SNAPBACK}>


Want to wager 100,000,000$ on that asumption?
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#4 jabelar

jabelar

    GMC Member

  • GMC Member
  • 3003 posts

Posted 30 January 2008 - 09:27 PM

I like the idea of the low-cost cloning.

The one tip I'd disagree with is your first tip about not drawing the sprite for off-screen instances ... the code actually slowed my game down.

I have a "fog of war" I'm working on which restricts visibility until a unit comes within line of sight. The fog of war is implemented in 16x16 grey squares, and I'm using objects (instead of tiles) because I found that figuring out "collisions" with tiles was just as slow (and much more complicated) than relying on the built-in collision system for objects.

Anyway, I tried your code just for the fog of war object and it dropped the FPS down to 13 from 23 (goal is 30).

Drawing the sprite does take some CPU work (if I simply disable drawing the sprite it speeds up to 30 FPS). However, the if statements you suggest slow it down again. Perhaps it is because I do my FPS testing on an older computer or something ...
  • 0

#5 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 01 February 2008 - 06:29 AM

I like the idea of the low-cost cloning.

The one tip I'd disagree with is your first tip about not drawing the sprite for off-screen instances ... the code actually slowed my game down. 

I have a "fog of war" I'm working on which restricts visibility until a unit comes within line of sight.  The fog of war is implemented in 16x16 grey squares, and I'm using objects (instead of tiles) because I found that figuring out "collisions" with tiles was just as slow (and much more complicated) than relying on the built-in collision system for objects.

Anyway, I tried your code just for the fog of war object and it dropped the FPS down to 13 from 23 (goal is 30).

Drawing the sprite does take some CPU work (if I simply disable drawing the sprite it speeds up to 30 FPS).  However, the if statements you suggest slow it down again.  Perhaps it is because I do my FPS testing on an older computer or something ...

<{POST_SNAPBACK}>


Yes... I have another thread going on on the subject of checking before drawing... It's turn out I am the only one that benefits from the check. Unless your draw event does a lot of other things, I now recomemend not doing the check at all as the majority of people will not benefit from it.

http://gmc.yoyogames...opic=353363&hl=
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#6 LegacyCrono

LegacyCrono

    GMC Member

  • GMC Member
  • 616 posts

Posted 02 February 2008 - 07:07 PM

I believe this "outside-room" checking is more efficient if you put the code on "step" event and, when outside the room, simply set visible to false:
visible = true;
if(bbox_bottom<view_yview[view_current]) visible = false;
if(bbox_right<view_xview[view_current]) visible = false;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) visible = false;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) visible = false;
Still, I may be wrong, anyway... I couldn't test it, but it should make things speed up, since the "draw" event isn't called.

Nice tutorial, preety well-explained, and the low-cost clonning is a cool idea.

BTW, you said using a single object to draw every sprite won't make things quicker. If you don't use the surface thing, you can store sprite drawing informations in a data structure (mainly a grid) and use a single object to draw them. This'll surelly speed up the proccess, since there's no object handling (no alarm, step or other events...). Alpha values can be subtracted every drawing, and when a sprite's alpha is 0 it is deleted from the data structure. Once more, I haven't tried, it's just a theory... :( But should work fine.

SEE YA!!!!!
  • 0

Posted Image


#7 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 04 February 2008 - 09:47 AM

I believe this "outside-room" checking is more efficient if you put the code on "step" event and, when outside the room, simply set visible to false:

visible = true;
if(bbox_bottom<view_yview[view_current]) visible = false;
if(bbox_right<view_xview[view_current]) visible = false;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) visible = false;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) visible = false;
Still, I may be wrong, anyway... I couldn't test it, but it should make things speed up, since the "draw" event isn't called.


Correct (if most are invisible), but currentview would by out of context, perhaps defaulting to 0...

But the refence thread I linked to regarding this issue suggests the extra 4 lines actualy cost more than letting the video card decide.

If the code was in the draw event, not the step, you would certainly benefit once the instance is invisible since the 4 lines would no longer be interpreted... But not when visible, again, the extra cost of the 4 lines.... But how would you turn it back to visible if in the draw.

Nice tutorial, preety well-explained, and the low-cost clonning is a cool idea.

Thanks

BTW, you said using a single object to draw every sprite won't make things quicker. If you don't use the surface thing, you can store sprite drawing informations in a data structure (mainly a grid) and use a single object to draw them. This'll surelly speed up the proccess, since there's no object handling (no alarm, step or other events...). Alpha values can be subtracted every drawing, and when a sprite's alpha is 0 it is deleted from the data structure. Once more, I haven't tried, it's just a theory... :) But should work fine.


Actually, no, looping through a grid and taking over the drawing that way is the least efficient method.

Compounded with the decision to draw if in view, you also have the loop and the grid find value to deal with... More interpreted code than the already proven slow "if not in view exit draw" method. Not to mention you are now limited to one sprite per cell and the dreaded "too many things to draw"

At that point, you SHOULD use tiles since you are basically doing the same thing as GM's internal tile system. That is the fastest method for drawing inactive sprites, aside from the surface method of course. But you would need them to be in your background resource already.

You can consider my surface tiling method as the grid looping system you mentionned. Except the looping is handled by GM native code... Where each grid cell is 256x256, each cell holding one image containing what looks like hundreds (if not millions) of images.
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#8 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 04 February 2008 - 03:18 PM

The grid looping thing is as fast as just leaving each object separate on the floor. I have tried this. The only way to draw infinite sprites on the screen (bullets, blood and so on) would be using surfaces, and I have used this method in numerous projects, so I can assure that it is also fast, and if you use 1024x768 big surfaces and just tile them, then it will also work on old hardware.
  • 0

#9 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 05 February 2008 - 01:53 AM

1)The grid looping thing is as fast as just leaving each object separate on the floor. I have tried this. The only way to draw infinite sprites on the screen (bullets, blood and so on) would be using surfaces, and I have used this method in numerous projects, so I can assure that it is also fast, and if you use 2)1024x768 big surfaces and just tile them, then it will also work on old hardware.

<{POST_SNAPBACK}>


1) It depends on your PC. Most likelly, with slower PC, gml interpretation will be slower... And the bigger the room, to slower it would get... But, if you are smart enough to optimise the grid fetch to only get grids cells in view (using floor((viewx+dx)/celxwidth) or something like that), yes it will be fast. But, like you said, most likely as fast as leaving instances for most users.

2) That surface is too big for my geForce 7600 when creating many tiles, it will fail. Yes I can create a few that big, but not many. My code fails with 512x512 size surfaces (smaller than yours). 256x256 is the size for me.
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#10 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 05 February 2008 - 02:23 PM

icuurd12b42: It doesn't really matter if you have several 256x256 or one 1024x768, its just that there is the texture size limit, so some gfx cards won't even create surface with 2048x2048, but 1024x768 should be possible on all modern gfx cards.
  • 0

#11 topogigio

topogigio

    GMC Member

  • New Member
  • 1 posts

Posted 05 February 2008 - 06:08 PM

i'd like to use your example but my pc can't handle more than 5 lowlow instances active. the others will self destruct.
Is your method expensive on video memory?
I'd like my game to be playable on slower machines so us there a way
to reduce the cost?
  • 0

#12 LegacyCrono

LegacyCrono

    GMC Member

  • GMC Member
  • 616 posts

Posted 05 February 2008 - 07:42 PM

1) It depends on your PC. Most likelly, with slower PC, gml interpretation will be slower... And the bigger the room, to slower it would get... But, if you are smart enough to optimise the grid fetch to only get grids cells in view (using floor((viewx+dx)/celxwidth) or something like that), yes it will be fast. But, like you said, most likely as fast as leaving instances for most users.


I think you guys misunderstood the grid method.

Think on the grid as a table. The columns are: sprite index, image index, x, y, x-scale, y-scale, angle, blend and alpha. Each line is a sprite that'll be displayed on the screen.
Using a grid as "another screen" is unnecessary and will make the game slow down.

You can use other data structures, too, like queues or lists... For those, you'll need a different ds for each of the "columns" of the grid.

SEE YA!!!!!
  • 0

Posted Image


#13 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 05 February 2008 - 11:19 PM

I think you guys misunderstood the grid method.

I didn't, he did. As I said, I have tried this and actually lost speed a lot, it was a lot faster to leave instances (I said something different before, because I had forgotten my results from the test). This is my test from the past, then I had a VERY crappy computer and video card had 16mb of vram, this is what I got:
//uses array to store blood data
//~100 blood pools = 1-2 FPS loss (starts to loose fps fast)
//uses objects to store blood
//~1000 objects, 1-2 FPS loss (starts to loose fps)
//uses surface to store blood
//more then 4500 pools, no frame drop
//THE BEST WAY
In the surface method I had 640x480 (size of room) and my crappy gfx had no problem, so I don't believe you have problems with 7600 when having larger surfaces then 256x256, because you should be able to create A LOT of them until you ran out of vram. I don't know why a actually wrote the number of pools in surface version, because it doesn't matter on how many you have drawn. Now I retested this with my new monster PC, and now I have these results:
Array method, 2542 blood pools (the sprite) and started to loose framerate.
Object method, 5505 blood pools and started to loose framerate.
Surface method, infinite number of blood pools, no frame loss.

Maybe using grid instead of array would speed it up... but I don't believe it will be that much that it will be a better solution than surfaces. Also, I didn't hold things like rotation ect. in array, only x,y, and image_single variables. So if I had saved everything, then it would slow down even more.
  • 0

#14 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 05 February 2008 - 11:49 PM

icuurd12b42: It doesn't really matter if you have several 256x256 or one 1024x768, its just that there is the texture size limit, so some gfx cards won't even create surface with 2048x2048, but 1024x768 should be possible on all modern gfx cards.

Please, I'm not talking through my hat here... Please reread what i said carefully. Looks like you forgot to read a few key words or sentences.

i'd like to use your example but my pc can't handle more than 5 lowlow instances active. the others will self destruct.
Is your method expensive on video memory?
I'd like my game to be playable on slower machines so us there a way
to reduce the cost?

<{POST_SNAPBACK}>

Yes, it happens. With my card, if I use 512x512, I can only tile half/aquarter of the room. If using 256x256, I can tile the entire room. I know the number of tiles will vary from card to card. That is why it reverts to the lowcost instance. So don't worry about it too much. Good cards will not have a problem. Super duper card would be able to use bigger tiles. Mine does not (it's a mid range GeForce 7600)

256x256 is to optimal speed/max coverage for my card. Bigger tiles are actually slower to draw and fail to created...

1) It depends on your PC. Most likelly, with slower PC, gml interpretation will be slower... And the bigger the room, to slower it would get... But, if you are smart enough to optimise the grid fetch to only get grids cells in view (using floor((viewx+dx)/celxwidth) or something like that), yes it will be fast. But, like you said, most likely as fast as leaving instances for most users.

I think you guys misunderstood the grid method.

Think on the grid as a table. The columns are: sprite index, image index, x, y, x-scale, y-scale, angle, blend and alpha. Each line is a sprite that'll be displayed on the screen.
Using a grid as "another screen" is unnecessary and will make the game slow down.

You can use other data structures, too, like queues or lists... For those, you'll need a different ds for each of the "columns" of the grid.

I think it is you who failed to see I fully understood every aspect of this solution... Even showing you an effective way to decide what cell to draw as opposed to loop through the entire grid.

Let's not a debate things we already covered and know. You don’t really think from my experience that I posted this tutorial without knowing this is the fastest method?

If you want to prove your idea is better, do what I did for the “if in view” speculation. Make a test program that tests all similar methods and make a thread and ask people to try it out and give you the result… You will see that even if it’s the solution on your PC, it may not be the solution at all.

Edited by KC LC, 06 February 2008 - 01:23 PM.

  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#15 csscom

csscom

    GMC Member

  • New Member
  • 74 posts

Posted 08 February 2008 - 03:59 AM

you could get one instance to draw all the dead bodies, instead of surfaces which i think would be fast seeing how only the sprite gets drawn no more no less., and the game will deal will use less varibles, because..
when you create an object gm has to set a bunch of new varibles into ram (i think)
or make varibles and put them some where

list of varibles which seem to be auto created once a object it created.

sprite_index
mask_index
x
y
image_index
friction
speed
hspeed
vspeed gravity

you get the idea all the blue varibles, which don;t need declaring.

but usally when you need a dead body on the screen you only need 4 or 3 varibles to draw it correctly like
-sprite_index
-image index(if there is only one image index for dead sprite then it saves you a varible)
-x
-y

so you can just destroy the dead body and get there varibles and thorw them on an object which will draw it

now you would make an array and just add a new body to the array.

so if you had an array which drew a max of 20 bodies.
then it would remeber 20 x 4 varibles
80 varibles instead of
all the auto created varibles for an object

say an objec has 10 varibles which don;t have to be declared
so that's 10 times 20 varibles

so 200 varibles versus 80.

and the surfaces idea the whole part of the screen copied would be heavier on the video card.

but maybe there's more to it than that.??
  • 0

#16 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 08 February 2008 - 07:56 PM

list of varibles which seem to be auto created once a object it created.

Every GM object has 49 built in variables. But somehow going trough an array and drawing the sprites is slower, than creating an object for every sprite.

Please, I'm not talking through my hat here... Please reread what i said carefully. Looks like you forgot to read a few key words or sentences.

Well you said you can't create many tiles of 1024x1024 or even 512x512, but even my voodoo3 16mb didn't have problems with tiling a pretty big room with those size (512x612) surfaces, so I just tough how can it be that a modern gfx card (low end or not) can't create many of these size surfaces. Anyhow, making it changeable could be a good thing in a game, so bad gfx card users could just use smaller tiles.

Anyway, this is the top 3 list of ways to use:
1)Surface method, creating surfaces and tiling them. Then just draw sprites on them when needed. Fast (can have as many sprites as you want) and does not need that great PC to use this method.
2)Object (fake object) method, creating an instance for every sprite. Can get slow when lots are created, old instances should be destroyed thus removing the visual decals.
3)Array, put x,y,image_angle, image_single, and sprite in an array, and then draw them where and when needed. Slower then object method for some weird reason.
  • 0

#17 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 10 February 2008 - 05:49 AM

list of varibles which seem to be auto created once a object it created.

Every GM object has 49 built in variables. But somehow going trough an array and drawing the sprites is slower, than creating an object for every sprite.

Because the loop is GML interpreted language. Not native. That is the main problem with such implementation. If GM created pure machine code, it would be faster. that is the main reason I go through great extent to let GM do the thinking(collision event)/looping (draw event)...

Please, I'm not talking through my hat here... Please reread what i said carefully. Looks like you forgot to read a few key words or sentences.

Well you said you can't create many tiles of 1024x1024 or even 512x512, but even my voodoo3 16mb didn't have problems with tiling a pretty big room with those size (512x612) surfaces, so I just tough how can it be that a modern gfx card (low end or not) can't create many of these size surfaces. Anyhow, making it changeable could be a good thing in a game, so bad gfx card users could just use smaller tiles.

The main reason people hate writing games for PCs there is so many differences from PC to PC.

http://gmc.yoyogames...dpost&p=2513109

Anyway, this is the top 3 list of ways to use:
1)Surface method, creating surfaces and tiling them. Then just draw sprites on them when needed. Fast (can have as many sprites as you want) and does not need that great PC to use this method.
2)Object (fake object) method, creating an instance for every sprite. Can get slow when lots are created, old instances should be destroyed thus removing the visual decals.
3)Array, put x,y,image_angle, image_single, and sprite in an array, and then draw them where and when needed. Slower then object method for some weird reason.

<{POST_SNAPBACK}>


1 and 2 are covered by this example. 3 I experimented with a while back and trashed the idea. Playing with a 64x64 grid on screen 16x16 sprite tiles. 4096 draw sprites in an interpreted loop. Yuk.

You remember that realistic sand example in that magazine? Just the looping was painful. Even after converting it to arrays.
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#18 LoopStan

LoopStan

    North-See Developer

  • GMC Member
  • 1398 posts

Posted 12 February 2008 - 03:04 PM

I think that alot of online games could benifit from this. THere may be a racing game and it will draw the tracks of the tires. Now, thats alot to send info to and from. SO i like ur idea.
  • 0

Posted Image


#19 armigus

armigus

    GMC Member

  • New Member
  • 94 posts

Posted 02 April 2008 - 05:44 PM

I'm having a problem hiding parts of my forest via your bbox method--the images are disappearing too soon. This version works:
[codebox]if(bbox_bottom+sprite_height<view_yview[view_current]) exit;
if(bbox_right+sprite_width<view_xview[view_current]) exit;
if(bbox_top-sprite_height>view_yview[view_current]+view_hview[view_curren
t]) exit;
if(bbox_left-sprite_width>view_xview[view_current]+view_wview[view_curren
t]) exit;
draw_sprite_ext(sprite_index,-1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)[/codebox]
  • 0

#20 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 03 April 2008 - 05:23 AM

I'm having a problem hiding parts of my forest via your bbox method--the images are disappearing too soon. This version works:

if(bbox_bottom+sprite_height<view_yview[view_current]) exit;if(bbox_right+sprite_width<view_xview[view_current]) exit;if(bbox_top-sprite_height>view_yview[view_current]+view_hview[view_current]) exit;if(bbox_left-sprite_width>view_xview[view_current]+view_wview[view_current]) exit;draw_sprite_ext(sprite_index,-1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)



Ha, you must have manualy set the bounding box. Like arround the tree trunk...

In any case, you may remove the check (in your case, if this is you entire draw event, remove the event entirely) as it has been now proven that this actually slows down GM on most computers. Let GM decide to draw or not.
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#21 makerofthegames

makerofthegames

    My last custom title

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

Posted 08 April 2008 - 07:52 AM

Renaming a .gmk as .gm6 does nothing

Make it an exe, I can't load it.
  • 0

#22 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 11 April 2008 - 03:48 PM

Renaming a .gmk as .gm6 does nothing

Make it an exe, I can't load it.



Huh? Why are you renaming the GMK to a gm6 file when there is already a gm6 file included in the zip!!!???
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#23 makerofthegames

makerofthegames

    My last custom title

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

Posted 30 May 2008 - 07:36 PM

Renaming a .gmk as .gm6 does nothing

Make it an exe, I can't load it.



Huh? Why are you renaming the GMK to a gm6 file when there is already a gm6 file included in the zip!!!???

I don't know, I made that post awhile ago.
  • 0

#24 Glen

Glen

    GMC Member

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

Posted 20 June 2008 - 06:54 PM

//Draw_event//

if(bbox_bottom<view_yview[view_current]) exit;
if(bbox_right<view_xview[view_current]) exit;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) exit;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) exit;
draw_sprite_ext(sprite_index,-1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)

I tested this technique opposed to mine, and I get 5-10 more FPS with my technique which is:

//Alarm0//

if room=rm_level {if point_distance(x,y,o_player.x,o_player.y)<900 visible=true; else visible=false;} else exit; alarm[0]=25;

it makes a check every 25 steps and decides whether it should be visible. I chose 25 because it takes 25 steps for my character to reach an object that is 900 pixels away which is outside of my view in every direction. It keeps everything within 900 visible and everything beyond it invisible. All I do is put that code in alarm[0] and set alarm[0]=25 in the create event of the objects that have sprites. It worked with my objects that had a draw event, and ones that did not have a draw event. My reason for trying this technique was my game is suppose to run at 60 FPS and I had about 100 objects drawn to make a terrain. But the FPS jumped down to 30 with all the objects drawing their sprites every step. And I made a test where I unchecked visible on the terrain object and I had perfect 60 FPS. Turning off the visible function seemed to be much faster than just exiting a draw phase. And I used point_distance checks instead of a 4 line view check because it's less code coming from 100+ objects... totaling about 300 less lines than yours for simple position checking.

Try it out. You might like it more. I went from 30 FPS to 45-53 FPS out of 60.
  • 0
Avic Pro (Work in Progress):
Portable media manager. Just pop in your usb drive and use Avic Pro to organize and present all of your media content in categories. On top of that, it makes handling portable games, software, and other utilities a breeze. It allows you to launch just about any of your media content quickly and efficiently from your system tray. No more long paths to finding content.
Savage Defence| Text FX | Ragdoll Axe Engine | Professionalism | Online Games | Game Progression | 3D Game Development | Online Anti-Hack Strategies

#25 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 21 June 2008 - 12:40 AM

//Draw_event//

if(bbox_bottom<view_yview[view_current]) exit;
if(bbox_right<view_xview[view_current]) exit;
if(bbox_top>view_yview[view_current]+view_hview[view_current]) exit;
if(bbox_left>view_xview[view_current]+view_wview[view_current]) exit;
draw_sprite_ext(sprite_index,-1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)

I tested this technique opposed to mine, and I get 5-10 more FPS with my technique which is:

//Alarm0//

if room=rm_level {if point_distance(x,y,o_player.x,o_player.y)<900 visible=true; else visible=false;} else exit; alarm[0]=25;

it makes a check every 25 steps and decides whether it should be visible. I chose 25 because it takes 25 steps for my character to reach an object that is 900 pixels away which is outside of my view in every direction. It keeps everything within 900 visible and everything beyond it invisible. All I do is put that code in alarm[0] and set alarm[0]=25 in the create event of the objects that have sprites. It worked with my objects that had a draw event, and ones that did not have a draw event. My reason for trying this technique was my game is suppose to run at 60 FPS and I had about 100 objects drawn to make a terrain. But the FPS jumped down to 30 with all the objects drawing their sprites every step. And I made a test where I unchecked visible on the terrain object and I had perfect 60 FPS. Turning off the visible function seemed to be much faster than just exiting a draw phase. And I used point_distance checks instead of a 4 line view check because it's less code coming from 100+ objects... totaling about 300 less lines than yours for simple position checking.

Try it out. You might like it more. I went from 30 FPS to 45-53 FPS out of 60.



Yes, I mentionned this techniquie (alarm method) a few times in other threads. I know that is the best solution, except for very fast objects like bullets (which you should probably not use the check for anyway).

You take the maximal combined speed of your 2 fastest objects (heading towards one another) and that defines your alarm steps. For a larger room with many objects, you can even do it every second or 2 seconds... The border, in this case is current_view size + max combined speed * room_speed (*2 for 2 seconds).

But the point distance, now that was too obvious for me I guess. Good thinking. Instead of 4 checks, you only have 1. As long as your character is mostly centered, it should be the fastest method.


I will change my code in one of the games I'm fiddling with to use that. Thanks.
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#26 Glen

Glen

    GMC Member

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

Posted 21 June 2008 - 03:02 PM

I did a point distance check of 900 because my view is 640x480 and no matter where my character is on the screen, objects 900 pixels away are always outside of the view. So as long as the distance you are checking is far enough so your character can be anywhere on the screen, then it doesn't matter and you have the freedom of not being centered the whole time.
  • 0
Avic Pro (Work in Progress):
Portable media manager. Just pop in your usb drive and use Avic Pro to organize and present all of your media content in categories. On top of that, it makes handling portable games, software, and other utilities a breeze. It allows you to launch just about any of your media content quickly and efficiently from your system tray. No more long paths to finding content.
Savage Defence| Text FX | Ragdoll Axe Engine | Professionalism | Online Games | Game Progression | 3D Game Development | Online Anti-Hack Strategies

#27 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 22 July 2011 - 06:39 PM

Std Msg: Please use the tutorial template header (The Tutorial Clean Up Crew).
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#28 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 25708 posts
  • Version:GM:Studio

Posted 22 July 2011 - 06:47 PM

LOL! Icuurd, this is a fantastic tutorial that is EXTREMELY useful and I don't give a damn if it uses the tutorial template or not!

Staff Pick!

PS: You can clean/tidy it up in your own time...
  • 1

U1FVsm3.png

40799.png


#29 makerofthegames

makerofthegames

    My last custom title

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

Posted 08 August 2011 - 05:47 AM

Wait, did you just undo icuurd12b42's moderator action against his own topic? What is this, I don't even? Can you...what?
  • 0

#30 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 25708 posts
  • Version:GM:Studio

Posted 08 August 2011 - 06:31 AM

Wait, did you just undo icuurd12b42's moderator action against his own topic? What is this, I don't even? Can you...what?


Yes... Icuurd was being fair by following the rules and placing his tutorial i the rejected section until he could fix it up... but I used my moderator status to place this tutorial where it should be. And before you cry favoritism, I've moved more than a few posts that don't adhere to the template but are exellent tools for all GML programmers, and Icuurd has assured me via PM that he will fix the topic for the new rules.
  • 0

U1FVsm3.png

40799.png


#31 makerofthegames

makerofthegames

    My last custom title

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

Posted 09 August 2011 - 04:31 AM

It was just confusing. Especially since icuurd used the default message, asking himself to do something about it. He could probably have just edited his topic instead of doing that. :P
  • 1