using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(SpriteRenderer))] public class Tiling : MonoBehaviour { [System.Serializable] public class HeightSpritePair { public float minHeight; public float maxHeight; public Sprite sprite; } public int offsetX = 2; public int offsetY = 2; public HeightSpritePair[] heightSprites; public bool hasRightBuddy = false; public bool hasLeftBuddy = false; public bool hasTopBuddy = false; public bool hasBottomBuddy = false; public bool reverseScale = false; private float spriteWidth = 0f; private float spriteHeight = 0f; private Camera cam; private Transform myTransform; private SpriteRenderer spriteRenderer; private void Awake() { cam = Camera.main; myTransform = transform; spriteRenderer = GetComponent(); } void Start() { UpdateSpriteForHeight(); spriteWidth = spriteRenderer.sprite.bounds.size.x; spriteHeight = spriteRenderer.sprite.bounds.size.y; } void Update() { if (CheckOffscreenAndDestroy()) return; // Return early if destroyed CheckHorizontalTiling(); CheckVerticalTiling(); } private void UpdateSpriteForHeight() { if (heightSprites == null || heightSprites.Length == 0) return; float worldY = transform.position.y; Sprite oldSprite = spriteRenderer.sprite; foreach (HeightSpritePair pair in heightSprites) { if (pair.sprite == null) continue; // Skip invalid sprites if ((pair.minHeight == 0 && pair.maxHeight == 0) || (worldY >= pair.minHeight && worldY <= pair.maxHeight)) { if (oldSprite != pair.sprite) { spriteRenderer.sprite = pair.sprite; // Update sprite dimensions if sprite changed spriteWidth = spriteRenderer.sprite.bounds.size.x; spriteHeight = spriteRenderer.sprite.bounds.size.y; } break; } } } private void CheckHorizontalTiling() { if (!hasLeftBuddy || !hasRightBuddy) { float camHorizontalExtend = cam.orthographicSize * Screen.width / Screen.height; float edgeVisiblePositionRight = (transform.position.x + spriteWidth / 2) - camHorizontalExtend; float edgeVisiblePositionLeft = (transform.position.x - spriteWidth / 2) + camHorizontalExtend; if (cam.transform.position.x >= edgeVisiblePositionRight - offsetX && !hasRightBuddy) { MakeNewBuddy(1, 0); hasRightBuddy = true; } else if (cam.transform.position.x <= edgeVisiblePositionLeft + offsetX && !hasLeftBuddy) { MakeNewBuddy(-1, 0); hasLeftBuddy = true; } } } private void CheckVerticalTiling() { if (!hasTopBuddy || !hasBottomBuddy) { float camVerticalExtend = cam.orthographicSize; float edgeVisiblePositionTop = (transform.position.y + spriteHeight / 2) - camVerticalExtend; float edgeVisiblePositionBottom = (transform.position.y - spriteHeight / 2) + camVerticalExtend; if (cam.transform.position.y >= edgeVisiblePositionTop - offsetY && !hasTopBuddy) { MakeNewBuddy(0, 1); hasTopBuddy = true; } else if (cam.transform.position.y <= edgeVisiblePositionBottom + offsetY && !hasBottomBuddy) { MakeNewBuddy(0, -1); hasBottomBuddy = true; } } } private void MakeNewBuddy(int rightOrLeft, int topOrBottom) { Vector3 newPosition = new Vector3( myTransform.position.x + spriteWidth * rightOrLeft, myTransform.position.y + spriteHeight * topOrBottom, myTransform.position.z ); Transform newBuddy = Instantiate(myTransform, newPosition, myTransform.rotation); Tiling buddyTiling = newBuddy.GetComponent(); if (reverseScale) { newBuddy.localScale = new Vector3( rightOrLeft != 0 ? newBuddy.localScale.x * -1 : newBuddy.localScale.x, topOrBottom != 0 ? newBuddy.localScale.y * -1 : newBuddy.localScale.y, newBuddy.localScale.z ); } newBuddy.parent = myTransform.parent; newBuddy.name = myTransform.name; if (rightOrLeft > 0) buddyTiling.hasLeftBuddy = true; else if (rightOrLeft < 0) buddyTiling.hasRightBuddy = true; if (topOrBottom > 0) buddyTiling.hasBottomBuddy = true; else if (topOrBottom < 0) buddyTiling.hasTopBuddy = true; buddyTiling.UpdateSpriteForHeight(); } private bool CheckOffscreenAndDestroy() { Vector3 viewportPosition = cam.WorldToViewportPoint(transform.position); float buffer = 1.5f; if (viewportPosition.x < -buffer || viewportPosition.x > 1 + buffer || viewportPosition.y < -buffer || viewportPosition.y > 1 + buffer) { NotifyNeighbors(); Destroy(gameObject); return true; } return false; } private void NotifyNeighbors() { // Use a slightly smaller size than the sprite to ensure we only hit immediate neighbors Vector2 checkSize = new Vector2(spriteWidth * 0.9f, spriteHeight * 0.9f); Vector2 position = transform.position; ContactFilter2D filter = new ContactFilter2D().NoFilter(); Collider2D[] results = new Collider2D[1]; // Check each direction using OverlapBox // Right neighbor if (Physics2D.OverlapBox(position + new Vector2(spriteWidth, 0), checkSize, 0f, filter, results) > 0) { Tiling rightTile = results[0].GetComponent(); if (rightTile != null) rightTile.hasLeftBuddy = false; } // Left neighbor if (Physics2D.OverlapBox(position + new Vector2(-spriteWidth, 0), checkSize, 0f, filter, results) > 0) { Tiling leftTile = results[0].GetComponent(); if (leftTile != null) leftTile.hasRightBuddy = false; } // Top neighbor if (Physics2D.OverlapBox(position + new Vector2(0, spriteHeight), checkSize, 0f, filter, results) > 0) { Tiling topTile = results[0].GetComponent(); if (topTile != null) topTile.hasBottomBuddy = false; } // Bottom neighbor if (Physics2D.OverlapBox(position + new Vector2(0, -spriteHeight), checkSize, 0f, filter, results) > 0) { Tiling bottomTile = results[0].GetComponent(); if (bottomTile != null) bottomTile.hasTopBuddy = false; } } //private void OnDrawGizmos() //{ // if (!Application.isPlaying) return; // Vector2 checkSize = new Vector2(spriteWidth * 0.9f, spriteHeight * 0.9f); // Gizmos.color = Color.yellow; // // Draw detection boxes for each direction // Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(spriteWidth, 0), checkSize); // Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(-spriteWidth, 0), checkSize); // Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(0, spriteHeight), checkSize); // Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(0, -spriteHeight), checkSize); //} }