Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Procedural Cave Generation

Discussion in 'Community Learning & Teaching' started by SebastianLague, Feb 9, 2015.

  1. AaronC5513

    AaronC5513

    Joined:
    Oct 31, 2015
    Posts:
    5
    Hey, Sebastian I have a question. Is it possible to disable components on the player depending on whether it is 2D or 3D mode? If so how it is possible? The Rigidbody component did not seem to have an enabled field.
     
  2. FireHawkX

    FireHawkX

    Joined:
    Apr 26, 2016
    Posts:
    28
    Hi @SebastianLague : Hope you are well, its been quite some time since you last came here to answer a post... I am using your tutorial as a base for a stage in my game... its working perfectly so far... But I was wondering if you ever had the idea of doing that "part 10th" you talked about so long ago?... You also wrote about having an add-on where you would talk about player spawn or treasure spawn... I actually created one in the code, i added it in the "ConnectClosestRooms" method while making sure it would only add one thing per loop... it works, but its nowhere close to perfect... I have no control that sometimes the player spawns pretty much near the exit or where stuff appears...

    I would love to have that part 10 as it would be so much help for me and many others i am sure!! :)
     
  3. masaraat00

    masaraat00

    Joined:
    Dec 16, 2016
    Posts:
    1
    Hey @SebastianLague I'm a first time programmer using your code and tutorials for a semester project in my beginner computer science class. I'm on the first tutorial, and when I click the left click of the button, it doesn't change the map. Also, the map still has the lines on it that we got rid of at about at 9:55. Can you help me out? At first, I was coding alongside you in the tutorials, but I had some issues I couldn't figure out so I copy and pasted yours. Any input as to why this may be occurring? Thanks!
     
  4. careyduane

    careyduane

    Joined:
    Jun 16, 2015
    Posts:
    9
    I'm don't know if anyone has added a way to save the meshes, but here is a simple script that will save each mesh
    then you can recreate the cave by just putting them together. You can save multiple cave just by doing your normal
    click for a new cave and then you can save it with the "F3" key. Here is the script:

    #if UNITY_EDITOR
    using UnityEngine;
    using UnityEditor;
    // Usage: Attach to gameobject, assign target gameobject (from where the mesh is taken), Run, Press savekey
    public class SaveMeshInEditor : MonoBehaviour
    {
    private string objectPath = "Assets/Templates/";
    private int saveNumber = 0;
    public KeyCode saveKey = KeyCode.F3;
    private string saveName0 = "Ground";
    private string saveName1 = "Walls";
    private string saveName2 = "Cave_Mesh";
    public Transform selectedGameObject0;
    public Transform selectedGameObject1;
    public Transform selectedGameObject2;
    void Update()
    {
    if (Input.GetKeyDown(saveKey))
    {
    SaveAsset(saveName0, selectedGameObject0);
    SaveAsset(saveName1, selectedGameObject1);
    SaveAsset(saveName2, selectedGameObject2);
    saveNumber++;
    }
    }
    void SaveAsset(string saveName, Transform selectedGameObject)
    {
    var mf = selectedGameObject.GetComponent<MeshFilter>();
    if (mf)
    {
    var savePath = objectPath + saveName + saveNumber + ".asset";
    Debug.Log("Saved Mesh to:" + savePath);
    AssetDatabase.CreateAsset(mf.mesh, savePath);
    }
    }
    }
    #endif

    It will save the meshes in Assets/Templates and then the name of the asset with a number on the end
    so that you can have multiple saves and keep the data correct. In other words

    Ground0
    Walls0
    Cave_Mesh0

    Make up one map

    Ground1
    Walls1
    Cave_Mesh1
    Make up another map
     
    BerniceChua likes this.
  5. BerniceChua

    BerniceChua

    Joined:
    Nov 30, 2016
    Posts:
    32
    Hi @SebastianLague, thank you very much for making this tutorial!! ^__^ It is really interesting and useful.

    I have a question about video "E03. Creating the Mesh". In the part where you make the switch statements for 3 points, is there a reason why there's no option for:
    Code (CSharp):
    1. case 7:
    2.         MeshFromPoints(square.topLeft, square.topRight, square.bottomRight);
    3.         break;
    4. case 11:
    5.        MeshFromPoints(square.topRight, square.bottomRight, square.bottomLeft);
    6.        break;
    7. case 13:
    8.        MeshFromPoints(square.bottomRight, square.bottomLeft, square.topLeft);
    9.        break;
    10. case 14:
    11.        MeshFromPoints(square.bottomLeft, square.topLeft, square.topRight);
    12.        break;
    Thanks in advance.

    (Edited for formatting.)
     
  6. jwheeler1106

    jwheeler1106

    Joined:
    Feb 6, 2017
    Posts:
    1
    Sebastian, thanks for putting this up. Now, I'm doing my own project which uses procedural generation, is it possible to work on my own project and follow along with your tutorial, or do the steps have to be followed to a T?
     
  7. ApocFI

    ApocFI

    Joined:
    May 26, 2017
    Posts:
    33
    E: Solved this. I used the same method as in the processmap() room threshold method.
    I realise this is not "hot" topic anymore, but as I feel that this tutorial has a sturdy base for random generation, so I'd like to ask for some help... Any help is greatly appreciated :)
    I've set up the source code to function according to this series. What I'd like to do is find the free dungeon floor squares and be able to randomly spawn things on them. I've got it working, but only in quite a primitive way. What I do is use the same method as in the mapgenerator script Randomfill(). This will randomly roll for each "0,0" tile and see if stuff should be instantiated on it. While it works, it still spawns some things inside the walls, since randomFillMap() is called before the smoothing function possibly fills in the smaller rooms left isolated.

    While my method kinda works, I'm not satisfied with it. What I think should be done is:
    - Create a list of available "free" coordinates during randomfill() method
    - Remove coordinates that are filled with walls during smoothing
    - Add coordinates for tiles that are "zeroed" during the smoothing

    Then with the complete list, go through each tile and calculate if a thing should be instantiated on it. Or perhaps set predefined amount of "stuff" to be generated on random tiles? I feel this should be done from a separate script to keep things tidy.

    However, I'm very bad with dealing with lists. I watched the unity list tutorial, but I just can't grasp this stuff completely. Even though the cave generation tutorials contain lots of dealing with the lists I'm not really assimilating the information. If anyone could help I'd be so glad!

    Source at github: https://github.com/SebLague/Procedural-Cave-Generation
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System;
    5.  
    6. public class MapGenerator : MonoBehaviour {
    7.  
    8.     public int width;
    9.     public int height;
    10.  
    11.     public string seed;
    12.     public bool useRandomSeed;
    13.  
    14.     [Range(0,100)]
    15.     public int randomFillPercent;
    16.  
    17.     int[,] map;
    18.  
    19.     void Start() {
    20.         GenerateMap();
    21.     }
    22.  
    23.     void Update() {
    24.         if (Input.GetMouseButtonDown(0)) {
    25.             GenerateMap();
    26.         }
    27.     }
    28.  
    29.     void GenerateMap() {
    30.         map = new int[width,height];
    31.         RandomFillMap();
    32.  
    33.         for (int i = 0; i < 5; i ++) {
    34.             SmoothMap();
    35.         }
    36.  
    37.         ProcessMap ();
    38.  
    39.         int borderSize = 1;
    40.         int[,] borderedMap = new int[width + borderSize * 2,height + borderSize * 2];
    41.  
    42.         for (int x = 0; x < borderedMap.GetLength(0); x ++) {
    43.             for (int y = 0; y < borderedMap.GetLength(1); y ++) {
    44.                 if (x >= borderSize && x < width + borderSize && y >= borderSize && y < height + borderSize) {
    45.                     borderedMap[x,y] = map[x-borderSize,y-borderSize];
    46.                 }
    47.                 else {
    48.                     borderedMap[x,y] =1;
    49.                 }
    50.             }
    51.         }
    52.  
    53.         MeshGenerator meshGen = GetComponent<MeshGenerator>();
    54.         meshGen.GenerateMesh(borderedMap, 1);
    55.     }
    56.  
    57.     void ProcessMap() {
    58.         List<List<Coord>> wallRegions = GetRegions (1);
    59.         int wallThresholdSize = 50;
    60.  
    61.         foreach (List<Coord> wallRegion in wallRegions) {
    62.             if (wallRegion.Count < wallThresholdSize) {
    63.                 foreach (Coord tile in wallRegion) {
    64.                     map[tile.tileX,tile.tileY] = 0;
    65.                 }
    66.             }
    67.         }
    68.  
    69.         List<List<Coord>> roomRegions = GetRegions (0);
    70.         int roomThresholdSize = 50;
    71.         List<Room> survivingRooms = new List<Room> ();
    72.    
    73.         foreach (List<Coord> roomRegion in roomRegions) {
    74.             if (roomRegion.Count < roomThresholdSize) {
    75.                 foreach (Coord tile in roomRegion) {
    76.                     map[tile.tileX,tile.tileY] = 1;
    77.                 }
    78.             }
    79.             else {
    80.                 survivingRooms.Add(new Room(roomRegion, map));
    81.             }
    82.         }
    83.         survivingRooms.Sort ();
    84.         survivingRooms [0].isMainRoom = true;
    85.         survivingRooms [0].isAccessibleFromMainRoom = true;
    86.  
    87.         ConnectClosestRooms (survivingRooms);
    88.     }
    89.  
    90.     void ConnectClosestRooms(List<Room> allRooms, bool forceAccessibilityFromMainRoom = false) {
    91.  
    92.         List<Room> roomListA = new List<Room> ();
    93.         List<Room> roomListB = new List<Room> ();
    94.  
    95.         if (forceAccessibilityFromMainRoom) {
    96.             foreach (Room room in allRooms) {
    97.                 if (room.isAccessibleFromMainRoom) {
    98.                     roomListB.Add (room);
    99.                 } else {
    100.                     roomListA.Add (room);
    101.                 }
    102.             }
    103.         } else {
    104.             roomListA = allRooms;
    105.             roomListB = allRooms;
    106.         }
    107.  
    108.         int bestDistance = 0;
    109.         Coord bestTileA = new Coord ();
    110.         Coord bestTileB = new Coord ();
    111.         Room bestRoomA = new Room ();
    112.         Room bestRoomB = new Room ();
    113.         bool possibleConnectionFound = false;
    114.  
    115.         foreach (Room roomA in roomListA) {
    116.             if (!forceAccessibilityFromMainRoom) {
    117.                 possibleConnectionFound = false;
    118.                 if (roomA.connectedRooms.Count > 0) {
    119.                     continue;
    120.                 }
    121.             }
    122.  
    123.             foreach (Room roomB in roomListB) {
    124.                 if (roomA == roomB || roomA.IsConnected(roomB)) {
    125.                     continue;
    126.                 }
    127.        
    128.                 for (int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; tileIndexA ++) {
    129.                     for (int tileIndexB = 0; tileIndexB < roomB.edgeTiles.Count; tileIndexB ++) {
    130.                         Coord tileA = roomA.edgeTiles[tileIndexA];
    131.                         Coord tileB = roomB.edgeTiles[tileIndexB];
    132.                         int distanceBetweenRooms = (int)(Mathf.Pow (tileA.tileX-tileB.tileX,2) + Mathf.Pow (tileA.tileY-tileB.tileY,2));
    133.  
    134.                         if (distanceBetweenRooms < bestDistance || !possibleConnectionFound) {
    135.                             bestDistance = distanceBetweenRooms;
    136.                             possibleConnectionFound = true;
    137.                             bestTileA = tileA;
    138.                             bestTileB = tileB;
    139.                             bestRoomA = roomA;
    140.                             bestRoomB = roomB;
    141.                         }
    142.                     }
    143.                 }
    144.             }
    145.             if (possibleConnectionFound && !forceAccessibilityFromMainRoom) {
    146.                 CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
    147.             }
    148.         }
    149.  
    150.         if (possibleConnectionFound && forceAccessibilityFromMainRoom) {
    151.             CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
    152.             ConnectClosestRooms(allRooms, true);
    153.         }
    154.  
    155.         if (!forceAccessibilityFromMainRoom) {
    156.             ConnectClosestRooms(allRooms, true);
    157.         }
    158.     }
    159.  
    160.     void CreatePassage(Room roomA, Room roomB, Coord tileA, Coord tileB) {
    161.         Room.ConnectRooms (roomA, roomB);
    162.         //Debug.DrawLine (CoordToWorldPoint (tileA), CoordToWorldPoint (tileB), Color.green, 100);
    163.  
    164.         List<Coord> line = GetLine (tileA, tileB);
    165.         foreach (Coord c in line) {
    166.             DrawCircle(c,5);
    167.         }
    168.     }
    169.  
    170.     void DrawCircle(Coord c, int r) {
    171.         for (int x = -r; x <= r; x++) {
    172.             for (int y = -r; y <= r; y++) {
    173.                 if (x*x + y*y <= r*r) {
    174.                     int drawX = c.tileX + x;
    175.                     int drawY = c.tileY + y;
    176.                     if (IsInMapRange(drawX, drawY)) {
    177.                         map[drawX,drawY] = 0;
    178.                     }
    179.                 }
    180.             }
    181.         }
    182.     }
    183.  
    184.     List<Coord> GetLine(Coord from, Coord to) {
    185.         List<Coord> line = new List<Coord> ();
    186.  
    187.         int x = from.tileX;
    188.         int y = from.tileY;
    189.  
    190.         int dx = to.tileX - from.tileX;
    191.         int dy = to.tileY - from.tileY;
    192.  
    193.         bool inverted = false;
    194.         int step = Math.Sign (dx);
    195.         int gradientStep = Math.Sign (dy);
    196.  
    197.         int longest = Mathf.Abs (dx);
    198.         int shortest = Mathf.Abs (dy);
    199.  
    200.         if (longest < shortest) {
    201.             inverted = true;
    202.             longest = Mathf.Abs(dy);
    203.             shortest = Mathf.Abs(dx);
    204.  
    205.             step = Math.Sign (dy);
    206.             gradientStep = Math.Sign (dx);
    207.         }
    208.  
    209.         int gradientAccumulation = longest / 2;
    210.         for (int i =0; i < longest; i ++) {
    211.             line.Add(new Coord(x,y));
    212.  
    213.             if (inverted) {
    214.                 y += step;
    215.             }
    216.             else {
    217.                 x += step;
    218.             }
    219.  
    220.             gradientAccumulation += shortest;
    221.             if (gradientAccumulation >= longest) {
    222.                 if (inverted) {
    223.                     x += gradientStep;
    224.                 }
    225.                 else {
    226.                     y += gradientStep;
    227.                 }
    228.                 gradientAccumulation -= longest;
    229.             }
    230.         }
    231.  
    232.         return line;
    233.     }
    234.  
    235.     Vector3 CoordToWorldPoint(Coord tile) {
    236.         return new Vector3 (-width / 2 + .5f + tile.tileX, 2, -height / 2 + .5f + tile.tileY);
    237.     }
    238.  
    239.     List<List<Coord>> GetRegions(int tileType) {
    240.         List<List<Coord>> regions = new List<List<Coord>> ();
    241.         int[,] mapFlags = new int[width,height];
    242.  
    243.         for (int x = 0; x < width; x ++) {
    244.             for (int y = 0; y < height; y ++) {
    245.                 if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
    246.                     List<Coord> newRegion = GetRegionTiles(x,y);
    247.                     regions.Add(newRegion);
    248.  
    249.                     foreach (Coord tile in newRegion) {
    250.                         mapFlags[tile.tileX, tile.tileY] = 1;
    251.                     }
    252.                 }
    253.             }
    254.         }
    255.  
    256.         return regions;
    257.     }
    258.  
    259.     List<Coord> GetRegionTiles(int startX, int startY) {
    260.         List<Coord> tiles = new List<Coord> ();
    261.         int[,] mapFlags = new int[width,height];
    262.         int tileType = map [startX, startY];
    263.  
    264.         Queue<Coord> queue = new Queue<Coord> ();
    265.         queue.Enqueue (new Coord (startX, startY));
    266.         mapFlags [startX, startY] = 1;
    267.  
    268.         while (queue.Count > 0) {
    269.             Coord tile = queue.Dequeue();
    270.             tiles.Add(tile);
    271.  
    272.             for (int x = tile.tileX - 1; x <= tile.tileX + 1; x++) {
    273.                 for (int y = tile.tileY - 1; y <= tile.tileY + 1; y++) {
    274.                     if (IsInMapRange(x,y) && (y == tile.tileY || x == tile.tileX)) {
    275.                         if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
    276.                             mapFlags[x,y] = 1;
    277.                             queue.Enqueue(new Coord(x,y));
    278.                         }
    279.                     }
    280.                 }
    281.             }
    282.         }
    283.         return tiles;
    284.     }
    285.  
    286.     bool IsInMapRange(int x, int y) {
    287.         return x >= 0 && x < width && y >= 0 && y < height;
    288.     }
    289.  
    290.  
    291.     void RandomFillMap() {
    292.  
    293.         if (useRandomSeed) {
    294.             seed = Time.time.ToString();
    295.         }
    296.  
    297.         System.Random pseudoRandom = new System.Random(seed.GetHashCode());
    298.  
    299.         for (int x = 0; x < width; x ++) {
    300.             for (int y = 0; y < height; y ++) {
    301.                 if (x == 0 || x == width-1 || y == 0 || y == height -1) {
    302.                     map[x,y] = 1;
    303.                 }
    304.                 else {
    305.                     map[x,y] = (pseudoRandom.Next(0,100) < randomFillPercent)? 1: 0;
    306.                 }
    307.             }
    308.         }
    309.     }
    310.  
    311.     void SmoothMap() {
    312.         for (int x = 0; x < width; x ++) {
    313.             for (int y = 0; y < height; y ++) {
    314.                 int neighbourWallTiles = GetSurroundingWallCount(x,y);
    315.  
    316.                 if (neighbourWallTiles > 4)
    317.                     map[x,y] = 1;
    318.                 else if (neighbourWallTiles < 4)
    319.                     map[x,y] = 0;
    320.  
    321.             }
    322.         }
    323.     }
    324.  
    325.     int GetSurroundingWallCount(int gridX, int gridY) {
    326.         int wallCount = 0;
    327.         for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX ++) {
    328.             for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY ++) {
    329.                 if (IsInMapRange(neighbourX,neighbourY)) {
    330.                     if (neighbourX != gridX || neighbourY != gridY) {
    331.                         wallCount += map[neighbourX,neighbourY];
    332.                     }
    333.                 }
    334.                 else {
    335.                     wallCount ++;
    336.                 }
    337.             }
    338.         }
    339.  
    340.         return wallCount;
    341.     }
    342.  
    343.     struct Coord {
    344.         public int tileX;
    345.         public int tileY;
    346.  
    347.         public Coord(int x, int y) {
    348.             tileX = x;
    349.             tileY = y;
    350.         }
    351.     }
    352.  
    353.  
    354.     class Room : IComparable<Room> {
    355.         public List<Coord> tiles;
    356.         public List<Coord> edgeTiles;
    357.         public List<Room> connectedRooms;
    358.         public int roomSize;
    359.         public bool isAccessibleFromMainRoom;
    360.         public bool isMainRoom;
    361.  
    362.         public Room() {
    363.         }
    364.  
    365.         public Room(List<Coord> roomTiles, int[,] map) {
    366.             tiles = roomTiles;
    367.             roomSize = tiles.Count;
    368.             connectedRooms = new List<Room>();
    369.  
    370.             edgeTiles = new List<Coord>();
    371.             foreach (Coord tile in tiles) {
    372.                 for (int x = tile.tileX-1; x <= tile.tileX+1; x++) {
    373.                     for (int y = tile.tileY-1; y <= tile.tileY+1; y++) {
    374.                         if (x == tile.tileX || y == tile.tileY) {
    375.                             if (map[x,y] == 1) {
    376.                                 edgeTiles.Add(tile);
    377.                             }
    378.                         }
    379.                     }
    380.                 }
    381.             }
    382.         }
    383.  
    384.         public void SetAccessibleFromMainRoom() {
    385.             if (!isAccessibleFromMainRoom) {
    386.                 isAccessibleFromMainRoom = true;
    387.                 foreach (Room connectedRoom in connectedRooms) {
    388.                     connectedRoom.SetAccessibleFromMainRoom();
    389.                 }
    390.             }
    391.         }
    392.  
    393.         public static void ConnectRooms(Room roomA, Room roomB) {
    394.             if (roomA.isAccessibleFromMainRoom) {
    395.                 roomB.SetAccessibleFromMainRoom ();
    396.             } else if (roomB.isAccessibleFromMainRoom) {
    397.                 roomA.SetAccessibleFromMainRoom();
    398.             }
    399.             roomA.connectedRooms.Add (roomB);
    400.             roomB.connectedRooms.Add (roomA);
    401.         }
    402.  
    403.         public bool IsConnected(Room otherRoom) {
    404.             return connectedRooms.Contains(otherRoom);
    405.         }
    406.  
    407.         public int CompareTo(Room otherRoom) {
    408.             return otherRoom.roomSize.CompareTo (roomSize);
    409.         }
    410.     }
    411.  
    412. }
    413.  
     
    Last edited: Oct 19, 2017
  8. GregoryFenn

    GregoryFenn

    Joined:
    Feb 13, 2018
    Posts:
    43

    Are you sure you need it? Why not just create an empty GameObject with the 2D and 3D copies of the same object (or same object but with 2d vs 3d components) as two child-objects? Then you can script it to turn one child on active and the other off when you need.
     
    Last edited: Jun 9, 2018
  9. GregoryFenn

    GregoryFenn

    Joined:
    Feb 13, 2018
    Posts:
    43
    "The variable walls of MeshGenerator has not been assigned."

    The error is at line 'walls.mesh = wallMesh;'


    I can't see what I'm doing wrong. The 2d meshg works great but I can't build tall walls yet, Both my code and the code copied from the website produce identical errors.

    Anyone got any ideas? I'm guessing it's something to do with the new unity, because I notice 'Mesh' isn't a valid type anymore, but that's just a hunch.
     
  10. djones_unity841

    djones_unity841

    Joined:
    May 24, 2018
    Posts:
    1
    This is the error message that I'm getting on episode 1. "The associated script can not be loaded. Please fix any compile errors and assign a valid script." I guessed that I typed the code wrong so I deleted what I had and copied what Sebastian has, but I still get this message. Can someone please help me?
     
  11. GabrielSteffens

    GabrielSteffens

    Joined:
    Jul 12, 2018
    Posts:
    1
    Hi @SebastianLague , I'm new to Unity, I wonder how I created a respawn where it would always stay in the upper left corner.
     
  12. Haradev

    Haradev

    Joined:
    Sep 5, 2018
    Posts:
    1
    Hello guys, I'm trying to learn at 100% this work and an issue bothered my mind: how can I do to make walls not only in the outlines but in the entire map? In this way the wall colliders will become the whole cave.

    Thank you for the help
     
  13. Deleted User

    Deleted User

    Guest

    @SebastianLague

    So, the support for this tutorial is dead? Is it worth putting any effort in it yet?
     
  14. appcompgroup

    appcompgroup

    Joined:
    Apr 10, 2019
    Posts:
    2
    Not sure if this is still active, but I am currently working with a disabled student working on developing his Unity skills. He tried your tutorial - typing in as he followed the video - but nothing appeared when he runs the code. I tried it with the same result, and I just downloaded your source from Github and still get nothing appearing. Does the code need an update to run with newer versions of Unity? Did we miss something? Cheers....
     
  15. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,297
    The project works in newer versions - just tried 2017 LTS and latest 2018.3 - in both Scene2D and Scene3D runs correctly
    - be sure to open 'Unity Project' from repository in Unity/Hub - the other folders contain just exercise scripts not projects..

    Hope this helps!
     
  16. appcompgroup

    appcompgroup

    Joined:
    Apr 10, 2019
    Posts:
    2
    I am not an expert in this.... and I still can't anything to work (I'm 64so I blame my age). Downloaded the repository which has the Episode folders and a Project folder. Tried adding the test scripts, an episode at a time for checking alongside the videos. Episode one added the script to the empty object and ran it - nothing appeared to happen, then by accident clicked the pause button and the 'map' appeared in the scene window. Nothing happened at all with the other scripts. Tried to add the project, but I'm obviously missing something as the project folder contains asset folder and settings folder but no 'project?'. What's the easy way to get the project up and running so I can go over it with the student?
    Cheers

    Dave (Miserable Old Git) Ireland
     
  17. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,297
    The 'Assets' folder, and 'ProjectSettings' and basically the only two things unity needs to open a directory in which they're in as 'a project' - so in case of this repository you should open 'Unity Project' *from* Unity ( the project in unity is then known as 'Unity Project' )

    I don't have time to go thru videos, sorry; you'd have to ask concrete questions

    But I recommend joining e.g. discord https://discord.gg/unity or official IRC channel - that's (way) better place for interactive troubleshooting than forums
     
  18. lus-sco

    lus-sco

    Joined:
    Jan 18, 2019
    Posts:
    3
    hey i have an issue with this tutorial. In the first video, after you put "return wallCount;" and playtest it, my computer just will not load it and unity crashes. Please help?
     
  19. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    I loved this. I was trying to challenge my self by turning this into squares only, turning the actual shapes into squares was easy enough, I just modified the
    TriangulateSquare
    function in the MeshGenerator.

    However, when I do this, it messes up the walls completely, I simply tried adding this which gives me my desired shape:

    Code (CSharp):
    1. void TriangulateSquare(Square square)
    2.     {
    3.         if (onlySquares)
    4.         {
    5.             if(square.configuration != 0)
    6.             {
    7.                 square.configuration = 15;
    8.                 MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.bottomLeft);
    9.                 return;
    10.             }
    11.         }
    12.  
    13. //...


    The above code has the desired effect, however all walls are rendered the wrong direction.

    I've been playing around with all options I can think of, but it never really works the same, always some bug with the walls not properly following the shape, or being turned the wrong way (not rendering right side of wall).

    Anyone that has any ideas?
     
    Last edited: Nov 24, 2019
  20. Thood82

    Thood82

    Joined:
    Feb 13, 2021
    Posts:
    1
    mastrsushi how did you turn it into a maze