Created
November 6, 2016 16:05
-
-
Save nothke/7caa58a7b76e87691825d58de3dc9f84 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// | |
/// Placas objects dynamically around the player | |
/// by Nothke | |
/// | |
/// unlicensed, aka do whatever you want with it | |
/// | |
using UnityEngine; | |
using System.Collections.Generic; | |
public class PoolPlacer : MonoBehaviour | |
{ | |
[Tooltip("Prefab to pool, it needs to have a renderer to work")] | |
public GameObject prefab; | |
[Tooltip("Track position of this transform")] | |
public Transform player; | |
[Tooltip("Grid dimension, there will be n*n pooled objects")] | |
public int chunksGridSize = 10; | |
[Tooltip("Separation width between 2 chunks")] | |
public float chunkScale = 1; | |
[Tooltip("LayerMask to raycast against when placing objects")] | |
public LayerMask raycastLayerMask; | |
public bool debug; | |
public class Chunk | |
{ | |
public int x; | |
public int y; | |
public Renderer renderer; | |
public bool visible | |
{ | |
get { return renderer.enabled; } | |
set { renderer.enabled = value; } | |
} | |
public bool IsWithinRange(Range range) | |
{ | |
return range.IsWithin(x, y); | |
} | |
} | |
public struct Coord | |
{ | |
public int x, y; | |
public Coord(int x, int y) | |
{ | |
this.x = x; | |
this.y = y; | |
} | |
} | |
public struct Range | |
{ | |
public int x, y, w, h; | |
public int endX { get { return x + w; } } | |
public int endY { get { return y + h; } } | |
public Range(int x, int y, int w, int h) | |
{ | |
this.x = x; | |
this.y = y; | |
this.w = w; | |
this.h = h; | |
} | |
public bool IsWithin(int pX, int pY) | |
{ | |
return pX >= x | |
&& pX < x + w | |
&& pY >= y | |
&& pY < y + h; | |
} | |
public override string ToString() | |
{ | |
return x + ", " + y + ", " + w + ", " + h; | |
} | |
} | |
Range curRange; | |
Range prevRange; | |
Chunk[] chunks; | |
int curX = 0; | |
int curY = 0; | |
float halfWidth; | |
void Start() | |
{ | |
if (chunkScale == 0) chunkScale = 1; | |
halfWidth = (chunksGridSize * chunkScale) / 2; | |
if (!prefab) | |
{ | |
Debug.LogError("No prefab assigned"); | |
enabled = false; | |
return; | |
} | |
InitChunks(); | |
} | |
void InitChunks() | |
{ | |
chunks = new Chunk[chunksGridSize * chunksGridSize]; | |
for (int i = 0; i < chunks.Length; i++) | |
{ | |
chunks[i] = new Chunk(); | |
GameObject go = Instantiate(prefab); | |
go.name = "DetailChunk_" + i; | |
chunks[i].renderer = go.GetComponent<Renderer>(); | |
chunks[i].visible = false; | |
} | |
} | |
void RefreshChunks() | |
{ | |
Queue<Coord> redoCoords = new Queue<Coord>(); | |
// First, find all coords that need to be redone | |
for (int y = curRange.y; y < curRange.endY; y++) | |
for (int x = curRange.x; x < curRange.endX; x++) | |
{ | |
// if a new point is not within the old range, queue it for regen | |
if (!prevRange.IsWithin(x, y)) | |
redoCoords.Enqueue(new Coord(x, y)); | |
} | |
if (debug) | |
foreach (var redoCoord in redoCoords) | |
Debug.DrawRay(new Vector3(redoCoord.x * chunkScale - halfWidth, 0, redoCoord.y * chunkScale - halfWidth), Vector3.up, Color.white, 0.2f); | |
foreach (var chunk in chunks) | |
{ | |
// if chunk is not within the new range, reassign it's coords to one that needs to be redone | |
if (!chunk.IsWithinRange(curRange)) | |
{ | |
// if there are no coords in queue, hide the chunk | |
if (redoCoords.Count == 0) | |
{ | |
chunk.visible = false; | |
continue; | |
} | |
Coord coord = redoCoords.Dequeue(); | |
chunk.x = coord.x; | |
chunk.y = coord.y; | |
// show it and set new position | |
PlaceChunkRaycast(chunk); | |
} | |
} | |
} | |
// Without raycast, just at y = 0 | |
void PlaceChunk(Chunk chunk) | |
{ | |
chunk.visible = true; | |
chunk.renderer.transform.position = GetChunkPos(chunk.x, chunk.y); | |
} | |
void PlaceChunkRaycast(Chunk chunk) | |
{ | |
Vector3 chunkPos = GetChunkPosRandomGridOffset(chunk.x, chunk.y); | |
RaycastHit hit; | |
if (Physics.Raycast(chunkPos + Vector3.up, Vector3.down, out hit, Mathf.Infinity, raycastLayerMask)) | |
{ | |
chunk.visible = true; | |
chunk.renderer.transform.position = hit.point; | |
} | |
else | |
{ | |
chunk.visible = false; | |
} | |
} | |
Vector3 GetChunkPos(int x, int y) | |
{ | |
return new Vector3(x * chunkScale - halfWidth, 0, y * chunkScale - halfWidth); | |
} | |
Vector3 GetChunkPosRandomGridOffset(int x, int y) | |
{ | |
Random.InitState((x + y * chunksGridSize) * 323 % 3414); | |
float X = (x + Random.value) * chunkScale - halfWidth; | |
float Y = (y + Random.value) * chunkScale - halfWidth; | |
return new Vector3(X, 0, Y); | |
} | |
void Check() | |
{ | |
int x = Mathf.RoundToInt(player.position.x / chunkScale); | |
int y = Mathf.RoundToInt(player.position.z / chunkScale); | |
if (x != curX || y != curY) | |
{ | |
curRange = new Range(x, y, chunksGridSize, chunksGridSize); | |
Debug.Log(curRange); | |
RefreshChunks(); | |
prevRange = curRange; | |
} | |
curX = x; | |
curY = y; | |
} | |
void Update() | |
{ | |
Check(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment