[정영민] 설비 겹침 정렬 기능 수정

26.03.11
설비 겹침 기능 수정
This commit is contained in:
정영민
2026-03-11 16:52:24 +09:00
parent e4b3a91321
commit 6f1c335c73
22 changed files with 620 additions and 270 deletions

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"recommendations": [
"visualstudiotoolsforunity.vstuc"
]
}

10
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Unity",
"type": "vstuc",
"request": "attach"
}
]
}

71
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,71 @@
{
"files.exclude": {
"**/.DS_Store": true,
"**/.git": true,
"**/.vs": true,
"**/.gitmodules": true,
"**/.vsconfig": true,
"**/*.booproj": true,
"**/*.pidb": true,
"**/*.suo": true,
"**/*.user": true,
"**/*.userprefs": true,
"**/*.unityproj": true,
"**/*.dll": true,
"**/*.exe": true,
"**/*.pdf": true,
"**/*.mid": true,
"**/*.midi": true,
"**/*.wav": true,
"**/*.gif": true,
"**/*.ico": true,
"**/*.jpg": true,
"**/*.jpeg": true,
"**/*.png": true,
"**/*.psd": true,
"**/*.tga": true,
"**/*.tif": true,
"**/*.tiff": true,
"**/*.3ds": true,
"**/*.3DS": true,
"**/*.fbx": true,
"**/*.FBX": true,
"**/*.lxo": true,
"**/*.LXO": true,
"**/*.ma": true,
"**/*.MA": true,
"**/*.obj": true,
"**/*.OBJ": true,
"**/*.asset": true,
"**/*.cubemap": true,
"**/*.flare": true,
"**/*.mat": true,
"**/*.meta": true,
"**/*.prefab": true,
"**/*.unity": true,
"build/": true,
"Build/": true,
"Library/": true,
"library/": true,
"obj/": true,
"Obj/": true,
"Logs/": true,
"logs/": true,
"ProjectSettings/": true,
"UserSettings/": true,
"temp/": true,
"Temp/": true
},
"files.associations": {
"*.asset": "yaml",
"*.meta": "yaml",
"*.prefab": "yaml",
"*.unity": "yaml",
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.sln": "*.csproj",
"*.slnx": "*.csproj"
},
"dotnet.defaultSolution": "AZTECH_WB.slnx"
}

15
AZTECH_WB.slnx Normal file
View File

@@ -0,0 +1,15 @@
<Solution>
<Project Path="Assembly-CSharp.csproj" />
<Project Path="com.Tivadar.Best.HTTP.csproj" />
<Project Path="RenderHeads.AVProMovieCapture.Demos.csproj" />
<Project Path="com.Tivadar.Best.MQTT.csproj" />
<Project Path="RenderHeads.AVProMovieCapture.Runtime.csproj" />
<Project Path="RenderHeads.AVProMovieCapture.Editor.csproj" />
<Project Path="Assembly-CSharp-firstpass.csproj" />
<Project Path="GLTFExporter.Runtime.csproj" />
<Project Path="com.Tivadar.Best.WebSockets.csproj" />
<Project Path="Assembly-CSharp-Editor.csproj" />
<Project Path="SimpleFileBrowser.Runtime.csproj" />
<Project Path="Assembly-CSharp-Editor-firstpass.csproj" />
<Project Path="com.Tivadar.Best.HTTP.Profiler.Editor.csproj" />
</Solution>

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,117 @@
fileFormatVersion: 2
guid: e9074fab59981e24ea177f1361c7dd5f
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,117 @@
fileFormatVersion: 2
guid: 9458e5537061e7945a771b442a1d3413
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -496,15 +496,17 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
isInit: 0
machineStatusItem: {fileID: 0}
machines: []
defaultNameHeight: 1.5
originScale: {x: 1, y: 1, z: 1}
activeIconEnable: 0
minScale: 0.6
maxScale: 1.2
scaleClamp: 1
uiElements: []
worldOffset: {x: 0, y: 1.5, z: 0}
verticalPadding: 0
overlapThreshold: 2
smoothSpeed: 50
occlusionLayer:
serializedVersion: 2
m_Bits: 0
occlusionCheckInterval: 0.1
minScale: 1.2
maxScale: 1.4
scaleSmoothing: 5
--- !u!114 &69824778
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -175,7 +175,7 @@ namespace AZTECHWB
var moveVector = camera.transform.TransformDirection(x, y, -z);
moveVector.y = 0;
//0.5 값은 카메라 속도 보정값
//0.5 媛믪?? 移대찓?씪 ?냽?룄 蹂댁젙媛?
moveVector *= (moveSpeed * 0.5f) * (currentDistance / maxDistance);
nextPosition = cameraPivot.transform.position - moveVector;
}
@@ -303,10 +303,5 @@ namespace AZTECHWB
break;
}
}
internal void SetControllOptionValue()
{
throw new NotImplementedException();
}
}
}

View File

@@ -15,6 +15,9 @@ namespace AZTECHWB.Command
var raycaster = AZTECHSceneMain.Instance.GetManager<Raycaster>();
raycaster.SetInteractable(false);
//var building = AZTECHSceneMain.Instance.building;
//building.ActiveRoof(true);
var machineStatusItemManager = AZTECHSceneMain.Instance.GetManager<MachineStatusItemManager>();
machineStatusItemManager.SetActiveIcons(false);
machineStatusItemManager.SetInteractableIcons(true);

View File

@@ -105,7 +105,7 @@ namespace AZTECHWB.Management
machines = building.floors.SelectMany(f => f.machines).ToArray();
foreach (var info in standardInfos)
{
var p = machines.Where(x => x.machineName.Equals(info.code)).FirstOrDefault();
var p = machines.FirstOrDefault(x => x.machineName.Equals(info.code));
if (p == null)
continue;
p.typeOptions = info.filterInfo;

View File

@@ -1,7 +1,7 @@
using AZTECHWB.Command;
using AZTECHWB.Constants;
using AZTECHWB.Core;
using Cysharp.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -10,111 +10,50 @@ namespace AZTECHWB.Management
{
public class MachineStatusItemManager : Manager
{
public MachineStatusItem machineStatusItem;
[Header("References")]
private MachineStatusItem machineStatusItem;
private OrbitalController controller;
private Building building;
public Machine[] machines;
private List<Machine> matchingMachines = new();
[Header("Position Settings")]
public Vector3 worldOffset = new Vector3(0, 1.5f, 0);
public float verticalPadding = 5f;
public float overlapThreshold = 2f;
public float smoothSpeed = 10f;
[Header("Visibility Settings")]
public LayerMask occlusionLayer;
public float occlusionCheckInterval = 0.1f;
private Dictionary<MachineStatusItem, Vector2> smoothedPositions = new Dictionary<MachineStatusItem, Vector2>();
private float occlusionTimer;
[Header("Scale Settings")]
public float minScale = 0.5f; // 가장 멀 때 크기
public float maxScale = 1.2f; // 가장 가까울 때 크기
public float scaleSmoothing = 5f; // 스케일 변화 스무딩 속도
private float maxDistance = 50f; // 스케일 계산 기준 최대 거리
private Dictionary<MachineStatusItem, float> smoothedScales = new Dictionary<MachineStatusItem, float>();
private Dictionary<string, MachineStatusItem> machineIcons = new();
private Dictionary<MachineStatusItem, Machine> iconToMachines = new();
public float defaultNameHeight;
public Vector3 originScale;
public bool activeIconEnable;
[Range(0.1f, 0.8f)]
public float minScale;
[Range(0.5f, 1.5f)]
public float maxScale;
[Range(0.1f, 2f)]
public float scaleClamp;
private OrbitalController controller;
private Machine[] machines;
private bool activeIconEnable;
public override async UniTask Init()
{
controller = FindAnyObjectByType<OrbitalController>();
machineStatusItem = Resources.Load<MachineStatusItem>($"{ResourceURL.uiPrefabFolderPath}{nameof(MachineStatusItem)}");
building = FindAnyObjectByType<Building>();
controller = AZTECHAppMain.Instance.cameraController;
machines = AZTECHSceneMain.Instance.building.floors.SelectMany(f => f.machines).ToArray();
maxDistance = controller.maxDistance;
await UniTask.CompletedTask;
}
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(machineStatusItem, transform);
machineIcon.Init(data.worknm);
machineIcon.SetData(data, machine.machineName);
machineIcon.onClickIcon += OnClickMachineKPI;
machineIcon.gameObject.SetActive(false);
uiElements.Add(machineIcon.rectTransform);
machineIcons.Add(data.worknm, machineIcon);
}
foreach (var machine in machines)
{
if (machineIcons.ContainsKey(machine.machineName))
{
machine.machineStatusItem = machineIcons[machine.machineName];
matchingMachines.Add(machine);
iconToMachines.Add(machine.machineStatusItem, 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(MachineStatusItem machineKPI)
{
machineKPI.transform.SetAsLastSibling();
var currentMachine = iconToMachines[machineKPI];
new OpenMachineDetailDashboardPanelCommand(currentMachine, machineKPI.data).Execute();
}
public void SetInteractableIcons(bool isActive)
{
foreach(var machineIcon in machineIcons.Values)
foreach (var machineIcon in machineIcons.Values)
{
machineIcon.isInteractable = isActive;
}
@@ -129,148 +68,232 @@ namespace AZTECHWB.Management
}
}
public void SetMachineData(List<CompleteInfo> machineData)
{
foreach (var data in machineData)
{
var machine = FindMachineWithCode(data.worknm);
if (machine == null)
continue;
if (machineIcons.ContainsKey(data.worknm))
{
machineIcons[data.worknm].SetData(data);
continue;
}
var machineIcon = Instantiate(machineStatusItem, transform);
machineIcon.Init(machine);
machineIcon.SetData(data);
machineIcon.onClickIcon += OnClickMachineKPI;
machineIcons.Add(data.worknm, machineIcon);
machineIcon.gameObject.SetActive(false);
machine.machineStatusItem = machineIcon;
iconToMachines.Add(machineIcon, machine);
}
}
private void OnClickMachineKPI(MachineStatusItem machineKPI)
{
machineKPI.transform.SetAsLastSibling();
var currentMachine = iconToMachines[machineKPI];
new OpenMachineDetailDashboardPanelCommand(currentMachine, machineKPI.data).Execute();
}
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 LateUpdate()
{
GroupOverlappingUIElements();
RangeDetection();
if (machineIcons.Values.Count == 0 || controller.Camera == null)
return;
List<MachineStatusItem> allLabels = new List<MachineStatusItem>(machineIcons.Values);
// 1단계: 전체 라벨 스크린 위치 & 거리 계산
UpdateScreenData(allLabels);
// 2단계: 활성화 여부 판정 (화면 이탈 + 가려짐)
occlusionTimer += Time.deltaTime;
if (occlusionTimer >= occlusionCheckInterval)
{
UpdateVisibility(allLabels);
occlusionTimer = 0f;
}
// 3단계: 활성화된 라벨만 카메라 거리순 정렬
List<MachineStatusItem> visibleLabels = allLabels.FindAll(l => l.gameObject.activeSelf);
visibleLabels.Sort((a, b) => a.distanceToCamera.CompareTo(b.distanceToCamera));
// 4단계: 거리에 따른 UI 크기 조정
UpdateScales(visibleLabels);
// 5단계: 겹침 해소 → 목표 위치 계산
Dictionary<MachineStatusItem, Vector2> targetPositions = ResolveOverlaps(visibleLabels);
// 6단계: 스무딩 적용 후 RectTransform에 반영
ApplyPositions(targetPositions);
}
public List<RectTransform> uiElements = new List<RectTransform>();
public List<List<RectTransform>> groupedElements = new List<List<RectTransform>>();
void GroupOverlappingUIElements()
void UpdateScreenData(List<MachineStatusItem> labels)
{
foreach (var matchingMachine in matchingMachines)
foreach (var label in labels)
{
var machinePos = matchingMachine.centerPos;
var screenPos = controller.Camera.WorldToScreenPoint(new Vector3(machinePos.x, machinePos.y + defaultNameHeight, machinePos.z));
if (label.targetTransform == null) continue;
matchingMachine.machineStatusItem.transform.position = screenPos;
}
groupedElements.Clear();
var uncheckedElements = new List<RectTransform>(uiElements);
Vector3 worldPos = label.targetTransform.position + worldOffset;
Vector3 screenPos = controller.Camera.WorldToScreenPoint(worldPos);
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;
}
label.screenPosition = new Vector2(screenPos.x, screenPos.y);
label.distanceToCamera = Vector3.Distance(controller.Camera.transform.position, label.targetTransform.position);
}
}
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.maxDistance, 0f, controller.currentDistance);
float scale = Mathf.Lerp(minScale, maxScale, t);
var newScale = new Vector3(scale, scale, scale);
float expandScale = Mathf.Lerp(1.6f, 1f, t);
var newExpandScale = new Vector3(expandScale, expandScale, expandScale);
foreach (var machine in matchingMachines)
{
MachineKPIsActive(machine, layerMask);
var machineKPI = machine.machineStatusItem;
machineKPI.transform.localScale = newScale;
machineKPI.Expand_KPI.transform.localScale = newExpandScale;
}
}
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)
void UpdateVisibility(List<MachineStatusItem> labels)
{
if (!activeIconEnable) return;
var dir = (controller.Camera.transform.position - machine.centerPos).normalized;
var radius = 1f;
var ray = new Ray(machine.centerPos, dir);
if (Physics.SphereCast(ray, radius, out RaycastHit hit, Mathf.Infinity, layerMask))
foreach (var label in labels)
{
var hitCameraLayer = hit.collider.gameObject.layer.Equals(LayerMask.NameToLayer("Camera"));
// 카메라 뒤쪽 체크
Vector3 screenPos = controller.Camera.WorldToScreenPoint(label.targetTransform.position + worldOffset);
if (screenPos.z < 0)
{
label.gameObject.SetActive(false);
continue;
}
if (hitCameraLayer)
// 화면 이탈 체크
if (!IsOnScreen(label.screenPosition))
{
if (!IsScreenRange(machine))
{
machine.machineStatusItem.Deactive();
}
else
{
machine.machineStatusItem.Active();
}
label.gameObject.SetActive(false);
continue;
}
else
// 특정 레이어에 가려짐 체크
if (IsOccluded(label.targetTransform.position))
{
machine.machineStatusItem.Deactive();
label.gameObject.SetActive(false);
continue;
}
label.gameObject.SetActive(true);
}
}
bool IsOnScreen(Vector2 screenPos)
{
return screenPos.x >= 0 && screenPos.x <= Screen.width && screenPos.y >= 0 && screenPos.y <= Screen.height;
}
bool IsOccluded(Vector3 targetWorldPos)
{
Vector3 camPos = controller.Camera.transform.position;
Vector3 direction = targetWorldPos - camPos;
float distance = direction.magnitude;
return Physics.Raycast(camPos, direction.normalized, distance - 0.1f, occlusionLayer);
}
Dictionary<MachineStatusItem, Vector2> ResolveOverlaps(List<MachineStatusItem> visibleLabels)
{
Dictionary<MachineStatusItem, Vector2> targetPositions = new Dictionary<MachineStatusItem, Vector2>();
List<Rect> placedRects = new List<Rect>();
foreach (var label in visibleLabels)
{
Vector2 size = label.GetSize();
Vector2 targetPos = label.screenPosition;
bool overlapping = true;
int maxIterations = 20;
while (overlapping && maxIterations-- > 0)
{
overlapping = false;
Rect currentRect = GetRect(targetPos, size);
foreach (Rect placed in placedRects)
{
if (IsOverlapping(currentRect, placed))
{
// X는 겹친 라벨의 X로 고정, Y만 위로 밀어올림
targetPos.x = placed.center.x;
targetPos.y = placed.yMax + verticalPadding + size.y * 0.5f;
overlapping = true;
break;
}
}
}
targetPositions[label] = targetPos;
placedRects.Add(GetRect(targetPos, size));
}
return targetPositions;
}
void ApplyPositions(Dictionary<MachineStatusItem, Vector2> targetPositions)
{
foreach (var kvp in targetPositions)
{
MachineStatusItem label = kvp.Key;
Vector2 target = kvp.Value;
if (!smoothedPositions.ContainsKey(label))
smoothedPositions[label] = target;
smoothedPositions[label] = Vector2.Lerp(smoothedPositions[label],target,Time.deltaTime * smoothSpeed);
// Manager가 직접 RectTransform 조작
label.rectTransform.position = new Vector3(smoothedPositions[label].x, smoothedPositions[label].y, 0);
}
}
void UpdateScales(List<MachineStatusItem> visibleLabels)
{
foreach (var label in visibleLabels)
{
// 거리 비율 → 목표 스케일 계산 (원본과 동일한 방식)
float t = Mathf.InverseLerp(maxDistance, 0f, label.distanceToCamera);
float targetScale = Mathf.Lerp(minScale, maxScale, t);
// 스무딩 초기값 설정
if (!smoothedScales.ContainsKey(label))
smoothedScales[label] = targetScale;
// Lerp로 부드럽게 스케일 변화
smoothedScales[label] = Mathf.Lerp(
smoothedScales[label],
targetScale,
Time.deltaTime * scaleSmoothing
);
label.transform.localScale = Vector3.one * smoothedScales[label];
}
}
Rect GetRect(Vector2 centerPos, Vector2 size)
{
return new Rect(centerPos.x - size.x * 0.5f, centerPos.y - size.y * 0.5f, size.x, size.y);
}
bool IsOverlapping(Rect a, Rect b)
{
return a.xMin < b.xMax - overlapThreshold && a.xMax > b.xMin + overlapThreshold &&
a.yMin < b.yMax - overlapThreshold && a.yMax > b.yMin + overlapThreshold;
}
}
}

View File

@@ -62,7 +62,7 @@ namespace AZTECHWB.UI
{
var building = AZTECHSceneMain.Instance.building;
var machines = building.floors.SelectMany(f => f.machines);
var selectedMachine = machines.Where(m => m.machineName == alarmInfo.completeInfo.worknm).FirstOrDefault();
var selectedMachine = machines.FirstOrDefault(m => m.machineName == alarmInfo.completeInfo.worknm);
new SelectedMachineCommand(selectedMachine, false).Execute();
}

View File

@@ -12,7 +12,6 @@ namespace AZTECHWB.UI
public Button Button_Close;
private LayerPanel layerPanel;
public Action<bool> isClickUI;
public override async UniTask Init()
{
@@ -32,13 +31,11 @@ namespace AZTECHWB.UI
gameObject.SetActive(true);
layerPanel.Open();
gameObject.transform.SetAsLastSibling();
isClickUI?.Invoke(true);
}
public override void Close()
{
layerPanel.Close();
gameObject.SetActive(false);
isClickUI?.Invoke(false);
}
private void OnClickExitButton()
{

View File

@@ -99,6 +99,16 @@ namespace AZTECHWB.UI
null,
"설비 요약 정보 UI를 활성화/비활성화 합니다.");
toolbarModel.AddToggleButton("button_floor_control", true,
"Prefabs/UI/Toolbar/images/ic_floor_active",
"Prefabs/UI/Toolbar/images/ic_floor_deactive",
(isSelected) =>
{
//AZTECHSceneMain.Instance.building.ActiveRoof(isSelected);
},
null,
"설비가 없는 층을 활성화/비활성화 합니다.");
// --- 툴바 모델 구성 끝 ---
toolbar.SetData(toolbarModel);
toolbar.Initialize();

