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 }