1 using UnityEngine;
2 using
System.Collections;
3
4 public
class LandGenerator : MonoBehaviour {
5
6     
public GameObject landTile; // the current tile nearest the player
7     
public GameObject newTile; // the tile prefab
8     
float tileSize = 20000; // the default size of the prefab tile
9     
float tileGenerationThreshold = 2500; // the component distance from center past which a new tile instantiates
10     
bool[] tileChecklist; // a checklist to track whether tiles around the landTile have been laid
11
12     
enum Axis
13     {
14         x,
15         z,
16         both
17     }

18
19     ///
<summary>
20     ///
Instantiate the tile checklist.
21     ///
</summary>
22     
void Start()
23     {
24         tileChecklist =
new bool[8];
25         
for (int i=0; i<8; i++) {
26             tileChecklist[i] =
false;
27         }
28     }

29
30
31         
32     ///
<summary>
33     ///
Every frame, determine whether to lay a new tile based upon the player's position.
34     ///
Also, update the landTile object if it is no longer the nearest to the player.
35     ///
</summary>
36     
void Update () {
37
38         
if (!TilesAreFull ()) {
39
40             
// If the player is near enough to a corner, draw a corner tile if it hasn't yet been drawn
41             
if (PlaneIsFarEnoughAwayFromTileCenter (Axis.x) && PlaneIsFarEnoughAwayFromTileCenter (Axis.z)) {
42                 GenerateNewTileIfNecessary (Axis.both);
43             }
else {
44
45                 
// If the player is near an adjacent tile, draw it if it hasn't yet been drawn
46                 
if (PlaneIsFarEnoughAwayFromTileCenter(Axis.x)) {
47                     GenerateNewTileIfNecessary (Axis.x);
48                 }
49                 
if (PlaneIsFarEnoughAwayFromTileCenter(Axis.z)) {
50                     GenerateNewTileIfNecessary (Axis.z);
51                 }
52             }
53         }
54
55         
// Check to see if the current landTile is still the closest one to the player.
56         
// If not, find the closest tile and set that as landTile.
57         SwitchCurrentTileIfNecessary ();
58
59     }

60
61     ///
<summary>
62     ///
Flag a boolean true for each tile around landTile as each is drawn.
63     ///
</summary>
64     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
65     
void FlagChecklistTile(Axis currentAxis)
66     {
67         
switch (currentAxis) {
68         
case Axis.x:
69             
if (PlaneDirectionFromTileCenter (Axis.x) > 0) {
70                 tileChecklist [
0] = true;
71             }
else {
72                 tileChecklist [
1] = true;
73             }
74             
break;
75         
case Axis.z:
76             
if (PlaneDirectionFromTileCenter (Axis.z) > 0) {
77                 tileChecklist [
2] = true;
78             }
else {
79                 tileChecklist [
3] = true;
80             }
81             
break;
82         
case Axis.both:
83             
if (PlaneDirectionFromTileCenter (Axis.x) > 0) {
84                 
if (PlaneDirectionFromTileCenter (Axis.z) > 0) {
85                     tileChecklist [
4] = true;
86                 }
else {
87                     tileChecklist [
5] = true;
88                 }
89
90             }
else {
91                 
if (PlaneDirectionFromTileCenter (Axis.z) > 0) {
92                     tileChecklist [
6] = true;
93                 }
else {
94                     tileChecklist [
7] = true;
95                 }
96             }
97             
break;
98         }
99
100     }

101
102     ///
<summary>
103     ///
Check whether all the tiles around the landTile are drawn.
104     ///
</summary>
105     ///
<returns><c>true</c>, if all tiles in tileChecklist are true, <c>false</c> otherwise.</returns>
106     
bool TilesAreFull()
107     {
108         
bool retVal = true;
109         
foreach (bool item in tileChecklist)
110             
if (!item)
111                 retVal =
false;
112         
return retVal;
113     }

114
115     ///
<summary>
116     ///
Check whether the plane is far enough away from landTile's center. The tileGenerationThreshold defines that amount.
117     ///
</summary>
118     ///
<returns><c>true</c>, if the plane has crossed beyond the tileGenerationThreshold, <c>false</c> otherwise.</returns>
119     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
120     
bool PlaneIsFarEnoughAwayFromTileCenter(Axis currentAxis)
121     {
122         
return Mathf.Abs (GetPlaneDistanceFromTileCenter(currentAxis)) > tileGenerationThreshold;
123     }

124
125     ///
<summary>
126     ///
Check whether the player the has crossed over to a new tile.
127     ///
</summary>
128     ///
<returns><c>true</c>, if the player is no longer directly above landTile, <c>false</c> otherwise.</returns>
129     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
130     
bool PlayerHasCrossedOverToANewTile(Axis currentAxis)
131     {
132         
return false;
133     }

134
135     ///
<summary>
136     ///
Generates the new tile ahead of the player if one doesn't exist in that space yet.
137     ///
</summary>
138     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
139     
void GenerateNewTileIfNecessary(Axis currentAxis)
140     {
141         
142         
if (NewTileDoesNotYetExist (currentAxis)) {
143
144             Vector3 newPosition =
new Vector3();
145
146             
switch (currentAxis) {
147             
case Axis.x:
148                 newPosition = landTile.transform.position +
new Vector3 (tileSize * PlaneDirectionFromTileCenter (Axis.x), 0, 0);
149                 
break;
150             
case Axis.z:
151                 newPosition = landTile.transform.position +
new Vector3 (0, 0, tileSize * PlaneDirectionFromTileCenter (Axis.x));
152                 
break;
153             
case Axis.both:
154                 newPosition = landTile.transform.position +
155                                 
new Vector3 (
156                                     tileSize * PlaneDirectionFromTileCenter (Axis.x),
157                                     
0,
158                                     tileSize * PlaneDirectionFromTileCenter (Axis.z)
159                                 );
160                 
break;
161             }
162
163             Instantiate(newTile, newPosition, landTile.transform.rotation);
164             FlagChecklistTile (currentAxis);
165         }
166     }

167
168     ///
<summary>
169     ///
Check whether a tile exists in the spot we want to create one.
170     ///
</summary>
171     ///
<returns><c>true</c>, if a tile already occupies the space where we want to create one, <c>false</c> otherwise.</returns>
172     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
173     
bool NewTileDoesNotYetExist(Axis currentAxis)
174     {
175         
bool retVal = true; // return value assumes there is no tile in our way unless proven otherwise
176         GameObject[] tiles = GameObject.FindGameObjectsWithTag(
"LandTile"); // all tiles currently instantiated in the scene
177         
float currentTilePosition = 0, // single-axis landTile position for x or z, double-axis position for x only
178                     nextTilePosition =
0, // single-axis tile position for x or z, double-axis position for x only
179                     altCurrentPos =
0, // double-axis landTile position for z
180                     altNextPos =
0; // double-axis tile position for z
181
182
183         
// iterate through all instantiated tiles
184         
foreach (GameObject tile in tiles) {
185
186             
switch (currentAxis) {
187             
case Axis.x:
188                 currentTilePosition = landTile.transform.position.x;
189                 nextTilePosition = tile.transform.position.x;
190                 
break;
191             
case Axis.z:
192                 currentTilePosition = landTile.transform.position.z;
193                 nextTilePosition = tile.transform.position.z;
194                 
break;
195             
case Axis.both:
196                 currentTilePosition = landTile.transform.position.x;
197                 nextTilePosition = tile.transform.position.x;
198                 altCurrentPos = landTile.transform.position.z;
199                 altNextPos = tile.transform.position.z;
200                 
break;
201             }
202
203             
// if the tile's single-axis position or first double-axis position is
204             
// located at the coordinates where we want to create a new tile...
205             
if (nextTilePosition == currentTilePosition + tileSize * PlaneDirectionFromTileCenter(Axis.x)) {
206
207                 
// if we're dealing with a corner piece (i.e. double-axis both x and z)...
208                 
if (currentAxis == Axis.both) {
209                     
210                     
// if tile's second double-axis position is
211                     
// located at the coordinates where we want to create a new tile...
212                     
if (altNextPos == altCurrentPos + tileSize * PlaneDirectionFromTileCenter (Axis.z)) {
213
214                         
// ...then a tile DOES exist where we want to create one, so return false
215                         retVal =
false;
216                     }
217                 }
else {
218                     
// we're dealing with an adjacent piece (i.e. single-axis x only or z only)
219                     
// on the axis in question, a tile DOES exist where we want to create one, so return false
220                     retVal =
false;
221                 }
222
223             }
224         }
225         
return retVal;
226     }

227
228
229     ///
<summary>
230     ///
Gets the plane distance from tile center.
231     ///
</summary>
232     ///
<returns>The plane distance from tile center.</returns>
233     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
234     
float GetPlaneDistanceFromTileCenter(Axis currentAxis)
235     {
236         
float planePosition, landTilePosition;
237
238         
if (currentAxis == Axis.x) {
239             planePosition = transform.position.x;
240             landTilePosition = landTile.transform.position.x;
241         }
242         
else {
243             planePosition = transform.position.z;
244             landTilePosition = landTile.transform.position.z;
245         }
246         Debug.Log (
"Distance: " + (planePosition - landTilePosition));
247         
return planePosition - landTilePosition;
248     }

249
250     ///
<summary>
251     ///
Planes the direction from tile center.
252     ///
</summary>
253     ///
<returns>The direction from tile center.</returns>
254     ///
<param name="currentAxis">The axis currently parralel to the player's facing, x or z. Both if the player is facing diagonally.</param>
255     
float PlaneDirectionFromTileCenter(Axis currentAxis)
256     {
257         
258         
float distance = GetPlaneDistanceFromTileCenter (currentAxis);
259         
float retVal = 0;
260         
if (distance > 0)
261             retVal =
1;
262         
else
263             retVal = -
1;
264         
return retVal;
265     }

266
267     ///
<summary>
268     ///
Switch the current landTile to a new tile if landTile is no longer the closest tile to the player.
269     ///
</summary>
270     
void SwitchCurrentTileIfNecessary()
271     {
272         
if (Mathf.Abs(GetPlaneDistanceFromTileCenter (Axis.x)) > tileSize / 2 // if the player is no longer over landTile on x
273             || Mathf.Abs(GetPlaneDistanceFromTileCenter(Axis.z)) > tileSize /
2) // if the player is no longer over landTile on z
274         {
275             SwitchCurrentTile();
276         }
277             
278     }

279
280     ///
<summary>
281     ///
Reassign landTile to be the closest tile to the player.
282     ///
</summary>
283     
void SwitchCurrentTile()
284     {
285         
// all currently instantiated tiles
286         GameObject[] tiles = GameObject.FindGameObjectsWithTag(
"LandTile");
287
288         
// iterate through all tiles
289         
foreach (GameObject tile in tiles) {
290
291             Debug.Log (
"Distance between current tile and others: " + (tile.transform.position - landTile.transform.position).magnitude);
292             
// if the distance between the player and a given tile is less than that of the player and landTile
293             
if (Mathf.Abs((transform.position - tile.transform.position).magnitude) < Mathf.Abs((transform.position - landTile.transform.position).magnitude)) {
294
295                 
// Reassign landTile to be the tile that is nearer the player.
296                 landTile = tile;
297             }
298         }
299     }
300
301 }