Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
2
Question by blaster182 · Dec 19, 2013 at 05:38 AM · randomgenerationsplitrectanglehouse

How do I split a rectangle into random smaller rectangles?

It's on a grid, these smaller rectangles should have a minimum size and they should have random size. I will probably need to cap the amount of rooms too. I'm having a problem on the "repeat until it's too small to split" part mainly. I've got it to divide it one time, but I can't get my head around this loop.

I'm using Javascript(Unityscript).

This is what I would like to make. A house similar to this.

alt text

The grey tiles are empty, white tiles are the floor that I'm trying to build and rooms should have 7 tiles in size to be divided, for rooms to have a minimum of 3x3 in size and maximum of 6x6.

I'm using an int[,] array as grid and setting values to instantiate objects later on another function.

After building the floor (white) I'll build the walls around, and the doors, which I have no idea how to put them where they'll work.

I'll attach the code in case someone would like to take a look.

 #pragma strict
 
 var size:int;
 var minroomsize:int;
 var splitpointx:int;
 var splitpointy:int;
 var grid:int[,];
 var wall:GameObject;
 var floor:GameObject;
 var binary:int;
 var newgrid;
 var walls:GameObject;
 var floors:GameObject;
 var grid1:int[,];
 var grid2:int[,];
 
 var g1lengthx:int;
 var g2lengthx:int;
 var g1lengthy:int;
 var g2lengthy:int;
 
 var group:GameObject;
 var group1:GameObject;
 var group2:GameObject;
 
 function Start(){
 size=20;
 minroomsize=4;
 splitpointx=0;
 splitpointy=0;
 grid= new int[size,size];
 Run(size);
 
 }
 
 function Run(size:int){
     House(size);
     binary=Random.Range(0.0,2.0);
     if(binary==1){
         SplitV(grid);
     }else{
         SplitH(grid);
     }
     Debug.Log("g1lengthx = "+g1lengthx+" g1lengthy = "+g1lengthy+" g2lengthx = "+g2lengthx+" g2lengthy = "+g2lengthy);
     Loop(g1lengthx,g1lengthy,grid1);
     Loop(g2lengthx,g2lengthy,grid2);
     Test(size,grid1,grid2);
 }
 
 function Update(){
     if(Input.GetButtonDown("F5")){
         Reset();
         Run(size);
 
     }
 }
 
 function House(size:int){
 
     for(var x:int;x<size;x++){
         for(var y:int;y<size;y++){
             if(x>0&&x<size-1&&y>0&&y<size-1){
                 grid[x,y]=2;        
             }            
         }
     }
 }
 function Loop(x:int,y:int,grid:int[,]){
     binary=Random.Range(0.0,2.0);
     var number:int;
     number=0;
     if(binary==1){
         while(x>minroomsize){
             SplitV(grid);
             if(x<=minroomsize){
                 break;
             }
             number++;
             if(number>20){
                 break;
             }
             if(number==20){
                 Debug.Log("wrong");
             }
         }
     }else{
         while(y>minroomsize){
             SplitH(grid);
             number++;
             if(y<=minroomsize){
                 break;
             }
             if(number>20){
                 break;
             }
             if(number==20){
                 Debug.Log("wrong");
             }
         }
     }
 }
 
 function SplitV(grid:int[,]){
     
     splitpointx=Random.Range(minroomsize,size-1-minroomsize);
 
     //Debug.Log("vertical split");
     grid1=new int[size,size];
     grid2=new int[size,size];
     
     for(var m:int=1;m<grid.GetLength(0);m++){
         for(var n:int=1;n<grid.GetLength(1);n++){
             if(m<splitpointx){
                 //grid2[m,n]=0;
                 grid1[m,n]=grid[m,n];
                 if(grid1[1,n]==2){
                     g1lengthy++;
                 }
                 if(grid1[m,1]==2){
                     g1lengthx++;
                 }
             }else if(m>splitpointx){
                 //grid1[m,n]=0;
                 grid2[m,n]=grid[m,n];
                 if(grid2[grid.GetLength(0)-1,n]==2){
                     g2lengthy++;
                 }
                 if(grid2[m,grid.GetLength(1)-1]==2){
                     g2lengthx++;
                 }
             }
         }
     }
 }
 
 function SplitH(grid:int[,]){
     splitpointy=Random.Range(minroomsize,size-1-minroomsize);
 //Debug.Log("horizontal split");
     grid1=new int[size,size];
     grid2=new int[size,size];
     
     for(var m:int=1;m<grid.GetLength(0);m++){
         for(var n:int=1;n<grid.GetLength(1);n++){
             if(n<splitpointy){            
                 grid1[m,n]=grid[m,n];
                 if(grid1[1,n]==2){
                     g1lengthy++;
                 }
                 if(grid1[m,1]==2){
                     g1lengthx++;
                 }
             }else if(n>splitpointy){
                 grid2[m,n]=grid[m,n];
                 if(grid2[grid.GetLength(0)-1,n]==2){
                     g2lengthy++;
                 }
                 if(grid2[m,grid.GetLength(1)-1]==2){
                     g2lengthx++;
                 }
             }
         }
     }
 }
 
 
 function Build(size:int){
     for(var x:int;x<size;x++){
         for(var y:int;y<size;y++){
             if(grid[x,y]==1){
                 var walls=Instantiate(wall,Vector3(x,wall.transform.localScale.y/2,y),Quaternion.identity);
                 walls.transform.parent=this.transform;
             }
             if(grid[x,y]==2){
                 var floors=Instantiate(floor,Vector3(x,0,y),Quaternion.Euler(90,0,0));
                 floors.transform.parent=this.transform;
             }
         }
     }
 }
 
 function Test(size:int,grid1:int[,],grid2:int[,]){
     //Debug.Log("Test");
     
     for(var x:int=1;x<size;x++){
         for(var y:int=1;y<size;y++){
             
             if(grid1[x,y]==1){
                 //Debug.Log("grid1 wall");
                 var walls=Instantiate(wall,Vector3(x,wall.transform.localScale.y/2,y),Quaternion.identity);
                 walls.transform.parent=group1.transform;
             }
             if(grid1[x,y]==2){
                 //Debug.Log("grid1 floor");
                 var floors=Instantiate(floor,Vector3(x,0,y),Quaternion.Euler(90,0,0));
                 floors.transform.parent=group1.transform;
             }
             if(grid2[x,y]==1){
                 //Debug.Log("grid2 wall");
                 walls=Instantiate(wall,Vector3(x,wall.transform.localScale.y/2,y),Quaternion.identity);
                 walls.transform.parent=group2.transform;
             }
             if(grid2[x,y]==2){
                 //Debug.Log("grid2 floor");
                 floors=Instantiate(floor,Vector3(x,0,y),Quaternion.Euler(90,0,0));
                 floors.transform.parent=group2.transform;
             }
         }
     }
 }
 
 function Reset(){
     if(this.transform.childCount!=0){
         var child:int;
         child=this.transform.childCount;
         for(var x:int;x<child;x++){
             Destroy(this.transform.GetChild(x).gameObject);
         }
     }
 }

