3
\$\begingroup\$

Background

I'm tring to make a First-Person-Shooter Game in a Voxel-World (Finit Size) with Unity3d.

The Player has some kind of a Base that he has to protect against Enemy units. There are also one or more enemy Bases that the Player has to destroy, but in a different Level/Map.

The Game has multiple Levels that are connected through predefined Ports. So the Player and other Units can travel from Level to Level. There are a couple of Levels to explore. (Maybe there could be infinit Levels in the future.)

At game start I create a LevelManager and all Levels as Children of them. They can spawn an manage the Units and Voxel-Blocks independently. One ChunkManager renders always the current Level where the Player is in. He creates multiple Chunks which itself generate the Mesh from the current Voxel-Data of the Level. This works all very well and I'm also able to travel between the Levels. (This runs all in one Scene.)

At the moment I try to implement some kind of a Worm unit. They spawn from time to time anywhere in each level and can move randomly around and modify the Voxel-World by eating the Blocks away... type of random enviroment event.

Problem

The problem I can't solve is how to simulate all the Worms in parallel Levels? And the Blocks they have eaten? Same problem would occur for the enemy bases if they grow and build new defences and so on. Because when the Player enter a Level there should be some differences since his last visit.

My attempt

All my Units and Buildings have already separated logic and rendering components. So they can work properly even when not rendered by the ChunkManager. Its working for maybe 3 Levels and a handfull of worms but if I increase the amount of Levels it gets starting to go laggy (4-10FPS). So this would not be the right way to go or is it and my code is crap?

Has someone any suggestions for me how I can solve this?

Edit

I disable now all none active Levels and reactivate always the current Level where the Player is in. So I can better manage the objects that realy need computation time.

The problem I get now is how can I simulate the progress in a Level since start? Example for the worm unit. He would have moved across the Level and left a path of removed voxels. Should I made a seperate method to calculate the path that would be made or the last X minutes or should I just call the Update method multipletimes to match the missed calls since last X minutes? This should then be made by all Objects that can modify the Level or produce something.

\$\endgroup\$
1
\$\begingroup\$

Option 1 Decrease the size / number / complexity of the levels

Option 2 Use WorkerThreads.

Option 3 Process more distant levels less frequently. Maybe this frequency relies on how close the player currently is to that level... so the current level might be affected every update, a neighbouring level might only be affected once in 2 updates, more distant ones every 4-8 updates (just example numbers). And beyond a certain distance or where there are no enemy bases, don't do anything.

For things like enemy base building, maybe this also means you don't only add 1 voxel every n updates, but maybe you add n voxels every nth update: you're still likely to speed things up this way because at that point in time you're doing all your ops on that level, getting it done with, and moving on with other things (resulting in better cache coherence, for one). Or maybe you build one whole wall at once. Whatever seems efficient to do in one go, every nth update. What you can manage in this regard depends on what your bottleneck is, e.g. if it still takes 8 times longer to add 8 voxels rather than 1, then you'd better stick with adding fewer voxels per update, regardless.

Option 4 Look for obvious bottlenecks in existing code; specifically look at costs surrounding modification of voxels. Don't do so for very long as it isn't worth doing heavy optimisation early on.

As regards worms If their bodies stream between levels, you'll have to make a special case for them. Work only on voxels that may be affected by the worm e.g. using a bounding box, or divide your levels into smaller parts and only operate on parts around the worm, each update.

\$\endgroup\$
  • \$\begingroup\$ Option 1: Not required because at the moment all levels are only 128-256 in size. Option 2: Can be combined with option 3. Option 3: Sounds like a realy good idea. The LevelManager can update the current level every frame while to surrounding Levels can put into Worker Threads and compute in less frequently intervalls. So not all Objects use the main Update loop. Option 4: Maybe the access to the Voxeldata. A Worm ask the Level for the Voxel of the current position, the Level looks first for modified blocks in a dictionary if nothing found the VoxelType is computed by the LevelSeed and a Noise \$\endgroup\$ – RobinHood Sep 26 '15 at 9:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.