Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Supremetor · Apr 30 at 08:17 PM · coroutineenumprocedural generation2d array

Enum value is being reset during runtime

I am working on a project where I procedurally generate a map for a metroidvania game. I use a 2-dimensional grid of CellInfos to hold important information about the map layout and allow the algorithm to know what has been generated. The CellInfo class has four (left, right, up, and down) PassageType enums which together describe how that cell of the grid connects to the rest of the map.

PassageType works as follows:

  1. Open: the cell has a door in the direction of that variable.

  2. Closed: the cell has a wall (or another part of a bigger room) in the direction of that variable.

  3. Free: the cell is not used by the currently generated map (for now).

For an unknown reason, when the PassageType is supposed to be Closed, it is instead Free, which causes the generation algorithm to make mistakes. Using Debug.Log statements, I have verified that the PassageTypes are never set to Free (except when the grid is first created) and have verified that the PassageTypes are correctly told to be Closed when room are spawned. Despite this, every cell direction is only either Open or Free, but never Closed. I managed to manually set the first cell's downType to Closed (as shown in the below image) so sometimes it keeps the change and sometimes it does not.

I changed one of the enum variables in CellInfo to a property which creates debug logs whenever anything happens to that variable, and it never logs a change to Free (except at grid creation).

Below are the scripts for the Generator (the more relevant parts are GenerateWorld(), CreateGrid(), and the SpawnRoom() methods ) and CellInfo classes along with a screenshot that uses gizmos to display the grid of CellInfos (Blue=Free, Green=Open, Red=Closed).

Generator:

 // Start is called before the first frame update
     void Start()
     {
         //Create the world
         StartCoroutine(GenerateWorld());
     }
 
     private void OnDrawGizmos()
     {
         if(drawGizmos)
         {
             if(grid != null)
             {
                 for (int i = 0; i < grid.Length; i++)
                 {
                     if(grid[i] != null)
                     {
                         for (int j = 0; j < grid[i].Length; j++)
                         {
                             CellInfo cell = grid[i][j];
 
                             Color leftColor = freeColor;
                             Color rightColor = freeColor;
                             Color upColor = freeColor;
                             Color downColor = freeColor;
 
                             if(cell.GetLeftType() == PassageType.Closed)
                             {
                                 leftColor = closedColor;
                             }
                             else if(cell.GetLeftType() == PassageType.Open)
                             {
                                 leftColor = openColor;
                             }
 
                             if (cell.GetRightType() == PassageType.Closed)
                             {
                                 rightColor = closedColor;
                             }
                             else if (cell.GetRightType() == PassageType.Open)
                             {
                                 rightColor = openColor;
                             }
 
                             if (cell.GetUpType() == PassageType.Closed)
                             {
                                 upColor = closedColor;
                             }
                             else if (cell.GetUpType() == PassageType.Open)
                             {
                                 upColor = openColor;
                             }
 
                             if (cell.GetDownType() == PassageType.Closed)
                             {
                                 downColor = closedColor;
                             }
                             else if (cell.GetDownType() == PassageType.Open)
                             {
                                 downColor = openColor;
                             }
 
                             Vector3 cellPos = new Vector3(i * cellSize.x, j * cellSize.y, 0f);
                             Vector3 leftPos = cellPos + new Vector3(-1f, 0f, 0f);
                             Vector3 rightPos = cellPos + new Vector3(1f, 0f, 0f);
                             Vector3 upPos = cellPos + new Vector3(0f, 1f, 0f);
                             Vector3 downPos = cellPos + new Vector3(0f, -1f, 0f);
 
                             Gizmos.color = leftColor;
                             Gizmos.DrawWireSphere(leftPos, 1f);
 
                             Gizmos.color = rightColor;
                             Gizmos.DrawWireSphere(rightPos, 1f);
 
                             Gizmos.color = upColor;
                             Gizmos.DrawWireSphere(upPos, 1f);
 
                             Gizmos.color = downColor;
                             Gizmos.DrawWireSphere(downPos, 1f);
                         }
                     }
                 }
             }
         }
     }
 
     
     private IEnumerator GenerateWorld()
     {
         //Create the grid of CellInfos
         CreateGrid();
 
         //Spawn in the start room at the start position and get the new cells where rooms can be created
         List<Vector3Int> newRoomCells = SpawnRoom(startRoom, startPoint);
 
         Debug.Log("Starting down type: " + grid[50][50].GetDownType());
         grid[50][50].SetDownType(PassageType.Closed);
         Debug.Log("Ending down type: " + grid[50][50].GetDownType());
 
         Camera.main.transform.position = new Vector3(startPoint.x * cellSize.x, startPoint.y * cellSize.y, -10f);
 
         //While there are still cells where rooms can be spawned, keep generating the world
         while(newRoomCells.Count > 0)
         {
             yield return new WaitForSeconds(1f);
 
             //Get a random cell from the list of possible cells where rooms need to be spawned
             int randCellIndex = Random.Range(0, newRoomCells.Count);
             Vector3Int randCell = newRoomCells[randCellIndex];
             
             //If this cell is not valid (is occupied), remove and skip it
             if(!grid[randCell.x][randCell.y].IsFree())
             {
                 newRoomCells.RemoveAt(randCellIndex);
                 continue;
             }
             
             //Get the room that should be spawned (look at restraints, find valid rooms, randomly choose one of them)
             RoomInfo roomToSpawn = GetRoomToSpawn(worldRooms, randCell);
 
             //Spawn in the new room at the new position and get the new cells where rooms can be created
             List<Vector3Int> newCells = SpawnRoom(roomToSpawn, randCell);
 
             //Loop through the new room's new cells and add them to the list of cells where new rooms can be created
             for (int i = 0; i < newCells.Count; i++)
             {
                 newRoomCells.Add(newCells[i]);
             }
 
             //Remove this cell from the list since it is now occupied
             newRoomCells.RemoveAt(randCellIndex);
         }
     }//end GenerateWorld
 
     /// <summary>
     /// Create the grid of CellInfos
     /// </summary>
     private void CreateGrid()
     {
         //Create the column array
         grid = new CellInfo[GRID_SIZE.x][];
 
         //Loop through the column array to create the row arrays
         for (int i = 0; i < grid.Length; i++)
         {
             //Create the row array
             grid[i] = new CellInfo[GRID_SIZE.y];
 
             //Loop through the row array (access every cell in the grid)
             for (int j = 0; j < grid[i].Length; j++)
             {
                 //Create the cell
                 grid[i][j] = new CellInfo();
             }
         }
     }//end CreateGrid
 
     //
     private List<Vector3Int> SpawnRoom(RoomInfo roomInfo, Vector3Int sourceCell)
     {
         //Default the origin cell to the passed source cell
         Vector2Int originCell = new Vector2Int(sourceCell.x, sourceCell.y);
 
         //Get the possible origin cells for this room
         List<Vector2Int> originCells = GetValidOriginCells(roomInfo, sourceCell);
 
         //If there are valid origin cells to randomly choose from
         if(originCells.Count > 0)
         {
             //Get a random cell from the list of possible origin cells
             int randCellIndex = Random.Range(0, originCells.Count);
 
             //Set this random cell as the origin cell
             originCell = originCells[randCellIndex];
         }
 
         //Spawn the room at the determined origin cell and return its new available source cells
         return SpawnRoom(roomInfo, originCell);
     }
 
     /// <summary>
     /// Spawn the given room at the given grid cell and update the grid accordingly
     /// </summary>
     /// <param name="roomInfo">The RoomInfo whose room needs to be spawned in to the world</param>
     /// <param name="coords">The(0,0) cell coordinates in the grid for this room</param>
     /// <returns>Returns a list of cell coordinates where new rooms can (and need to) be created</returns>
     private List<Vector3Int> SpawnRoom(RoomInfo roomInfo, Vector2Int coords)
     {
         //Spawn the passed room object
         GameObject room = Instantiate(roomInfo.GetRoom(), worldParent);
 
         //Move the room to the correct position
         room.transform.position = new Vector3(coords.x * cellSize.x, coords.y * cellSize.y, 0f);
 
         //Get the size of the room
         Vector2Int roomSize = roomInfo.GetRoomSize();
 
         //Mark the cells occupied by this new room as Closed
         //Loop through the columns the room occupies
         for (int i = 0; i < roomSize.x; i++)
         {
             //Loop through the rows the room occupies
             for (int j = 0; j < roomSize.y; j++)
             {
                 //Mark the cell as closed
                 //grid[i][j].SetAllClosed();
                 grid[i][j].SetLeftType(PassageType.Closed);
                 grid[i][j].SetRightType(PassageType.Closed);
                 grid[i][j].SetUpType(PassageType.Closed);
                 grid[i][j].SetDownType(PassageType.Closed);
             }
         }
 
         //Create a list which will hold the cell coordinates where new rooms need to be created
         List<Vector3Int> newRoomCells = new List<Vector3Int>();
 
         //Get the string array which represents the room's doors
         string[] doors = roomInfo.GetDoors();
 
         //Mark the cells occupied by this new room's doors as Open
         //Loop through the array of doors
         for (int i = 0; i < doors.Length; i++)
         {
             //Get the different elements of the door string
             string[] pieces = doors[i].Split(RoomInfo.DOOR_STRING_SEPARATOR);
 
             //Get the doors coordinate offset from the room's origin
             int xOffset = (int)char.GetNumericValue(pieces[1][0]);
             int yOffset = (int)char.GetNumericValue(pieces[1][1]);
             //Debug.Log("00: " + pieces[0][0] + ", 10: " + pieces[1][0] + ", 11: " + pieces[1][1]);
 
             //If the door is a left door, set the cell to open left
             if(pieces[0][0].Equals('L'))
             {
                 grid[coords.x + xOffset][coords.y + yOffset].SetLeftType(PassageType.Open);
 
                 //If the cell this door leads to is free, a new room needs to be spawned here
                 if(grid[coords.x + xOffset - 1][coords.y + yOffset].IsFree())
                 {
                     newRoomCells.Add(new Vector3Int(coords.x + xOffset - 1, coords.y + yOffset, 0));
                 }
             }
             //If the door is a right door, set the cell to open right
             else if (pieces[0][0].Equals('R'))
             {
                 grid[coords.x + xOffset][coords.y + yOffset].SetRightType(PassageType.Open);
 
                 //If the cell this door leads to is free, a new room needs to be spawned here
                 if (grid[coords.x + xOffset + 1][coords.y + yOffset].IsFree())
                 {
                     newRoomCells.Add(new Vector3Int(coords.x + xOffset + 1, coords.y + yOffset, 1));
                 }
             }
             //If the door is an up door, set the cell to open up
             else if (pieces[0][0].Equals('U'))
             {
                 grid[coords.x + xOffset][coords.y + yOffset].SetUpType(PassageType.Open);
 
                 //If the cell this door leads to is free, a new room needs to be spawned here
                 if (grid[coords.x + xOffset][coords.y + yOffset + 1].IsFree())
                 {
                     newRoomCells.Add(new Vector3Int(coords.x + xOffset, coords.y + yOffset + 1, 2));
                 }
             }
             //If the door is a down door, set the cell to open down
             else if (pieces[0][0].Equals('D'))
             {
                 grid[coords.x + xOffset][coords.y + yOffset].SetDownType(PassageType.Open);
 
                 //If the cell this door leads to is free, a new room needs to be spawned here
                 if (grid[coords.x + xOffset][coords.y + yOffset - 1].IsFree())
                 {
                     newRoomCells.Add(new Vector3Int(coords.x + xOffset, coords.y + yOffset - 1, 3));
                 }
             }
         }
 
         //Return the list of cells where new rooms need to be spawned
         return newRoomCells;
     }//end SpawnRoom


CellInfo:

 public class CellInfo
 {
     private PassageType leftType;
     private PassageType rightType;
     private PassageType upType;
     private PassageType _downType;
     public PassageType downType
     {
         get { Debug.Log("Getting Down Type: " + _downType); return _downType; }
         set { Debug.Log("Down Type changed from " + _downType + " to " + value); _downType = value; }
     }
 
     public CellInfo()
     {
         leftType = PassageType.Free;
         rightType = PassageType.Free;
         upType = PassageType.Free;
         downType = PassageType.Free;
     }
 
     public PassageType GetLeftType()
     {
         return leftType;
     }
 
     public PassageType GetRightType()
     {
         return rightType;
     }
 
     public PassageType GetUpType()
     {
         return upType;
     }
 
     public PassageType GetDownType()
     {
         return downType;
     }
 
     public bool IsFree()
     {
         return leftType == PassageType.Free && rightType == PassageType.Free && upType == PassageType.Free && downType == PassageType.Free;
     }
 
     public void SetAllClosed()
     {
         Debug.Log("setting all closed");
         SetLeftType(PassageType.Closed);
         SetRightType(PassageType.Closed);
         SetUpType(PassageType.Closed);
         SetDownType(PassageType.Closed);
     }
 
     public void SetLeftType(PassageType newType)
     {
         leftType = newType;
     }
 
     public void SetRightType(PassageType newType)
     {
         rightType = newType;
     }
 
     public void SetUpType(PassageType newType)
     {
         upType = newType;
     }
 
     public void SetDownType(PassageType newType)
     {
         downType = newType;
     }
 }
 public enum PassageType { Open, Closed, Free }


Image:

The one red circle only exists because I manually set that CellInfo's downType to Closed in GenerateWorld() of Generator

So to recap: there are enums which should be set to Closed but always change to Free on their own (except when they don't). I would like to know why this is happening so I can fix it or I would like a feasible alternative system for handling the generation.

There is more code I could share but I already feel like this is too much so I'll restrain myself unless someone asks for the rest of it. In case it matters, the project uses Unity version 2021.3.0f1.

Any help is appreciated. Thank you.

project-screenshot-edit.png (31.3 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

149 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Need opinions, or facts, about how to best go about programming this behavior. Basically Redstone. 0 Answers

StartCoroutine() and yield return www does not work with Unity Web Player build 0 Answers

LoadLevel*Aynsc() and Coroutine 3 Answers

Execution manner of co routine 2 Answers

Issue With Simultaneous ReadPixels Calls 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges