using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; [SelectionBase] public class IsoHandler : MonoBehaviour { private HashSet<IsoItem> items = new HashSet<IsoItem>(); private List<IsoItem> spriteList = new List<IsoItem>(); private List<IsoItem> objectList = new List<IsoItem>(); private List<IsoItem> allList = new List<IsoItem>(); private Camera mainCamera; public int ChunksX = 40; public int ChunksY = 40; private int numChunks; private List<List<IsoItem>> chunks; // Use this for initialization void Start() { numChunks = ChunksX * ChunksY; mainCamera = GameObject.Find("Main Camera").GetComponent<Camera>(); mainCamera.transparencySortMode = TransparencySortMode.Orthographic; chunks = new List<List<IsoItem>>(); for (int i = 0; i < numChunks; i++) { chunks.Add(new List<IsoItem>()); } } public void AddIsoItem(IsoItem item) { if (items.Add(item)) { if (item.IsoType == IsoItem.IsoTypes.Sprite) { spriteList.Add(item); } else { objectList.Add(item); } allList.Add(item); } } public void RemoveIsoItem(IsoItem item) { if (items.Remove(item)) { if (item.IsoType == IsoItem.IsoTypes.Sprite) { spriteList.Remove(item); } else { objectList.Remove(item); } allList.Remove(item); } } int ItemSort(IsoItem a, IsoItem b) { float diff = b.CameraSpace.z - a.CameraSpace.z; if (diff > 0) return 1; if (diff < 0) return -1; return 0; } private float nextDepth = 0; private Vector3 camForward; private Vector3 camRight; private Vector3 camUp; private Vector3 camPos; private List<IsoItem> ordered = new List<IsoItem>(); private HashSet<int> usedChunks = new HashSet<int>(); void LateUpdate() { camForward = mainCamera.transform.forward; camRight = mainCamera.transform.right; camUp = mainCamera.transform.up; camPos = mainCamera.transform.position; float worldSizeH = mainCamera.orthographicSize * 2; float worldSizeW = worldSizeH * mainCamera.aspect; Vector3 worldBottomLeft = mainCamera.ViewportToWorldPoint(new Vector3()); //remaining.Clear(); ordered.Clear(); nextDepth = 10; for (int i = 0; i < spriteList.Count; i++) { spriteList[i].Behind.Clear(); spriteList[i].MarkTemp = false; spriteList[i].MarkPerm = false; //remaining.Add(spriteList[i]); } for (int i = 0; i < objectList.Count; i++) { objectList[i].Behind.Clear(); objectList[i].MarkTemp = false; objectList[i].MarkPerm = false; //remaining.Add(objectList[i]); } Ray outRay = new Ray(); outRay.direction = camForward; Ray inRay = new Ray(); inRay.direction = -camForward; usedChunks.Clear(); for (int i = 0; i < spriteList.Count; i++) { IsoItem item = spriteList[i]; Vector3 screenSpace = mainCamera.WorldToViewportPoint(item.transform.position); //item.CameraSpace.x = worldBottomLeft.x + screenSpace.x * worldSizeW; //item.CameraSpace.y = worldBottomLeft.y + screenSpace.y * worldSizeH; //item.CameraSpace.z = screenSpace.z; item.CameraSpace = screenSpace; if (item.IsoRadius > 0) { float scale = Mathf.Max(item.LinkedImage.transform.lossyScale.x, Mathf.Max(item.LinkedImage.transform.lossyScale.y, item.LinkedImage.transform.lossyScale.z)); float radiusCamX = item.IsoRadius / worldSizeW * scale; float radiusCamY = item.IsoRadius / worldSizeH * scale; int leftBucket = Mathf.Max(0, Mathf.Min(ChunksX - 1, (int)Mathf.Floor((screenSpace.x - radiusCamX) * ChunksX))); int rightBucket = Mathf.Max(0, Mathf.Min(ChunksX - 1, (int)Mathf.Ceil((screenSpace.x + radiusCamX) * ChunksX))); int bottomBucket = Mathf.Max(0, Mathf.Min(ChunksY - 1, (int)Mathf.Floor((screenSpace.y - radiusCamY) * ChunksY))); int topBucket = Mathf.Max(0, Mathf.Min(ChunksY - 1, (int)Mathf.Ceil((screenSpace.y + radiusCamY) * ChunksY))); for (int x = leftBucket; x <= rightBucket; x++) { for (int y = bottomBucket; y <= topBucket; y++) { int chunkIndex = y * ChunksX + x; List<IsoItem> chunk = chunks[chunkIndex]; bool placed = false; for (var j = 0; j < chunk.Count; j++) { if (item == chunk[j]) { placed = true; break; } float thisZ = item.CameraSpace.z; float otherZ = chunk[j].CameraSpace.z; if (thisZ > otherZ) { chunk.Insert(j, item); /* for (int k = 0; k < chunk.Count - 1; k++) { if (chunk[k].CameraSpace.z < chunk[k + 1].CameraSpace.z) { Debug.LogError("OUT OF ORDER ITEM"); bool bp = true; } } */ placed = true; break; } } if (!placed) { chunk.Add(item); /* for (int k = 0; k < chunk.Count - 1; k++) { if (chunk[k].CameraSpace.z < chunk[k + 1].CameraSpace.z) { Debug.LogError("OUT OF ORDER ITEM"); bool bp = true; } } */ } usedChunks.Add(chunkIndex); } } } int layer = LayerMask.GetMask("iso_piece"); RaycastHit hitInfo = new RaycastHit(); outRay.origin = inRay.origin = item.transform.position; if (Physics.Raycast(inRay, out hitInfo, item.CameraSpace.z, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null) { item.Behind.Add(otherItem); } } if (Physics.Raycast(outRay, out hitInfo, 50, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null) { otherItem.Behind.Add(item); } } } foreach (int i in usedChunks) { List<IsoItem> chunk = chunks[i]; for (int j = 0; j < chunk.Count - 1; j++) { chunk[j].Behind.Add(chunk[j + 1]); /* if (chunk[j].CameraSpace.z < chunk[j + 1].CameraSpace.z) { Debug.LogError("OUT OF ORDER ITEM"); bool bp = true; } */ } chunk.Clear(); } for (int i = 0; i < objectList.Count; i++) { IsoItem item = objectList[i]; item.CameraSpace = mainCamera.WorldToViewportPoint(item.LinkedImage.transform.position); } objectList.Sort(ItemSort); for (int i = 0; i < objectList.Count - 1; i++) { objectList[i].Behind.Add(objectList[i + 1]); } int nextUnmarked = 0; while (nextUnmarked < allList.Count) { if (!allList[nextUnmarked].MarkPerm) { IsoItem item = allList[nextUnmarked]; Visit(item); } nextUnmarked++; } } private void Visit(IsoItem item) { if (item.MarkPerm) return; if (item.MarkTemp) { //Debug.LogError("CYCLICAL RENDER GRAPH"); item.MarkTemp = false; item.MarkPerm = true; //remaining.Remove(item); return; } item.MarkTemp = true; foreach (IsoItem newItem in item.Behind) { Visit(newItem); } item.MarkTemp = false; item.MarkPerm = true; //remaining.Remove(item); item.SetDepth = nextDepth; Vector3 camPos = item.CameraSpace; camPos.z = nextDepth; item.LinkedImage.transform.position = mainCamera.ViewportToWorldPoint(camPos); nextDepth += 0.01f; } }