View File

@@ -14,9 +14,6 @@ namespace AZTECHWB.UI
private TextMeshProUGUI Text_Selected;
private TextMeshProUGUI Text_Deselected;
public Color selectColor;
public Color origingColor;
public void SettingButton(string labelName)
{
transform.TryGetComponentInChildren(nameof(Text_Selected), out Text_Selected);
@@ -24,8 +21,6 @@ namespace AZTECHWB.UI
var button = transform.GetComponentInChildren<Button>();
button.onClick.AddListener(OnClickButton);
origingColor = button.image.color;
}
private void OnClickButton()

View File

@@ -14,8 +14,6 @@ namespace AZTECHWB
{
public RectTransform rectTransform;
public CompleteInfo data;
private List<CompleteInfo> alarmInfos = new();
public RectTransform Default_KPI;
public RectTransform Expand_KPI;
@@ -38,12 +36,17 @@ namespace AZTECHWB
public bool isInteractable;
public bool isExpand;
[HideInInspector] public Transform targetTransform;
[HideInInspector] public Vector2 screenPosition;
[HideInInspector] public float distanceToCamera;
public Action<MachineStatusItem> onClickIcon;
public void Init(string itemName)
public void Init(Machine machine)
{
isInteractable = true;
gameObject.name = itemName;
gameObject.name = machine.machineName;
targetTransform = machine.transform;
rectTransform = GetComponent<RectTransform>();
transform.TryGetComponentInChildren(nameof(Default_KPI), out Default_KPI);
@@ -57,29 +60,25 @@ namespace AZTECHWB
transform.TryGetComponentInChildren(nameof(Default_Alarm), out Default_Alarm);
transform.TryGetComponentInChildren(nameof(Expand_Alarm), out Expand_Alarm);
//eorate
transform.TryGetComponentInChildren(nameof(pvp), out pvp);
transform.TryGetComponentInChildren(nameof(workcd), out workcd);
//porate
transform.TryGetComponentInChildren(nameof(goodqtyrate), out goodqtyrate);
transform.TryGetComponentInChildren(nameof(workdt), out workdt);
transform.TryGetComponentInChildren(nameof(wordno), out wordno);
}
public void SetData(CompleteInfo data, string machineName)
public void SetData(CompleteInfo data)
{
this.data = data;
//eorate.SetText(PercentCalculate(data.eorate).ToString() + "%");
pvp.SetText(PercentCalculate(data.pvp).ToString() + "%");
workcd.SetText(SetTextData(data.workcd));
goodqtyrate.SetText(DecimalPointPercentCalculate(data.goodqtyrate).ToString() + "%");
//porate.SetText(PercentCalculate(data.porate).ToString() + "%");
workdt.SetText(CorrectionTime(data.workdt, "yyyy-MM-dd"));
wordno.SetText(SetTextData(data.wordno));
DefaultMachineName.SetText(SetNameData(data.worknm, machineName));
ExpandMachineName.SetText(SetNameData(data.worknm, machineName));
DefaultMachineName.SetText(SetNameData(data.worknm));
ExpandMachineName.SetText(SetNameData(data.worknm));
Default_Status.color = SetStatusColor(data.statusnm);
Expand_Status.color = SetStatusColor(data.statusnm);
@@ -87,27 +86,11 @@ namespace AZTECHWB
DefaultMachineName.color = SetStatusColor(data.statusnm) == Color.gray ? Color.gray : DefaultMachineName.color;
ExpandMachineName.color = SetStatusColor(data.statusnm) == Color.gray ? Color.gray : ExpandMachineName.color;
}
//public void SetAlarmData(List<CompleteInfo> alarmInfos)
//{
// if (alarmInfos != null || alarmInfos.Count != 0)
// {
// this.alarmInfos = alarmInfos;
// var isAlarm = alarmInfos.Any(a => a.state.Trim().Equals("SET", StringComparison.OrdinalIgnoreCase));
// Default_Alarm.gameObject.SetActive(isAlarm);
// Expand_Alarm.gameObject.SetActive(isAlarm);
// }
// else
// {
// Default_Alarm.gameObject.SetActive(false);
// Expand_Alarm.gameObject.SetActive(false);
// }
//}
private string SetNameData(string value, string machineName)
private string SetNameData(string value)
{
if (!CheckDataExists(value))
{
return machineName;
return gameObject.name;
}
return value;
}
@@ -224,6 +207,13 @@ namespace AZTECHWB
isExpand = false;
}
}
public Vector2 GetSize()
{
Vector2 baseSize = rectTransform.sizeDelta;
float scale = transform.localScale.x; // UpdateScales에서 적용한 스케일
return baseSize * scale;
}
}
}

