Environment Generator
Environment Generator
Perlin noise can generated endless seamless noise.
Placing different types of rocks, tree types and grass, etc using different value of the pixel in the noise texture can procedurally generate natural endless forest.
// Pseudo Code of pixel of noise to set environment element in the scene
for pixel in texture (x, y):
if 1.0 >= pixel.value > 0.6 then Rock (A, B, C)
if 0,6 >= pixel.value > 0.3 then Tree (A, B, C)
if 0.3 >= pixel.value > 0.0 then Grass (A, B, C)
// Compute Perlin noise at coordinates x, y
float perlin(float x, float y) {
// Determine grid cell coordinates
int x0 = int(x);
int x1 = x0 + 1;
int y0 = int(y);
int y1 = y0 + 1;
// Determine interpolation weights
// Could also use higher order polynomial/s-curve here
float sx = x - (float)x0;
float sy = y - (float)y0;
// Interpolate between grid point gradients
float n0, n1, ix0, ix1, value;
n0 = dotGridGradient(x0, y0, x, y);
n1 = dotGridGradient(x1, y0, x, y);
ix0 = lerp(n0, n1, sx);
n0 = dotGridGradient(x0, y1, x, y);
n1 = dotGridGradient(x1, y1, x, y);
ix1 = lerp(n0, n1, sx);
value = lerp(ix0, ix1, sy);
return value;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GroundGenerator : MonoBehaviourHelper {
public GameObject Target;
public PoolManager GeneralPool;
public PoolManager PuzzlePool;
public PoolManager EventPool;
public int Size = 40;
float[] AnchorPos = new float[2];
float[] AnchorPosPrev = new float[2];
float[] RandRotation = new float[4];
[HideInInspector]
public List<MeshRenderer> Plants = new List<MeshRenderer> ();
[HideInInspector]
public GameObject[] MapObjects = new GameObject[9];
[HideInInspector]
public List<FlockController> FlockButterflies = new List<FlockController>();
GameObject[] MapObjectsTmp = new GameObject[9];
Vector3[] CurrentMapPositions = new Vector3[9];
float[] CoordRange = new float[3];
// Use this for initialization
void Start () {
CoordRange [0] = Size * -1f;
CoordRange [1] = 0f;
CoordRange [2] = (float)Size;
RandRotation [0] = 0f;
RandRotation [1] = 90f;
RandRotation [2] = 180f;
RandRotation [3] = 270f;
AnchorPos [0] = Mathf.Floor(((Target.transform.position.x + Size * 0.5f) / Size)) * Size;
AnchorPos [1] = Mathf.Floor(((Target.transform.position.z + Size * 0.5f) / Size)) * Size;
System.Array.Copy (AnchorPos, AnchorPosPrev, AnchorPos.Length);
float DelayForLoading = 0.5f;
Invoke ("Init", DelayForLoading);
//InvokeRepeating ("ZoneSync", 0.1f, 0.1f); // call every 0.1 second
InvokeRepeating ("PlantsVisibilityAndShadowCasterOptimizer", DelayForLoading, 0.2f);
InvokeRepeating ("ButterflyVisibilityAndShadowCasterOptimizer", DelayForLoading, 0.2f);
}
// Update is called once per frame
void Update () {
ZoneSync ();
}
void ZoneSync(){
// Set the anchor based on player movement
AnchorPos [0] = Mathf.Floor(((Target.transform.position.x + Size * 0.5f) / Size)) * Size;
AnchorPos [1] = Mathf.Floor(((Target.transform.position.z + Size * 0.5f) / Size)) * Size;
if (AnchorPos[0] != AnchorPosPrev[0] || AnchorPos[1] != AnchorPosPrev[1]) {
UpdateMapPositions ();
ZoneReLink ();
System.Array.Copy (AnchorPos, AnchorPosPrev, AnchorPos.Length);
//Debug.Log ("Changed:::(" + AnchorPosPrev[0] + "," + AnchorPosPrev[1] + ")");
}
}
void UpdateMapPositions(){
int id = 0;
for (int x = 0; x < CoordRange.Length; x++) {
for (int z = 0; z < CoordRange.Length; z++) {
Vector3 pos = new Vector3 (CoordRange [x] + AnchorPos [0], 0f, CoordRange [z] + AnchorPos [1]);
CurrentMapPositions [id] = pos;
id++;
}
}
}
void Init(){
ZoneSync ();
UpdateMapPositions ();
for (int i = 0; i < CurrentMapPositions.Length; i++) {
SetupGroundWithPosition(CurrentMapPositions[i], ref MapObjects[i]);
}
GlobalGameCharacter.gameObject.GetComponent<Rigidbody> ().useGravity = true; // available character a bit later
}
void SetupGroundWithPosition(Vector3 Position, ref GameObject MapObject) {
int MapID = EventData.GetPuzzleID(Position);
if (MapID > -1)
{
MapObject = PuzzlePool.GetAsset(MapID);
MapObject.transform.position = Position;
return;
}
MapID = EventData.GetEventID(Position);
if (MapID > -1)
{
MapObject = EventPool.GetAsset(MapID);
MapObject.transform.position = Position;
return;
}
if (MapID == -1)
{
MapObject = GeneralPool.GetAsset();
MapObject.transform.position = Position;
MapObject.GetComponentInChildren<TerranNoise> ().GetPropsIn (Mathf.FloorToInt(Position.z/40f));
return;
}
}
void PlantsVisibilityAndShadowCasterOptimizer(){
foreach (MeshRenderer m in Plants) {
// tree and non tree have to be separated..!
if (!m)
continue;
if (!m.gameObject.transform.parent.gameObject.activeSelf)
continue;
float dist = Vector3.Distance (m.gameObject.transform.position, GlobalCamera.transform.position);
if (dist > 55f) {
m.gameObject.SetActive (false);
} else if (dist <= 55f && dist > 35f) {
m.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
m.receiveShadows = false;
m.gameObject.SetActive (true);
} else {
m.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
m.receiveShadows = true;
m.gameObject.SetActive (true);
}
//maybe do the DistanceJoint2D checked.. for each.. divide into 2 different height groups.. AndroidJNI for
}
}
void ButterflyVisibilityAndShadowCasterOptimizer(){
// don't spawn any butterfly until the first puzzle.
if (GlobalPuzzleData.EventInfos [0].State != MapState.Beated) {
return;
}
foreach (FlockController m in FlockButterflies) {
// tree and non tree have to be separated..!
if (!m)
continue;
if (!m.gameObject.transform.parent.gameObject.activeSelf)
continue;
float dist = Vector3.Distance (m.gameObject.transform.position, GlobalCamera.transform.position);
if (dist > 35f) {
m.gameObject.SetActive (false);
} else if (!m.gameObject.activeSelf) {
//m.
m.gameObject.SetActive (true);
}
//maybe do the DistanceJoint2D checked.. for each.. divide into 2 different height groups.. AndroidJNI for
}
}
bool Visibility(MeshRenderer m){
Vector2 groundpos2d = new Vector2 (m.gameObject.transform.position.x, m.gameObject.transform.position.z);
Vector2 campos2d = new Vector2 (GlobalCamera.transform.position.x, GlobalCamera.transform.position.z);
Vector2 a = (campos2d - groundpos2d).normalized;
Vector2 b = new Vector2 (GlobalCamera.transform.forward.x, GlobalCamera.transform.forward.z) * -1f;
float res = Vector2.Dot (a, b);
if (res > -0.2f) {
return false;
} else {
return true;
}
}
void ZoneReLink(){
int id = 0;
for (int i = 0; i < CurrentMapPositions.Length; i++) {
//Debug.Log (id + " - " + CurrentMapPositions[i]);
bool replaced = false;
// CASE 1 : Found reuseable asset from existing
for (int j = 0; j < MapObjects.Length; j++) {
if (!MapObjects [j])
return;
if (MapObjects [j].transform.position.Equals(CurrentMapPositions[i])) {
MapObjectsTmp [id] = MapObjects [j];
replaced = true;
break;
}
}
// CASE 2 : Did not found asset - Get one from pool
if (!replaced) {
SetupGroundWithPosition(CurrentMapPositions[i], ref MapObjectsTmp[id]);
}
id++;
}
// Reset assets that are not in used anymore
ZoneClean ();
// Assign the ready-to-go array to MapsObjects now
System.Array.Copy(MapObjectsTmp, MapObjects, MapObjects.Length);
//System.Array.Clear (MapObjectsTmp, 0, MapObjectsTmp.Length);
}
void ZoneClean(){
for (int i = 0; i < MapObjects.Length; i++) {
bool Keep = false;
for (int j = 0; j < CurrentMapPositions.Length; j++) {
if (MapObjects [i].transform.position.Equals(CurrentMapPositions[j])) {
Keep = true;
break;
}
}
if (!Keep) {
if (MapObjects [i].tag == "EventGround") {
PuzzlePool.ResetAsset (MapObjects [i]);
MapObjects [i] = null;
} else {
MapObjects [i].GetComponentInChildren<TerranNoise> ().ClearProps ();
GeneralPool.ResetAsset (MapObjects [i]);
MapObjects [i] = null;
}
}
}
}
}