How do I reduce lag with a scene full of actors that need collision checking?

Fayabella

  • Posts: 239
Okay, so I got the hxscout to work.

I think I figured out the problem: A behavior I've downloaded from StencylForge that z-orders my scene.

Disabling it, there seems to no longer be any lag in the trees.

But I kind of need z-ordering.

Is there a simple way to do z-ordering that doesn't cause lag?

Sorry if I'm asking too many questions, just, I want to reduce the lag without reducing game features.

Thanks!

CmdrWhitey13

  • Posts: 505
Any idea as oppose to setting up hxscout? I have tried an may have your issue as well.

merrak

  • *
  • Posts: 2738
Okay, so I got the hxscout to work.

I think I figured out the problem: A behavior I've downloaded from StencylForge that z-orders my scene.

Disabling it, there seems to no longer be any lag in the trees.

But I kind of need z-ordering.

Is there a simple way to do z-ordering that doesn't cause lag?

Sorry if I'm asking too many questions, just, I want to reduce the lag without reducing game features.

Thanks!

I'm not familiar with that behavior, but I suspect there are unnecessary checks that can be eliminated to optimize it. Can you post a screenshot of the behavior code?

Fayabella

  • Posts: 239




The only input on the behavior is the layers I want to z-order.

JeffreyDriver

  • Posts: 2262
It looks like the 'when updating' event is the issue. Would it not work in a 'created' event?

Updating events run 100 times per second so the 'do after' code is also being triggered 100 times per second.

Fayabella

  • Posts: 239
What about a 'do every N seconds' event? I can't do that as a 'created' event because I need the z-order of objects to be updated constantly.

So instead of 100 times per second, I could do every .05 seconds to trigger 20 times a second?

I'm gonna test that right now. I'll get back to you with the results.

Fayabella

  • Posts: 239
Ok, it's definitely better after fixing that; however, it still lags a little, and that's just with trees only.

Is there any way I can reduce this further or do I just have to live with the lag?

JeffreyDriver

  • Posts: 2262
There's always something that can be tweaked and optimised. Are you sure that you need collision shapes? You could instead check if your player is within a certain distance of a tree.

Fayabella

  • Posts: 239
Could you elaborate? Not sure if I understand.

I've thought of disabling collisions unless the player is within one tile of the tree, but that might be counterproductive because then, the trees will each have to be checking the distance between themselves and the player instead of just doing nothing.

merrak

  • *
  • Posts: 2738
There's a lot of opportunities to make this faster for your particular needs.

I don't know why there's a 0.02 second delay in the updating event. I suspect this was a fix to prevent the re-ordering from occurring before all the actors loaded. In that case, this isn't an efficient way to impose a delay, since you're constantly creating and deleting listeners. Try replacing the do after loop with an 'if (attribute) is true' wrapper. Set the attribute to false initially. Then, in the 'on created' event, say 'do after 0.02 seconds, set (attribute) to true'. This will take the do after wrappers out of the always event and still impose the 0.02 second delay

Next, you shouldn't need to be constantly reordering every actor. You only need to order the trees when they're initially placed, then insert moving actors into the z-order list when their y-value changes. This is your biggest bottleneck here. An actor's z-value only needs to be set if it moves vertically, or is created and placed into the scene. Even then, you only need to set that particular actor's z-value. You don't need to change all of the other actors'.

Fayabella

  • Posts: 239
1st paragraph:
There isn't an 'on created' event, where should I be setting and resetting this attribute? (The delay is happening in a 'every .075 secs' event)

2nd paragraph:
So how exactly would I do this? I didn't write the behavior, so I don't know how I could modify it without messing it up.

merrak

  • *
  • Posts: 2738
1st paragraph:
There isn't an 'on created' event, where should I be setting and resetting this attribute? (The delay is happening in a 'every .075 secs' event)

2nd paragraph:
So how exactly would I do this? I didn't write the behavior, so I don't know how I could modify it without messing it up.