View File

@@ -54,7 +54,7 @@ MonoBehaviour:
m_ReflectionProbeBlending: 1
m_ReflectionProbeBoxProjection: 1
m_ReflectionProbeAtlas: 1
m_ShadowDistance: 50
m_ShadowDistance: 0
m_ShadowCascadeCount: 4
m_Cascade2Split: 0.25
m_Cascade3Split: {x: 0.1, y: 0.3}

View File

@@ -2,7 +2,7 @@
Resolution=1600x900
ScreenMode=0
Texture=0
Shadow=1
Shadow=0
AA=2
VSync=1
AF=0

View File

@@ -4,7 +4,7 @@
"com.unity.2d.sprite": "1.0.0",
"com.unity.ai.navigation": "2.0.9",
"com.unity.cloud.gltfast": "6.16.0",
"com.unity.collab-proxy": "2.10.1",
"com.unity.collab-proxy": "2.10.2",
"com.unity.ide.rider": "3.0.38",
"com.unity.ide.visualstudio": "2.0.25",
"com.unity.inputsystem": "1.14.2",

View File

@@ -73,7 +73,7 @@
"url": "https://packages.unity.com"
},
"com.unity.collab-proxy": {
"version": "2.10.1",
"version": "2.10.2",
"depth": 0,
"source": "registry",
"dependencies": {},