Files
Fruitomation/Assets/Scripts/Game/Buildings/BuildingManager.cs
2026-04-27 19:17:07 +01:00

193 lines
6.4 KiB
C#

using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine.Scripting;
using UnityEngine;
using System.Linq;
using System.IO;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif // UNITY_EDITOR
namespace Fruitomation.Game
{
public class BuildingManager : MonoBehaviour
{
[SerializeField] private BuildingRegistry Registry;
private class BuildingInfo
{
public BuildingInfo(Building b, RectTransform rt)
{
Building = b;
Rect = rt;
}
public Building Building { get; }
public RectTransform Rect { get; }
}
[Serializable] private class SerializedBuilding
{
[SerializeField, Preserve, UsedImplicitly] public Vector2Int GridPosition;
[SerializeField, Preserve, UsedImplicitly] public Vector2Int Position;
[SerializeField, Preserve, UsedImplicitly] public string PrefabName;
[SerializeField, Preserve, UsedImplicitly] public bool IsFlipped;
public SerializedBuilding(Vector2Int gridPosition, Vector2Int pos, string name, bool flipped)
{
GridPosition = gridPosition;
IsFlipped = flipped;
PrefabName = name;
Position = pos;
}
}
[Serializable] private class SerializedBuildings
{
[SerializeField, Preserve, UsedImplicitly] private SerializedBuilding[] Buildings;
public SerializedBuilding[] Get() => Buildings;
public SerializedBuildings(List<SerializedBuilding> buildings) =>
Buildings = buildings.ToArray();
}
private static string Filepath => Path.Combine(Application.persistentDataPath, "buildings.json");
private bool[,] InhabitedCells { get; } = new bool[96, 49];
private List<Building> Buildings { get; } = new();
#if UNITY_EDITOR
private static BuildingManager Instance;
private void Awake() => Instance = this;
[MenuItem("Fruitomation/Clear Buildings")]
public static void ClearBuildings()
{
foreach (Building b in Instance.Buildings)
{
Destroy(b.gameObject);
}
Instance.Buildings.Clear();
}
#endif // UNITY_EDITOR
private void Start()
{
if (!File.Exists(Filepath))
{
return;
}
string json = File.ReadAllText(Filepath);
SerializedBuilding[] buildings = JsonUtility.FromJson<SerializedBuildings>(json).Get();
foreach (SerializedBuilding building in buildings)
{
GameObject prefab = Registry.GetBuildingOf(building.PrefabName);
GameObject go = Instantiate(prefab, transform);
BuildingInfo info = new
(
go.GetComponent<Building>(),
go.GetComponent<RectTransform>()
);
info.Rect.transform.localScale = new Vector3(building.IsFlipped ? -1f : 1f, 1f, 1f);
info.Rect.sizeDelta = info.Building.SizeOnGrid * 40;
info.Rect.anchoredPosition = building.Position;
go.name = $"{building.PrefabName}";
info.Building.Init(this, building.GridPosition, building.Position, building.IsFlipped);
Buildings.Add(info.Building);
for (int x = building.GridPosition.x; x < building.GridPosition.x + info.Building.SizeOnGrid.x; x++)
for (int y = building.GridPosition.y; y < building.GridPosition.y + info.Building.SizeOnGrid.y; y++)
{
InhabitedCells[x, y] = true;
}
}
}
private void OnDestroy()
{
Debug.Log($"Buildings: [{Buildings.Count}]");
List<SerializedBuilding> serialized = Buildings.Select(building => new SerializedBuilding
(
building.GridPosition,
building.Position,
building.name,
building.IsFlipped
)
).ToList();
string json = JsonUtility.ToJson(new SerializedBuildings(serialized), true);
File.WriteAllText(Filepath, json);
}
public void RemoveBuilding(Building building)
{
Buildings.Remove(building);
for (int x = building.GridPosition.x; x < building.GridPosition.x + building.SizeOnGrid.x; x++)
for (int y = building.GridPosition.y; y < building.GridPosition.y + building.SizeOnGrid.y; y++)
{
InhabitedCells[x, y] = false;
}
}
public bool AddBuildingAt(Vector2Int position, BuildingRegistry.BuildingInfo building, bool isFlipped)
{
//
GameObject go = Instantiate(building.Prefab, transform);
BuildingInfo info = new
(
go.GetComponent<Building>(),
go.GetComponent<RectTransform>()
);
go.name = $"{building.Name}";
Vector2Int p0 = position * 40;
Vector2Int p1 = p0 + new Vector2Int(20, 100);
Vector2Int g0 = position + new Vector2Int(48, 24);
Vector2Int off0 = info.Building.SizeOnGrid - Vector2Int.one;
Vector2Int off1 = off0 * 20;
Vector2Int p2 = p1 + off1;
info.Rect.sizeDelta = info.Building.SizeOnGrid * 40;
info.Rect.anchoredPosition = p2;
info.Rect.transform.localScale = new Vector3(isFlipped ? -1f : 1f, 1f, 1f);
//
for (int x = g0.x; x < g0.x + info.Building.SizeOnGrid.x; x++)
for (int y = g0.y; y < g0.y + info.Building.SizeOnGrid.y; y++)
{
if (InhabitedCells[x, y])
{
DestroyImmediate(go);
return false;
}
}
//
for (int x = g0.x; x < g0.x + info.Building.SizeOnGrid.x; x++)
for (int y = g0.y; y < g0.y + info.Building.SizeOnGrid.y; y++)
{
InhabitedCells[x, y] = true;
}
info.Building.Init(this, g0, p2, isFlipped);
Buildings.Add(info.Building);
return true;
}
}
}