Untitled

 avatar
unknown
plain_text
2 months ago
6.5 kB
2
Indexable
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class DraggyRoad : MonoBehaviour
{
    [SerializeField] private GameObject straightTemplate;
    [SerializeField] private GameObject cornerTemplate;
    [SerializeField] private float gridScale = 1.5f;
    [SerializeField] private ToastManager toastManager;

    [Header("UI Controls")]
    [SerializeField] private Button upButton;
    [SerializeField] private Button downButton;
    [SerializeField] private Button leftButton;
    [SerializeField] private Button rightButton;

    [Header("Sound Effects")]
    [SerializeField] private AudioClip roadPlaceSound;

    [Header("Animation Settings")]
    [SerializeField] private float placementDuration = 0.3f;
    [SerializeField] private Ease placementEase = Ease.OutBack;

    private AudioSource audioSource;
    private bool soundEnabled = true;

    private Vector3Int lastPosition;
    private float lastAngle;
    private GameObject lastPlacedSection;
    private Dictionary<Vector3Int, GameObject> roadTiles = new();

    private GameObject[] roadTilesLoop = new GameObject[30];
    private int loopStoreIndex = 0;
    private int loopRetrieveIndex = 0;
    private int lastLoopStoreIndex = 0;

    void Start()
    {
        audioSource = gameObject.AddComponent<AudioSource>();
        audioSource.playOnAwake = false;
        soundEnabled = false;
        InitializeRoad();
        soundEnabled = true;

        upButton.onClick.AddListener(() =>{PlaceRoad(Vector3Int.up, 90f);});
        downButton.onClick.AddListener(() =>{PlaceRoad(Vector3Int.down, -90f);});
        leftButton.onClick.AddListener(() =>{PlaceRoad(Vector3Int.left, 180f);});
        rightButton.onClick.AddListener(() =>{PlaceRoad(Vector3Int.right, 0f);});
    }

    private void InitializeRoad()
    {
        Vector3Int startingPosition = new(-7, 0, 0); 
        Vector3 worldStartPosition = (Vector3)startingPosition * gridScale;
        lastPlacedSection = Instantiate(straightTemplate, worldStartPosition, Quaternion.Euler(0, 0, 0));
        roadTiles.Add(startingPosition, lastPlacedSection);
        roadTilesLoop[0] = lastPlacedSection;
        loopStoreIndex = 1;
        loopRetrieveIndex = 0;
        lastLoopStoreIndex = 0;
        lastPosition = startingPosition;
        lastAngle = 0;
        for (int i = 0; i < 6; i++)
        {
            TryPlaceRoad(Vector3Int.right, straightTemplate, 0f);
        }
    }


    private void PlaceRoad(Vector3Int direction, float angle)
    {
        TryPlaceRoad(direction, straightTemplate, angle);
    }

    void TryPlaceRoad(Vector3Int direction, GameObject template, float angle)
    {
        Vector3Int newPosition = lastPosition + direction;
        Vector3 worldPosition = (Vector3)newPosition * gridScale;

        if (CanPlaceRoad(newPosition) && IsWithinCameraBounds(worldPosition))
        {
            GameObject newRoad = Instantiate(template, worldPosition, Quaternion.Euler(0, 0, angle));
            newRoad.transform.localScale = Vector3.zero;
            newRoad.transform.DOScale(Vector3.one, placementDuration)
                .SetEase(placementEase);

            roadTiles[newPosition] = newRoad;

            if (roadTilesLoop[loopStoreIndex] != null)
            {
                Destroy(roadTilesLoop[loopStoreIndex]);
            }

            roadTilesLoop[loopStoreIndex] = newRoad;

            if (angle != lastAngle)
            {
                Vector3 cornerPosition = (Vector3)lastPosition * gridScale;
                Destroy(lastPlacedSection);
                GameObject cornerPiece = null;
                
                switch (angle - lastAngle)
                {
                    case 90:
                    case -270:
                        cornerPiece = Instantiate(cornerTemplate, cornerPosition, Quaternion.Euler(0, 0, lastAngle));
                        break;
                    case -90:
                    case 270:
                        cornerPiece = Instantiate(cornerTemplate, cornerPosition, Quaternion.Euler(0, 0, lastAngle + 90));
                        break;
                }

                if (cornerPiece != null)
                {
                    lastPlacedSection = cornerPiece;
                    roadTiles[lastPosition] = cornerPiece;
                    roadTilesLoop[lastLoopStoreIndex] = cornerPiece;
                }
            }

            lastLoopStoreIndex = loopStoreIndex;
            loopStoreIndex = (loopStoreIndex + 1) % roadTilesLoop.Length;
            lastAngle = angle;
            lastPlacedSection = newRoad;
            lastPosition += direction;
            
            if (soundEnabled)
            {
                PlayRoadPlaceSound();
            }
        }
        else
        {
           if (!IsWithinCameraBounds(worldPosition))
           {
               toastManager.ShowToast("Road out of bounds!");
           }
           else
           {
               toastManager.ShowToast("Cannot place road here!");
           }
        }
    }

    private void PlayRoadPlaceSound()
    {
        if (audioSource != null && roadPlaceSound != null)
        {
            audioSource.PlayOneShot(roadPlaceSound);
        }
    }

    bool IsWithinCameraBounds(Vector3 position)
    {
        Camera mainCamera = Camera.main;
        if (mainCamera == null) return false;

        Vector3 viewportPoint = mainCamera.WorldToViewportPoint(position);
        return viewportPoint.x >= 0 && viewportPoint.x <= 1 && viewportPoint.y >= 0 && viewportPoint.y <= 1;
    }

   bool CanPlaceRoad(Vector3Int position)
   {
       if (roadTiles.TryGetValue(position, out GameObject result) && result != null)
       {
           return false;
       }
   
       Vector3 worldPosition = (Vector3)position * gridScale;
       Collider2D obstacle = Physics2D.OverlapPoint(worldPosition, LayerMask.GetMask("Obstacle"));
       if (obstacle != null)
       {
           return false;
       }
       return true;
   }


    public GameObject GetNextSection()
    {
        if (loopRetrieveIndex == loopStoreIndex)
        {
            return null;
        }
        GameObject nextSection = roadTilesLoop[loopRetrieveIndex];
        loopRetrieveIndex = (loopRetrieveIndex + 1) % roadTilesLoop.Length;
        return nextSection;
    }
}
Leave a Comment