Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Creating HUGE 2d world with 3 layers

Discussion in '2D' started by retrj986, Feb 24, 2020.

  1. retrj986

    retrj986

    Joined:
    Feb 7, 2020
    Posts:
    8
    Hello, i've got a problem:
    I have created a chunk system for my game, using instation and destory (wiyh prefabs).
    But it was too laggy at mobiles...but perfectly at PC. I've learnt a lot of forums and queitly didn't get, what is
    the best way to create this world with chunk system (that updates).

    Could somebody pls give me an advise how to make it beauty.
    P.S. sorry for my eng,
     
  2. Cornysam

    Cornysam

    Joined:
    Feb 8, 2018
    Posts:
    1,353
    Occlusion Culling could help with frame rate on mobile if your world is too large.



    I dont really understand the layers part or the "chunk" but if you gave more details I think the forum peeps could help more.
     
  3. Tom-Atom

    Tom-Atom

    Joined:
    Jun 29, 2014
    Posts:
    153
    1) size of chunk may play role - is your map predrawn or generated procedurally?,

    2) Instantiate / destroy may cause lags - instead, try to create pool of tilemaps for your chunks and when new chunk is about to appear, take it from pool and overwrite its content with new area. In connection with 1) - if chunk is small, this will happen often, but it will be fast. When chunk is no longer needed, than do not destroy it, but only deactivate and return back into pool,

    3) correct me somebody if I am wrong, but tiles in Tilemap are not instances of tiles, but references to Scriptable Object with tile "template"? Then approach in 2) should be rally fast and without any Instantiations.
     
  4. retrj986

    retrj986

    Joined:
    Feb 7, 2020
    Posts:
    8

    I was thinking about creating a poll, but there are blocks that updates if player near them, so pools are requered a lot of RAM, as i understood
     
  5. retrj986

    retrj986

    Joined:
    Feb 7, 2020
    Posts:
    8
    I mean:
    8x8 chunk has
    int[chunk,chunk] block_front_id; // ores
    int[chunk,chunk] block_background_id; // walls
    GameObject[chunk,chunk] block; // for prefabs with script(data),box collision,sprite renderrer
     
  6. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Its hard to say, can you show your code?, I mean if you are instantiating and destroying its gonna cause issues when you instantiate something, its better for example to just replace only the data that needs to be replaced, adding and removing only the absolute minimum, you have to make sure that chunks stores as little information as possible, or rather if you can use procedural generation that way you wont store much at all, or you could use images to store information and access it when needed for example, using the rgba channels, there is a ton of different ways to solve it, we just dont know what would be best for your problem since we have no clue how you coded it, so gonna need to see your code to help.
     
  7. retrj986

    retrj986

    Joined:
    Feb 7, 2020
    Posts:
    8
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. //using Unity.Jobs;
    5. //using Unity.Collections;
    6. //using Unity.Burst;
    7.  
    8.     public class CHUNK : WORLD
    9.     {
    10.         public int[,] bl_type = new int[chunk, chunk];
    11.         public short[,] bl_info = new short[chunk, chunk];
    12.  
    13.         public CHUNK()
    14.         {
    15.  
    16.         }
    17.     }
    18.  
    19.     public class GM_CHUNK : WORLD
    20.     {
    21.         public GM_CHUNK()
    22.         {
    23.             for (int i = 0; i < chunk; i++)
    24.                 for (int j = 0; j < chunk; j++)
    25.                     data[i, j] = new GameObject();
    26.         }
    27.  
    28.  
    29.         public void disable()
    30.         {
    31.  
    32.             for (int i = 0; i < chunk; i++)
    33.                 for (int j = 0; j < chunk; j++)
    34.                     Destroy(data[i, j]);
    35.  
    36.             enable = false;
    37.         }
    38.         public GameObject[,] data = new GameObject[chunk, chunk];
    39.         public bool enable = false;
    40.     }
    41.  
    42.  
    43.  
    44.  
    45.  
    46.  
    47.  
    48.     public class WORLD : MonoBehaviour
    49.     {
    50.         public Transform Target; //игрок коорд //player coord
    51.  
    52.  
    53.         public const int chunk = 8;
    54.         public const int chunk_cX = 50;// chunk count X
    55.         public const int chunk_cY = chunk_cX;
    56.  
    57.  
    58.  
    59.         public CHUNK[,] mapChunk = new CHUNK[chunk_cX, chunk_cY];
    60.         public GM_CHUNK[,] GM_mapChunk = new GM_CHUNK[chunk_cX, chunk_cY];
    61.  
    62.         public GameObject[] BLOCKS = new GameObject[5];
    63.  
    64.         private int pX;
    65.         private int pY;
    66.  
    67.         public int visionX = 4;
    68.         public int visionY = 4;
    69.  
    70.         private int movedX;
    71.         private int movedY;
    72.  
    73.         private int p_pX;
    74.         private int p_pY;
    75.  
    76.         private int sw = 0;
    77.  
    78.         public void Ebable_ch(int x, int y)
    79.         {
    80.             if (!GM_mapChunk[x, y].enable)
    81.             {
    82.                 GM_mapChunk[x, y].enable = true;
    83.  
    84.                 for (int i = 0; i < chunk; i++)
    85.                     for (int j = 0; j < chunk; j++)
    86.                         GM_mapChunk[x, y].data[i, j] = Instantiate(BLOCKS[mapChunk[x, y].bl_type[i, j]], new Vector2(x * chunk + i, y * chunk + j), new Quaternion(0, 0, 0, 0));
    87.             }
    88.         }
    89.  
    90.  
    91.  
    92.         void Start()
    93.         {
    94.             int[] lvl = new int[chunk_cX * chunk];
    95.  
    96.             lvl[0] = chunk_cY * chunk / 2;
    97.             for (int i = 1, buff; i < chunk_cX * chunk; i++)
    98.             {
    99.                 if (i % 300 != 299 )
    100.                 {
    101.                     buff = Random.Range(-2, 3);
    102.                     if (lvl[i - 1] + buff > 20 && lvl[i - 1] + buff < 400)
    103.                         lvl[i] = lvl[i - 1] + buff;
    104.                     else
    105.                         lvl[i] = lvl[i - 1];
    106.                 }
    107.                 else if(i < chunk_cX - 50)
    108.                 {
    109.                     // int buf = lvl[i-1];
    110.                     if (Random.Range(0, 11) % 3 != 0)
    111.                     {
    112.  
    113.                         for (int k = 0; k < 20; k++)
    114.                         {
    115.                             if (k < 10)
    116.                                 buff = Random.Range(-40, -5);
    117.                             else if (k > 10)
    118.                                 buff = Random.Range(8, 35);
    119.                             else
    120.                                 buff = 0;
    121.  
    122.                             if (lvl[i + k - 1] + buff > 50 && lvl[i + k - 1] + buff < chunk_cY*8 - chunk_cY)
    123.                                 lvl[i + k] = lvl[i + k - 1] + buff;
    124.                             else
    125.                                 lvl[i + k] = lvl[i + k - 1];
    126.                         }
    127.                     }
    128.                     else
    129.                     {
    130.                         for (int k = 0; k < 20; k++)
    131.                         {
    132.                             if (k < 10)
    133.                                 buff = Random.Range(5, 15);
    134.                             else if (k > 10)
    135.                                 buff = Random.Range(-15, -5);
    136.                             else
    137.                                 buff = 0;
    138.  
    139.                             if (lvl[i + k - 1] + buff > 50 && lvl[i + k - 1] + buff < chunk_cY * 8 - chunk_cY)
    140.                                 lvl[i + k] = lvl[i + k - 1] + buff;
    141.                             else
    142.                                 lvl[i + k] = lvl[i + k - 1];
    143.                         }
    144.                     }
    145.  
    146.                     i += 19;
    147.                     //  Debug.Log(i);
    148.                     //  Debug.Log(lvl[i]);
    149.                 }
    150.             }
    151.  
    152.  
    153.  
    154.             //инициализация
    155.             for (int x = 0; x < chunk_cX; x++)
    156.                 for (int y = 0; y < chunk_cY; y++)
    157.                 {
    158.                     mapChunk[x, y] = new CHUNK();
    159.                     GM_mapChunk[x, y] = new GM_CHUNK();
    160.  
    161.                 }
    162.  
    163.             //чанк игрока
    164.             pX = Mathf.RoundToInt(Target.position.x / chunk);
    165.             pY = Mathf.RoundToInt(Target.position.y / chunk);
    166.             p_pX = pX;
    167.             p_pY = pY;
    168.  
    169.             for (int x = 0; x < chunk_cX; x++)
    170.             {
    171.  
    172.                 for (int y = 0; y < chunk_cY; y++)
    173.                 {
    174.                     for (int i = 0; i < chunk; i++)
    175.                     {
    176.                         for (int j = 0; j < chunk; j++)
    177.                         {
    178.                             if (y * chunk + j < lvl[x * chunk + i])
    179.                                 mapChunk[x, y].bl_type[i, j] = 1;
    180.                             else if (y * chunk + j == lvl[x * chunk + i])
    181.                                 mapChunk[x, y].bl_type[i, j] = 2;
    182.                             else
    183.                                 mapChunk[x, y].bl_type[i, j] = 0;
    184.                         }
    185.                     }
    186.                 }
    187.             }
    188.  
    189.             Target.position = new Vector2(32, chunk * chunk_cY / 2 + 32);
    190.             // включение чанков
    191.             for (int x = pX - visionX; x < pX + visionX; x++)
    192.                 for (int y = pY - visionY; y < pY + visionY; y++)
    193.                     if (x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    194.                         Ebable_ch(x, y);
    195.  
    196.  
    197.             //System.Array.Clear(lvl, 0, lvl.Length);
    198.  
    199.         }
    200.  
    201.  
    202.  
    203.         public float time = 0.4f;
    204.         void LateUpdate()
    205.         {
    206.  
    207.             if (time < 0f)
    208.             {
    209.                 time = 0.2f;
    210.                 pX = Mathf.RoundToInt(Target.position.x / chunk);
    211.                 pY = Mathf.RoundToInt(Target.position.y / chunk);
    212.                 movedX = pX - p_pX;
    213.                 movedY = pY - p_pY;
    214.  
    215.  
    216.                 if (movedX != 0 || movedY != 0)
    217.                 {
    218.                     if (movedX < 0)
    219.                     {
    220.                         if (movedY < 0)
    221.                         {
    222.                             for (int x = p_pX - visionX - visionX / 2; x < p_pX + visionX + visionX / 2; x++)
    223.                                 for (int y = p_pY - visionY - visionY / 2; y < p_pY + visionY + visionY / 2; y++)
    224.                                     if (!(x <= pX + visionX && y <= pY + visionY) && x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    225.                                     { GM_mapChunk[x, y].disable(); }
    226.  
    227.                         }
    228.                         else
    229.                         {
    230.                             for (int x = p_pX - visionX - visionX / 2; x < p_pX + visionX + visionX / 2; x++)
    231.                                 for (int y = p_pY - visionY - visionY / 2; y < p_pY + visionY + visionY / 2; y++)
    232.                                     if (!(x <= pX + visionX && y >= pY - visionY) && x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    233.                                     { GM_mapChunk[x, y].disable(); }
    234.  
    235.                         }
    236.  
    237.  
    238.                     }
    239.                     else
    240.                     {
    241.                         if (movedY < 0)
    242.                         {
    243.                             for (int x = p_pX - visionX - visionX / 2; x < p_pX + visionX + visionX / 2; x++)
    244.                                 for (int y = p_pY - visionY - visionY / 2; y < p_pY + visionY + visionY / 2; y++)
    245.                                     if (!(x >= pX - visionX && y <= pY + visionY) && x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    246.                                     { GM_mapChunk[x, y].disable(); }
    247.  
    248.                         }
    249.                         else
    250.                         {
    251.                             for (int x = p_pX - visionX - visionX / 2; x < p_pX + visionX + visionX / 2; x++)
    252.                                 for (int y = p_pY - visionY - visionY / 2; y < p_pY + visionY + visionY / 2; y++)
    253.                                     if (!(x >= pX - visionX && y >= pY - visionY) && x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    254.                                     { GM_mapChunk[x, y].disable(); }
    255.                         }
    256.                     }
    257.  
    258.  
    259.                    
    260.  
    261.                     for (int x = pX - visionX; x < pX + visionX; x++)
    262.                         for (int y = pY - visionY; y < pY + visionY; y++) if (x >= 0 && y >= 0 && y < chunk_cY && x < chunk_cX)
    263.                             {
    264.                                 Ebable_ch(x, y);
    265.                                 }
    266.  
    267.                       p_pX = pX;
    268.                     p_pY = pY;
    269.                 }
    270.             }
    271.             time -= Time.deltaTime;
    272.             if (Target.position.y < 0)
    273.             {
    274.                 Target.position = new Vector2(32, 450);
    275.             }
    276.         }
    277.     }
    278.  
    279.  
     
  8. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Okay if i get this right, you move, then you "disable" all the GM_mapchunks around the player, in a player - visionX -visionX/2 to player + visionX + visionX/2 and same in the y direction.
    Then you can Ebable_ch to create new instantiate of a gameObject in a area of px-visionX to px+visionX and same in the y direction.

    first of all, GM_mapChunk[x,y].disable() doesn't really disable gameobjects it just destroys them, which is a waste,
    you could ad a function to GM_mapChunk where instead of destroying the GameObject which is very expensive, you have a function to switch the content instead where you instead of destroying it add it to a queue for when you call Ebable_ch and change it contents, that way you do not need to destroy the gameobject and instantiate a new object.

    second of all, you are destroying all the object around the player to then redraw em around em instead which is alot of extra work, think about just switching out only the once that are out of sight, for example if you move y+1, you only remove the blocks from y - visionY so you only create and make the once that needs to be used. wanted to be more through but got to work hope it helps
     
    retrj986 likes this.
  9. retrj986

    retrj986

    Joined:
    Feb 7, 2020
    Posts:
    8
    No, there are MoveX and MoveY, so im able to destroy only that i need. And it wont instation twice

    Your advise about switching data sounds very good
    // i will try to rewrite some code
    So i can create
    GM_CHUNK[VisionX,VisionY] GM_chunkVision;

    then i need to ADD int x,y; to GM_CHUNK, so when player in another
    position game will change X and Y of CHUNK (without destroying), and then it just rewrite GameObject (instead of destorying it?? )


    so i will made only 1 array instation of GM_CHUNK[VisionX,VisionY] GM_chunkVision;
    Am i right??
     
  10. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Yeah sounds about right, basically you are just recycling the chunks, just rewriting them, that way you dont have to destroy or instantiate anymore gameobject except for the ones in the start.