cameraController 기능 개선
This commit is contained in:
8
Assets/Resources/Prefabs/UI/Factory.meta
Normal file
8
Assets/Resources/Prefabs/UI/Factory.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 89c2e61af66edfc418938381caf7673f
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -92,8 +92,8 @@ MonoBehaviour:
|
|||||||
m_faceColor:
|
m_faceColor:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
rgba: 4294967295
|
rgba: 4294967295
|
||||||
m_fontSize: 36
|
m_fontSize: 12
|
||||||
m_fontSizeBase: 36
|
m_fontSizeBase: 12
|
||||||
m_fontWeight: 400
|
m_fontWeight: 400
|
||||||
m_enableAutoSizing: 0
|
m_enableAutoSizing: 0
|
||||||
m_fontSizeMin: 18
|
m_fontSizeMin: 18
|
||||||
@@ -163,13 +163,16 @@ RectTransform:
|
|||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children:
|
||||||
|
- {fileID: 7131291007070285513}
|
||||||
|
- {fileID: 5271924166542973796}
|
||||||
|
- {fileID: 3646766325915033839}
|
||||||
m_Father: {fileID: 2463437008278947656}
|
m_Father: {fileID: 2463437008278947656}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
m_AnchoredPosition: {x: 0, y: -20}
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
m_SizeDelta: {x: 20, y: 60}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1 &1828762385695490929
|
--- !u!1 &1828762385695490929
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -226,6 +229,292 @@ MonoBehaviour:
|
|||||||
alarmCountText: {fileID: 8650239058674280921}
|
alarmCountText: {fileID: 8650239058674280921}
|
||||||
expandedView: {fileID: 952545100964675415}
|
expandedView: {fileID: 952545100964675415}
|
||||||
singleAlarmIconPrefab: {fileID: 7314511769243682470, guid: e9acc8c9a93a2b5409fc01661660b217, type: 3}
|
singleAlarmIconPrefab: {fileID: 7314511769243682470, guid: e9acc8c9a93a2b5409fc01661660b217, type: 3}
|
||||||
|
--- !u!1 &1960784422133791095
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3646766325915033839}
|
||||||
|
- component: {fileID: 4629718865595954553}
|
||||||
|
- component: {fileID: 353088631153534614}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Text (TMP) (1)
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &3646766325915033839
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1960784422133791095}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 8574585598928791195}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: -20, y: -20}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &4629718865595954553
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1960784422133791095}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &353088631153534614
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1960784422133791095}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_text:
|
||||||
|
m_isRightToLeft: 0
|
||||||
|
m_fontAsset: {fileID: 11400000, guid: 08cebd004d97ca742ac80400f37f4eed, type: 2}
|
||||||
|
m_sharedMaterial: {fileID: 4860575619018115804, guid: 08cebd004d97ca742ac80400f37f4eed, type: 2}
|
||||||
|
m_fontSharedMaterials: []
|
||||||
|
m_fontMaterial: {fileID: 0}
|
||||||
|
m_fontMaterials: []
|
||||||
|
m_fontColor32:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 4278190080
|
||||||
|
m_fontColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
m_enableVertexGradient: 0
|
||||||
|
m_colorMode: 3
|
||||||
|
m_fontColorGradient:
|
||||||
|
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_fontColorGradientPreset: {fileID: 0}
|
||||||
|
m_spriteAsset: {fileID: 0}
|
||||||
|
m_tintAllSprites: 0
|
||||||
|
m_StyleSheet: {fileID: 0}
|
||||||
|
m_TextStyleHashCode: -1183493901
|
||||||
|
m_overrideHtmlColors: 0
|
||||||
|
m_faceColor:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 4294967295
|
||||||
|
m_fontSize: 12
|
||||||
|
m_fontSizeBase: 12
|
||||||
|
m_fontWeight: 400
|
||||||
|
m_enableAutoSizing: 0
|
||||||
|
m_fontSizeMin: 18
|
||||||
|
m_fontSizeMax: 72
|
||||||
|
m_fontStyle: 0
|
||||||
|
m_HorizontalAlignment: 1
|
||||||
|
m_VerticalAlignment: 256
|
||||||
|
m_textAlignment: 65535
|
||||||
|
m_characterSpacing: 0
|
||||||
|
m_wordSpacing: 0
|
||||||
|
m_lineSpacing: 0
|
||||||
|
m_lineSpacingMax: 0
|
||||||
|
m_paragraphSpacing: 0
|
||||||
|
m_charWidthMaxAdj: 0
|
||||||
|
m_TextWrappingMode: 1
|
||||||
|
m_wordWrappingRatios: 0.4
|
||||||
|
m_overflowMode: 0
|
||||||
|
m_linkedTextComponent: {fileID: 0}
|
||||||
|
parentLinkedComponent: {fileID: 0}
|
||||||
|
m_enableKerning: 0
|
||||||
|
m_ActiveFontFeatures: 6e72656b
|
||||||
|
m_enableExtraPadding: 0
|
||||||
|
checkPaddingRequired: 0
|
||||||
|
m_isRichText: 1
|
||||||
|
m_EmojiFallbackSupport: 1
|
||||||
|
m_parseCtrlCharacters: 1
|
||||||
|
m_isOrthographic: 1
|
||||||
|
m_isCullingEnabled: 0
|
||||||
|
m_horizontalMapping: 0
|
||||||
|
m_verticalMapping: 0
|
||||||
|
m_uvLineOffset: 0
|
||||||
|
m_geometrySortingOrder: 0
|
||||||
|
m_IsTextObjectScaleStatic: 0
|
||||||
|
m_VertexBufferAutoSizeReduction: 0
|
||||||
|
m_useMaxVisibleDescender: 1
|
||||||
|
m_pageToDisplay: 1
|
||||||
|
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_isUsingLegacyAnimationComponent: 0
|
||||||
|
m_isVolumetricText: 0
|
||||||
|
m_hasFontAssetChanged: 0
|
||||||
|
m_baseMaterial: {fileID: 0}
|
||||||
|
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
--- !u!1 &3143968334505601971
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 7131291007070285513}
|
||||||
|
- component: {fileID: 7326861565818029875}
|
||||||
|
- component: {fileID: 927238525312826162}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: shadow
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &7131291007070285513
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3143968334505601971}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 8574585598928791195}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 5, y: -5}
|
||||||
|
m_SizeDelta: {x: 10, y: 10}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &7326861565818029875
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3143968334505601971}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &927238525312826162
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3143968334505601971}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||||
|
m_Type: 1
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!1 &4577807398885837071
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 5271924166542973796}
|
||||||
|
- component: {fileID: 9155506323335068705}
|
||||||
|
- component: {fileID: 4147791058937629139}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: bg
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &5271924166542973796
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4577807398885837071}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 8574585598928791195}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &9155506323335068705
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4577807398885837071}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &4147791058937629139
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4577807398885837071}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 0.5235849, b: 0.5235849, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: -895992892, guid: 73d757b5d1b754245969af12daf01e78, type: 3}
|
||||||
|
m_Type: 1
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
--- !u!1 &4918696741701580718
|
--- !u!1 &4918696741701580718
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -35,7 +35,7 @@ RectTransform:
|
|||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
m_SizeDelta: {x: -20, y: -20}
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!222 &5770335694761070239
|
--- !u!222 &5770335694761070239
|
||||||
CanvasRenderer:
|
CanvasRenderer:
|
||||||
@@ -67,8 +67,8 @@ MonoBehaviour:
|
|||||||
m_Calls: []
|
m_Calls: []
|
||||||
m_text: TR
|
m_text: TR
|
||||||
m_isRightToLeft: 0
|
m_isRightToLeft: 0
|
||||||
m_fontAsset: {fileID: 11400000, guid: 08cebd004d97ca742ac80400f37f4eed, type: 2}
|
m_fontAsset: {fileID: 11400000, guid: 2c77cc500db5adc499bfa50030f7e8c2, type: 2}
|
||||||
m_sharedMaterial: {fileID: 4860575619018115804, guid: 08cebd004d97ca742ac80400f37f4eed, type: 2}
|
m_sharedMaterial: {fileID: -8159279640617175905, guid: 2c77cc500db5adc499bfa50030f7e8c2, type: 2}
|
||||||
m_fontSharedMaterials: []
|
m_fontSharedMaterials: []
|
||||||
m_fontMaterial: {fileID: 0}
|
m_fontMaterial: {fileID: 0}
|
||||||
m_fontMaterials: []
|
m_fontMaterials: []
|
||||||
@@ -92,17 +92,17 @@ MonoBehaviour:
|
|||||||
m_faceColor:
|
m_faceColor:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
rgba: 4294967295
|
rgba: 4294967295
|
||||||
m_fontSize: 12
|
m_fontSize: 9
|
||||||
m_fontSizeBase: 12
|
m_fontSizeBase: 9
|
||||||
m_fontWeight: 400
|
m_fontWeight: 400
|
||||||
m_enableAutoSizing: 0
|
m_enableAutoSizing: 0
|
||||||
m_fontSizeMin: 18
|
m_fontSizeMin: 18
|
||||||
m_fontSizeMax: 72
|
m_fontSizeMax: 72
|
||||||
m_fontStyle: 0
|
m_fontStyle: 1
|
||||||
m_HorizontalAlignment: 1
|
m_HorizontalAlignment: 2
|
||||||
m_VerticalAlignment: 256
|
m_VerticalAlignment: 512
|
||||||
m_textAlignment: 65535
|
m_textAlignment: 65535
|
||||||
m_characterSpacing: 0
|
m_characterSpacing: -15
|
||||||
m_wordSpacing: 0
|
m_wordSpacing: 0
|
||||||
m_lineSpacing: 0
|
m_lineSpacing: 0
|
||||||
m_lineSpacingMax: 0
|
m_lineSpacingMax: 0
|
||||||
@@ -170,8 +170,8 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
m_AnchoredPosition: {x: 5, y: -5}
|
m_AnchoredPosition: {x: 2.5, y: -2.5}
|
||||||
m_SizeDelta: {x: 10, y: 10}
|
m_SizeDelta: {x: 5, y: 5}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!222 &2825211744860677609
|
--- !u!222 &2825211744860677609
|
||||||
CanvasRenderer:
|
CanvasRenderer:
|
||||||
@@ -248,7 +248,7 @@ RectTransform:
|
|||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
m_SizeDelta: {x: 100, y: 150}
|
m_SizeDelta: {x: 20, y: 20}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &5545478218830425297
|
--- !u!114 &5545478218830425297
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
@@ -277,11 +277,11 @@ GameObject:
|
|||||||
serializedVersion: 6
|
serializedVersion: 6
|
||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 330585546}
|
- component: {fileID: 330585546}
|
||||||
|
- component: {fileID: 330585549}
|
||||||
- component: {fileID: 330585545}
|
- component: {fileID: 330585545}
|
||||||
- component: {fileID: 330585544}
|
- component: {fileID: 330585544}
|
||||||
- component: {fileID: 330585547}
|
- component: {fileID: 330585547}
|
||||||
- component: {fileID: 330585548}
|
- component: {fileID: 330585548}
|
||||||
- component: {fileID: 330585549}
|
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Main Camera
|
m_Name: Main Camera
|
||||||
m_TagString: MainCamera
|
m_TagString: MainCamera
|
||||||
@@ -435,10 +435,13 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 61deddb674c074049a9b43fd58f1b355, type: 3}
|
m_Script: {fileID: 11500000, guid: 61deddb674c074049a9b43fd58f1b355, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
panSpeed: 20
|
lowAltitudePanSpeed: 0.5
|
||||||
|
highAltitudePanSpeed: 10
|
||||||
rotationSpeed: 300
|
rotationSpeed: 300
|
||||||
zoomSpeed: 10
|
zoomSpeed: 10
|
||||||
maxPanDelta: 50
|
maxPanDelta: 50
|
||||||
|
minCameraY: 2
|
||||||
|
maxCameraY: 50
|
||||||
--- !u!1 &410087039
|
--- !u!1 &410087039
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -926,51 +929,6 @@ RectTransform:
|
|||||||
m_CorrespondingSourceObject: {fileID: 8849628700159893901, guid: 5a23b2bd2bd04c045878e1a06b3b9aa2, type: 3}
|
m_CorrespondingSourceObject: {fileID: 8849628700159893901, guid: 5a23b2bd2bd04c045878e1a06b3b9aa2, type: 3}
|
||||||
m_PrefabInstance: {fileID: 769109585}
|
m_PrefabInstance: {fileID: 769109585}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
--- !u!1 &784978156
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 784978157}
|
|
||||||
- component: {fileID: 784978158}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: AlarmManager
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &784978157
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 784978156}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 429.2735, y: 488.27496, z: 49.768143}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!114 &784978158
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 784978156}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6765c5d969530e44cbe4fc91d5e52ca1, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
alarmUIPrefab: {fileID: 1828762385695490929, guid: e8b88e69e607ee448806427e91440a8e, type: 3}
|
|
||||||
--- !u!1 &832575517
|
--- !u!1 &832575517
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1025,6 +983,121 @@ RectTransform:
|
|||||||
m_CorrespondingSourceObject: {fileID: 5064510836022735693, guid: 27ddee6261f49584c8634ba7c5f4ae46, type: 3}
|
m_CorrespondingSourceObject: {fileID: 5064510836022735693, guid: 27ddee6261f49584c8634ba7c5f4ae46, type: 3}
|
||||||
m_PrefabInstance: {fileID: 8261569461642068635}
|
m_PrefabInstance: {fileID: 8261569461642068635}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
--- !u!1 &1087949228
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1087949233}
|
||||||
|
- component: {fileID: 1087949232}
|
||||||
|
- component: {fileID: 1087949231}
|
||||||
|
- component: {fileID: 1087949230}
|
||||||
|
- component: {fileID: 1087949229}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: AlarmManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1087949229
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1087949228}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 6765c5d969530e44cbe4fc91d5e52ca1, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
alarmUIPrefab: {fileID: 1828762385695490929, guid: e8b88e69e607ee448806427e91440a8e, type: 3}
|
||||||
|
--- !u!114 &1087949230
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1087949228}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_IgnoreReversedGraphics: 1
|
||||||
|
m_BlockingObjects: 0
|
||||||
|
m_BlockingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
--- !u!114 &1087949231
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1087949228}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UiScaleMode: 0
|
||||||
|
m_ReferencePixelsPerUnit: 100
|
||||||
|
m_ScaleFactor: 1
|
||||||
|
m_ReferenceResolution: {x: 800, y: 600}
|
||||||
|
m_ScreenMatchMode: 0
|
||||||
|
m_MatchWidthOrHeight: 0
|
||||||
|
m_PhysicalUnit: 3
|
||||||
|
m_FallbackScreenDPI: 96
|
||||||
|
m_DefaultSpriteDPI: 96
|
||||||
|
m_DynamicPixelsPerUnit: 1
|
||||||
|
m_PresetInfoIsWorld: 0
|
||||||
|
--- !u!223 &1087949232
|
||||||
|
Canvas:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1087949228}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_Camera: {fileID: 330585545}
|
||||||
|
m_PlaneDistance: 100
|
||||||
|
m_PixelPerfect: 1
|
||||||
|
m_ReceivesEvents: 1
|
||||||
|
m_OverrideSorting: 0
|
||||||
|
m_OverridePixelPerfect: 0
|
||||||
|
m_SortingBucketNormalizedSize: 0
|
||||||
|
m_VertexColorAlwaysGammaSpace: 0
|
||||||
|
m_AdditionalShaderChannelsFlag: 0
|
||||||
|
m_UpdateRectTransformForStandalone: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
--- !u!224 &1087949233
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1087949228}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0, y: 0}
|
||||||
--- !u!1 &1091201604
|
--- !u!1 &1091201604
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2223,7 +2296,7 @@ SceneRoots:
|
|||||||
- {fileID: 832575519}
|
- {fileID: 832575519}
|
||||||
- {fileID: 632541407}
|
- {fileID: 632541407}
|
||||||
- {fileID: 27812499}
|
- {fileID: 27812499}
|
||||||
- {fileID: 784978157}
|
- {fileID: 1087949233}
|
||||||
- {fileID: 2030316712}
|
- {fileID: 2030316712}
|
||||||
- {fileID: 483439351}
|
- {fileID: 483439351}
|
||||||
- {fileID: 495653798}
|
- {fileID: 495653798}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace SampleProject
|
|||||||
|
|
||||||
mqttPipeLine = new MQTTPipeLine("localhost", 1883);
|
mqttPipeLine = new MQTTPipeLine("localhost", 1883);
|
||||||
mqttPipeLine.AddTopic("AGV");
|
mqttPipeLine.AddTopic("AGV");
|
||||||
//mqttPipeLine.AddTopic("ALARM");
|
mqttPipeLine.AddTopic("ALARM");
|
||||||
mqttPipeLine.Execute();
|
mqttPipeLine.Execute();
|
||||||
|
|
||||||
//10초 후 정지
|
//10초 후 정지
|
||||||
|
|||||||
@@ -278,13 +278,20 @@ namespace UVC.Data
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 업데이트 된 객체를 반환합니다.
|
/// 현재 데이터 객체의 업데이트된 버전을 생성하고 반환합니다. 선택적으로 메모리 할당 최적화를 위해 풀을 사용합니다.
|
||||||
/// </summary>
|
// </summary>
|
||||||
/// <returns></returns>
|
/// <remarks>이 메서드는 현재 데이터 객체와 관련 요소의 깊은 복사를 수행합니다.
|
||||||
public IDataObject GetUpdatedObject()
|
/// <paramref name="fromPool"/>이 <see langword="true"/>이면 메서드는 메모리 사용을 최적화하기 위해 객체 풀에서 새 인스턴스를 검색합니다. 그렇지 않으면 새 인스턴스가 직접 생성됩니다. 반환된
|
||||||
|
/// 객체는 추가, 제거 및 수정을 포함하여 현재 객체의 상태에 대한 업데이트를 반영합니다.
|
||||||
|
/// 변경 사항은 추적되어 업데이트된 객체의 해당 목록에 적용됩니다.</remarks>
|
||||||
|
/// <param name="fromPool">객체 풀에서 새 인스턴스를 검색할지 여부를 나타내는 부울 값입니다. <see langword="true"/>
|
||||||
|
/// 객체 풀을 사용합니다. <see langword="false"/>를 사용하여 새 인스턴스를 직접 생성합니다.</param>
|
||||||
|
/// <returns>추가, 제거 또는 수정된 목록에서 추적된 모든 변경 사항을 포함하여 현재 객체 데이터의 깊은 복사본을 포함하는 업데이트된 <see cref="IDataObject"/> 인스턴스입니다.
|
||||||
|
///</returns>
|
||||||
|
public IDataObject GetUpdatedObject(bool fromPool = true)
|
||||||
{
|
{
|
||||||
// 풀에서 새 DataArray 인스턴스를 가져옵니다.
|
// 풀에서 새 DataArray 인스턴스를 가져옵니다.
|
||||||
var clone = DataArrayPool.Get();
|
var clone = fromPool ? DataArrayPool.Get() : new DataArray();
|
||||||
clone.FromCapacity(this.Count);
|
clone.FromCapacity(this.Count);
|
||||||
|
|
||||||
// 배열의 모든 DataObject를 순회하며 각각을 복제합니다.
|
// 배열의 모든 DataObject를 순회하며 각각을 복제합니다.
|
||||||
@@ -292,7 +299,7 @@ namespace UVC.Data
|
|||||||
{
|
{
|
||||||
// DataObject의 Clone 메서드를 호출하여 깊은 복사를 수행하고,
|
// DataObject의 Clone 메서드를 호출하여 깊은 복사를 수행하고,
|
||||||
// base.Add를 사용해 추적 로직 없이 직접 추가합니다.
|
// base.Add를 사용해 추적 로직 없이 직접 추가합니다.
|
||||||
if (item.GetUpdatedObject() is DataObject updatedObject)
|
if (item.GetUpdatedObject(fromPool) is DataObject updatedObject)
|
||||||
{
|
{
|
||||||
clone.Add(updatedObject);
|
clone.Add(updatedObject);
|
||||||
if (addedList.Contains(item))
|
if (addedList.Contains(item))
|
||||||
|
|||||||
@@ -807,17 +807,37 @@ namespace UVC.Data
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 업데이트된 속성만 포함하는 새로운 DataObject를 반환합니다.
|
/// 현재 객체의 상태를 기반으로 업데이트된 <see cref="IDataObject"/> 인스턴스를 생성하고 반환합니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>업데이트 된 항목만 가지고 있는 DataObject</returns>
|
/// <remarks>이 메서드는 <see cref="DataObject"/> 및 <see
|
||||||
public IDataObject GetUpdatedObject()
|
/// cref="DataArray"/> 유형의 속성은 깊이 복사되고, 다른 유형의 속성은 직접 복사되도록 합니다. <c>IdKey</c>가 없으면
|
||||||
|
/// 현재 객체의 첫 번째 키-값 쌍이 업데이트된 객체에 포함됩니다.
|
||||||
|
///</remarks>
|
||||||
|
/// <param name="fromPool">업데이트된 객체를 풀에서 검색해야 하는지 여부를 나타내는 값입니다. <see langword="true"/>인 경우
|
||||||
|
/// <see cref="DataObjectPool"/>에서 객체를 가져옵니다. 그렇지 않으면 새 <see cref="DataObject"/>
|
||||||
|
/// 인스턴스가 생성됩니다.</param>
|
||||||
|
/// <returns>현재 객체에서 복사된 속성과 값을 포함하는 업데이트된 <see cref="IDataObject"/> 인스턴스입니다.
|
||||||
|
/// 반환된 객체에는 변경된 모든 속성, <c>IdKey</c> 및 <c>Name</c>이 포함됩니다.
|
||||||
|
/// <c>IdKey</c>가 현재 객체에 있는 경우 해당 값도 업데이트된 객체에 포함됩니다.</returns>
|
||||||
|
public IDataObject GetUpdatedObject(bool fromPool = true)
|
||||||
{
|
{
|
||||||
DataObject updated = DataObjectPool.Get();
|
DataObject updated = fromPool ? DataObjectPool.Get() : new DataObject();
|
||||||
foreach (var key in changedProperies)
|
foreach (var key in changedProperies)
|
||||||
{
|
{
|
||||||
if (this.ContainsKey(key))
|
if (this.ContainsKey(key))
|
||||||
{
|
{
|
||||||
updated[key] = this[key];
|
if(this[key] is DataObject dataObject)
|
||||||
|
{
|
||||||
|
updated[key] = dataObject.Copy(fromPool); // DataObject는 복사합니다.
|
||||||
|
}
|
||||||
|
else if (this[key] is DataArray dataArray)
|
||||||
|
{
|
||||||
|
updated[key] = dataArray.Copy(fromPool); // DataArray는 복사합니다.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updated[key] = this[key]; // 그 외의 값은 그대로 복사합니다.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updated.IdKey = IdKey; // ID 키를 복사합니다.
|
updated.IdKey = IdKey; // ID 키를 복사합니다.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace UVC.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 풀의 최대 크기입니다. 이 크기를 초과하는 객체는 풀에 저장되지 않습니다.
|
/// 풀의 최대 크기입니다. 이 크기를 초과하는 객체는 풀에 저장되지 않습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static int maxPoolSize = 4000;
|
private static int maxPoolSize = 2000;
|
||||||
|
|
||||||
// --- 통계용 필드 ---
|
// --- 통계용 필드 ---
|
||||||
private static int _inUseCount = 0; // 현재 사용 중인 DataObject 인스턴스의 수
|
private static int _inUseCount = 0; // 현재 사용 중인 DataObject 인스턴스의 수
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace UVC.Data
|
|||||||
{
|
{
|
||||||
if (!dataObjects.ContainsKey(key))
|
if (!dataObjects.ContainsKey(key))
|
||||||
{
|
{
|
||||||
var newData = dataObject.Clone(false);
|
var newData = dataObject.Clone(fromPool: false);
|
||||||
|
|
||||||
dataObjects.Add(key, newData);
|
dataObjects.Add(key, newData);
|
||||||
dataObject.MarkAllAsUpdated();
|
dataObject.MarkAllAsUpdated();
|
||||||
@@ -83,7 +83,7 @@ namespace UVC.Data
|
|||||||
IDataObject newDataObject;
|
IDataObject newDataObject;
|
||||||
if (updatedDataOnly)
|
if (updatedDataOnly)
|
||||||
{
|
{
|
||||||
newDataObject = obj.GetUpdatedObject();
|
newDataObject = obj.GetUpdatedObject(fromPool: false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ namespace UVC.Data
|
|||||||
if (mappedObject != null)
|
if (mappedObject != null)
|
||||||
{
|
{
|
||||||
repoObject = DataRepository.Instance.AddData(key, mappedObject, info.UpdatedDataOnly);
|
repoObject = DataRepository.Instance.AddData(key, mappedObject, info.UpdatedDataOnly);
|
||||||
if (repoObject == mappedObject) repoObject = mappedObject.Clone();
|
if (repoObject == mappedObject) repoObject = mappedObject.Clone(fromPool: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,9 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 업데이트된 속성만 포함하는 새로운 DataObject를 반환합니다.
|
/// 업데이트된 속성만 포함하는 새로운 DataObject를 반환합니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="fromPool">객체 풀에서 복제할지 여부를 지정합니다. 기본값은 true입니다.</param>
|
||||||
/// <returns>업데이트 된 항목만 가지고 있는 DataObject</returns>
|
/// <returns>업데이트 된 항목만 가지고 있는 DataObject</returns>
|
||||||
public IDataObject GetUpdatedObject();
|
public IDataObject GetUpdatedObject(bool fromPool = true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// /// <summary>
|
/// /// <summary>
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ namespace UVC.Data
|
|||||||
if (mappedObject == null) return;
|
if (mappedObject == null) return;
|
||||||
// DataRepository는 내부적으로 데이터를 복사/업데이트하므로, mappedObject는 여기서 임시 객체가 됩니다.
|
// DataRepository는 내부적으로 데이터를 복사/업데이트하므로, mappedObject는 여기서 임시 객체가 됩니다.
|
||||||
var repoObject = DataRepository.Instance.AddData(topic, mappedObject, info.UpdatedDataOnly);
|
var repoObject = DataRepository.Instance.AddData(topic, mappedObject, info.UpdatedDataOnly);
|
||||||
if(repoObject == mappedObject) repoObject = mappedObject.Clone();
|
if(repoObject == mappedObject) repoObject = mappedObject.Clone(fromPool: false);
|
||||||
// 핸들러 호출이 필요한지 확인
|
// 핸들러 호출이 필요한지 확인
|
||||||
bool shouldInvoke = !info.UpdatedDataOnly || (repoObject != null && repoObject.UpdatedCount > 0);
|
bool shouldInvoke = !info.UpdatedDataOnly || (repoObject != null && repoObject.UpdatedCount > 0);
|
||||||
if (shouldInvoke)
|
if (shouldInvoke)
|
||||||
|
|||||||
@@ -9,18 +9,24 @@ using UVC.Core;
|
|||||||
using UVC.Data;
|
using UVC.Data;
|
||||||
using UVC.Extention;
|
using UVC.Extention;
|
||||||
using UVC.Factory.Component;
|
using UVC.Factory.Component;
|
||||||
|
using UVC.Util;
|
||||||
|
|
||||||
namespace UVC.Factory.Alarm
|
namespace UVC.Factory.Alarm
|
||||||
{
|
{
|
||||||
public class AlarmManager : SingletonScene<AlarmManager>
|
public class AlarmManager : SingletonScene<AlarmManager>
|
||||||
{
|
{
|
||||||
[Tooltip("알람 UI 프리팹입니다. 이 프리팹은 알람 정보를 표시하는 UI 요소를 포함해야 합니다.")]
|
[Tooltip("알람 UI 프리팹입니다. 이 프리팹은 알람 정보를 표시하는 UI 요소를 포함해야 합니다.")]
|
||||||
public GameObject alarmUIPrefab; // 알람 UI 프리팹 (아래에서 설명)
|
[SerializeField]
|
||||||
|
protected GameObject alarmUIPrefab; // 알람 UI 프리팹 (아래에서 설명)
|
||||||
private Dictionary<string, AlarmUIController> activeAlarmUIs = new Dictionary<string, AlarmUIController>();
|
private Dictionary<string, AlarmUIController> activeAlarmUIs = new Dictionary<string, AlarmUIController>();
|
||||||
|
|
||||||
|
private List<string> agvNames = new List<string>();
|
||||||
|
private Dictionary<string, string> alarmAgvNames = new Dictionary<string, string>();
|
||||||
|
|
||||||
// FactoryDataManager에서 찾을 수 있도록 참조를 저장
|
// FactoryDataManager에서 찾을 수 있도록 참조를 저장
|
||||||
private FactoryObjectManager? dataManager;
|
private FactoryObjectManager? dataManager;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AlarmManager의 초기화 메서드입니다.
|
/// AlarmManager의 초기화 메서드입니다.
|
||||||
/// Awake 메서드에서 호출되며, MonoBehaviour가 생성될 때 한 번만 실행됩니다.
|
/// Awake 메서드에서 호출되며, MonoBehaviour가 생성될 때 한 번만 실행됩니다.
|
||||||
@@ -33,8 +39,17 @@ namespace UVC.Factory.Alarm
|
|||||||
private void OnSceneInitialized()
|
private void OnSceneInitialized()
|
||||||
{
|
{
|
||||||
dataManager = FactoryObjectManager.Instance;
|
dataManager = FactoryObjectManager.Instance;
|
||||||
|
|
||||||
|
//test code
|
||||||
|
//알람 데이터가 AGV와 관련 없는것이 많아서, AGV 이름을 미리 정의합니다.
|
||||||
|
for (int i = 1; i <= 115; i++)
|
||||||
|
{
|
||||||
|
agvNames.Add($"HFF09CNA8{i.ToString("D3")}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Alarm 데이터를 수신하기 위한 MQTT 파이프라인을 설정합니다.
|
/// Alarm 데이터를 수신하기 위한 MQTT 파이프라인을 설정합니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -58,6 +73,7 @@ namespace UVC.Factory.Alarm
|
|||||||
dataMask["TRANSPORT_UNIT_NAME"] = "";
|
dataMask["TRANSPORT_UNIT_NAME"] = "";
|
||||||
dataMask["TRANSPORT_EQP_ID"] = "";
|
dataMask["TRANSPORT_EQP_ID"] = "";
|
||||||
dataMask["TRANSPORT_UNIT_ID"] = "";
|
dataMask["TRANSPORT_UNIT_ID"] = "";
|
||||||
|
dataMask["CLEAR_TIME"] = DateTime.Now;
|
||||||
dataMask["SET_TIME"] = DateTime.Now;
|
dataMask["SET_TIME"] = DateTime.Now;
|
||||||
dataMask["UPDATE_TIME"] = DateTime.Now;
|
dataMask["UPDATE_TIME"] = DateTime.Now;
|
||||||
dataMask["TIMESTAMP"] = DateTime.Now;
|
dataMask["TIMESTAMP"] = DateTime.Now;
|
||||||
@@ -78,6 +94,9 @@ namespace UVC.Factory.Alarm
|
|||||||
// 생성한 파이프라인 정보를 전역 MQTT 파이프라인에 추가합니다.
|
// 생성한 파이프라인 정보를 전역 MQTT 파이프라인에 추가합니다.
|
||||||
AppMain.Instance.MQTTPipeLine.Add(pipelineInfo);
|
AppMain.Instance.MQTTPipeLine.Add(pipelineInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int agvIdx = 50;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 데이터 수신 시 호출되는 공개 핸들러입니다.
|
/// 데이터 수신 시 호출되는 공개 핸들러입니다.
|
||||||
/// 수신된 ALARM 데이터 배열을 비동기적으로 처리하여 씬에 반영합니다.
|
/// 수신된 ALARM 데이터 배열을 비동기적으로 처리하여 씬에 반영합니다.
|
||||||
@@ -86,43 +105,67 @@ namespace UVC.Factory.Alarm
|
|||||||
/// <param name="data">수신된 데이터 객체 (DataArray 형태)</param>
|
/// <param name="data">수신된 데이터 객체 (DataArray 형태)</param>
|
||||||
public void OnUpdateData(IDataObject? data)
|
public void OnUpdateData(IDataObject? data)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
DataArray? arr = data as DataArray;
|
DataArray? arr = data as DataArray;
|
||||||
if (arr == null) return;
|
if (arr == null || arr.Count == 0) return;
|
||||||
if (arr.Count == 0)
|
|
||||||
{
|
|
||||||
arr.ReturnToPool();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
||||||
var AddedItems = arr.AddedItems;
|
var AddedItems = arr.AddedItems;
|
||||||
var RemovedItems = arr.RemovedItems;
|
var RemovedItems = new List<DataObject>(arr.RemovedItems);
|
||||||
var ModifiedList = arr.ModifiedList;
|
var ModifiedList = arr.ModifiedList;
|
||||||
|
|
||||||
Debug.Log($"AlarmManager OnUpdateData: Added={AddedItems.Count}, Removed={RemovedItems.Count}, Modified={ModifiedList.Count}");
|
Debug.Log($"AlarmManager OnUpdateData: Added={AddedItems.Count}, Removed={RemovedItems.Count}, Modified={ModifiedList.Count}");
|
||||||
|
|
||||||
|
// clear_time이 있는 항목만 제거 리스트에 추가합니다.
|
||||||
|
foreach (var item in AddedItems.ToList())
|
||||||
|
{
|
||||||
|
if (item.GetDateTime("CLEAR_TIME") != null)
|
||||||
|
{
|
||||||
|
if (RemovedItems.FindIndex((i) => i.Id == item.Id) == -1) RemovedItems.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in ModifiedList.ToList())
|
||||||
|
{
|
||||||
|
if (item.GetDateTime("CLEAR_TIME") != null)
|
||||||
|
{
|
||||||
|
if (RemovedItems.FindIndex((i) => i.Id == item.Id) == -1) RemovedItems.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 새로 추가된 ALARM 처리
|
// 새로 추가된 ALARM 처리
|
||||||
foreach (var item in AddedItems.ToList())
|
foreach (var item in AddedItems.ToList())
|
||||||
{
|
{
|
||||||
HandleNewAlarm(item.Copy());
|
if (item.GetDateTime("CLEAR_TIME") == null && !item.Id.IsNullOrEmpty())
|
||||||
}
|
{
|
||||||
|
item["TRANSPORT_EQP_ID"] = agvNames[agvIdx]; // AGV 이름을 TRANSPORT_EQP_ID에 설정
|
||||||
// 제거된 ALARM 처리
|
alarmAgvNames.Add(item.Id!, agvNames[agvIdx]);
|
||||||
foreach (var item in RemovedItems.ToList())
|
HandleNewAlarm(item);
|
||||||
{
|
agvIdx++;
|
||||||
HandleClearedAlarm(item.Copy());
|
if(agvIdx >= agvNames.Count) agvIdx = 0; // AGV 이름이 부족할 경우 순환
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 정보가 수정된 ALARM 처리
|
// 정보가 수정된 ALARM 처리
|
||||||
foreach (var item in ModifiedList.ToList())
|
foreach (var item in ModifiedList.ToList())
|
||||||
{
|
{
|
||||||
HandleModifyAlarm(item.Copy());
|
if (item.GetDateTime("CLEAR_TIME") == null && !item.Id.IsNullOrEmpty() && alarmAgvNames.ContainsKey(item.Id!))
|
||||||
|
{
|
||||||
|
item["TRANSPORT_EQP_ID"] = alarmAgvNames[item.Id!]; // 기존 AGV 이름 유지
|
||||||
|
HandleModifyAlarm(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.ReturnToPool();
|
// 제거된 ALARM 처리
|
||||||
|
foreach (var item in RemovedItems.ToList())
|
||||||
|
{
|
||||||
|
if (!item.Id.IsNullOrEmpty() && alarmAgvNames.ContainsKey(item.Id!))
|
||||||
|
{
|
||||||
|
item["TRANSPORT_EQP_ID"] = alarmAgvNames[item.Id!]; // 기존 AGV 이름 유지
|
||||||
|
HandleClearedAlarm(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -140,12 +183,12 @@ namespace UVC.Factory.Alarm
|
|||||||
if (data.Id == null)
|
if (data.Id == null)
|
||||||
{
|
{
|
||||||
Debug.LogError($"New Alarm Received No data. {data}");
|
Debug.LogError($"New Alarm Received No data. {data}");
|
||||||
data.ReturnToPool();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 없으면 새로 생성
|
// 없으면 새로 생성
|
||||||
FactoryObject? targetObject = dataManager!.FindById(data.GetString("MACHINENAME")!);
|
FactoryObject? targetObject = dataManager!.FindByName(data.GetString("TRANSPORT_EQP_ID")!);
|
||||||
|
Debug.Log($"AlarmManager {targetObject==null} {data.Id}, {data.GetString("TRANSPORT_EQP_ID")}");
|
||||||
if (targetObject != null)
|
if (targetObject != null)
|
||||||
{
|
{
|
||||||
GameObject newUIObject = Instantiate(alarmUIPrefab, transform); // 매니저 하위에 생성
|
GameObject newUIObject = Instantiate(alarmUIPrefab, transform); // 매니저 하위에 생성
|
||||||
@@ -162,7 +205,6 @@ namespace UVC.Factory.Alarm
|
|||||||
if (data.Id == null)
|
if (data.Id == null)
|
||||||
{
|
{
|
||||||
Debug.LogError($"Modify Alarm Received No data. {data}");
|
Debug.LogError($"Modify Alarm Received No data. {data}");
|
||||||
data.ReturnToPool();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 이미 해당 설비에 알람 UI가 떠 있는지 확인
|
// 이미 해당 설비에 알람 UI가 떠 있는지 확인
|
||||||
@@ -178,7 +220,6 @@ namespace UVC.Factory.Alarm
|
|||||||
if (data.Id.IsNullOrEmpty())
|
if (data.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
Debug.LogError($"Clear Alarm Received No data. {data}");
|
Debug.LogError($"Clear Alarm Received No data. {data}");
|
||||||
data.ReturnToPool();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (activeAlarmUIs.TryGetValue(data.Id!, out AlarmUIController uiController))
|
if (activeAlarmUIs.TryGetValue(data.Id!, out AlarmUIController uiController))
|
||||||
@@ -189,7 +230,6 @@ namespace UVC.Factory.Alarm
|
|||||||
activeAlarmUIs.Remove(data.Id!);
|
activeAlarmUIs.Remove(data.Id!);
|
||||||
Destroy(uiController.gameObject);
|
Destroy(uiController.gameObject);
|
||||||
}
|
}
|
||||||
data.ReturnToPool();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using DG.Tweening;
|
||||||
|
using System.Collections.Generic;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
@@ -22,6 +23,21 @@ namespace UVC.Factory.Alarm
|
|||||||
private Transform targetObject;
|
private Transform targetObject;
|
||||||
private List<DataObject> alarms = new List<DataObject>();
|
private List<DataObject> alarms = new List<DataObject>();
|
||||||
private bool isExpanded = false;
|
private bool isExpanded = false;
|
||||||
|
private SingleAlarmIcon singleAlarmIcon1 = null;
|
||||||
|
|
||||||
|
private RectTransform rectTransform;
|
||||||
|
private Canvas mainCanvas;
|
||||||
|
|
||||||
|
private float uiSpacing = 20f; // 간격
|
||||||
|
private Tweener uiSpacingTweener;
|
||||||
|
|
||||||
|
private bool isZoomIn = false; // 줌 인 상태를 추적하기 위한 변수
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
rectTransform = GetComponent<RectTransform>();
|
||||||
|
mainCanvas = GetComponentInParent<Canvas>();
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialize(FactoryObject target, DataObject initialAlarm)
|
public void Initialize(FactoryObject target, DataObject initialAlarm)
|
||||||
{
|
{
|
||||||
@@ -31,9 +47,56 @@ namespace UVC.Factory.Alarm
|
|||||||
|
|
||||||
void LateUpdate()
|
void LateUpdate()
|
||||||
{
|
{
|
||||||
// 빌보드 효과: 항상 카메라를 바라보도록 하고, 타겟 오브젝트를 따라다님
|
if (targetObject == null || Camera.main == null || mainCanvas == null)
|
||||||
transform.position = targetObject.position + Vector3.up * 2.0f; // 예시: 머리 위 2미터
|
{
|
||||||
transform.rotation = Camera.main.transform.rotation;
|
// 필수 컴포넌트가 없으면 UI를 비활성화합니다.
|
||||||
|
if (clusterView.activeSelf) clusterView.SetActive(false);
|
||||||
|
if (expandedView.activeSelf) expandedView.SetActive(false);
|
||||||
|
if (alarmCountText != null && alarmCountText.gameObject.activeSelf) alarmCountText.gameObject.SetActive(false);
|
||||||
|
if (singleAlarmIcon1 != null && singleAlarmIcon1.gameObject.activeSelf) singleAlarmIcon1.gameObject.SetActive(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 카메라의 정면 방향과 타겟을 향하는 방향을 계산합니다.
|
||||||
|
Vector3 cameraForward = Camera.main.transform.forward;
|
||||||
|
Vector3 toTarget = (targetObject.position - Camera.main.transform.position).normalized;
|
||||||
|
|
||||||
|
// 두 벡터의 내적을 계산하여 타겟이 카메라 앞에 있는지 확인합니다.
|
||||||
|
// 내적 값이 0보다 크면 타겟이 카메라 앞에 있는 것입니다.
|
||||||
|
if (Vector3.Dot(cameraForward, toTarget) > 0)
|
||||||
|
{
|
||||||
|
// 타겟이 앞에 있을 때만 UI를 활성화하고 위치를 업데이트합니다.
|
||||||
|
if (!gameObject.activeSelf)
|
||||||
|
{
|
||||||
|
UpdateView(); // 비활성화 상태였다면 뷰를 다시 활성화합니다.
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetObject의 월드 좌표를 스크린 좌표로 변환
|
||||||
|
Vector3 screenPoint = Camera.main.WorldToScreenPoint(targetObject.position + Vector3.up);
|
||||||
|
|
||||||
|
// Canvas Render Mode가 Screen Space - Camera일 경우
|
||||||
|
if (mainCanvas.renderMode == RenderMode.ScreenSpaceCamera)
|
||||||
|
{
|
||||||
|
Vector2 localPoint;
|
||||||
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(mainCanvas.transform as RectTransform, screenPoint, mainCanvas.worldCamera, out localPoint);
|
||||||
|
localPoint.y += uiSpacing;
|
||||||
|
rectTransform.localPosition = localPoint;
|
||||||
|
}
|
||||||
|
// Canvas Render Mode가 Screen Space - Overlay일 경우
|
||||||
|
else
|
||||||
|
{
|
||||||
|
screenPoint.y += uiSpacing;
|
||||||
|
rectTransform.position = screenPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 타겟이 카메라 뒤에 있으면 모든 관련 UI를 비활성화합니다.
|
||||||
|
if (clusterView.activeSelf) clusterView.SetActive(false);
|
||||||
|
if (expandedView.activeSelf) expandedView.SetActive(false);
|
||||||
|
if (alarmCountText != null && alarmCountText.gameObject.activeSelf) alarmCountText.gameObject.SetActive(false);
|
||||||
|
if (singleAlarmIcon1 != null && singleAlarmIcon1.gameObject.activeSelf) singleAlarmIcon1.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAlarm(DataObject alarm)
|
public void AddAlarm(DataObject alarm)
|
||||||
@@ -52,7 +115,6 @@ namespace UVC.Factory.Alarm
|
|||||||
{
|
{
|
||||||
alarms[index][key] = alarm[key]; // 기존 알람 데이터 업데이트
|
alarms[index][key] = alarm[key]; // 기존 알람 데이터 업데이트
|
||||||
}
|
}
|
||||||
alarm.ReturnToPool();
|
|
||||||
UpdateView();
|
UpdateView();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -81,14 +143,23 @@ namespace UVC.Factory.Alarm
|
|||||||
if (alarms.Count > 1)
|
if (alarms.Count > 1)
|
||||||
{
|
{
|
||||||
clusterView.SetActive(true);
|
clusterView.SetActive(true);
|
||||||
expandedView.SetActive(false); // 단일 뷰도 꺼야 함
|
expandedView.SetActive(false);
|
||||||
|
if (singleAlarmIcon1 != null) singleAlarmIcon1.gameObject.SetActive(false); // 단일 뷰도 꺼야 함
|
||||||
|
alarmCountText.gameObject.SetActive(true);
|
||||||
alarmCountText.text = alarms.Count.ToString();
|
alarmCountText.text = alarms.Count.ToString();
|
||||||
}
|
}
|
||||||
else if (alarms.Count == 1)
|
else if (alarms.Count == 1)
|
||||||
{
|
{
|
||||||
clusterView.SetActive(false);
|
clusterView.SetActive(false);
|
||||||
expandedView.SetActive(false);
|
expandedView.SetActive(false);
|
||||||
|
alarmCountText.gameObject.SetActive(false); // 알람 개수 텍스트 숨김
|
||||||
// 여기에 단일 알람 아이콘을 보여주는 로직 추가
|
// 여기에 단일 알람 아이콘을 보여주는 로직 추가
|
||||||
|
if (singleAlarmIcon1 == null)
|
||||||
|
{
|
||||||
|
singleAlarmIcon1 = Instantiate(singleAlarmIconPrefab, transform).GetComponent<SingleAlarmIcon>();
|
||||||
|
}
|
||||||
|
singleAlarmIcon1.gameObject.SetActive(true);
|
||||||
|
singleAlarmIcon1.SetData(alarms[0], targetObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,14 +174,18 @@ namespace UVC.Factory.Alarm
|
|||||||
{
|
{
|
||||||
if (alarms.Count > 1)
|
if (alarms.Count > 1)
|
||||||
{
|
{
|
||||||
|
isZoomIn = true;
|
||||||
// 클러스터 확장
|
// 클러스터 확장
|
||||||
CameraController.Instance.FocusOnTarget(transform, 5.0f); // 예시: 5미터 거리로 줌
|
CameraController.Instance.FocusOnTarget(targetObject.position, 15.0f); // 예시: 5미터 거리로 줌
|
||||||
ExpandCluster();
|
ExpandCluster();
|
||||||
}
|
}
|
||||||
else if (alarms.Count == 1)
|
else if (alarms.Count == 1)
|
||||||
{
|
{
|
||||||
|
isZoomIn = true;
|
||||||
|
//AnimateUISpace(1f); // 간격을 0으로 애니메이션
|
||||||
|
|
||||||
// 단일 알람 클릭
|
// 단일 알람 클릭
|
||||||
CameraController.Instance.FocusOnTarget(targetObject, 3.0f);
|
CameraController.Instance.FocusOnTarget(targetObject.position, 10.0f);
|
||||||
// 추가로 알람 상세 정보 UI를 띄울 수 있음
|
// 추가로 알람 상세 정보 UI를 띄울 수 있음
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +196,7 @@ namespace UVC.Factory.Alarm
|
|||||||
isExpanded = true;
|
isExpanded = true;
|
||||||
clusterView.SetActive(false);
|
clusterView.SetActive(false);
|
||||||
expandedView.SetActive(true);
|
expandedView.SetActive(true);
|
||||||
|
singleAlarmIcon1.gameObject.SetActive(false);
|
||||||
|
|
||||||
// 기존 아이콘들 삭제
|
// 기존 아이콘들 삭제
|
||||||
foreach (Transform child in expandedView.transform)
|
foreach (Transform child in expandedView.transform)
|
||||||
@@ -129,16 +205,19 @@ namespace UVC.Factory.Alarm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 원형으로 아이콘 배치
|
// 원형으로 아이콘 배치
|
||||||
|
float radius = 100.0f; // Canvas 좌표계에 맞는 반지름 값
|
||||||
for (int i = 0; i < alarms.Count; i++)
|
for (int i = 0; i < alarms.Count; i++)
|
||||||
{
|
{
|
||||||
float angle = i * Mathf.PI * 2f / alarms.Count;
|
float angle = i * Mathf.PI * 2f / alarms.Count;
|
||||||
Vector3 pos = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * 0.5f; // 0.5f는 반지름
|
Vector3 pos = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * radius;
|
||||||
|
|
||||||
GameObject iconObj = Instantiate(singleAlarmIconPrefab, expandedView.transform);
|
GameObject iconObj = Instantiate(singleAlarmIconPrefab, expandedView.transform);
|
||||||
iconObj.transform.localPosition = pos;
|
iconObj.transform.localPosition = pos;
|
||||||
// iconObj의 SingleAlarmIcon 스크립트에 알람 데이터 전달
|
// iconObj의 SingleAlarmIcon 스크립트에 알람 데이터 전달
|
||||||
iconObj.GetComponent<SingleAlarmIcon>().SetData(alarms[i], targetObject);
|
iconObj.GetComponent<SingleAlarmIcon>().SetData(alarms[i], targetObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//AnimateUISpace(0f); // 간격을 0으로 애니메이션
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CollapseCluster()
|
private void CollapseCluster()
|
||||||
@@ -153,5 +232,25 @@ namespace UVC.Factory.Alarm
|
|||||||
{
|
{
|
||||||
OnPointerClick();
|
OnPointerClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AnimateUISpace(float targetSpacing, float duration = 1.0f)
|
||||||
|
{
|
||||||
|
if (uiSpacingTweener != null && uiSpacingTweener.IsActive() && uiSpacingTweener.IsPlaying())
|
||||||
|
{
|
||||||
|
uiSpacingTweener.Kill();
|
||||||
|
}
|
||||||
|
uiSpacingTweener = DOVirtual.Float(uiSpacing, targetSpacing, duration, (value) =>
|
||||||
|
{
|
||||||
|
uiSpacing = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (uiSpacingTweener != null && uiSpacingTweener.IsActive() && uiSpacingTweener.IsPlaying())
|
||||||
|
{
|
||||||
|
uiSpacingTweener.Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,23 +33,17 @@ namespace UVC.Factory.Alarm
|
|||||||
|
|
||||||
equipmentTransform = equipment;
|
equipmentTransform = equipment;
|
||||||
|
|
||||||
if (text != null)
|
string icon = data.GetString("ICON");
|
||||||
|
if (text != null && icon != null)
|
||||||
{
|
{
|
||||||
string combinedString = string.Empty;
|
text.text = icon;
|
||||||
foreach (var kvp in data)
|
|
||||||
{
|
|
||||||
// <indent> 태그를 사용하여 줄바꿈 시에도 정렬이 유지되도록 합니다.
|
|
||||||
combinedString += $"{kvp.Key}<pos=40%><indent=40%>{kvp.Value ?? "null"}</indent>\n";
|
|
||||||
}
|
|
||||||
combinedString = combinedString.TrimEnd('\n'); // 마지막 줄바꿈 제거
|
|
||||||
text.text = combinedString;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPointerClick()
|
public void OnPointerClick()
|
||||||
{
|
{
|
||||||
// 클릭 시 해당 설비로 카메라 포커스
|
// 클릭 시 해당 설비로 카메라 포커스
|
||||||
CameraController.Instance.FocusOnTarget(equipmentTransform, 3.0f);
|
CameraController.Instance.FocusOnTarget(equipmentTransform.position, 3.0f);
|
||||||
Debug.Log($"알람 [{data.GetString("MESSAGE")}]이 발생한 설비로 이동합니다.");
|
Debug.Log($"알람 [{data.GetString("MESSAGE")}]이 발생한 설비로 이동합니다.");
|
||||||
// 여기서 알람 상세정보 패널을 띄워도 좋음
|
// 여기서 알람 상세정보 패널을 띄워도 좋음
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ namespace UVC.Factory.Component
|
|||||||
data[keyValue.Key] = keyValue.Value;
|
data[keyValue.Key] = keyValue.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newData.ReturnToPool(); // 사용이 끝난 데이터 객체를 풀에 반환합니다.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace UVC.Factory.Component
|
|||||||
public class AGVManager : SingletonScene<AGVManager>
|
public class AGVManager : SingletonScene<AGVManager>
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly string prefabPath = "Prefabs/SampleProject/Factory/AGV";
|
private readonly string prefabPath = "Prefabs/UI/Factory/AGV";
|
||||||
private GameObjectPool<AGV>? agvPool;
|
private GameObjectPool<AGV>? agvPool;
|
||||||
|
|
||||||
public GameObjectPool<AGV> AGVPool
|
public GameObjectPool<AGV> AGVPool
|
||||||
@@ -178,12 +178,7 @@ namespace UVC.Factory.Component
|
|||||||
if (data == null || agvPool == null) return;
|
if (data == null || agvPool == null) return;
|
||||||
|
|
||||||
DataArray? arr = data as DataArray;
|
DataArray? arr = data as DataArray;
|
||||||
if (arr == null) return;
|
if (arr == null || arr.Count == 0) return;
|
||||||
if (arr.Count == 0)
|
|
||||||
{
|
|
||||||
arr.ReturnToPool();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
||||||
var AddedItems = arr.AddedItems;
|
var AddedItems = arr.AddedItems;
|
||||||
@@ -208,7 +203,7 @@ namespace UVC.Factory.Component
|
|||||||
"",
|
"",
|
||||||
item.GetString("MODE")
|
item.GetString("MODE")
|
||||||
);
|
);
|
||||||
agv.UpdateData(item.Copy());
|
agv.UpdateData(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 제거된 AGV 처리
|
// 제거된 AGV 처리
|
||||||
@@ -225,16 +220,14 @@ namespace UVC.Factory.Component
|
|||||||
// 정보가 수정된 AGV 처리
|
// 정보가 수정된 AGV 처리
|
||||||
foreach (var item in ModifiedList.ToList())
|
foreach (var item in ModifiedList.ToList())
|
||||||
{
|
{
|
||||||
if(item.Id == "HFF09CNA8047") Debug.Log($"AGVManager modified data: {item.ToString()}");
|
|
||||||
string vhlName = item.GetString("VHL_NAME")!;
|
string vhlName = item.GetString("VHL_NAME")!;
|
||||||
AGV? agv = agvPool.FindActiveItem(vhlName);
|
AGV? agv = agvPool.FindActiveItem(vhlName);
|
||||||
if (agv != null)
|
if (agv != null)
|
||||||
{
|
{
|
||||||
agv.UpdateData(item.Copy());
|
agv.UpdateData(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.ReturnToPool();
|
|
||||||
if(created == false)
|
if(created == false)
|
||||||
{
|
{
|
||||||
created = true;
|
created = true;
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ namespace UVC.Factory.Component
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
info = value;
|
info = value;
|
||||||
if (value != null)
|
if (info != null)
|
||||||
{
|
{
|
||||||
// 객체의 이름을 GameObject의 이름으로 설정합니다.
|
// 객체의 이름을 GameObject의 이름으로 설정합니다.
|
||||||
gameObject.name = value.Name;
|
gameObject.name = info.Name;
|
||||||
FactoryObjectManager.Instance.RegisterFactoryObject(this);
|
FactoryObjectManager.Instance.RegisterFactoryObject(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
using UVC.Core;
|
using UVC.Core;
|
||||||
|
|
||||||
namespace UVC.Util
|
namespace UVC.Util
|
||||||
@@ -13,8 +14,12 @@ namespace UVC.Util
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CameraController : SingletonScene<CameraController>
|
public class CameraController : SingletonScene<CameraController>
|
||||||
{
|
{
|
||||||
[Tooltip("카메라 평행 이동 속도")]
|
[Header("Panning Speed")]
|
||||||
public float panSpeed = 20f;
|
[Tooltip("카메라 높이가 임계값보다 낮을 때의 평행 이동 속도")]
|
||||||
|
public float lowAltitudePanSpeed = 0.5f;
|
||||||
|
|
||||||
|
[Tooltip("카메라 높이가 임계값보다 높을 때의 평행 이동 속도")]
|
||||||
|
public float highAltitudePanSpeed = 10f;
|
||||||
|
|
||||||
[Tooltip("카메라 회전 속도")]
|
[Tooltip("카메라 회전 속도")]
|
||||||
public float rotationSpeed = 300f;
|
public float rotationSpeed = 300f;
|
||||||
@@ -26,16 +31,167 @@ namespace UVC.Util
|
|||||||
[Tooltip("패닝 시 마우스 이동량의 최대값을 제한하여, 프레임 드랍 시 카메라가 급격하게 튀는 현상을 방지합니다.")]
|
[Tooltip("패닝 시 마우스 이동량의 최대값을 제한하여, 프레임 드랍 시 카메라가 급격하게 튀는 현상을 방지합니다.")]
|
||||||
public float maxPanDelta = 50f;
|
public float maxPanDelta = 50f;
|
||||||
|
|
||||||
|
[Header("Camera")]
|
||||||
|
[Tooltip("카메라 최소 높이")]
|
||||||
|
public float minCameraY = 2f;
|
||||||
|
|
||||||
|
[Tooltip("카메라 최대 높이")]
|
||||||
|
public float maxCameraY = 50f;
|
||||||
|
|
||||||
|
[Tooltip("카메라의 최소 수직 회전 각도 (X축)")]
|
||||||
|
public float minPitch = 20f;
|
||||||
|
|
||||||
|
[Tooltip("카메라의 최대 수직 회전 각도 (X축)")]
|
||||||
|
public float maxPitch = 85f;
|
||||||
|
|
||||||
|
[Tooltip("카메라의 최소 수평 회전 각도 (y축)")]
|
||||||
|
public float minYaw = -45f;
|
||||||
|
|
||||||
|
[Tooltip("카메라의 최대 수평 회전 각도 (y축)")]
|
||||||
|
public float maxYaw = 45f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 카메라의 변형이 변경될 때 발생합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>이 이벤트는 카메라의 변형이 업데이트될 때마다 트리거되며,
|
||||||
|
/// 구독자는 위치, 회전 또는 크기 변경에 응답할 수 있습니다. 이 이벤트를 사용하여
|
||||||
|
/// UI 요소 업데이트 또는 종속 값 재계산과 같은 작업을 수행할 수 있습니다.</remarks>
|
||||||
|
public event Action<Transform> OnCameraChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 카메라 위치가 변경될 때 발생합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>이 이벤트는 카메라 위치가 업데이트될 때마다 트리거됩니다. 구독자는
|
||||||
|
/// 이 이벤트를 사용하여 UI 요소를 업데이트하거나 새 위치를 기반으로 계산을 수행하는 등 카메라 위치 변경에 대응할 수 있습니다.
|
||||||
|
///</remarks>
|
||||||
|
public event Action<Vector3> OnCameraPositionChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 카메라의 회전이 변경될 때 발생합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>이 이벤트는 카메라의 회전이 업데이트될 때마다 트리거됩니다. 구독자는
|
||||||
|
/// 이 이벤트를 사용하여 카메라 방향의 변경에 응답할 수 있습니다.</remarks>
|
||||||
|
public event Action<Quaternion> OnCameraRotionChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 정의된 범위 내에서 카메라의 정규화된 수직 위치를 가져옵니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>값은 카메라의 현재 수직 위치를 기반으로 계산되며
|
||||||
|
/// [0, 1] 범위로 고정됩니다.</remarks>
|
||||||
|
public float CameraYRate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// 카메라 높이에 따라 0~1 사이의 값을 반환합니다.
|
||||||
|
return Mathf.Clamp01((transform.position.y - minCameraY) / (maxCameraY - minCameraY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Transform prevTransform; // 이전 카메라 거리
|
||||||
|
|
||||||
private Vector3 lastPanPosition;
|
private Vector3 lastPanPosition;
|
||||||
private Vector3 rotationPivot;
|
private Vector3 rotationPivot;
|
||||||
private bool isRotating = false;
|
private bool isRotating = false;
|
||||||
|
|
||||||
|
private Coroutine focusCoroutine; // 현재 실행 중인 포커싱 코루틴을 저장할 변수
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
// 스크립트 시작 시, 회전의 기준이 되는 중심점을 카메라 앞쪽으로 초기화합니다.
|
// 스크립트 시작 시, 회전의 기준이 되는 중심점을 카메라 앞쪽으로 초기화합니다.
|
||||||
rotationPivot = transform.position + transform.forward * 10f;
|
rotationPivot = transform.position + transform.forward * 10f;
|
||||||
|
this.prevTransform = transform; // 초기 카메라 위치 저장
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StopFocusCoroutine()
|
||||||
|
{
|
||||||
|
if (focusCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(focusCoroutine);
|
||||||
|
focusCoroutine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DispatchEvnet()
|
||||||
|
{
|
||||||
|
if (prevTransform != null && (prevTransform.position != transform.position || prevTransform.rotation != transform.rotation))
|
||||||
|
{
|
||||||
|
OnCameraChanged?.Invoke(transform);
|
||||||
|
if(prevTransform.position != transform.position)
|
||||||
|
{
|
||||||
|
OnCameraPositionChanged?.Invoke(transform.position);
|
||||||
|
}
|
||||||
|
if(prevTransform.rotation != transform.rotation)
|
||||||
|
{
|
||||||
|
OnCameraRotionChanged?.Invoke(transform.rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevTransform = transform; // 현재 카메라 위치 저장
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateCameraTransform()
|
||||||
|
{
|
||||||
|
// 카메라의 위치가 최소/최대 높이 범위를 벗어나지 않도록 합니다.
|
||||||
|
Vector3 currentPosition = transform.position;
|
||||||
|
currentPosition.y = Mathf.Clamp(currentPosition.y, minCameraY, maxCameraY);
|
||||||
|
transform.position = currentPosition;
|
||||||
|
ValidateCameraRotation();
|
||||||
|
|
||||||
|
// 카메라의 위치가 너무 멀리 떨어지지 않도록 합니다.
|
||||||
|
//float distance = Vector3.Distance(transform.position, rotationPivot);
|
||||||
|
//if (distance > 100f) // 예시로 100f를 최대 거리로 설정
|
||||||
|
//{
|
||||||
|
// transform.position = rotationPivot + (transform.position - rotationPivot).normalized * 100f;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateCameraRotation()
|
||||||
|
{
|
||||||
|
// 현재 회전값을 오일러 각으로 가져옵니다.
|
||||||
|
Vector3 eulerAngles = transform.eulerAngles;
|
||||||
|
// 오일러 각의 X축(Pitch) 값을 정규화하고 제한합니다.
|
||||||
|
// 각도가 180도를 넘어가면 음수 값으로 변환하여 처리합니다. (예: 350도 -> -10도)
|
||||||
|
float angleX = eulerAngles.x;
|
||||||
|
if (angleX > 180f) angleX -= 360f;
|
||||||
|
angleX = Mathf.Clamp(angleX, minPitch, maxPitch);
|
||||||
|
eulerAngles.x = angleX;
|
||||||
|
|
||||||
|
float angleY = eulerAngles.y;
|
||||||
|
if (angleY > 180f) angleY -= 360f;
|
||||||
|
angleY = Mathf.Clamp(angleY, minYaw, maxYaw);
|
||||||
|
eulerAngles.y = angleY;
|
||||||
|
|
||||||
|
// Z축 회전(롤)을 0으로 설정하여 카메라가 옆으로 기울어지는 것을 방지합니다.
|
||||||
|
eulerAngles.z = 0f;
|
||||||
|
|
||||||
|
// 수정된 오일러 각을 다시 쿼터니언으로 변환하여 적용합니다.
|
||||||
|
transform.rotation = Quaternion.Euler(eulerAngles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Quaternion ValidateRotation(Quaternion rotation)
|
||||||
|
{
|
||||||
|
// 현재 회전값을 오일러 각으로 가져옵니다.
|
||||||
|
Vector3 eulerAngles = rotation.eulerAngles;
|
||||||
|
// 오일러 각의 X축(Pitch) 값을 정규화하고 제한합니다.
|
||||||
|
// 각도가 180도를 넘어가면 음수 값으로 변환하여 처리합니다. (예: 350도 -> -10도)
|
||||||
|
float angleX = eulerAngles.x;
|
||||||
|
if (angleX > 180f) angleX -= 360f;
|
||||||
|
angleX = Mathf.Clamp(angleX, minPitch, maxPitch);
|
||||||
|
eulerAngles.x = angleX;
|
||||||
|
|
||||||
|
float angleY = eulerAngles.y;
|
||||||
|
if (angleY > 180f) angleY -= 360f;
|
||||||
|
angleY = Mathf.Clamp(angleY, minYaw, maxYaw);
|
||||||
|
eulerAngles.y = angleY;
|
||||||
|
|
||||||
|
// Z축 회전(롤)을 0으로 설정하여 카메라가 옆으로 기울어지는 것을 방지합니다.
|
||||||
|
eulerAngles.z = 0f;
|
||||||
|
|
||||||
|
// 수정된 오일러 각을 다시 쿼터니언으로 변환하여 적용합니다.
|
||||||
|
return Quaternion.Euler(eulerAngles);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Update 대신 LateUpdate를 사용하여 카메라 움직임이 다른 모든 업데이트 이후에 처리되도록 합니다.
|
// Update 대신 LateUpdate를 사용하여 카메라 움직임이 다른 모든 업데이트 이후에 처리되도록 합니다.
|
||||||
// 이를 통해 카메라의 떨림이나 끊김 현상을 줄일 수 있습니다.
|
// 이를 통해 카메라의 떨림이나 끊김 현상을 줄일 수 있습니다.
|
||||||
void LateUpdate()
|
void LateUpdate()
|
||||||
@@ -53,6 +209,7 @@ namespace UVC.Util
|
|||||||
{
|
{
|
||||||
if (Input.GetMouseButtonDown(2))
|
if (Input.GetMouseButtonDown(2))
|
||||||
{
|
{
|
||||||
|
StopFocusCoroutine();
|
||||||
lastPanPosition = Input.mousePosition;
|
lastPanPosition = Input.mousePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +223,16 @@ namespace UVC.Util
|
|||||||
delta = delta.normalized * maxPanDelta;
|
delta = delta.normalized * maxPanDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 높이에 따라 동적으로 패닝 속도 결정.
|
||||||
|
float currentPanSpeed = Mathf.Lerp(lowAltitudePanSpeed, highAltitudePanSpeed, CameraYRate); // 현재 카메라 높이에 따라 패닝 속도를 보간합니다.
|
||||||
// 카메라의 로컬 좌표계를 기준으로 이동량을 변환하여 월드 좌표계에서 이동시킵니다.
|
// 카메라의 로컬 좌표계를 기준으로 이동량을 변환하여 월드 좌표계에서 이동시킵니다.
|
||||||
transform.Translate(transform.right * -delta.x * panSpeed * Time.deltaTime, Space.World);
|
transform.Translate(transform.right * -delta.x * currentPanSpeed * Time.deltaTime, Space.World);
|
||||||
transform.Translate(transform.up * -delta.y * panSpeed * Time.deltaTime, Space.World);
|
transform.Translate(transform.up * -delta.y * currentPanSpeed * Time.deltaTime, Space.World);
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
lastPanPosition = Input.mousePosition;
|
lastPanPosition = Input.mousePosition;
|
||||||
|
DispatchEvnet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +244,7 @@ namespace UVC.Util
|
|||||||
{
|
{
|
||||||
if (Input.GetMouseButtonDown(1))
|
if (Input.GetMouseButtonDown(1))
|
||||||
{
|
{
|
||||||
|
StopFocusCoroutine();
|
||||||
isRotating = true;
|
isRotating = true;
|
||||||
// 마우스 클릭 지점으로 Ray를 쏴서 회전의 중심점(pivot)을 설정합니다.
|
// 마우스 클릭 지점으로 Ray를 쏴서 회전의 중심점(pivot)을 설정합니다.
|
||||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||||
@@ -106,6 +269,21 @@ namespace UVC.Util
|
|||||||
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime;
|
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime;
|
||||||
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed * Time.deltaTime;
|
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed * Time.deltaTime;
|
||||||
|
|
||||||
|
// 현재 X축 회전 각도를 가져와서 -180 ~ 180 범위로 정규화합니다.
|
||||||
|
float currentPitch = transform.eulerAngles.x;
|
||||||
|
if (currentPitch > 180f) currentPitch -= 360f;
|
||||||
|
|
||||||
|
// 현재 Y축 회전 각도를 가져와서 -180 ~ 180 범위로 정규화합니다.
|
||||||
|
float currentYaw = transform.eulerAngles.y;
|
||||||
|
if (currentYaw > 180f) currentYaw -= 360f;
|
||||||
|
|
||||||
|
// 마우스 입력으로 인해 Pitch 또는 Yaw 각도가 한계를 벗어나는지 확인합니다.
|
||||||
|
if ((mouseY > 0 && currentPitch >= maxPitch) || (mouseY < 0 && currentPitch <= minPitch)
|
||||||
|
|| (mouseX < 0 && currentYaw >= maxYaw) || (mouseX > 0 && currentYaw <= minYaw))
|
||||||
|
{
|
||||||
|
return; // 한계를 넘어서는 회전은 막습니다.
|
||||||
|
}
|
||||||
|
|
||||||
// 수평 회전으로 인해 수직 회전 축(transform.right)이 변질되는 것을 방지하기 위해
|
// 수평 회전으로 인해 수직 회전 축(transform.right)이 변질되는 것을 방지하기 위해
|
||||||
// 회전 전의 right 벡터를 미리 저장해 둡니다.
|
// 회전 전의 right 벡터를 미리 저장해 둡니다.
|
||||||
Vector3 verticalRotationAxis = transform.right;
|
Vector3 verticalRotationAxis = transform.right;
|
||||||
@@ -115,6 +293,10 @@ namespace UVC.Util
|
|||||||
transform.RotateAround(rotationPivot, Vector3.up, -mouseX);
|
transform.RotateAround(rotationPivot, Vector3.up, -mouseX);
|
||||||
// 2. 수직 회전 (미리 저장해 둔 카메라의 오른쪽 축 기준)
|
// 2. 수직 회전 (미리 저장해 둔 카메라의 오른쪽 축 기준)
|
||||||
transform.RotateAround(rotationPivot, verticalRotationAxis, mouseY);
|
transform.RotateAround(rotationPivot, verticalRotationAxis, mouseY);
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
|
DispatchEvnet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +308,11 @@ namespace UVC.Util
|
|||||||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||||||
if (scroll != 0f)
|
if (scroll != 0f)
|
||||||
{
|
{
|
||||||
|
// 현재 X축 회전 각도를 확인하여 한계 범위 밖이면 줌을 막습니다.
|
||||||
|
float currentPitch = transform.eulerAngles.x;
|
||||||
|
if (currentPitch > 180f) currentPitch -= 360f;
|
||||||
|
if (currentPitch < minPitch || currentPitch > maxPitch) return;
|
||||||
|
|
||||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||||
Vector3 zoomTarget;
|
Vector3 zoomTarget;
|
||||||
|
|
||||||
@@ -139,9 +326,22 @@ namespace UVC.Util
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector3 direction = zoomTarget - transform.position;
|
Vector3 direction = zoomTarget - transform.position;
|
||||||
|
Vector3 moveVector = direction.normalized * scroll * zoomSpeed;
|
||||||
|
|
||||||
|
// 카메라가 아래로 움직이려 하고(moveVector.y < 0), 이미 최소 높이에 도달했다면 중단합니다.
|
||||||
|
if (moveVector.y < 0 && transform.position.y <= minCameraY) return;
|
||||||
|
|
||||||
|
// 카메라가 위로 움직이려 하고(moveVector.y > 0), 이미 최대 높이에 도달했다면 중단합니다.
|
||||||
|
if (moveVector.y > 0 && transform.position.y >= maxCameraY) return;
|
||||||
|
|
||||||
|
StopFocusCoroutine();
|
||||||
|
|
||||||
// 줌 실행
|
// 줌 실행
|
||||||
transform.position += direction.normalized * scroll * zoomSpeed;
|
transform.position += direction.normalized * scroll * zoomSpeed;
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
|
DispatchEvnet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,15 +349,25 @@ namespace UVC.Util
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 지정된 Transform을 중심으로 카메라를 포커싱합니다.
|
/// 지정된 Transform을 중심으로 카메라를 포커싱합니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="equipmentTransform">포커스할 대상의 Transform</param>
|
/// <param name="equipmentPosition">포커스할 대상의 Transform</param>
|
||||||
/// <param name="distance">대상과의 거리</param>
|
/// <param name="distance">대상과의 거리</param>
|
||||||
public void FocusOnTargetFast(Transform equipmentTransform, float distance)
|
public void FocusOnTargetFast(Vector3 equipmentPosition, float distance)
|
||||||
{
|
{
|
||||||
if (equipmentTransform == null)
|
if (equipmentPosition == null) return;
|
||||||
return;
|
|
||||||
|
Vector3 position = equipmentPosition;
|
||||||
|
if (position.y < minCameraY)
|
||||||
|
{
|
||||||
|
position.y = minCameraY; // 최소 높이 제한
|
||||||
|
}
|
||||||
|
else if (position.y > maxCameraY)
|
||||||
|
{
|
||||||
|
position.y = maxCameraY; // 최대 높이 제한
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 카메라가 바라볼 대상의 중심점
|
// 카메라가 바라볼 대상의 중심점
|
||||||
Vector3 targetPosition = equipmentTransform.position;
|
Vector3 targetPosition = equipmentPosition;
|
||||||
|
|
||||||
// 현재 카메라의 회전각을 유지하면서 타겟을 바라보는 방향 설정
|
// 현재 카메라의 회전각을 유지하면서 타겟을 바라보는 방향 설정
|
||||||
Vector3 directionToTarget = (targetPosition - transform.position).normalized;
|
Vector3 directionToTarget = (targetPosition - transform.position).normalized;
|
||||||
@@ -171,30 +381,67 @@ namespace UVC.Util
|
|||||||
|
|
||||||
// 회전 피봇 포인트 업데이트
|
// 회전 피봇 포인트 업데이트
|
||||||
rotationPivot = targetPosition;
|
rotationPivot = targetPosition;
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
|
DispatchEvnet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 지정된 Transform을 중심으로 카메라를 포커싱합니다.
|
/// 지정된 Transform을 중심으로 카메라를 포커싱합니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="equipmentTransform">포커스할 대상의 Transform</param>
|
/// <param name="equipmentPosition">포커스할 대상의 Transform</param>
|
||||||
/// <param name="distance">대상과의 거리</param>
|
/// <param name="distance">대상과의 거리</param>
|
||||||
/// <param name="duration">이동에 걸리는 시간(초), 기본값 1초</param>
|
/// <param name="duration">이동에 걸리는 시간(초), 기본값 1초</param>
|
||||||
public void FocusOnTarget(Transform equipmentTransform, float distance, float duration = 1.0f)
|
public void FocusOnTarget(Vector3 equipmentPosition, float distance, float duration = 1.0f)
|
||||||
{
|
{
|
||||||
if (equipmentTransform == null)
|
if (equipmentPosition == null) return;
|
||||||
return;
|
|
||||||
|
StopFocusCoroutine();
|
||||||
|
|
||||||
|
Vector3 position = equipmentPosition;
|
||||||
|
if(position.y < minCameraY)
|
||||||
|
{
|
||||||
|
position.y = minCameraY; // 최소 높이 제한
|
||||||
|
}
|
||||||
|
else if(position.y > maxCameraY)
|
||||||
|
{
|
||||||
|
position.y = maxCameraY; // 최대 높이 제한
|
||||||
|
}
|
||||||
|
|
||||||
// 코루틴을 사용하여 부드러운 이동 구현
|
// 코루틴을 사용하여 부드러운 이동 구현
|
||||||
StartCoroutine(SmoothFocusOnTarget(equipmentTransform, distance, duration));
|
focusCoroutine = StartCoroutine(SmoothFocusOnTarget(position, distance, duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 카메라를 앞쪽 방향으로 지정된 거리만큼 바깥쪽으로 부드럽게 이동합니다.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>이 메서드는 코루틴을 사용하여 카메라의 위치를 앞쪽 방향으로 바깥쪽으로 부드럽게 전환합니다.
|
||||||
|
/// 전환은 지정된 시간 동안 수행되므로
|
||||||
|
/// 시각적으로 부드러운 움직임을 구현할 수 있습니다.</remarks>
|
||||||
|
/// <param name="distance">카메라를 현재 위치에서 바깥쪽으로 이동할 거리(단위)입니다.</param>
|
||||||
|
/// <param name="duration">카메라 전환이 발생하는 시간(초)입니다. 기본값은 1.0초입니다.</param>
|
||||||
|
public void FocusOut(float distance, float duration = 1.0f)
|
||||||
|
{
|
||||||
|
|
||||||
|
StopFocusCoroutine();
|
||||||
|
|
||||||
|
// 현재 카메라 위치와 회전값을 저장
|
||||||
|
Vector3 startPosition = transform.position;
|
||||||
|
Quaternion startRotation = transform.rotation;
|
||||||
|
// 카메라가 바라보는 방향으로 지정된 거리만큼 이동
|
||||||
|
Vector3 targetPosition = transform.position + transform.forward * distance;
|
||||||
|
// 코루틴을 사용하여 부드러운 이동 구현
|
||||||
|
focusCoroutine = StartCoroutine(SmoothFocusOnTarget(targetPosition, distance, duration));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 부드럽게 타겟까지 이동하는 코루틴
|
/// 부드럽게 타겟까지 이동하는 코루틴
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerator SmoothFocusOnTarget(Transform targetTransform, float distance, float duration)
|
private IEnumerator SmoothFocusOnTarget(Vector3 targetTransform, float distance, float duration)
|
||||||
{
|
{
|
||||||
// 카메라가 바라볼 대상의 중심점
|
// 카메라가 바라볼 대상의 중심점
|
||||||
Vector3 targetPosition = targetTransform.position;
|
Vector3 targetPosition = targetTransform;
|
||||||
|
|
||||||
// 시작 위치와 회전 저장
|
// 시작 위치와 회전 저장
|
||||||
Vector3 startPosition = transform.position;
|
Vector3 startPosition = transform.position;
|
||||||
@@ -206,7 +453,8 @@ namespace UVC.Util
|
|||||||
|
|
||||||
// 최종 회전값 계산
|
// 최종 회전값 계산
|
||||||
Quaternion endRotation = Quaternion.LookRotation(targetPosition - endPosition);
|
Quaternion endRotation = Quaternion.LookRotation(targetPosition - endPosition);
|
||||||
|
endRotation = ValidateRotation(endRotation); // 회전값 검증 및 수정
|
||||||
|
|
||||||
// 이동 시간 계산을 위한 변수
|
// 이동 시간 계산을 위한 변수
|
||||||
float elapsedTime = 0f;
|
float elapsedTime = 0f;
|
||||||
|
|
||||||
@@ -221,7 +469,9 @@ namespace UVC.Util
|
|||||||
// 위치와 회전 보간
|
// 위치와 회전 보간
|
||||||
transform.position = Vector3.Lerp(startPosition, endPosition, smoothT);
|
transform.position = Vector3.Lerp(startPosition, endPosition, smoothT);
|
||||||
transform.rotation = Quaternion.Slerp(startRotation, endRotation, smoothT);
|
transform.rotation = Quaternion.Slerp(startRotation, endRotation, smoothT);
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +481,11 @@ namespace UVC.Util
|
|||||||
|
|
||||||
// 회전 피봇 포인트 업데이트
|
// 회전 피봇 포인트 업데이트
|
||||||
rotationPivot = targetPosition;
|
rotationPivot = targetPosition;
|
||||||
|
|
||||||
|
ValidateCameraTransform();
|
||||||
|
|
||||||
|
DispatchEvnet();
|
||||||
|
focusCoroutine = null; // 코루틴 완료 후 참조를 null로 설정
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -240,5 +495,9 @@ namespace UVC.Util
|
|||||||
{
|
{
|
||||||
return t < 0.5f ? 4f * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 3f) / 2f;
|
return t < 0.5f ? 4f * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 3f) / 2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user