[SOLVED] Handling off screen entities


(Kyuur) #1

Hi folks!

I currently have a system that demands a grid of entities with only graphics and a pixelmask. Right now, without any optimization, FP can handle roughly 75x75 entities without dropping below 30fps. It starts to drop with 100x100 and going up only slows it down more on my PC (AIR application by the way, not web).

I have tinkered with onCamera() and turning off super.render(), active and collidable in the entities, but there doesn’t seem to be much of a performance boost. This leads me to believe it’s the overhead of managing these entities performed by the World that is doing the most harm.

So I see two options:

  1. Remove and re-add the entities as they come on and off screen. This would require running through an array of entities and adding the ones near camera bounds, and removing those that aren’t. Would need to run every frame.

  2. Tinker with overriding the World update function. I’m kind of clueless here, it looks like it does the same kind of thing (maintaining an array of entities) but the functions to add and remove are private (probably with good reason). What would be done is stop updating the entities off camera entirely, but not have to remove them or add them again.

I am unsure how much overhead adding/removing a bunch of entities would add, if it would even be faster. Does anyone have any experience with a situation like this and could offer some suggestions?


Hints on improving performance
(Zachary Lewis) #2

It looks like World iterates through every Entity that’s been added to the world, asking it to update and rendering it if it is visible.

If you don’t want to update and render every Entity each tick, I’d suggest overriding World.update() and use a broad phase analysis (like a quadtree) to quickly determine if an Entity needs to update.

Another suggestion would be to explain exactly what you’re trying to do. You might think that your system “demands a grid of entities with only graphics and a pixelmask,” but it may not. Someone might have more efficient approach to solving your problem.


(azrafe7) #3

Hey, you’re suprisingly right on time with my thoughts (was going to post something along the following just a couple of hours ago, but then decided not to… aaaaaand bear with me!)

I’m very interested in finding a way to optimize some aspects of FlashPunk (especially collisions), and had messed with the core many times to make it work seamlessly with my little projects.

But the main thing I noticed is that there’s hardly a single way to get better performance. It will always vary depending on specific cases.

That said, I’m pretty sure some improvements can be done, and I wish we can all work on that. (Already had a couple ideas* floating around for a while and I’m willing to see if they lead somewhere comforting adjective.)

What I ask is to have a little playground to test them, a game-prototype with basic features (camera movement, sprite animations, dynamic scale, not-so-standard hitboxes, etc.), so that we could all try to improve the fundamental functions of FP and make it a bit faster. I know I could try to code the test-game myself, but having a somewhat real one would really help the process (so that actual problems can be addressed). Maybe I’m asking a bit too much… could you/anyone provide it?

Also… Would really be nice to have a github repo with the game-prototype + FP so that it can be forked | modified | improved by the community.



*

Some have already been proposed/partially implemented but…

  • internal viewport/culling
  • proximity grid for collisions
  • polygon mask (maybe with MarchingSquares as an alternative to Pixelmask)
  • layers array -> dictionary
  • namespaces

Testbed Environment Requirements
(Kyuur) #4

First off, I attempted my first idea and added the entities when they came into camera range. This is extremely fast, and causes no lag until the full scene is added after moving the camera around the entire area. The removing part, on the other hand, slows it down immensely. I’m not sure if there is a way to check if an Entity has been added to the world before removing, maybe that would help out some.

@zachwlewis I’m not all that familiar with quadtrees. Looking it up I can only find examples to help with collision (which makes sense to me with the “quadrants”). Any chance you could provide some very rough psuedo code?

What I am managing is a isometric tile system. Each tile has a x/y coord and a ‘height’, which is reflected graphically. Each has a clickable region that consists of the ‘ground’ at the ‘top’ (not the walls) which makes the traditional mouse position projection method of isometric tile selection difficult, so I have opted to use Pixelmask + collidePointInto, sorting by layer so it grabs the tile “in front”. This also makes it easy to grab the tile coords, height and layer from the Entity for use in pathfinding, placing characters and cursors and such.

That’s the best system I could come up without modifying FP’s source much. Suggestions are welcome! Here’s a picture (only using one level of height) just in case I didn’t create a clear image with my description:

@azrafe7 I think the problem with a game prototype being used to update the core framework is that it can tend to skew fixes towards certain problems with that type of game. What I love about FP, is in comparison to other libraries it doesn’t feel geared towards platformers or another type of game. I don’t feel like I am ‘hacking’ other genres into the base functionality.

A community game project does sound like a neat idea though. :smile:


(Zachary Lewis) #5

Are you making use of World.create() and World.recycle() to efficiently create and destroy your tiles? If used properly, the maximum number of tiles would be the number you can see onscreen.

My idea with a broad phase collision system is, any tile that couldn’t possibly collide with the screen rectangle (camera position + screen size) can be safely ignored.

If you’re only using a PixelMask for mouse collision and aren’t colliding them into each other, you should be good.


(Kyuur) #6

I was trying to figure out a way to use Create() and Recycle() in my code a bit earlier. It doesn’t seem you can pass an existing Entity object to create? All my tiles are generated when the level loads, granting them their position, height, tile type etc. With Create() I would have to reassign these values to the entity generated from the source every frame. I would also need a system to figure out which tiles I need to create, making this more complex than just ‘when tiles come on screen, add them’, unless I’m missing something.

I’ll look into the broad phase system as well, thanks for the helpful replies!


(Zachary Lewis) #7

Nope, you’ve nailed the way create() and recycle() work. If you have a data structure that contains the map information (such as a two-dimensional array), you should be able to figure out what is on the screen.

The camera is at (500, 200) and the screen is 400x300, so the player can see every tile from tiles[7][3] to tiles[14][6] and any others can be safely hidden.


(Kyuur) #8

Ah, I see! That makes perfect sense! It’s just a bit harder for me to wrap my head around which tiles fit on screen when they are isometric, haha.

I found a way to do this without performance loss using my 1st idea (running through the entire array of entity and deciding which to add/remove). The performance loss was caused by running remove() on every tile in the array. What I did was create a bool signifying if the current tile was added, which switched using the added() and removed() functions. Then I checked if the tile was added using this bool before trying to remove, and viola! Getting FPS near 60 now!

The downside to this is that you need to instantiate every Entity at the beginning of the world, meaning large maps (I tried 1000x1000 at first, haha) are impossible or very slow to load. So I think Zach’s logic is preferable, and will probably implement it that way if there are no performance losses from creating/recycling tile instances so often.

Thanks again for your help Zach! It’s been very informative.


(Zachary Lewis) #9

Glad I could help, @Kyuur! It’s what I’m here for.