I’m working on a mario-ish game with long horizontal levels, but 99% of the level is nothing but sprites and 2d box colliders to represent the floor/platforms. The amount of objects on any one screen will always be low (under 100 sprites, usually well under), but levels are pretty long, so a single complete level might consist of hundreds and hundreds of sprites spread out over 30-40 screen lengths. Am I likely to run into problems generating the entire level at runtime and trusting frustum/viewport culling to keep performance in check?
My current approach has been to break the level down into chunks and load/unload chunks based on the camera’s position, but that’s going to become very complicated the instant I add enemies who need to be able to pathfind offscreen. Is there anything about my proposal to just create the entire level at runtime which is sufficiently foolhardy to prompt terrified screaming, or is it reasonable enough to merit starting there and hoping real hard that it never becomes a big enough bottleneck to merit refactoring?
You could divide the level into chucks where each chunk is placed into an empty GameObject and then set them as active/inactive depending on which ones are seen by the camera. That should be easier and faster than loading/unloading the chunks. (Yes, I do realize that there might be problems with moving objects, but unloading/loading will have the same problems)
Are you using animations? Have you set the Culling Mode, so that objects won’t animate unnecessarily.
Hmm, that’s an interesting idea(and yep, culling is set!); my current ramshackle approach (which I’m not 100% convinced will hold up as I expand the featureset) is to create a pool of three chunk prefabs that are each twice the width of my widest resolution (1920x1080), then set up a function that runs every time one of the chunks becomes centered on-camera which moves the rearmost chunk ahead of it, such that if your character moved from chunks 1-2-3, when he hit chunk 3 chunk 1 would jump ahead, so the pool was now laid out 2-3-1.
The leapfrogging approach works in the sense that it’s pretty fast (no instantiate/destroy/GC calls), but I can imagine cases where I would want enemies/persistent content to move between chunks or stay behind after their chunk unloads, which is why I was pondering spawning whole levels at once.
I’ve used the approach I suggested and it does work rather well, even on mobile devices. It is probably uses less resources and causes less lag on mobile devices, compared to the unload/load approach.
The problem is if an enemy that is parented in one of the chunks that is to be disabled and the enemy has walked into a chunk that is still visible, once the parent chunk is disabled, so is the enemy. Which will cause it to disappear from the screen. So, it is necessary to reparent enemies to the chunk that they are actually in as they move about. Then again, this problem would probably happen in a unload/load scenario as well.
Also, if you need an enemy to keep moving even when it is a long way away, this approach won’t work. Even if the enemy is kept active and alive, it would (of course) fall away into eternity once the chunks around him was disabled.