270 lines
9.0 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |