Files
SAMKWANG/Assets/Scripts/Branch/Manager/MachineStatusIconManager.cs
2025-10-24 16:11:28 +09:00

270 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using WI;
namespace Samkwang
{
public class MachineStatusIconManager : MonoBehaviour
{
public UI_MachineStatusIcon prefab_MachineStatusIcon;
private OrbitalController controller;
private Building building;
public Machine[] machines;
private List<Machine> matchingMachines = new();
private Dictionary<string, UI_MachineStatusIcon> machineIcons = new();
private Dictionary<UI_MachineStatusIcon, Machine> iconToMachines = new();
public float defaultNameHeight;
public Vector3 originScale;
public Action<Machine, CompleteInfo> onClickIconToMachine;
public Action<string> onClickIcon;
[Range(0.1f, 0.8f)]
public float minScale;
[Range(0.5f, 1.5f)]
public float maxScale;
[Range(0.1f, 2f)]
public float scaleClamp;
private bool isPlaying;
private void Awake()
{
controller = FindAnyObjectByType<OrbitalController>();
prefab_MachineStatusIcon = Resources.Load<UI_MachineStatusIcon>("Prefabs/UI/PRF_UI_MachineStatusIcon");
building = FindAnyObjectByType<Building>();
}
public void Clear()
{
uiElements.Clear();
matchingMachines.Clear();
iconToMachines.Clear();
}
public void SetMachineData(List<CompleteInfo> machineData)
{
Clear();
if (machines.Length <= 0)
{
machines = building.floors.SelectMany(f => f.machines).ToArray();
}
foreach (var data in machineData)
{
var machine = FindMachineWithCode(data.worknm);
if (machine == null)
continue;
if (machineIcons.ContainsKey(data.worknm))
{
machineIcons[data.worknm].SetData(data, machine.machineName);
uiElements.Add(machineIcons[data.worknm].rectTransform);
continue;
}
var machineIcon = Instantiate(prefab_MachineStatusIcon, transform);
machineIcon.SetData(data, machine.machineName);
machineIcon.onClickIcon += OnClickMachineKPI;
machineIcon.name = data.worknm;
machineIcon.gameObject.SetActive(false);
uiElements.Add(machineIcon.rectTransform);
machineIcons.Add(data.worknm, machineIcon);
}
foreach (var machine in machines)
{
if (machineIcons.ContainsKey(machine.machineName))
{
machine.machineStatusIcon = machineIcons[machine.machineName];
matchingMachines.Add(machine);
iconToMachines.Add(machine.machineStatusIcon, machine);
}
}
}
private Machine FindMachineWithCode(string worknm)
{
Machine machine = null;
for (int i = 0; i < machines.Length; i++)
{
if (machines[i].machineName == worknm)
{
machine = machines[i];
break;
}
}
return machine;
}
private void OnClickMachineKPI(UI_MachineStatusIcon machineKPI)
{
machineKPI.transform.SetAsLastSibling();
var currentMachine = iconToMachines[machineKPI];
onClickIconToMachine?.Invoke(currentMachine, machineKPI.data);
onClickIcon?.Invoke("MachineDetailDashboard");
}
public void ActiveIcons()
{
if (isPlaying)
{
isPlaying = false;
}
else
{
isPlaying = true;
}
}
private void Update()
{
GroupOverlappingUIElements();
RangeDetection();
}
public List<RectTransform> uiElements = new List<RectTransform>();
public List<List<RectTransform>> groupedElements = new List<List<RectTransform>>();
void GroupOverlappingUIElements()
{
foreach (var matchingMachine in matchingMachines)
{
var machinePos = matchingMachine.centerPos;
var screenPos = controller.camera.WorldToScreenPoint(new Vector3(machinePos.x, machinePos.y + defaultNameHeight, machinePos.z));
matchingMachine.machineStatusIcon.transform.position = screenPos;
}
groupedElements.Clear();
var uncheckedElements = new List<RectTransform>(uiElements);
while (uncheckedElements.Count > 0)
{
var currentElement = uncheckedElements[0];
uncheckedElements.RemoveAt(0);
var group = new List<RectTransform> { currentElement };
for (int i = uncheckedElements.Count - 1; i >= 0; i--)
{
if (AreRectanglesOverlapping(currentElement, uncheckedElements[i]))
{
group.Add(uncheckedElements[i]);
uncheckedElements.RemoveAt(i);
}
}
groupedElements.Add(group);
}
foreach (var group in groupedElements)
{
var centerPos = GroupCenterCalculate(group);
for (int i = 0; i < group.Count; i++)
{
var kpi = group[i];
var newPos = new Vector3(centerPos.x, centerPos.y + kpi.rect.height * i * kpi.transform.localScale.y, centerPos.z);
kpi.transform.localPosition = newPos;
}
}
}
private bool AreRectanglesOverlapping(RectTransform rectA, RectTransform rectB)
{
if (!rectB.gameObject.activeSelf)
return false;
if (!rectA.gameObject.activeSelf)
return false;
Rect rectAWorld = GetWorldRect(rectA);
Rect rectBWorld = GetWorldRect(rectB);
return rectAWorld.Overlaps(rectBWorld);
}
private static Vector3[] worldCorners = new Vector3[4];
private Rect GetWorldRect(RectTransform rectTransform)
{
rectTransform.GetWorldCorners(worldCorners);
Vector2 min = worldCorners[0];
Vector2 max = worldCorners[2];
return new Rect(min, max - min);
}
private Vector3 GroupCenterCalculate(List<RectTransform> group)
{
var centerPos = Vector3.zero;
group.Sort((a, b) => a.transform.localPosition.y.CompareTo(b.transform.localPosition.y));
foreach (var kpi in group)
{
centerPos += kpi.transform.localPosition;
}
centerPos /= group.Count;
return centerPos;
}
void RangeDetection()
{
var layerMask = LayerMask.GetMask("Camera", "Floor Wall");
float t = Mathf.InverseLerp(controller.option.maxDistance, 0f, controller.option.currentDistance);
float scale = Mathf.Lerp(minScale, maxScale, t);
var newScale = new Vector3(scale, scale, scale);
foreach (var machine in matchingMachines)
{
MachineKPIsActive(machine, layerMask);
var machineKPI = machine.machineStatusIcon;
machineKPI.transform.localScale = newScale;
}
}
bool IsScreenRange(Machine machine)
{
Vector3 viewPos = controller.camera.WorldToViewportPoint(machine.centerPos);
if (viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0)
{
return true;
}
return false;
}
void MachineKPIsActive(Machine machine, LayerMask layerMask)
{
var dir = (controller.camera.transform.position - machine.centerPos).normalized;
var radius = 1f;
var ray = new Ray(machine.centerPos, dir);
if (isPlaying)
{
machine.machineStatusIcon.Deactive();
}
else
{
if (Physics.SphereCast(ray, radius, out RaycastHit hit, Mathf.Infinity, layerMask))
{
var hitCameraLayer = hit.collider.gameObject.layer.Equals(LayerMask.NameToLayer("Camera"));
if (hitCameraLayer)
{
if (!IsScreenRange(machine))
{
machine.machineStatusIcon.Deactive();
}
else
{
machine.machineStatusIcon.Active();
}
}
else
{
machine.machineStatusIcon.Deactive();
}
}
}
}
}
}