From ab5a24f4c0cffbc8e8f76e40293f2201027b7c50 Mon Sep 17 00:00:00 2001
From: miepzerino <o.skotnik@gmail.com>
Date: Mon, 07 Apr 2025 22:59:16 +0000
Subject: [PATCH] #49 added parallax and tiling to background

---
 Assets/BackgroundManager.cs |  203 +++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 166 insertions(+), 37 deletions(-)

diff --git a/Assets/BackgroundManager.cs b/Assets/BackgroundManager.cs
index 2722ba7..306cac4 100644
--- a/Assets/BackgroundManager.cs
+++ b/Assets/BackgroundManager.cs
@@ -14,27 +14,40 @@
     }
 
     [SerializeField] private SpriteRenderer spriteRenderer;
-    [SerializeField] private SpriteRenderer transitionRenderer; // Add this field
     [SerializeField] private BackgroundLayer[] backgroundLayers;
     [SerializeField] private Transform playerTransform; // Add this field
+    [SerializeField] private float tileBuffer = 1f; // Extra tiles beyond camera view
     private bool isTransitioning = false; // Add this field
 
     private Transform cameraTransform;
     private Vector3 lastCameraPosition;
     private int currentLayerIndex = 0;
+    private int lastLayerIndex = 0;
     private float startPositionX;
+    private float startPositionY;
 
     private float lastUpdatePlayerY = 0f; // Track the last Y position of the player
     private bool isMovingUp = false; // Track if the player is moving up
 
+    private Dictionary<Vector2Int, SpriteRenderer> backgroundTiles = new Dictionary<Vector2Int, SpriteRenderer>();
+    private Dictionary<Vector2Int, SpriteRenderer> transitionTiles = new Dictionary<Vector2Int, SpriteRenderer>();
+    private Vector2 tileSize;
+    private Camera mainCamera;
+
     private void Start()
     {
-        cameraTransform = Camera.main.transform;
+        mainCamera = Camera.main;
+        cameraTransform = mainCamera.transform;
         lastCameraPosition = cameraTransform.position;
         
         if (spriteRenderer == null)
             spriteRenderer = GetComponent<SpriteRenderer>();
 
+        if (backgroundLayers != null && backgroundLayers.Length > 0)
+        {
+            Sprite firstSprite = backgroundLayers[0].backgroundSprite;
+            tileSize = new Vector2(firstSprite.bounds.size.x, firstSprite.bounds.size.y);
+        }
         // Set initial background based on player position
         if (backgroundLayers != null && backgroundLayers.Length > 0)
         {
@@ -53,39 +66,77 @@
 
             spriteRenderer.sprite = backgroundLayers[initialLayerIndex].backgroundSprite;
             currentLayerIndex = initialLayerIndex;
+            lastLayerIndex = currentLayerIndex;
         }
+        InitializeInitialTiles();
 
-        if (transitionRenderer == null)
+        startPositionX = playerTransform.position.x;
+        startPositionY = playerTransform.position.y;
+    }
+    private void InitializeInitialTiles()
+    {
+        // Calculate visible area
+        float cameraHeight = 2f * mainCamera.orthographicSize;
+        float cameraWidth = cameraHeight * mainCamera.aspect;
+
+        // Calculate number of tiles needed
+        int horizontalTiles = Mathf.CeilToInt(cameraWidth / tileSize.x) + 2;
+        int verticalTiles = Mathf.CeilToInt(cameraHeight / tileSize.y) + 2;
+
+        // Create initial grid of tiles
+        for (int x = -horizontalTiles; x <= horizontalTiles; x++)
         {
-            var transitionObj = new GameObject("TransitionLayer");
-            transitionObj.transform.parent = transform;
-            transitionObj.transform.localPosition = new Vector3(0, 0, -2); // Set Z to -2
-            transitionObj.transform.localScale = Vector3.one; // Match scale
-            transitionRenderer = transitionObj.AddComponent<SpriteRenderer>();
-            transitionRenderer.sortingOrder = spriteRenderer.sortingOrder + 1;
-            transitionRenderer.sortingLayerName = spriteRenderer.sortingLayerName; // Match background layer
+            for (int y = -verticalTiles; y <= verticalTiles; y++)
+            {
+                CreateTile(new Vector2Int(x, y));
+            }
         }
-        transitionRenderer.color = new Color(1, 1, 1, 0); // Start fully transparent
+    }
+
+    private void CreateTile(Vector2Int gridPosition)
+    {
+        if (backgroundTiles.ContainsKey(gridPosition))
+            return;
+
+        GameObject tileObj = new GameObject($"Tile_{gridPosition.x}_{gridPosition.y}");
+        tileObj.transform.parent = transform;
+
+        SpriteRenderer tileSR = tileObj.AddComponent<SpriteRenderer>();
+        tileSR.sprite = backgroundLayers[currentLayerIndex].backgroundSprite;
+        tileSR.sortingOrder = spriteRenderer.sortingOrder;
+        tileSR.sortingLayerName = spriteRenderer.sortingLayerName;
+
+        // Position the tile
+        Vector3 position = new Vector3(
+            gridPosition.x * tileSize.x,
+            gridPosition.y * tileSize.y,
+            transform.position.z
+        );
+        tileObj.transform.localPosition = position;
+        tileObj.transform.localScale = Vector3.one; // Match scale
+
+        backgroundTiles.Add(gridPosition, tileSR);
     }
 
     private void Update()
     {
+        UpdateTiles();
         // Calculate parallax movement
         Vector3 cameraDelta = cameraTransform.position - lastCameraPosition;
         Vector3 newPosition = transform.position;
-
 
         // Update X position with parallax
         float parallaxX = (cameraTransform.position.x - startPositionX) * GetCurrentParallaxEffect();
         newPosition.x = startPositionX + parallaxX;
 
         // Update Y position to follow camera
-        newPosition.y = cameraTransform.position.y;
+        float parallaxY = (cameraTransform.position.y - startPositionY) * GetCurrentParallaxEffect();
+        newPosition.y = startPositionY + parallaxY;
 
         transform.position = newPosition;
 
         // Check for background change
-        float currentY = cameraTransform.position.y;
+        float currentY = playerTransform.position.y;
         int newLayerIndex = currentLayerIndex;
 
         for (int i = 0; i < backgroundLayers.Length; i++)
@@ -120,6 +171,57 @@
         }
 
     }
