[C2 Performance] Best Way To Handle Large Game Worlds

0 favourites
From the Asset Store
Best car suspension with spring effect and very cool terrain generation.
  • Introduction + Minor Request

    Hello there, before fully going into this, I would like to advise everyone that doesn't know anything about this, not to post on this topic!

    I don't mean this in an offensive way, I just want to avoid posts like "I want to know this too!", which tend to make topics like this unnecessarily big.

    Reason + Short Explanation

    This topic is meant for opinions on how to handle large "game worlds" (also knows as "game maps") and their impact on performance.

    For this purpose I've made a poorly drawn example of a typical game world.

    Game World Example (with sections named as "layers")

    Game World System #1 (Layer Based Loading)

    This system would be based on the current players position on the world.

    The layers would have world borders, which would detect on what part of the world the player currently is

    and unload* all other layers that are not next to the current layer.

    *with "unload" I mean setting the layer invisible/opacity 0%.

    Here are some scenarios that should make it clearer:

    Player is on

    Layer#1 = Load Layer #2 + Unload Layer #3

    Player is on

    Layer #3 = Load Layer #2 + Unload Layer#1

    Game World System #2 (Layout Based Loading)

    This system would separate each layer into its own layout.

    That means when the player has reached the edge of one layout, it will have to change to the next layout.

    Using this system also means that the game has to load a whole new layout and pass all the data

    from the previous layout over to the newly loaded one (e.g. last enemy positions, player state and many more).

    Here are some scenarios again:

    Player is on the

    right edge of the layout named Layer #2 = Go to the separated layout named Layer #3

    Player is on the

    left edge of the layout named Layer #2 = Go to the separated layout named Layer#1

    Game World System #3 (Full One-Time Layout Loading)

    This system would be the easiest to setup and basically have every layer loaded as a whole, inside one single layout.

    This also means that the layout will have a giant size of 100.000 or more.

    You could take this system as a lazy version of System #1 but without changing any visibility/opacity and only one layer.

    Conclusion

    Please note that my game is a multiplayer game, if that matters in any kind of way.

    The game also uses HD sprites which could drastically increase layout loading times.

    Which system would be the best performance wise and why?

    Please share your opinion or suggest better systems below.

  • We have a method to help with bottlenecks on large layouts with many static objects.

    Creating, and destroying objects based on a player's position is only useful for endless levels.

    The size of a layout should be determined by the number of objects you can safely have on the layout at any given time.

  • The layers would have world borders, which would detect on what part of the world the player currently is

    and unload* all other layers that are not next to the current layer.

    *with "unload" I mean setting the layer invisible/opacity 0%.

    This is kind of pointless cause everything that is not visible on screen is not rendered, so setting a layer to invisible for objects that are not rendered have no point at all.

    Using this system also means that the game has to load a whole new layout and pass all the data

    from the previous layout over to the newly loaded one (e.g. last enemy positions, player state and many more).

    For this one i think you are over complicating things a bit. All you have to do is store important stuff in arrays, dictionaries or whatever - which are global objects.

    You can also apply a lot of own rules what to do with that data, for example. If npc is on same layer as player -> do some stuff else do something else.

    I did something similar using about over 10 arrays and dictionaries and to store data for npc, inventory, items, quests for main map (900x900 tiles) + 80 minimaps.

    Everytime when player moved between main map -> mini map -> main map every important data from current map was saved, then layout changes and on start of new layout all important data was loaded again. And that was a game for mobiles, each change of level took no longer than 5 seconds on Samsung Galaxy S3. So on desktop you can easily push it limits a lot more.

    Here are some scenarios again:

    Player is on the right edge of the layout named Layer #2 = Go to the separated layout named Layer #3

    Player is on the left edge of the layout named Layer #2 = Go to the separated layout named Layer#1

    That's rather super simple thing to do

  • My game can only use solution 3, as it is a big game world with an emergent "ecology". Solution 1 is doable in theory, but the amount of layers is too high to use it, as many objects use their own layers also to trigger events and so on.

    There are some "persistent" objects which are destroyed / recreated based on camera position (happens on a timer, i carefully tested the trade-offs).

    All in all, if you know how to use timers and don't exceed with webgl effects, the main issue is number of objects, as we all know...

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • #2 is the safest method but you lose your "world reference" - you have no idea where each layout is connected so you'll have to draw out your map beforehand.

    Sounds like #1 and #3 are just dynamically loading portions of the layout based on zones. This is what I do in the Metroidvania Game Kit and other projects. This works fairly well and performance is nearly identical to having each zone a separate layout. Managing all the objects can be troublesome later on but I'll take that over managing 100+ layouts with independent layers and properties any day. Only drawback is like you said - the layout sizes will be pretty big. Loading times could blow up on larger maps or games with large graphics. Also you'll probably want to destroy objects and use "recreate initial objects" for unloading/loading instead of just setting their opacity to 0 or whatever like you mentioned.

  • We have a method to help with bottlenecks on large layouts with many static objects.

    I believe you mean "render cells" right? In any case I guess I will use that on my static background layers, I have 3 layers in total with different parallaxes for the illusion of dept. I hope that parallaxing doesn't turn the essentially static layers into a dynamic one or does it?

    This is kind of pointless cause everything that is not visible on screen is not rendered, so setting a layer to invisible for objects that are not rendered have no point at all.

    What exactly does this mean though?

    For my understanding this would mean that C2 games load content like the old Super Mario games did?

    For this one i think you are over complicating things a bit. All you have to do is store important stuff in arrays, dictionaries or whatever - which are global objects

    There are a ton of instances and things that I have to consider though, besides the fact that I also have to sync it up on the connected peer.

    I think for me this would be a pain to do, I'm not really good with "predictive" eventing that contains content from a lot of different instances.

    My game can only use solution 3, as it is a big game world with an emergent "ecology".

    There are some "persistent" objects which are destroyed / recreated based on camera position (happens on a timer, i carefully tested the trade-offs).

    All in all, if you know how to use timers and don't exceed with webgl effects, the main issue is number of objects, as we all know...

    quote]

    #2 is the safest method but you lose your "world reference" - you have no idea where each layout is connected so you'll have to draw out your map beforehand.

    Sounds like #1 and #3 are just dynamically loading portions of the layout based on zones. This is what I do in the Metroidvania Game Kit and other projects. This works fairly well and performance is nearly identical to having each zone a separate layout. Managing all the objects can be troublesome later on but I'll take that over managing 100+ layouts with independent layers and properties any day. Only drawback is like you said - the layout sizes will be pretty big. Loading times could blow up on larger maps or games with large graphics. Also you'll probably want to destroy objects and use "recreate initial objects" for unloading/loading instead of just setting their opacity to 0 or whatever like you mentioned.

    My background layers are static as mentioned before and I'm also not using 100 different building/tree sprites, I'm rather re-using existing ones and randomize the frames. So my background does always look different but I'm going a little off topic with this. Also the only weblgl effects that I'm using are bound to a layer that is on top of all others, "outline" and a bit of "noise". I think this was the recommended method, instead of applying the effects to each sprite individually.

    From a gameplay standpoint I would also chose to use system #3, not only because it's easy for me to do but also because I think that gameplay wise it would be better to have a giant game world instead of multiple smaller ones. I think that my player base would complain about the 5-10 sec. loading times, if I would use separated layouts.

    My question is, how could I handle the loading times well? As far as I know C2 doesn't offer any "loading screen" feature, so this would mean that each time when such a giant layout has to be loaded in, it would display a black screen for about 10 seconds or even longer. I believe that a lot of players would think that the game crashed when waiting over 10 seconds for a layout to load it.

  • What exactly does this mean though?

    For my understanding this would mean that C2 games load content like the old Super Mario games did?

    >

    > For this one i think you are over complicating things a bit. All you have to do is store important stuff in arrays, dictionaries or whatever - which are global objects

    >

    There are a ton of instances and things that I have to consider though, besides the fact that I also have to sync it up on the connected peer.

    I think for me this would be a pain to do, I'm not really good with "predictive" eventing that contains content from a lot of different instances.

    1. No no, there is a difference between loading assets and rendering them. On start of the layout C2 loads every single object that is placed on that layout to the memory (objects created or spawned during the runtime are added to memory at runtime), but renders only what is in active viewport.

    2. i think it could be even easier. Having for example one array for all enemies and their data (position, animation, HP, speed, etc etc) could let you easily sync it because all information you need are in one place. So from one and the same array you could send out data to the host and all the players.

    My question is, how could I handle the loading times well? As far as I know C2 doesn't offer any "loading screen" feature, so this would mean that each time when such a giant layout has to be loaded in, it would display a black screen for about 10 seconds or even longer. I believe that a lot of players would think that the game crashed when waiting over 10 seconds for a layout to load it.

    You could do your own custom loading screens. Remember you don't have to load everything right on the start of the layout. You can make it in stages.

    Maybe one day in C3 we would get an option to stream levels

  • You could do your own custom loading screens. Remember you don't have to load everything right on the start of the layout. You can make it in stages.

    Maybe one day in C3 we would get an option to stream levels

    I have a startup loading screen but that is not my problem.

    My problem would be the "rendering" into a layout which also takes quite a while on PC's with low/medium-end hardware.

    So this "rendering" into a layout would require a loading screen that C2 doesn't offer I guess?

  • That's why I meant by custom loading screen - the one made of sprite, spritefonts, text, or whatever you need... just to show that something is still going on at the background.

  • That's why I meant by custom loading screen - the one made of sprite, spritefonts, text, or whatever you need... just to show that something is still going on at the background.

    I get it, so you mean something like a "fake" loading screen. Well it's better than nothing I guess.

    Thanks for the idea.

  • The runtime is architected so that with "render cells" enabled, an offscreen sprite with no animations or events has a zero performance overhead. (Animated objects have to tick their animation and events still check against all the objects in the layout.)

    This means that if you create even a gigantic layout which consists solely of static objects (no animations or events), it should run perfectly no matter the size of the layout.

    The performance problems tend to stem from running events against a large number of "live" objects in the layout. You may need some techniques to avoid having too many of them at once, possibly by dividing the layout in to certain segments and destroying all the objects outside of the segment, but as far as the static objects go you should be able to create as many as you want (providing render cells is on).

  • The runtime is architected so that with "render cells" enabled, an offscreen sprite with no animations or events has a zero performance overhead. (Animated objects have to tick their animation and events still check against all the objects in the layout.)

    This means that if you create even a gigantic layout which consists solely of static objects (no animations or events), it should run perfectly no matter the size of the layout.

    Amazing, that eliminates all my concerns about having tons of static sprites in the background.

    The performance problems tend to stem from running events against a large number of "live" objects in the layout. You may need some techniques to avoid having too many of them at once, possibly by dividing the layout in to certain segments and destroying all the objects outside of the segment ...

    To be honest I personally have no idea on how I could approach this. My game is based on the concept of an old GBA game, meaning that there are units off-screen that fight each other and I have no clue on how I could destroy them and keep the illusion of them fighting off-screen.

  • The runtime is architected so that with "render cells" enabled, an offscreen sprite with no animations or events has a zero performance overhead. (Animated objects have to tick their animation and events still check against all the objects in the layout.)

    This means that if you create even a gigantic layout which consists solely of static objects (no animations or events), it should run perfectly no matter the size of the layout.

    The performance problems tend to stem from running events against a large number of "live" objects in the layout. You may need some techniques to avoid having too many of them at once, possibly by dividing the layout in to certain segments and destroying all the objects outside of the segment, but as far as the static objects go you should be able to create as many as you want (providing render cells is on).

    So, that's what render cells are.

    Ashley, It would be great if you make a sample capx regarding this with a lot of similar tiles and mouse movement so that users can understand and experience this quickly on their own.

    To be honest I personally have no idea on how I could approach this. My game is based on the concept of an old GBA game, meaning that there are units off-screen that fight each other and I have no clue on how I could destroy them and keep the illusion of them fighting off-screen.

    TheRealDannyyy, as I understand it, some old games do it by calculating the position, orientation and results in arrays/datatable for offscreen situations instead of enacting it in objects to save performance.

  • So, that's what render cells are.

    Ashley, It would be great if you make a sample capx regarding this with a lot of similar tiles and mouse movement so that users can understand and experience this quickly on their own.

    Already done and explained in full detail, as I just found out. (HERE)

    TheRealDannyyy, as I understand it, some old games do it by calculating the position, orientation and results in arrays/datatable for offscreen situations instead of enacting it in objects to save performance.

    I will have to find a way through trial and error I guess.

    At least I have a ton of options on how I could handle this, I just need to come up with a good technique.

  • To be honest I personally have no idea on how I could approach this. My game is based on the concept of an old GBA game, meaning that there are units off-screen that fight each other and I have no clue on how I could destroy them and keep the illusion of them fighting off-screen.

    I got a similiar game here. You can only work on the object that do not interact / fight while offscreen. You can use arrays to keep track of objects variables/position etc, and destroy/recreate them depending on their position/distance from the scrollx/y. Of course, this could be a double edged sword, as the performance impact of the creation/destruction (which should never happen every tick) could exceed the benefict of the reduced object number.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)