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

Question How to approch this problem

Discussion in 'Scripting' started by Protexxi, Nov 22, 2022.

  1. Protexxi

    Protexxi

    Joined:
    Oct 4, 2019
    Posts:
    7
    Hello all,

    first of all i would like to note i know this isnt the "correct" way of doing what this script is doing

    however i have created a script that will generate a world from sprites and it is currently random with only a water and a grass tile.

    the script is
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Gen : MonoBehaviour
    6. {
    7.  
    8.     public int sizex;
    9.     public int sizey;
    10.     public Texture2D grass;
    11.     public Texture2D water;
    12.     public Texture2D Using;
    13.  
    14.     private void Start()
    15.     { float posx = 0.0f;
    16.         float posy = 0.0f;
    17.         for (int x = 0; x < sizex; x++)
    18.         {
    19.             GameObject newobj = new GameObject(); //make new object
    20.             SpriteRenderer newspriteRenderer = newobj.AddComponent<SpriteRenderer>();
    21.             Using = Slection();
    22.             newspriteRenderer.sprite = Sprite.Create(Using, new Rect(0, 0, Using.width, Using.height), new Vector2(Using.width / 2, Using.height / 2));
    23.             newobj.transform.position = new Vector2(posx, posy);
    24.  
    25.             for (int y = 0; y < sizey; y++)
    26.             {
    27.                 newobj = new GameObject(); //make new object
    28.                 newspriteRenderer = newobj.AddComponent<SpriteRenderer>();
    29.                 Using = Slection();
    30.                 newspriteRenderer.sprite = Sprite.Create(Using, new Rect(0, 0, Using.width, Using.height), new Vector2(Using.width / 2, Using.height / 2));
    31.                 newobj.transform.position = new Vector2(posx, posy);
    32.                 posy += 0.25f;
    33.             }
    34.             posx += 0.25f;
    35.             posy = 0.0f;
    36.         }
    37.  
    38.     }
    39.  
    40.     public Texture2D Slection()
    41.     {
    42.         int t = Random.Range(0, 3);
    43.         switch (t)
    44.         {
    45.             case 2:
    46.                 return grass;
    47.  
    48.             case 1:
    49.                 return water;
    50.             default:
    51.                 return grass;
    52.         }
    53.     }
    54.  
    55.     }
    56.  
    57. /*
    58. * To Do
    59. *
    60. * Add More Tiles -- Added Water
    61. *
    62. * add rules for acceptable tiles
    63. *
    64. * Add coliders?
    65. *
    66. * Clone game objects rather than making new
    67. *
    68. * figure out how to make 0 0 map center prehaps using 4 loops for the 4 courners around 0 0
    69. *
    70. */

    my question is how would i move away from the randomness and have a set of rules that will define what a tile can and cant be.

    for example if i added a "sand" tile water could only touch a sand tile on all 4 sides and sand could touch anything.

    my current logic i need to created some sort if "virtal grid" with each grid block assined its x and y as coords then have a check that takes the grid block and looks what tiles touch it and what tiles are allowed to occupie that space then select one of them tiles at random.

    so my question is what is a good place to start with this?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,951
    Welcome to procedural generation!

    It's a deep rabbit hole, and it's a LOT of fun to dive into it.

    But it can also be baffling and/or frustrating.

    I like that you're leaping ahead and making notes in your comments: I do the same thing!

    There are ten billion different ways to do this stuff.

    Best thing is that others have made videos about it! (See below)

    One way is to do multiple passes: lay down all the water, then go back and dot in islands, then go back over and smooth the edges of the islands when you have transition tiles (eg, to make it smooth). Then go back and look for places to put trees or rocks or whatever. This multi-step process lets you consider what is present already before making random choices.

    Another way is to pre-make chunks of interesting stuff and then lay the chunks down randomly, perhaps against a backdrop of existing solid color, such as water. This might be some interesting pre-made island shapes that you slam into place over your water.

    There's a lot to consider as far as how you choose randomness, or even what kind of random number generator you use. Do you just pick random positions (x,y)? Or do you consider 100% of the board (iterate over the entire thing) and say that X% of the tiles will be one thing or another?

    Do things tend to clump together (trees and rocks tend to do this in real life)? Is there an upper limit to the clump size?

    Another great source of randomness is noise functions, such as Perlin noise. Perlin noise of different frequencies can be combined to make really complex organic-feeling results.

    Anyway, hope this sparks something. Here was a GDC talk:

     
  3. Protexxi

    Protexxi

    Joined:
    Oct 4, 2019
    Posts:
    7
    hey kurt thanks for the reply,

    playign the video now as i work

    i have used perlin noise before however the instructions i followed left me with less idea than when i started as the only coding knowlage i have is what iv taught myself so very limited.

    i guess what im trying to achive is a way to store what tile is where in the world maybe a stacked array so i could call the 1st item in an array then the 10th item in that array to return an array of data about that tile. however i feel that a very over engineerd way to achive this, and it would be slow when an (future NPC) trys to find a particuler tile
     
  4. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    That is exactly why we use noise. It simplifies things a lot, compared to coming up with arbitrary rules and trying to enforce them. For example, say you do indeed make sure that water can touch sand or itself. How does that generate us decent terrain? Without any other information, we'd still be looking at, basically, fully random tile placement. Instead of a random tile of water in the middle of nowhere, youd now have a random tile of water surrounded by 4 tiles of sand in the middle of nowhere. Sure, you could make the rules arbitrary complex, by saying that a water body needs to be at least x blocks in total, or of a certain shape, and so on. But this will get out of hand real quick, and sooner rather than later you wont have any idea anymore why rules are what they are, or how they are supposed to achieve your goals, why you chose them in the first place, or what you need to change to adjust certain terrain features.

    If only we had a function returning coherent values we use as a background for our decisionmaking.. ;)

    We usually treat noise "as the world itself", which we then have to visualize. First and foremost, this splits the actual problem into two. Now you have to come up with a noise function which creates interresting terrain for your usecase. This is usually a bit of a creative process, involving mixing and matching certain noise functions. This topic is well covered, but not an exact science. Secondly we now only need to visualize this noise function in some way. In 3D we oftentimes treat the noise as the terrain itself, by defining some threshold over which it counts as solid vs. empty space. In 2D we oftentimes treat noise as a heightmap. High values? Mountains. Lower values? Flatlands. Even lower? Deep Oceans. Want a beach? Thats simply the value range between ocean and flatlands. The exact range you define determines how thin of thick the beaches will be on average. And so on. You want biomes? Thats just another noise map, which you sample together with the heighmap to decide on the correct tile to use.

    A bit more sophisticated solutions can even use chunking (to speed up updates) and edit the underlying noise, then redraw the chunk, to apply arbitrary changes to the terrain. Wanna flatten a mountain? Simply reduce the noise in some area by a certain value and redraw the chunks involved. There, same map, mountain gone. Things like that are comparably easy if you keep the noise data representation of how your world hangs together.

    All of this is not to say that you cannot do procedural generation without noise. However, it's usually not less complex. Have a look at an example of someone who created a procedural dungeon generator. Just by looking at the nice GIFs depicting the algorithm roughly, you get an idea that it's certainly not simple. And a dungeon is a lot less complex to do compared to terrain, since you only need to create and connect rooms, which is effectively a graph. https://www.gamedeveloper.com/programming/procedural-dungeon-generation-algorithm

    The workflow with noise is a bit different, but not scary at all. You should also find plenty of ressources online, if you want to go that route. Noone forces you tho.
    Some biome examples using noise: https://www.procjam.com/tutorials/en/ooze/
    Some other biome example:
    http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/

    Tutorial series on procedural generation, involving everything from using noise as a heightmap in terrain generation, to multithreading. Worth checking out, even if you might not need it all.
     
    Last edited: Nov 23, 2022