Search Unity

Programming Pattern advice needed (semi-random obstacle generation in a 3d tunnel game)

Discussion in 'Scripting' started by IndieFromIndy, Oct 8, 2017.

  1. IndieFromIndy

    IndieFromIndy

    Joined:
    Sep 29, 2017
    Posts:
    2
    I am coding a game with 3D tunnel-runner style game play and need advice on how to organize and instantiate obstacle prefabs on a semi-random basis.

    Unfortunately, most of the tutorials out there are for static "level-like" environments which are simply built in the editor. This is not a solution for me. What I am needing is scripted level generation that is not completely random, but not deterministic either.

    The game naturally gets more difficult as you progress, so I can't simply throw all prefabs in a randomizer and spit them out. This would present harder obstacles earlier than desired, etc..

    Furthermore, some areas of the tunnel I do want to be the same every time. The best example is the beginning of the game which is a simple introduction to the controls. This needs to be the same.

    So I need advice on how to script/organize/deploy this semi-random, semi-static, sectional obstacle system.

    I don't need much advice on the coding itself. I have experience in that area and can find the nuts-and-bolts of the implementation. I need a high-level outline view of how this could work.
     
  2. hasanbayat

    hasanbayat

    Joined:
    Oct 18, 2016
    Posts:
    630
    You need a semi-random terrain generation.

    This project uses a semi-random terrain generation system, for example, the start of level always is same.

    https://github.com/BayatGames/RedRunner

    Every block needs conditions and fields and the most important field is the probability to spawn this block.

    And then you need a spawner that selects a block by probability and checks the conditions, if the conditions do not matches then the spawner will try to find another block, Otherwise, the spawner shouldn't spawn anything.

    As your need, you want to have the same start and some same areas in the generation.

    So you can define some conditions such as if the player score is equal to 500 or if the player traveled distance is equal to 500 then spawn the terrain. And also you can use this conditions to spawn the first element by checking if the player score is equal to 0.

    The most important part of this kind of level generation is the block selection, you need to set up a smart block selection system that selects blocks that match this place and then get the candidates and choose one of them using probability by following this tutorial: Adding Random Gameplay Elements

    Here is a simple structure of the whole system:

    Block Script:

    Code (CSharp):
    1. Block {
    2.  
    3.     // The length of the block
    4.     Vector3 length;
    5.     float probability;
    6.     Vector3 startSpawnPosition;
    7.     Vector3 endSpawnPosition;
    8.  
    9. }
    Spawner Script:

    Code (CSharp):
    1. Spawner {
    2.  
    3.     Block[] blocks;
    4.     Vector3 lastPosition;
    5.  
    6.     void Update () {
    7.         if (playerPosition < lastPosition - Vector3.right * 300) {
    8.             Generate ();
    9.         }
    10.     }
    11.  
    12.     void Generate () {
    13.         Block block = GetNeededBlock (lastPosition);
    14.         if (block != null) {
    15.             Instantiate (block.gameObject);
    16.             lastPosition += block.length;
    17.         }
    18.     }
    19.  
    20.     Block GetNeededBlock (Vector3 currentPosition) {
    21.         List<Block> candidates = new List<Block> ();
    22.         for (int i = 0; i < blocks.Length; i++) {
    23.             blocks[i]
    24.             if (blocks[i].startSpawnPosition < currentPosition &&
    25.                 blocks[i].endSpawnPosition > currentPosition) {
    26.                 candidates.Add (blocks[i]);
    27.             }
    28.         }
    29.         return ChooseFromCandidates (candidates);
    30.     }
    31.  
    32.     Block ChooseFromCandidates (List<Block> candidates) {
    33.         float total = 0f;
    34.         for (int i = 0; i < candidates.Count; i++) {
    35.             total += candidates[i].probability;
    36.         }
    37.         float randomPoint = Random.value * total;
    38.         for (int i = 0; i < candidates.Count; i++) {
    39.             if (randomPoint < candidates[i].probability) {
    40.                 return candidates[i];
    41.             } else {
    42.                 randomPoint -= candidates[i].probability;
    43.             }
    44.         }
    45.         return candidates[candidates.Count - 1];
    46.     }
    47.  
    48. }
    Hope this helps, Anything is welcome.

    Thanks.
     
  3. IndieFromIndy

    IndieFromIndy

    Joined:
    Sep 29, 2017
    Posts:
    2
    Thanks for your quick reply! I will have to wrap my brain around this. It does seem to be exactly what I need. I will check out that tutorial and example you provided and come back with any questions/problems I have, if any. Thanks again!