Вторник, 26 Ноября 2024, 01:24

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Мой тестовый генератор подземелий.
IrondustДата: Вторник, 15 Января 2013, 12:35 | Сообщение # 1
участник
Сейчас нет на сайте
Работал над генератором подземелий для обучения, чуть больше недели. Результаты вот:



Играбельная демка
Сначала выбираете размер лабиринта, потом выбираете либо просмотр сверху, либо побегать от первого лица. Самый большой лабиринт может генерироваться очень долго.

Код
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LevelGenerator : MonoBehaviour {
    public int blockSize;
    private int size = 5;
    private Cell[,] grid;
    private GameObject[] cubes;
    private class Block {
    public int startX, endX, startY, endY, bdirection;
    public bool  roomPlaced;
    public bool[] corridorPlaced;    
    public float RandomNumber;    
    public Block parentBlock, twinBlock;    
    }
    int splitIterations = 0;
    private List<Block> blocks = new List<Block>();
       
    public GameObject wallPrefab, borderPrefab;
    private Block startBlock = new Block();
    public enum LevelSize {tiny = 10, small = 20, medium = 50, large = 80, huge = 160}
       
    public LevelSize levelSize = LevelSize.medium;
       
       
    public float squarity = 0.4F;
       
    // Use this for initialization
    void Start () {
        
    }
    public void ClearCubes () {
     foreach( GameObject c in cubes){
      Destroy(c);
     }
    }
       
    public void StartGeneration () {
     StopAllCoroutines();
     blocks.Clear();
     startBlock = new Block();
     size = (int)levelSize;
        
     grid = new Cell[size,size];
     cubes = new GameObject[size*size];
    for (int i = 0; i<size; i++){
      for (int j = 0; j<size; j++){
      grid[i,j] = new Cell();
      grid[i,j].type = Cell.Type.wall;    
     }
     }
     startBlock.startX = 0;
     startBlock.startY = 0;
     startBlock.endX = size;
     startBlock.endY = size;
     startBlock.RandomNumber = Random.Range(0.0F, 100.0F);
     startBlock.parentBlock = new Block();
     SplitPrepare();
        
     StartCoroutine(WaitForCalc());
    }
       
    void SplitPrepare () {
        
     switch (levelSize){
     case LevelSize.tiny:
     splitIterations = 2;
     break;
     case LevelSize.small:
     splitIterations = 3;
     break;    
     case LevelSize.medium:
     splitIterations = 4;    
     break;
     case LevelSize.large:
     splitIterations = 5;    
     break;
     case LevelSize.huge:
     splitIterations = 7;    
     break;    
     }
        
     float sizeOfMassive = Mathf.Pow(2.0F,splitIterations);
        
     SplitLevel(startBlock, splitIterations);
    }
       
       
    void SplitLevel (Block bTS, int iter) {
        
        
     int blockN=-1;
        
        
        
     if(iter>1){    
     Block[] pro = Splitting(bTS, iter-1);    
     foreach (Block b in pro){
         
          
       SplitLevel(b,iter-1);
          
          
     }
     }
        
        
    }
       
       
    Block[] Splitting (Block splitBlock, int iter) {
        
     int direction = Random.Range(0,2);
     int position;
        
     Block[] retBlock = new Block[2];
     int pogr, kl;
     int length = splitBlock.endY-splitBlock.startY;
     int width = splitBlock.endX-splitBlock.startX;
     if(direction==0){
         
          
         
      kl = blocks.Count;    
      for (int l = 0; l<kl; l++){
        if(splitBlock.RandomNumber==blocks[l].RandomNumber){
           
           
        blocks.RemoveAt(l);
        kl--;
        }
       }
       pogr = (int)(width*squarity);
      position = Random.Range(splitBlock.startX+pogr, splitBlock.endX-pogr);
         
      for (int i = splitBlock.startY; i<splitBlock.endY; i++){
       grid[position,i].isBorder = true;
      }
         
      retBlock[0] = new Block{ endX = position, endY = splitBlock.endY, startX = splitBlock.startX, startY = splitBlock.startY, RandomNumber = Random.Range(0.0F, 100.0F),  parentBlock = splitBlock,  corridorPlaced = new bool[splitIterations-1], bdirection = direction};
      retBlock[1] = new Block{startX = position, endX = splitBlock.endX,startY = splitBlock.startY, endY = splitBlock.endY, RandomNumber = Random.Range(0.0F, 100.0F),parentBlock = splitBlock, corridorPlaced = new bool[splitIterations-1], bdirection = direction};
       retBlock[0].twinBlock = retBlock[1];
      retBlock[1].twinBlock = retBlock[0];
       blocks.Add(retBlock[0]);
       blocks.Add(retBlock[1]);
         
         
         
     }
        
     else {
         
      kl = blocks.Count;    
      for (int l = 0; l<kl; l++){
        if(splitBlock.RandomNumber==blocks[l].RandomNumber){
            
        blocks.RemoveAt(l);
        kl--;
        }
       }    
           
       pogr = (int)(length*squarity);    
      position = Random.Range(splitBlock.startY+pogr, splitBlock.endY-pogr);
         
      for (int i = splitBlock.startX; i<splitBlock.endX; i++){
       grid[i,position].isBorder = true;
      }
      retBlock[0] = new Block{startX = splitBlock.startX, endX = splitBlock.endX, startY = splitBlock.startY, endY = position, RandomNumber = Random.Range(0.0F, 100.0F), parentBlock = splitBlock, corridorPlaced = new bool[splitIterations], bdirection = direction};
      retBlock[1] = new Block{startX = splitBlock.startX, endX = splitBlock.endX, startY = position, endY = splitBlock.endY, RandomNumber = Random.Range(0.0F, 100.0F), parentBlock = splitBlock, corridorPlaced = new bool[splitIterations], bdirection = direction};
      retBlock[0].twinBlock = retBlock[1];
      retBlock[1].twinBlock = retBlock[0];    
       blocks.Add(retBlock[0]);
       blocks.Add(retBlock[1]);
         
         
        

        
     }
         
        
     return retBlock;
    }
       
IEnumerator WaitForCalc () {
     yield return new WaitForSeconds(0.5F);
     PlaceRooms();
     yield return new WaitForSeconds(0.5F);
     BuildCorridors();
     yield return new WaitForSeconds(0.5F);
     BuildLevel ();
        
        
    }    

       
void BuildCorridors () {
     foreach(Block jB in blocks){
      BuildCorridor(jB,splitIterations-2);
     }
        
    }
       
void PlaceRooms () {
        
     for (int u = 0; u<blocks.Count;u++){
         
      int length = (blocks[u].endY-blocks[u].startY)/2;
      int width = (blocks[u].endX-blocks[u].startX)/2;
         
         
          
      int positionX = width+blocks[u].startX;
      int positionY = length+blocks[u].startY;
         
      int roomSizeFinalX = (int)(width*Random.Range(0.65F,0.8F));
      int roomSizeFinalY = (int)(length*Random.Range(0.65F,0.8F));
      if(roomSizeFinalX==0)roomSizeFinalX=1;
      if(roomSizeFinalY==0)roomSizeFinalY=1;
        
      for (int i = 0; i<roomSizeFinalX;i++){
       for (int j = 0; j<roomSizeFinalY;j++){
           
       grid[positionX+i, positionY+j].type = Cell.Type.room;
       grid[positionX-i, positionY-j].type = Cell.Type.room;
       grid[positionX+i, positionY-j].type = Cell.Type.room;
       grid[positionX-i, positionY+j].type = Cell.Type.room;
         }
      }
          
         
        
          
     }
        
    }    
       
void BuildLevel () {
     int k = 0;
     for (int i = 0; i<size; i++){
      for (int j = 0; j<size; j++){
          
      if(grid[i,j].type == Cell.Type.room  || grid[i,j].type==Cell.Type.corridor){
       cubes[k] = Instantiate(borderPrefab,new Vector3(i*blockSize,0.0F,j*blockSize),Quaternion.identity) as GameObject;
          
       }
       else {
       cubes[k] = Instantiate(wallPrefab,new Vector3(i*blockSize,0.0F,j*blockSize),Quaternion.identity) as GameObject;    
       }
       grid[i,j].number = k;
       k++;
     }
     }
        
     for (int i=1; i<size-1; i++){
      for (int j = 1; j<size-1;j++){
       if(grid[i,j].type == Cell.Type.wall){
        if(checkNe(i,j)){
         Debug.Log("destroy");
         Destroy(cubes[grid[i,j].number]);
        }
           
           
       }
      }
     }
    }
       
bool checkNe (int i, int j){
     bool[] ne = new bool[8];
     ne[0] = grid[i,j+1].type==grid[i,j].type;
     ne[1] = grid[i,j-1].type==grid[i,j].type;
     ne[2] = grid[i+1,j+1].type==grid[i,j].type;
     ne[3] = grid[i+1,j-1].type==grid[i,j].type;
     ne[4] = grid[i+1,j].type==grid[i,j].type;
     ne[5] = grid[i-1,j+1].type==grid[i,j].type;
     ne[6] = grid[i-1,j-1].type==grid[i,j].type;
     ne[7] = grid[i-1,j].type==grid[i,j].type;
     bool neA=true;
     for (int o = 0; o<8; o++){
      if(!ne[o]){
       neA = false;
       break;
       }
      }
     return neA;
    }
       
void BuildCorridor (Block joinBlock, int iteration) {
     bool going=true;
     int nedost=0;
     if(iteration>=0){
     if(!joinBlock.corridorPlaced[iteration]){
     ///Building corridor
     if(joinBlock.bdirection == 0){
           
        int length = ((joinBlock.endY -  joinBlock.startY)/2);
        int corY = (length+joinBlock.startY) + (int)(length*Random.Range(-0.3F,0.3F));
        if(joinBlock.startX<=joinBlock.twinBlock.startX){
         //right
         nedost = joinBlock.endX;
        }
        else {
         //left
         nedost = joinBlock.twinBlock.endX;
        }
        going = true;
        int i = 0;
        while (going&&(nedost+i)<size) {
            
         if(grid[nedost+i,corY].type == Cell.Type.wall){
         grid[nedost+i,corY].type = Cell.Type.corridor;
         i++;
         }
         else {
          going = false;
         }
         }
            
            
        i=1;
        going = true;
        while (going&&(nedost-i)>=0) {
         if(grid[nedost-i,corY].type == Cell.Type.wall|| grid[nedost-i,corY].type == Cell.Type.corridor){
         grid[nedost-i,corY].type = Cell.Type.corridor;
          i++;
         }
         else {
          going = false;
         }
         }
         }
       else {
        int width = ((joinBlock.endX -  joinBlock.startX)/2);
        int corX = (width+joinBlock.startX) + (int)(width*Random.Range(-0.4F,0.4F));
        if(joinBlock.startY<=joinBlock.twinBlock.startY){
         //up
         nedost = joinBlock.endY;
        }
        else {
         //down
         nedost = joinBlock.twinBlock.endY;
        }
        int i = 0;
        going = true;
        while (going&&(nedost+i)<size) {
            
         if(grid[corX,nedost+i].type == Cell.Type.wall || grid[corX,nedost+i].type == Cell.Type.corridor){
         grid[corX,nedost+i].type = Cell.Type.corridor;
         i++;
         }
         else {
          going = false;
         }
         }
            
            
        i=1;
        going = true;
        while (going&&(nedost-i)>=0) {
         if(grid[corX,nedost-i].type == Cell.Type.wall){
         grid[corX,nedost-i].type = Cell.Type.corridor;
          i++;
         }
         else {
          going = false;
         }
         }
       }
          
     ///Building/     
     joinBlock.corridorPlaced[iteration] = true;
     joinBlock.twinBlock.corridorPlaced[iteration] = true;    
     }
        
         
       
    BuildCorridor(joinBlock.parentBlock, iteration-1);    
     }
    }    

       
       
}

public class Cell  {
    public enum Type {clear, wall, room, entrance, corridor}
    public Type type;
    public bool isBorder = false;
    public int number;
}

Комментарии писать было влом, спрашивайте если что непонятно.


Сообщение отредактировал Irondust - Среда, 16 Января 2013, 09:25
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг