| | |
| | | } |
| | | |
| | | [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) |
| | | { |
| | |
| | | |
| | | spriteRenderer.sprite = backgroundLayers[initialLayerIndex].backgroundSprite; |
| | | currentLayerIndex = initialLayerIndex; |
| | | lastLayerIndex = currentLayerIndex; |
| | | } |
| | | InitializeInitialTiles(); |
| | | |
| | | 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++) |
| | | { |
| | | for (int y = -verticalTiles; y <= verticalTiles; y++) |
| | | { |
| | | CreateTile(new Vector2Int(x, y)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (transitionRenderer == null) |
| | | private void CreateTile(Vector2Int gridPosition) |
| | | { |
| | | 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 |
| | | } |
| | | transitionRenderer.color = new Color(1, 1, 1, 0); // Start fully transparent |
| | | 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++) |
| | |
| | | } |
| | | |
| | | } |
| | | 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() |
| | | { |
| | |
| | | |
| | | 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 |
| | | // Check if direction changed |
| | | if (initialMovingUp != isMovingUp && |
| | | ((initialMovingUp ? initialY > currentY : initialY < currentY) |
| | | )) |
| | | ((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; |
| | | } |
| | | } |