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; int layerIn = LayerMask.GetMask("iso_piece", "leaf", "player_controller", "iso_piece_no_collide"); int layerOut = LayerMask.GetMask("iso_piece", "iso_piece_no_collide"); //usedChunks.Clear(); int count = spriteList.Count; for (int i = 0; i < 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 = 1; // 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.CameraSpace.z > chunk[j].CameraSpace.z) { chunk.Insert(j, item); placed = true; break; } } if (!placed) { chunk.Add(item); } //usedChunks.Add(chunkIndex); } } } */ //if (item.Moved) //{ outRay.origin = inRay.origin = item.transform.position; DepthHitCheck(item, inRay, item.CameraSpace.z, layerIn, false); //if (otherItem != null) //{ // item.Behind.Add(otherItem); //} DepthHitCheck(item, outRay, 50, layerIn, true); //if (otherItem != null) //{ // otherItem.Behind.Add(item); //} } /* //foreach (int i in usedChunks) //{ for (int i = 0; i < numChunks; i++) { List<IsoItem> chunk = chunks[i]; for (int j = 0; j < chunk.Count - 1; j++) { chunk[j].Behind.Add(chunk[j + 1]);/ } chunk.Clear(); } */ for (int i = 0; i < objectList.Count; i++) { IsoItem item = objectList[i]; item.CameraSpace = mainCamera.WorldToViewportPoint(item.LinkedImage.transform.position); } objectList.Sort((a, b) => b.ObjectManualDepth - a.ObjectManualDepth); for (int i = 0; i < objectList.Count - 1; i++) { objectList[i].Behind.Add(objectList[i + 1]); } int nextUnmarked = 0; int total = allList.Count; while (nextUnmarked < total) { IsoItem item = allList[nextUnmarked]; Visit(item); nextUnmarked++; while (nextUnmarked < total && allList[nextUnmarked].MarkPerm) { nextUnmarked++; } } } private RaycastHit hitInfo = new RaycastHit(); private void DepthHitCheck(IsoItem item, Ray ray, float dist, int layer, bool itemInFront) { IsoItem found = null; switch (item.Custom) { case IsoItem.CustomSort.None: bool hit = Physics.Raycast(ray, out hitInfo, dist, layer); if (hit) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null) { found = otherItem; } } break; case IsoItem.CustomSort.Capsule: { Vector3 p1 = ray.origin + Vector3.up * item.CustomCapsuleHeight * 0.25f; Vector3 p2 = ray.origin + Vector3.up * item.CustomCapsuleHeight * 0.75f; float closestDist = 0; foreach (RaycastHit hitInfo in Physics.CapsuleCastAll(p1, p2, item.CustomCapsuleHeight * 0.25f, ray.direction, dist, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null && otherItem != item) { if (otherItem.IsoType == IsoItem.IsoTypes.Sprite) { var otherDist = Vector3.Dot(otherItem.transform.position - ray.origin, ray.direction); if (otherDist > 0 && (found == null || otherDist < closestDist)) { closestDist = hitInfo.distance; found = otherItem; } } else { if (itemInFront || otherItem.ObjectManualDepth == 100) { if (!item.Behind.Contains(otherItem)) otherItem.Behind.Add(item); } else { if (!otherItem.Behind.Contains(item)) item.Behind.Add(otherItem); } } } } break; } case IsoItem.CustomSort.Sphere: { Vector3 o = ray.origin + Vector3.up * item.CustomSphereHeight; float closestDist = 0; foreach (RaycastHit hitInfo in Physics.SphereCastAll(o, item.CustomSphereRadius, ray.direction, dist, layer)) { IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>(); if (otherItem != null && otherItem != item) { if (otherItem.IsoType == IsoItem.IsoTypes.Sprite) { var otherDist = Vector3.Dot(otherItem.transform.position - ray.origin, ray.direction); if (otherDist > 0 && (found == null || otherDist < closestDist)) { closestDist = hitInfo.distance; found = otherItem; } } else { if (itemInFront || otherItem.ObjectManualDepth == 100) { if (!item.Behind.Contains(otherItem)) otherItem.Behind.Add(item); } else { if (!otherItem.Behind.Contains(item)) item.Behind.Add(otherItem); } } } } break; } } if (found != null) { if (itemInFront || found.ObjectManualDepth == 100) { if (!item.Behind.Contains(found)) found.Behind.Add(item); } else { if (!found.Behind.Contains(item)) item.Behind.Add(found); } } } 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; //for (int i = 0; i < item.Behind.Count; i++) //{ // Visit(item.Behind[i]); //} foreach (IsoItem nextItem in item.Behind) { Visit(nextItem); } item.MarkTemp = false; item.MarkPerm = true; //remaining.Remove(item); item.SetDepth = nextDepth + item.Thickness; Vector3 camPos = item.CameraSpace; camPos.z = nextDepth + item.Thickness; item.LinkedImage.transform.position = mainCamera.ViewportToWorldPoint(camPos); nextDepth += 0.01f + item.Thickness * 2; } }