mvaganov

GenerateMap.cs

Mar 5th, 2018
108
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class GenerateMap : MonoBehaviour {
  6.     [System.Serializable]
  7.     public class BuildingBlock
  8.     {
  9.         public string character;
  10.         public GameObject blockObject;
  11.     }
  12.     public BuildingBlock[] buildingBlocks;
  13.     private Vector3Int calculatedSize = Vector3Int.zero;
  14.     [TextArea(10,10)]
  15.     public string map =
  16.         "#######\n"+
  17.         ".....##\n"+
  18.         ".....#\n"+
  19.         "#\n"+
  20.         "#....#..........#\n"+
  21.         "###.###\n"+
  22.         "..#.###\n"+
  23.         ".\n"+
  24.         "####............#\n"+
  25.         "\n"+
  26.         "#.....###\n"+
  27.         "#.......#..###\n"+
  28.         "#.......#..#.#\n"+
  29.         "#..........###\n"+
  30.         "#...........#...#\n"+
  31.         "#...........#...#\n"+
  32.         "#..##############\n"+
  33.         "#..#............#\n"+
  34.         "#..#............#";
  35.     private char[,,] mutableData;
  36.     private GameObject[,,] allBlockObjects;
  37.     /// <summary>which index is dirty</summary>
  38.     private List<Vector3Int> dirtyList = new List<Vector3Int>();
  39.     public Vector3 cubeSize = new Vector3(3,3,3);
  40.     /// <summary>which index the user mouse is pointing at</summary>
  41.     public Vector3Int selectIndex;
  42.     /// <summary>which index is the creation point</summary>
  43.     public Vector3Int createIndex;
  44.     public string leftClickAdds = "#";
  45.     public bool rightClickRemoves = true;
  46.  
  47.  
  48.     [ContextMenu("Recalculate Bounds")]
  49.     void RecalculateBounds() {
  50.         // create the box collider, which will help position the generator in the game world
  51.         BoxCollider b = GetComponent<BoxCollider> ();
  52.         if (b == null) {
  53.             b = gameObject.AddComponent<BoxCollider> ();
  54.             b.isTrigger = true;
  55.             gameObject.layer = LayerMask.NameToLayer ("Ignore Raycast");;
  56.         }
  57.         calculatedSize = CalculateMapSize ();
  58.         Vector3 s = (Vector3)calculatedSize;
  59.         s.x = s.x * cubeSize.x;
  60.         s.y = s.z * cubeSize.y;
  61.         s.z = -calculatedSize.y * cubeSize.z;
  62.         b.size = s;
  63.         Vector3 offset = cubeSize / -2;
  64.         offset.z *= -1;
  65.         b.center = b.size / 2 + offset;
  66.         // ensure there is an entry for each character in the map
  67.         string letters = LettersUsedInMap ();
  68.         for (int i = 0; i < letters.Length; ++i) {
  69.             if (GetBlock (letters [i]) == null) {
  70.                 System.Array.Resize (ref buildingBlocks, buildingBlocks.Length + 1);
  71.                 BuildingBlock block = new BuildingBlock ();
  72.                 block.character = letters [i].ToString();
  73.                 buildingBlocks [buildingBlocks.Length - 1] = block;
  74.             }
  75.         }
  76.     }
  77.  
  78.     public char FindCharAtFromOriginalMap(Vector3Int index) {
  79.         if (calculatedSize == Vector3Int.zero) {
  80.             calculatedSize = CalculateMapSize ();
  81.         }
  82.         if (index.x >= 0 && index.y < calculatedSize.x &&
  83.             index.y >= 0 && index.y < calculatedSize.y &&
  84.             index.z >= 0 && index.y < calculatedSize.z) {
  85.             int row = 0, col = 0, dep = 0;
  86.             for (int i = 0; i < map.Length; i++) {
  87.                 char c = map [i];
  88.                 if (c == '\r') { continue; }
  89.                 else if (c == '\n') { if (col == 0) { dep++; row = 0; if (dep > index.z) { break; } } else { row++; } col = 0; }
  90.                 else {
  91.                     if (col == index.x && row == index.y && dep == index.z) { return c; }
  92.                 }
  93.             }
  94.         }
  95.         return (char)0;
  96.     }
  97.  
  98.     public char FindCharAt(Vector3Int index) { return mutableData [index.z, index.y, index.x];}
  99.  
  100.     public string LettersUsedInMap() {
  101.         string output = "";
  102.         for (int i = 0; i < map.Length; ++i) {
  103.             if (map [i] != '\n' && output.IndexOf (map [i]) < 0) {
  104.                 output += map [i];
  105.             }
  106.         }
  107.         return output;
  108.     }
  109.  
  110.     public string ToText(char emptyArea) {
  111.         System.Text.StringBuilder sb = new System.Text.StringBuilder ();
  112.         for (int dep = 0; dep < calculatedSize.z; dep++) {
  113.             for (int row = 0; row < calculatedSize.y; ++row) {
  114.                 int lastUsedIndex = -1;
  115.                 char c;
  116.                 for (int col = 0; col < calculatedSize.x; ++col) {
  117.                     c = mutableData [dep, row, col];
  118.                     if (c != (char)0 && c != emptyArea) {
  119.                         lastUsedIndex = col;
  120.                     }
  121.                 }
  122.                 if (lastUsedIndex < 0) {
  123.                     sb.Append (emptyArea);
  124.                 } else {
  125.                     for (int col = 0; col <= lastUsedIndex; ++col) {
  126.                         c = mutableData [dep, row, col];
  127.                         if (c == 0) {
  128.                             c = emptyArea;
  129.                         }
  130.                         sb.Append (c);
  131.                     }
  132.                 }
  133.                 sb.Append ("\n");
  134.             }
  135.             sb.Append ("\n");
  136.         }
  137.         return sb.ToString ();
  138.     }
  139.  
  140.     public GenerateMap ContainsRecursiveGenerator(List<GenerateMap> currentGenerators = null){
  141.         if (currentGenerators == null) {
  142.             currentGenerators = new List<GenerateMap> ();
  143.         }
  144.         if (currentGenerators.Contains (this)) {
  145.             return this;
  146.         }
  147.         for (int i = 0; i < buildingBlocks.Length; ++i) {
  148.             if (buildingBlocks [i].blockObject != null) {
  149.                 GenerateMap[] generators = buildingBlocks [i].blockObject.GetComponents<GenerateMap> ();
  150.                 if (generators != null) {
  151.                     for (int g = 0; g < generators.Length; ++g) {
  152.                         if (generators [g].ContainsRecursiveGenerator (currentGenerators)) {
  153.                             return generators [g];
  154.                         }
  155.                     }
  156.                 }
  157.             }
  158.         }
  159.         return null;
  160.     }
  161.  
  162.     // Use this for initialization
  163.     void Start () {
  164.         GenerateMap recursiveMap = ContainsRecursiveGenerator ();
  165.         if (recursiveMap != null) {
  166.             throw new System.Exception ("ERROR: about to infinite-recursively create objects with " + recursiveMap);
  167.         }
  168.         if (calculatedSize == Vector3Int.zero) {
  169.             calculatedSize = CalculateMapSize ();
  170.         }
  171.         SetMutableDataFrom (map);
  172.         RefreshMap (true);
  173.         Debug.Log(ToText ('.'));
  174.     }
  175.     void SetMutableDataFrom(string map) {
  176.         mutableData = new char[calculatedSize.z, calculatedSize.y, calculatedSize.x];
  177.         int row = 0, col = 0, dep = 0;
  178.         for (int index = 0; index < map.Length; index++) {
  179.             char c = map [index];
  180.             if (c == '\r') { continue; }
  181.             if (c == '\n') {
  182.                 if (col == 0) {
  183.                     dep++; row = 0;
  184.                 } else {
  185.                     row++;
  186.                 }
  187.                 col = 0;
  188.             } else {
  189.                 mutableData [dep, row, col] = c;
  190.                 col++;
  191.             }
  192.         }
  193.     }
  194.     public void DeleteAll() {
  195.         for (int dep = 0; dep < allBlockObjects.GetLength (0); dep++) {
  196.             for (int row = 0; row < allBlockObjects.GetLength (0); row++) {
  197.                 for (int col = 0; col < allBlockObjects.GetLength (1); col++) {
  198.                     Destroy (allBlockObjects [dep, row, col]);
  199.                     allBlockObjects [dep, row, col] = null;
  200.                 }
  201.             }
  202.         }
  203.     }
  204.     public BuildingBlock GetBlock(char c){
  205.         for (int b = 0; b < buildingBlocks.Length; ++b) {
  206.             BuildingBlock block = buildingBlocks [b];
  207.             if (block.character.Length > 0 && block.character [0] == c) {
  208.                 return block;
  209.             }
  210.         }
  211.         return null;
  212.     }
  213.     public GameObject RefreshBlockAt(Vector3Int i) {
  214.         char c = mutableData [i.z, i.y, i.x];
  215.         BuildingBlock block = GetBlock (c);
  216.         GameObject originalBlockObject = (block != null) ? block.blockObject : null;
  217.         GameObject newBlockObject = null;
  218.         if (allBlockObjects [i.z, i.y, i.x] != null) {
  219.             Destroy (allBlockObjects [i.z, i.y, i.x]);
  220.         }
  221.         if (originalBlockObject != null) {
  222.             Vector3 p = new Vector3 (i.x * cubeSize.x, i.z * cubeSize.y, -i.y * cubeSize.z);
  223.             p = transform.TransformPoint (p);
  224.             newBlockObject = Instantiate (originalBlockObject, p, transform.rotation) as GameObject;
  225.             newBlockObject.transform.SetParent (transform);
  226.         }
  227.         allBlockObjects [i.z, i.y, i.x] = newBlockObject;
  228.         return newBlockObject;
  229.     }
  230.     public bool IndexValid(Vector3Int index) {
  231.         return index.x >= 0 && index.x < calculatedSize.x
  232.             && index.y >= 0 && index.y < calculatedSize.y
  233.             && index.z >= 0 && index.z < calculatedSize.z;
  234.     }
  235.     public void SetBlock(Vector3Int index, char c) {
  236.         mutableData [index.z, index.y, index.x] = c;
  237.         dirtyList.Add (index);
  238.     }
  239.     public void RemoveBlock(Vector3Int index) { SetBlock (index, (char)0); }
  240.     public void RefreshMap(bool all) {
  241.         if (allBlockObjects == null) {
  242.             allBlockObjects = new GameObject[calculatedSize.z,calculatedSize.y,calculatedSize.x];
  243.         }
  244.         if (!all) {
  245.             for (int i = dirtyList.Count-1; i >= 0; i--) {
  246.                 RefreshBlockAt (dirtyList [i]);
  247.                 dirtyList.RemoveAt (i);
  248.             }
  249.         } else {
  250.             Vector3Int i = Vector3Int.zero;
  251.             for (i.z = 0; i.z < mutableData.GetLength (0); i.z++) {
  252.                 for (i.y = 0; i.y < mutableData.GetLength (1); i.y++) {
  253.                     for (i.x = 0; i.x < mutableData.GetLength (2); i.x++) {
  254.                         RefreshBlockAt (i);
  255.                     }
  256.                 }
  257.             }
  258.         }
  259.     }
  260.     /// <summary>read the map data and calculate the correct size based on text data</summary>
  261.     /// <returns>The map size.</returns>
  262.     public Vector3Int CalculateMapSize() {
  263.         int row = 0, col = 0, maxCol = 0, maxRow = 0, dep = 1;
  264.         for (int index = 0; index < map.Length; index++) {
  265.             char c = map [index];
  266.             if (c == '\r') { continue; }
  267.             if (c == '\n') {
  268.                 if (col == 0) {
  269.                     dep++; row = 0;
  270.                 } else {
  271.                     row++;
  272.                 }
  273.                 if (row > maxRow) {
  274.                     maxRow = row;
  275.                 }
  276.                 col = 0;
  277.             } else {
  278.                 col++;
  279.                 if (col > maxCol) {
  280.                     maxCol = col;
  281.                 }
  282.             }
  283.         }
  284.         return new Vector3Int (maxCol, maxRow, dep);
  285.     }
  286.  
  287.     void GetBoundingCorners(ref Vector3[] corners) {
  288.         if(corners == null || corners.Length != 8) { corners = new Vector3[8]; }
  289.         if (map == null || map == "" || enabled == false)
  290.             return;
  291.         if (calculatedSize == Vector3Int.zero) {
  292.             calculatedSize = CalculateMapSize ();
  293.         }
  294.         float w=(calculatedSize.x * cubeSize.x), h=(calculatedSize.y * cubeSize.y), d=(calculatedSize.z * cubeSize.z);
  295.         Vector3 offset = cubeSize / -2;
  296.         offset.z *= -1;
  297.         offset = transform.TransformVector (offset);
  298.         corners[0] = transform.position + offset; // lower top left
  299.         corners[1] = transform.position + transform.right * w + offset; // lower top right
  300.         corners[3] = transform.position - transform.forward * h + offset; // lower bottom left
  301.         corners[2] = corners[3] + transform.right * w; // lower bottom right
  302.         Vector3 u = transform.up * d;
  303.         for (int i = 0; i < 4; i++) {
  304.             corners [4 + i] = corners [i] + u;
  305.         }
  306.     }
  307.  
  308.     public static Vector3Int NOT_AN_INDEX = new Vector3Int (-65536, -65536, -65536);
  309.     /// <summary>Gets the index being pointed at by the given Camera+Mouse combo, at the given height.</summary>
  310.     /// <returns>The <see cref="UnityEngine.Vector3Int"/>, <see cref="GenerateMap.NOT_AN_INDEX"/> if nothing is hit.</returns>
  311.     /// <param name="cam">Cam.</param>
  312.     /// <param name="height">height of the plane.</param>
  313.     public Vector3Int GetIndexBeingPointedAtHeight(Camera cam, float height) {
  314.         Ray r = cam.ScreenPointToRay (Input.mousePosition);
  315.         Vector3 p = transform.position;
  316.         p.y += (height) * cubeSize.y;
  317.         Plane plane = new Plane (transform.up, p);
  318.         float whereHit = 0;
  319.         if (plane.Raycast (r, out whereHit)) {
  320.             Vector3 hit = r.origin + r.direction * whereHit;
  321.             return TranslateWorldToCoordinate (hit);
  322.         }
  323.         return NOT_AN_INDEX;
  324.     }
  325.     GameObject line_hit;
  326.     /// <summary>Gets the index being pointed at by the given Camera+Mouse combo</summary>
  327.     /// <returns>The <see cref="UnityEngine.Vector3Int"/>, <see cref="GenerateMap.NOT_AN_INDEX"/> if nothing is hit.</returns>
  328.     /// <param name="cam">Cam.</param>
  329.     /// <param name="face">returns which face is selected: {0, TOP, BOTTOM, FRONT, BACK, LEFT, RIGHT}</param>
  330.     public Vector3Int GetIndexBeingPointedAt(Camera cam, out int face) {
  331.         RaycastHit rh = new RaycastHit ();
  332.         if (Physics.Raycast (cam.ScreenPointToRay (Input.mousePosition), out rh)) {
  333.             Vector3 p = rh.point -= rh.normal * 0.125f;
  334.             Lines.Make (ref line_hit, rh.point, rh.point + rh.normal, Color.red);
  335.             Vector3Int index = TranslateWorldToCoordinate (p, out face);
  336.             if (face == 0) {
  337.                 float nx = Vector3.Dot (transform.right, rh.normal);
  338.                 float ny = Vector3.Dot (transform.up, rh.normal);
  339.                 float nz = Vector3.Dot (transform.forward, rh.normal);
  340.                 float anx = Mathf.Abs (nx);
  341.                 float any = Mathf.Abs (ny);
  342.                 float anz = Mathf.Abs (nz);
  343.                 if(anx > any && anx > anz) { face = nx < 0 ? LEFT : RIGHT; }
  344.                 if(any > anx && any > anz) { face = ny < 0 ? BOTTOM : TOP; }
  345.                 if(anz > any && anz > anx) { face = nz < 0 ? BACK : FRONT; }
  346.             }
  347.             return index;
  348.         }
  349.         face = 0;
  350.         return NOT_AN_INDEX;
  351.     }
  352.     public const int TOP = 1, BOTTOM = 2, FRONT = 4, BACK = 8, LEFT = 16, RIGHT = 32;
  353.     /// <summary>Translates the world coordinate to map coordinate space</summary>
  354.     /// <returns>The world to coordinate.</returns>
  355.     /// <param name="worldPosition">World position.</param>
  356.     /// <param name="face">returns which face is selected: {0, TOP, BOTTOM, FRONT, BACK, LEFT, RIGHT}</param>
  357.     /// <param name="allowMultipleFaces">If set to <c>true</c> allow multiple faces with binary |.</param>
  358.     public Vector3Int TranslateWorldToCoordinate(Vector3 worldPosition, out int face, bool allowMultipleFaces = false,
  359.         float faceThreshold = 0.45f) {
  360.         Vector3 hit = transform.InverseTransformPoint (worldPosition);
  361.         Vector3 index = new Vector3 (hit.x / cubeSize.x, hit.z / cubeSize.z, hit.y / cubeSize.y);
  362.         Vector3Int finalResult = new Vector3Int((int)Mathf.Round(index.x), (int)Mathf.Round(index.y), (int)Mathf.Round(index.z));
  363.         face = 0;
  364.         index.x -= (int)finalResult.x;
  365.         index.y -= (int)finalResult.y;
  366.         index.z -= (int)finalResult.z;
  367.         if(!allowMultipleFaces) {
  368.             int faceIndex = 0;
  369.             float[] faceWeight = new float[] {0,index.z,-index.z,index.y,-index.y,-index.x,index.x};
  370.             for (int i = 1; i < 7; ++i) { if (faceWeight [i] > faceWeight [faceIndex]) { faceIndex = i; } }
  371.             if (faceWeight [faceIndex] > faceThreshold) {
  372.                 face = 1 << (faceIndex - 1);
  373.             }
  374.         } else {
  375.             if(index.z > faceThreshold)  face += TOP;
  376.             if(index.z < -faceThreshold) face += BOTTOM;
  377.             if(index.y > faceThreshold)  face += FRONT;
  378.             if(index.y < -faceThreshold) face += BACK;
  379.             if(index.x > faceThreshold)  face += RIGHT;
  380.             if(index.x < -faceThreshold) face += LEFT;
  381.         }
  382.         finalResult.y *= -1;
  383.         return finalResult;
  384.     }
  385.     public Vector3Int TranslateWorldToCoordinate(Vector3 worldPosition) {
  386.         Vector3 hit = transform.InverseTransformPoint (worldPosition);
  387.         Vector3 index = new Vector3 (hit.x / cubeSize.x, hit.z / cubeSize.z, hit.y / cubeSize.y);
  388.         return new Vector3Int((int)Mathf.Round(index.x), (int)-Mathf.Round(index.y), (int)Mathf.Round(index.z));
  389.     }
  390.     public Vector3 TranslateCoordinateToWorld(Vector3Int index) {
  391.         Vector3 p = transform.position;
  392.         p += transform.right * index.x * cubeSize.x;
  393.         p += transform.forward * -index.y * cubeSize.z;
  394.         p += transform.up * index.z * cubeSize.y;
  395.         return p;
  396.     }
  397.     public Vector3Int AddFaceToIndex(Vector3Int index, int face) {
  398.         if((face & TOP) != 0)    index.z += 1;
  399.         if((face & BOTTOM) != 0) index.z -= 1;
  400.         if((face & FRONT) != 0)  index.y -= 1;
  401.         if((face & BACK) != 0)   index.y += 1;
  402.         if((face & RIGHT) != 0)  index.x += 1;
  403.         if((face & LEFT) != 0)   index.x -= 1;
  404.         return index;
  405.     }
  406.     public Vector3 TranslateCoordinateToWorld(Vector3Int index, int face) {
  407.         index = AddFaceToIndex (index, face);
  408.         Vector3 p = transform.position;
  409.         p += transform.right * index.x * cubeSize.x;
  410.         p += transform.forward * -index.y * cubeSize.z;
  411.         p += transform.up * index.z * cubeSize.y;
  412.         return p;
  413.     }
  414.     GameObject line_select, line_create;
  415.     public void HighlightFace(Vector3Int index, int face, ref GameObject line_select) {
  416.         Vector3 w = TranslateCoordinateToWorld (index), half = transform.TransformVector(cubeSize / 2);
  417.         Vector3 p = w + half; // upper top right
  418.         Vector3[] line = new Vector3[5];
  419.         Vector3 u = transform.up * cubeSize.y, r = transform.right * cubeSize.x, f = transform.forward * cubeSize.z;
  420.         switch(face) {
  421.         case TOP:
  422.             line [0] = p            ;
  423.             line [1] = p     - r    ;
  424.             line [2] = p     - r - f;
  425.             line [3] = p         - f; break;
  426.         case BOTTOM:
  427.             line [0] = p - u        ;
  428.             line [1] = p - u - r    ;
  429.             line [2] = p - u - r - f;
  430.             line [3] = p - u     - f; break;
  431.         case FRONT:
  432.             line [0] = p            ;
  433.             line [1] = p     - r    ;
  434.             line [2] = p - u - r    ;
  435.             line [3] = p - u        ; break;
  436.         case BACK:
  437.             line [0] = p         - f;
  438.             line [1] = p     - r - f;
  439.             line [2] = p - u - r - f;
  440.             line [3] = p - u     - f; break;
  441.         case RIGHT:
  442.             line [0] = p            ;
  443.             line [1] = p - u        ;
  444.             line [2] = p - u     - f;
  445.             line [3] = p         - f; break;
  446.         case LEFT:
  447.             line [0] = p     - r;
  448.             line [1] = p - u - r;
  449.             line [2] = p - u - r - f;
  450.             line [3] = p     - r - f; break;
  451.         }
  452.         line[4] = line[0];
  453.         Lines.Make (ref line_select, line, 5, Color.red);
  454.         line_select.SetActive (true);
  455.     }
  456.     void FixedUpdate() {
  457.         RefreshMap (false);
  458.     }
  459.     void Update () {
  460.         float dx = Input.GetAxis ("Mouse X"), dy = Input.GetAxis ("Mouse Y");
  461.         if (dx != 0 || dy != 0) { // if there is mouse motion
  462.             int face;
  463.             selectIndex = GetIndexBeingPointedAt(Camera.main, out face);
  464.             createIndex = AddFaceToIndex (selectIndex, face);
  465.             if (createIndex.z < 0) {
  466.                 createIndex = GetIndexBeingPointedAtHeight (Camera.main, -0.5f);
  467.                 face = 0;
  468.                 selectIndex = NOT_AN_INDEX;
  469.             }
  470.             Color ofBox = Color.grey;
  471.             if (IndexValid(createIndex)) {
  472.                 ofBox = Color.green;
  473.             }
  474.             if (face != 0) {
  475.                 if (rightClickRemoves) {
  476.                     HighlightFace (selectIndex, face, ref line_select);
  477.                 }
  478.                 if (leftClickAdds != "") {
  479.                     Lines.MakeBox (ref line_create, TranslateCoordinateToWorld (createIndex), cubeSize * 0.875f, transform.rotation, ofBox);
  480.                     line_create.SetActive (true);
  481.                 }
  482.             } else {
  483.                 if (leftClickAdds != "") {
  484.                     if (line_select != null) line_select.SetActive (false);
  485.                     Lines.MakeBox (ref line_create, TranslateCoordinateToWorld (selectIndex), cubeSize, transform.rotation, ofBox);
  486.                     line_create.SetActive (true);
  487.                 }
  488.             }
  489.         }
  490.         if (leftClickAdds != "" && Input.GetMouseButtonDown (0)) {
  491.             if (IndexValid (createIndex)) {
  492.                 SetBlock (createIndex, leftClickAdds[0]);
  493.                 Debug.Log (ToText ('.'));
  494.             }
  495.         }
  496.         if (rightClickRemoves && Input.GetMouseButtonDown (1)) {
  497.             if (IndexValid (selectIndex)) {
  498.                 RemoveBlock (selectIndex);
  499.                 Debug.Log (ToText ('.'));
  500.             }
  501.         }
  502.     }
  503. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×