I really appreciate if someone helped me out on this. =)

Comment
Add comment · Show 5
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
avatar image robertbu · Dec 19, 2013 at 06:04 AM 0
Share

You need to re-insert your image. Note there are size limits on images.

avatar image blaster182 · Dec 19, 2013 at 03:38 PM 0
Share

Thanks robertbu! I will.

avatar image blaster182 · Dec 19, 2013 at 03:52 PM 0
Share

Is the image working now? I can see it from here. I've hosted it now.

avatar image robertbu · Dec 19, 2013 at 04:18 PM 0
Share

So now I see the picture and understand the problem. You have a big body of code here. What is this code doing or not doing? In relation to the code, what are you asking of list? Your problem seems like the perfect excuse for using recursion.

There is also the issue here that it isn't a Unity question.

avatar image blaster182 · Dec 19, 2013 at 08:01 PM 0
Share

well I'm using Unity. And since I use Unityscript I thought this was the best place. I'll consider this next time. The code is adding values to a bi-dimensional array, then it gets half of this array values and write each to two new arrays, leaving an empty row or column (with random position) between them, then it instantiates tiles based on the values on the two grids. All I need is to make the loop happen until the rooms have from 6 to 3 tiles of space, and possibly get some tips on how to do it better. I'm new to program$$anonymous$$g, been like 6 months since I started so I don't know how to use recursion here.

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Dec 19, 2013 at 04:58 PM

I've just written two quick estension methods for Rect:

