eye-therapy-2 / Assets / Scripts / Builder / BuildingManagerAlt.cs
BuildingManagerAlt.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;

public class BuildingManagerAlt : MonoBehaviour, IListener
{
    [SerializeField] private float buildingMoveSpeed = 3f;
    [Tooltip("Opóźnienie przed włączeniem możliwości ustawienia kolejnego budynku.")]
    [SerializeField] private float buildDelay = 1f;
    [SerializeField] [Range(0f, 0.7f)] private float rowChangeThreshold = 0.70f;
    [SerializeField] [Min(0.1f)] private float rowChangeTime = 0.8f;

    [Header("Distance")]
    [SerializeField] private float distance = 0.5f;
    [SerializeField] private SliderWithEdit ui = null;

    [Header("Spawn Settings")]
    [SerializeField] private float leftSpawnX = -10f;
    [SerializeField] private float rightSpawnX = 10f;
    [SerializeField] private float spawnRange = 1f;
    [SerializeField] private float minX, maxX;

    BuildingBehaviourAlt[] buildings;
    BuildingBehaviourAlt currentBuilding;
    List<BuildingSiteBehaviour> buildingSites;
    float[] rows;
    bool[] buildingsBuilt;
    int currentBuildingIdx = 0;
    int currentRowIdx = 0;
    bool buildActive = false;
    int buildCount = 0;
    public bool ChangingRows { get; private set; } = false;
    public Vector3 MoveDir { get; set; } = Vector3.zero;

    void Start()
    {
        buildings = GetComponentsInChildren<BuildingBehaviourAlt>();
        buildingsBuilt = new bool[buildings.Length];

        buildingSites = GetComponentsInChildren<BuildingSiteBehaviour>().ToList();
        float[] coords = new float[buildingSites.Count];
        for (int i = 0; i < buildingSites.Count; ++i) coords[i] = buildingSites[i].transform.position.z;
        rows = coords.Distinct().ToArray();
        RandomizeDestinations();
        
        minX = Mathf.Min(minX, leftSpawnX - spawnRange);
        maxX = Mathf.Max(maxX, rightSpawnX + spawnRange);
        ui.UpdateParam(distance);

        EventManager.Instance.AddListener(EVENT_TYPE.ON_BUILDING_CONFIRMED, this);
        EventManager.Instance.AddListener(EVENT_TYPE.ON_BUILDING_BUILT, this);
        EventManager.Instance.AddListener(EVENT_TYPE.ON_BUILDING_DISTANCE_CHANGED, this);

        Invoke("SetupNewBuild", 0.5f);
    }

    private void RandomizeDestinations()
    {
        int siteIdx;
        foreach (BuildingBehaviourAlt build in buildings)
        {
            do
            {
                siteIdx = UnityEngine.Random.Range(0, buildingSites.Count);
            } while (buildingSites[siteIdx].Taken);
            buildingSites[siteIdx].TakeSite();
            Vector3 destinationPosition = buildingSites[siteIdx].transform.position;
            destinationPosition.y = build.building.position.y;
            buildingSites.RemoveAt(siteIdx);
            build.SetDestination(destinationPosition);
        }
    }

    private void Update()
    {
        if (buildActive)
        {
            float step = buildingMoveSpeed * Time.deltaTime;
            if (currentBuilding != null)
            {
                Vector3 t = currentBuilding.building.position;
                t = Vector3.Lerp(t, t + MoveDir, step);
                t.x = Mathf.Clamp(t.x, minX, maxX);
                currentBuilding.building.position = t;
            }
        }
    }

    private void SetupNewBuild()
    {
        // Random Building
        do
        {
            currentBuildingIdx = UnityEngine.Random.Range(0, buildings.Length);
        } while (buildingsBuilt[currentBuildingIdx]);
        currentBuilding = buildings[currentBuildingIdx];

        // Random Spawn
        currentRowIdx = UnityEngine.Random.Range(0, rows.Length);
        Vector3 buildingPosition = new Vector3(leftSpawnX, currentBuilding.building.position.y, rows[currentRowIdx]);
        if (UnityEngine.Random.value > 0.5f) buildingPosition.x = rightSpawnX;
        buildingPosition.x += UnityEngine.Random.Range(-1f, 1f) * spawnRange;

        currentBuilding.Init(buildingPosition);
        buildActive = true;
    }

    public void OnBuildingMoved(InputAction.CallbackContext ctx)
    {
        Vector2 moveVector = ctx.ReadValue<Vector2>();
        MoveDir = new Vector3(moveVector.x, 0, 0);

        if(!ChangingRows && Mathf.Abs(moveVector.y) > rowChangeThreshold)
        {
            if (moveVector.y > 0) ChangeBuildingRow(true);
            else ChangeBuildingRow(false);
        }
    }

    public void ChangeBuildingRow(bool dir)
    {
        if (!ChangingRows)
        {
            ChangingRows = true;
            StartCoroutine(ChangeRow(dir));
        }
    }

    private IEnumerator ChangeRow(bool dir)
    {
        if (dir && currentRowIdx < rows.Length - 1) currentRowIdx++;
        else if (!dir && currentRowIdx > 0) currentRowIdx--;
        Transform building = buildings[currentBuildingIdx].building.transform;
        float startPosition = building.position.z;
        float t = 0;
        while (t <= rowChangeTime)
        {
            t += Time.deltaTime;
            float newPosition = Mathf.Lerp(startPosition, rows[currentRowIdx], t / rowChangeTime);
            building.position = new Vector3(building.position.x, building.position.y, newPosition);
            yield return null;
        }
        building.position = new Vector3(building.position.x, building.position.y, rows[currentRowIdx]);
        ChangingRows = false;
    }

    public void OnBuildingConfirmed(InputAction.CallbackContext ctx)
    {
        if (ctx.performed && buildActive)
        {
            currentBuilding.CheckDistance(distance);
        }
    }

    public void OnBuildingRotated(InputAction.CallbackContext ctx)
    {
        if (ctx.performed && buildActive)
        {
            currentBuilding.Rotate();
        }
    }

    public void OnEvent<T>(EVENT_TYPE eventType, Component Sender, T param = default)
    {
        switch (eventType)
        {
            case EVENT_TYPE.ON_BUILDING_CONFIRMED:
                if (buildActive) currentBuilding.CheckDistance(distance);
                break;
            case EVENT_TYPE.ON_BUILDING_BUILT:
                buildActive = false;
                buildingsBuilt[currentBuildingIdx] = true;
                buildCount++;
                if (buildCount < buildings.Length)
                {
                    Invoke("SetupNewBuild", buildDelay + 1);
                }
                else
                {
                    EventManager.Instance.PostNotification<UnityEngine.Object>(EVENT_TYPE.ON_BUILDING_WON, this);
                }
                break;
            case EVENT_TYPE.ON_BUILDING_DISTANCE_CHANGED:
                distance = (dynamic)param;
                break;
        }
    }

#if UNITY_EDITOR
    private void OnValidate()
    {
        ui.UpdateParam(distance);
    }
#endif
}