+    private void UpdateTiles()
+    {
+        // Calculate visible area with buffer
+        float cameraHeight = 2f * mainCamera.orthographicSize * (1f + tileBuffer);
+        float cameraWidth = cameraHeight * mainCamera.aspect * (1f + tileBuffer);
+
+        // Calculate parallax offset
+        float parallaxX = (cameraTransform.position.x - startPositionX) * GetCurrentParallaxEffect();
+        float parallaxY = (cameraTransform.position.y - startPositionY) * GetCurrentParallaxEffect();
+
+        // Calculate grid positions that should be visible
+        Vector2 cameraPos = mainCamera.transform.position;
+
+        // Adjust the buffer based on parallax effect
+        float parallaxBuffer = 1f; // Base buffer size
+        float effectiveBuffer = parallaxBuffer * (1f + GetCurrentParallaxEffect());
+
+        int minX = Mathf.FloorToInt((parallaxX - (cameraWidth / 2 * effectiveBuffer)) / tileSize.x);
+        int maxX = Mathf.CeilToInt((parallaxX + (cameraWidth / 2 * effectiveBuffer)) / tileSize.x);
+        int minY = Mathf.FloorToInt((parallaxY - (cameraHeight / 2 * effectiveBuffer)) / tileSize.y);
+        int maxY = Mathf.CeilToInt((parallaxY + (cameraHeight / 2 * effectiveBuffer)) / tileSize.y);
+
+        // Create new tiles
+        for (int x = minX; x <= maxX; x++)
+        {
+            for (int y = minY; y <= maxY; y++)
+            {
+                CreateTile(new Vector2Int(x, y));
+            }
+        }
+
+        // Remove out-of-view tiles
+        List<Vector2Int> tilesToRemove = new List<Vector2Int>();
+        foreach (var tile in backgroundTiles)
+        {
+            if (tile.Key.x < minX - 1 || tile.Key.x > maxX + 1 ||
+                tile.Key.y < minY - 1 || tile.Key.y > maxY + 1)
+            {
+                tilesToRemove.Add(tile.Key);
+            }
+        }
+
+        foreach (var tilePos in tilesToRemove)
+        {
+            if (!transitionTiles.ContainsKey(tilePos))
+            {
+                Destroy(backgroundTiles[tilePos].gameObject);
+                backgroundTiles.Remove(tilePos);
+            }
+        }
+    }
 
     private float GetCurrentParallaxEffect()
     {
@@ -130,51 +232,78 @@
 
     private IEnumerator TransitionBackground(BackgroundLayer newLayer)
     {
-        // Check if the transition is already in progress or if the new sprite is the same as the current one
-        if (isTransitioning || newLayer.backgroundSprite.name == spriteRenderer.sprite.name) yield break;
+        if (isTransitioning || newLayer.backgroundSprite.name == backgroundLayers[lastLayerIndex].backgroundSprite.name)
+            yield break;
+
         isTransitioning = true;
-
-        // Setup transition renderer
-        transitionRenderer.sprite = newLayer.backgroundSprite;
-        transitionRenderer.transform.localPosition = Vector3.zero;
-
-        bool initialMovingUp = isMovingUp; // Store the initial moving direction
+        bool initialMovingUp = isMovingUp;
         float initialY = playerTransform.position.y;
-        //bool movingUp = playerTransform.position.y > initialY;
 
-        // Fade in new sprite over old one
+        // Create transition renderers for all existing tiles
+        foreach (var tile in backgroundTiles)
+        {
+            GameObject transObj = new GameObject($"TransitionTile_{tile.Key.x}_{tile.Key.y}");
+            transObj.transform.parent = transform;
+            transObj.transform.localPosition = tile.Value.transform.localPosition + new Vector3(0, 0, -0.1f);
+            transObj.transform.localScale = Vector3.one;
+
+            SpriteRenderer transSR = transObj.AddComponent<SpriteRenderer>();
+            transSR.sprite = newLayer.backgroundSprite;
+            transSR.sortingOrder = tile.Value.sortingOrder + 1;
+            transSR.sortingLayerName = tile.Value.sortingLayerName;
+            transSR.color = new Color(1, 1, 1, 0);
+
+            transitionTiles.Add(tile.Key, transSR);
+        }
+
+        // Fade in new sprites over old ones
         while (true)
         {
             float currentY = playerTransform.position.y;
 
-            // Check if the direction has changed
-            if (initialMovingUp != isMovingUp && 
-                ((initialMovingUp ? initialY > currentY : initialY < currentY)
-                ))
+            // Check if direction changed
+            if (initialMovingUp != isMovingUp &&
+                ((initialMovingUp ? initialY > currentY : initialY < currentY)))
             {
-                transitionRenderer.color = new Color(1, 1, 1, 0);
+                foreach (var transTile in transitionTiles.Values)
+                {
+                    Destroy(transTile.gameObject);
+                }
+                transitionTiles.Clear();
                 isTransitioning = false;
                 yield break;
             }
 
-            // Calculate the alpha based on the distance moved
+            // Calculate alpha
             float alpha = Mathf.Abs(currentY - initialY) / newLayer.transitionDistance;
-            transitionRenderer.color = new Color(1, 1, 1, Mathf.Clamp01(alpha));
+            Color newColor = new Color(1, 1, 1, Mathf.Clamp01(alpha));
 
-            // Check if transition is complete
+            // Update all transition tiles
+            foreach (var transTile in transitionTiles.Values)
+            {
+                transTile.color = newColor;
+            }
+
             if (alpha >= 1f)
                 break;
 
             yield return null;
         }
 
-        // Ensure the final alpha value is set correctly
-        transitionRenderer.color = new Color(1, 1, 1, 1);
+        // Switch sprites on all tiles
+        foreach (var tile in backgroundTiles.Values)
+        {
+            tile.sprite = newLayer.backgroundSprite;
+        }
 
-        // Switch the sprites
-        spriteRenderer.sprite = newLayer.backgroundSprite;
-        transitionRenderer.color = new Color(1, 1, 1, 0);
+        // Cleanup transition tiles
+        foreach (var transTile in transitionTiles.Values)
+        {
+            Destroy(transTile.gameObject);
+        }
+        transitionTiles.Clear();
 
         isTransitioning = false;
+        lastLayerIndex = currentLayerIndex;
     }
 }

--
Gitblit v1.9.3