1-- You'll need to create it. I attached an example from one of my behaviors--how I usually set this kind of delay up (ignore the other blocks, just look at the last wrapper).

2-- This is where things get tricky. You're probably better off writing a new behavior from scratch and using the current one as an example of how to use blocks to manipulate z-order. This same topic actually came up in the Discord Chat not too long ago. Torcado mentioned he had a write-up of how he did z-order in Bunosphere, and the source is also available for illustration. I don't know where the write-up is. I'd expect his solution would be better than mine for your game, since the solution I wrote up is designed for a game with a 3D world and an isometric perspective, and so I'm thinking about things different than for a 2D game world and oblique projection.

Also see: http://community.stencyl.com/index.php?topic=47517.0  But the haxecoder link they post is dead. I think this is the original text, though: https://keyreal-code.github.io/haxecoder-tutorials/59_depth_sorting_in_openfl.html

Fayabella

  • Posts: 239
Ok, this is all just going over my head. I'm lost.   ???

I find it hard to understand the 'z-index' of Stencyl in the first place. In programs like Gamemaker, you can set the depth to whatever number, and any sprite on any number (layer) will be in front of anything on the number above it, and behind anything on the number below it, allowing you to just set the depth to a y-value of a sprite and just be done with it.

Stencyl's z-index seems to work differently, and I don't know how to work with it, let alone write a whole new behavior for it.

I tried replacing the 'do every n secs' with a custom event, and ran that custom event if the player was moving, but it didn't help the performance since it just checked the same amount of times as before, just only when the player was moving.

Could you perhaps explain it a little more? I can't seem to grasp what you're telling me.

merrak

  • *
  • Posts: 2738
Could you perhaps explain it a little more? I can't seem to grasp what you're telling me.

Here are some basics. Stencyl is built on top of OpenFL, so it's helpful to understand a little about how OpenFL handles these kinds of things.

OpenFL implements Sprites, which you can take as anything visible or tangible in the scene. These include images, Actors, and even Layers. So you can think of Layers as large, invisible Sprites

Every Sprite can have child Sprites. If you're not familiar with this analogy, think of paper cut-out animation (like in South Park) where different visuals are glued together. In this example, the body is the parent Sprite, and the eyes, mouth, clothes, etc. the child Sprites. This hierarchy can be multiple levels deep. For instance, the eyes are child Sprites of the body, and each eye has a child Sprite of its own--the pupil.

There are a lot of advantages to this architecture. If you move the parent Sprite, the children move along with it. If you hide the parent Sprite, the children all hide as well.

So what you need to visualize is that every Sprite has a list of children, and z-index refers to the child's position in this list. Since a Layer is just a Sprite, then each actor's z-index is its position in the Layer's list of children.

Here are two approaches to implementing z-index based depth. You can continuously sort the list of children. This is the approach your behavior you're using takes. It's the simpler solution, but comes at the cost of not scaling very well when the number of actors gets large. The other approach is to insert actors into this list as they're created, and change their position as they move. This approach is more complicated to program, but will result in faster z-ordering.

The problem you're running into with the trees is that there are a lot of actors to continuously sort. So you either need to implement a more efficient sorting routine, or reduce the number of trees.

Keep in mind you don't actually have to delete trees to reduce their number. All you really need to do is find a way to not sort every tree. I thought of another solution that might work. I noticed your behavior loops through every layer. What if you broke your map up into small, screen-sized sections, and assigned a layer to each section. Modify the behavior so that instead of sorting  every actor on every layer, it only sorts every actor on the visible layer.

Fayabella

  • Posts: 239
Thank you. I understand the z-ordering now.

So basically, I need to only update the list when the player is moving/an object is created on the layer/any object is moving(like an enemy or animal)?
Modify the behavior so that instead of sorting  every actor on every layer, it only sorts every actor on the visible layer.
Does 'for each [actor on screen]' not already reduce the amount of actors being sorted? Or is that every actor in the scene?