Just place this code in a C# file inside the "plugins" folder in your assets folder. You can use it from C# and UnityScript that way.

 // C#
 public static class RectSplitter
 {
     public static List<Rect> SplitOnce(this Rect aSource, Vector2 aMinSize)
     {
         float aspect = aMinSize.x/aMinSize.y;
         if (aSource.width > aSource.height*aspect)
         {
             if (aSource.width > aMinSize.x*2)
             {
                 float range = (aSource.width-aMinSize.x*2);
                 float split = Random.Range(0,range) + aMinSize.x;
                 Rect R1 = aSource;
                 Rect R2 = aSource;
                 R1.xMax -= split;
                 R2.xMin = R1.xMax;
                 var result = new List<Rect>();
                 result.Add(R1);
                 result.Add(R2);
                 return result;
             }
             else
                 return null;
         }
         else
         {
             if (aSource.height > aMinSize.y*2)
             {
                 float range = (aSource.height-aMinSize.y*2);
                 float split = Random.Range(0,range) + aMinSize.y;
                 Rect R1 = aSource;
                 Rect R2 = aSource;
                 R1.yMax -= split;
                 R2.yMin = R1.yMax;
                 var result = new List<Rect>();
                 result.Add(R1);
                 result.Add(R2);
                 return result;
             }
             else
                 return null;
         }
     }
     
     public static List<Rect> Split(this Rect aSource, Vector2 aMinSize)
     {
         var result = new List<Rect>();
         var tmp = SplitOnce(aSource,aMinSize);
         if (tmp != null)
         {
             foreach(Rect R in tmp)
             {
                 result.AddRange(Split(R,aMinSize));
             }
         }
         else 
             result.Add(aSource);
         return result;
     }
 }

This method splits a given Rect into smaller rects based on the given min-size. It goes recursively over the rects until they reached a size that can't be splitted anymore.

Note: The method works on rects and float values, so if you need them applied to a grid, you have to round the min and max values.

 var rects = baseRect.Split(new Vector2(5,4));
 for (var i = 0; i < rects.Count; i++)
 {
     rects[i].xMin = Mathf.Round(rects[i].xMin);
     rects[i].yMin = Mathf.Round(rects[i].yMin);
     rects[i].xMax = Mathf.Round(rects[i].xMax);
     rects[i].yMax = Mathf.Round(rects[i].yMax);
 }

Also keep in mind that since you want a 1 grid wall, all rects should be 1 grid bigger. I used a min value of 5 and 4 to get a min room of 4x3

You just have to add the walls on two sides of each room (bottom and right for example). The baserect should be one grid smaller than the actual space since you need the border wall top and left.

Your whold room creation procedure should be based more on objects than on seperate tiles on a grid. Regarding your "door problem": Each final room-rect has 4 possible doors (on each wall), however you first have to figure out which rooms are actually "touching" and how much they overlap. It's up to you to define limits (if your door is 1, 2, ... grids wide). Once you know the overlapping "zone" you can just place a door in the middle. If you store the information which room has a connection to what other room you can do some "path" checks by vitually walking through the house by starting in a room and go from room to room without using the same door twice. If you walked the whole "tree" (so you used every door in each room) you should have visited each room. If not you're missing doors ;) Maybe your min size is too small in that case.

Comment
Add comment · Show 5 · Share
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
avatar image Bunny83 · Dec 19, 2013 at 05:12 PM 0
Share

ps, you can of course use a seperate $$anonymous$$ size for x and y if you want. I can adjust the code... just a moment

edit
changed the $$anonymous$$ size into a Vector2. Now you can specify the $$anonymous$$ size seperate for width and height.

avatar image Bunny83 · Dec 19, 2013 at 05:17 PM 0
Share

Oh forgot to make the class static ^^. Edited once more.

I have to say that i didn't tested it yet, but i will when i find the time ;)

avatar image Bunny83 · Dec 19, 2013 at 05:42 PM 0
Share

Another update ^^ Had the splitting wrong, now it works as expected. However a little problem is that this will split the rects down as much as possible as long as each rect is larger than the $$anonymous$$ size. This results in an astounding equally sized and distributed rects. $$anonymous$$aybe, if you want some "bigger" rooms you should implement a random "skipping", maybe based on the rect area size. The smaller the size the more likely you don't split it again even when it's possible.

avatar image blaster182 · Dec 19, 2013 at 08:04 PM 0
Share

Thank you very much Bunny83! It's a different approach but I think I can work with this. I'll give you feedback as soon as I have some time to test it. Thanks for being so thorough.

avatar image blaster182 · Dec 19, 2013 at 10:02 PM 0
Share

where should I round the $$anonymous$$ and max values? It doesn't find baseRect. I'll keep trying meanwhile.

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

19 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

Related Questions

Random Room Generator 1 Answer

Code to randomly generate a mesh? 0 Answers

how can i make randomly generated worlds with collectable resources 0 Answers

Infinite loop when I try to generate randomly a 2D dungeon.. 3 Answers

How can I make a Terraria Style game from sprites without using an enormous amount of gameobjects? 2 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