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 Camera mainCamera; public int ChunksX = 40; public int ChunksY = 40; private int numChunks; private List<HashSet<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<HashSet<IsoItem>>(); for (int i = 0; i < numChunks; i++) { chunks.Add(new HashSet<IsoItem>()); } } public void AddIsoItem(IsoItem item) { if (items.Add(item)) { if (item.IsoType == IsoItem.IsoTypes.Sprite) { spriteList.Add(item); } else { objectList.Add(item); } } } public void RemoveIsoItem(IsoItem item) { if (items.Remove(item)) { if (item.IsoType == IsoItem.IsoTypes.Sprite) { spriteList.Remove(item); } else { objectList.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 HashSet<IsoItem> remaining = new HashSet<IsoItem>(); private List<IsoItem> ordered = new List<IsoItem>(); private List<IsoItem> tmpSort = new List<IsoItem>(); 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]); } 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++) { HashSet<IsoItem> chunk = chunks[y * ChunksX + x]; ; chunk.Add(item); } } } int layer = LayerMask.GetMask("iso_piece"); RaycastHit hitInfo = new RaycastHit(); if (Physics.Raycast(new Ray(item.transform.position, -camForward), out hitInfo, item.CameraSpace.z, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null) { item.Behind.Add(otherItem); } } if (Physics.Raycast(new Ray(item.transform.position, camForward), out hitInfo, 50, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null) { otherItem.Behind.Add(item); } } } for (int i = 0; i < numChunks; i++) { if (chunks[i].Count > 0) { tmpSort.Clear(); tmpSort.AddRange(chunks[i]); chunks[i].Clear(); tmpSort.Sort(ItemSort); for (int j = 0; j < tmpSort.Count - 1; j++) { tmpSort[j].Behind.Add(tmpSort[j + 1]); if (tmpSort[j].CameraSpace.z < tmpSort[j + 1].CameraSpace.z) { bool bp = true; } } } } 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]); } while (remaining.Count > 0) { IsoItem item = remaining.First(); Visit(item); } } 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; } }