<feat> 위치 기록/수정/삭제

This commit is contained in:
SOOBEEN HAN
2025-11-06 20:14:27 +09:00
parent 033c6aeb8e
commit 74759b0ab5
24 changed files with 1385 additions and 380 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,143 @@
fileFormatVersion: 2
guid: 58038730b59dfc24bb195ff132bdd86b
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
- serializedVersion: 4
buildTarget: Android
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: WebGL
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

@@ -0,0 +1,140 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-7696615017582644767
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 9
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Mat_DragArrow
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: 3000
stringTagMap:
RenderType: Transparent
disabledShaderPasses:
- MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: 58038730b59dfc24bb195ff132bdd86b, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: 58038730b59dfc24bb195ff132bdd86b, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _DstBlendAlpha: 10
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 1
- _WorkflowMode: 1
- _ZWrite: 0
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 81b86ca076823e74fa6b1c367fdff1f0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,140 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-3855023207109352299
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 9
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Mat_Point
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: 3000
stringTagMap:
RenderType: Transparent
disabledShaderPasses:
- MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: a4e764ee05645514cab2cf0636654f5f, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: a4e764ee05645514cab2cf0636654f5f, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _DstBlendAlpha: 10
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 1
- _WorkflowMode: 1
- _ZWrite: 0
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 13a14a11293de9c4eb213d3f48bdeb21
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,143 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1305858504090351929
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2076029217436850817}
- component: {fileID: 1759525944991434243}
- component: {fileID: 3220026462657737159}
- component: {fileID: 2451538350324562745}
m_Layer: 0
m_Name: Quad
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2076029217436850817
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1305858504090351929}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 9195381025740825694}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &1759525944991434243
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1305858504090351929}
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &3220026462657737159
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1305858504090351929}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 81b86ca076823e74fa6b1c367fdff1f0, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!64 &2451538350324562745
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1305858504090351929}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 5
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!1 &9153036347640126610
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 9195381025740825694}
m_Layer: 0
m_Name: DragArrowPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!4 &9195381025740825694
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9153036347640126610}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 1.3460997, y: 1.245627, z: 4.6605406}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2076029217436850817}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3e14dc8ccaa006641934bf740bd1e88d
guid: 473e683afc015324ca5689bd27431027
PrefabImporter:
externalObjects: {}
userData:

View File

@@ -0,0 +1,265 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5391214215580958641
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7494286506634392216}
- component: {fileID: 5864829304368456199}
- component: {fileID: 4296824683502170198}
- component: {fileID: 5452343286867456252}
m_Layer: 0
m_Name: PointPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7494286506634392216
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5391214215580958641}
serializedVersion: 2
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:
- {fileID: 5018448860695903102}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!135 &5864829304368456199
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5391214215580958641}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.1
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &4296824683502170198
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5391214215580958641}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8a35f6cfbfba9b548aaa00d52cfe8a50, type: 3}
m_Name:
m_EditorClassIdentifier:
m_InteractionManager: {fileID: 0}
m_Colliders: []
m_InteractionLayers:
m_Bits: 1
m_DistanceCalculationMode: 1
m_SelectMode: 0
m_FocusMode: 1
m_CustomReticle: {fileID: 0}
m_AllowGazeInteraction: 0
m_AllowGazeSelect: 0
m_OverrideGazeTimeToSelect: 0
m_GazeTimeToSelect: 0.5
m_OverrideTimeToAutoDeselectGaze: 0
m_TimeToAutoDeselectGaze: 3
m_AllowGazeAssistance: 0
m_FirstHoverEntered:
m_PersistentCalls:
m_Calls: []
m_LastHoverExited:
m_PersistentCalls:
m_Calls: []
m_HoverEntered:
m_PersistentCalls:
m_Calls: []
m_HoverExited:
m_PersistentCalls:
m_Calls: []
m_FirstSelectEntered:
m_PersistentCalls:
m_Calls: []
m_LastSelectExited:
m_PersistentCalls:
m_Calls: []
m_SelectEntered:
m_PersistentCalls:
m_Calls: []
m_SelectExited:
m_PersistentCalls:
m_Calls: []
m_FirstFocusEntered:
m_PersistentCalls:
m_Calls: []
m_LastFocusExited:
m_PersistentCalls:
m_Calls: []
m_FocusEntered:
m_PersistentCalls:
m_Calls: []
m_FocusExited:
m_PersistentCalls:
m_Calls: []
m_Activated:
m_PersistentCalls:
m_Calls: []
m_Deactivated:
m_PersistentCalls:
m_Calls: []
m_StartingHoverFilters: []
m_StartingSelectFilters: []
m_StartingInteractionStrengthFilters: []
--- !u!114 &5452343286867456252
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5391214215580958641}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9b277895d391194691ecc18b3d442eb, type: 3}
m_Name:
m_EditorClassIdentifier:
pointIndex: -1
--- !u!1 &6319663465530813072
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5018448860695903102}
- component: {fileID: 2983163464765215243}
- component: {fileID: 5578951176610209169}
- component: {fileID: 5115545832972059210}
- component: {fileID: 4616617542146043255}
m_Layer: 0
m_Name: Quad
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5018448860695903102
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6319663465530813072}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.1, y: 0.1, z: 0.1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7494286506634392216}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &2983163464765215243
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6319663465530813072}
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &5578951176610209169
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6319663465530813072}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 13a14a11293de9c4eb213d3f48bdeb21, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!64 &5115545832972059210
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6319663465530813072}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 5
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!114 &4616617542146043255
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6319663465530813072}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a171ec05977edf345860bff884fab151, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bb50b26301943754e8d5e7a7b3e24085
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,77 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &280273810869499429
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 23272902704394604}
- component: {fileID: 8410384716740639099}
- component: {fileID: 7782236473570627370}
m_Layer: 5
m_Name: Point_Prefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &23272902704394604
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 280273810869499429}
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: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0.2, y: 0.3}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8410384716740639099
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 280273810869499429}
m_CullTransparentMesh: 1
--- !u!114 &7782236473570627370
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 280273810869499429}
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: 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_Sprite: {fileID: 21300000, guid: a4e764ee05645514cab2cf0636654f5f, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1

View File

@@ -0,0 +1,25 @@
using UnityEngine;
/// <summary>
/// 이 스크립트가 붙어있는 GameObject(Quad)가
/// 항상 메인 카메라를 바라보도록 만드는 클래스
/// </summary>
public class Billboard : MonoBehaviour
{
private Camera mainCamera;
void Start()
{
mainCamera = Camera.main;
}
void LateUpdate()
{
if (mainCamera == null)
return;
transform.rotation = mainCamera.transform.rotation;
// transform.Rotate(0, 180, 0);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a171ec05977edf345860bff884fab151

View File

@@ -39,6 +39,7 @@ public class ProgramModel : IProgramModel
public bool IsMoving;
public bool isError;
private Vector3 startMovementPosition;
private int currentToolNum = 0;
public ProgramModel(string hostip, int tcpPort, int udpPort, RobotController robotController)
{
@@ -61,7 +62,17 @@ public class ProgramModel : IProgramModel
hasNewData = false;
IsMoving = false;
isError = false;
try
{
currentToolNum = await GetRobotToolNum();
}
catch (Exception e)
{
Debug.LogWarning($"현재 툴 번호를 가져오는 데 실패했습니다: {e.Message}. 기본값(0)을 사용합니다.");
currentToolNum = 1;
}
return;
}
@@ -302,33 +313,65 @@ public class ProgramModel : IProgramModel
return false;
}
// 전송 객체 생성
var payload = new
{
programId = CurrentProgram.ProgramId,
indexToUpdate = index, // -1이면 새 포인트, 0 이상이면 해당 인덱스 수정
pose = pointData
};
string jsonPayload = JsonConvert.SerializeObject(payload);
HttpContent content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string requestUri = (index == -1)
? $"{tcpBaseUrl}/project/jobs/{CurrentProgram.ProgramId}/ins_cmd_line"
: $"{tcpBaseUrl}/project/jobs/{CurrentProgram.ProgramId}/pose_modify";
string jsonPayload;
string requestUri;
HttpContent content;
object payload;
try
{
if (index == -1)
{
// sno_ref = 마지막 스텝의 번호, 없으면 0
int sno_ref = (CurrentProgram.Steps.Count > 0) ? CurrentProgram.Steps.Last().StepNumber : 0;
payload = new
{
adjust_branch = true,
cmd_line = $"move P,spd=50%,accu=3,tool={currentToolNum}",
fno_ref = -1,
mechinfo = -1,
move_cursor = 1,
ofs = 0,
save_file = true,
set_cur_pose = -1,
sno_ref = sno_ref
};
requestUri = $"{tcpBaseUrl}/project/jobs/{CurrentProgram.ProgramId}/ins_cmd_line";
}
else
{
// sno = 수정할 스텝의 번호
int sno = CurrentProgram.Steps[index].StepNumber;
payload = new
{
mechinfo = -1,
save_file = true,
sno = sno
};
requestUri = $"{tcpBaseUrl}/project/jobs/{CurrentProgram.ProgramId}/pose_modify";
}
jsonPayload = JsonConvert.SerializeObject(payload);
content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
HttpResponseMessage result = await httpClient.PostAsync(requestUri, content);
if (result.IsSuccessStatusCode)
{
// 서버 저장이 성공하면, 메모리(CurrentProgram)에도 반영
// 서버 저장이 성공하면, 로컬 캐시에도 반영
if (index == -1)
CurrentProgram.AddStep(pointData); // RobotProgram에 새 RobotMoveStep 추가
CurrentProgram.AddStep(pointData, currentToolNum); // 로컬 캐시에 추가
else
CurrentProgram.UpdateStep(index, pointData); // RobotProgram의 해당 스텝 갱신
CurrentProgram.UpdateStep(index, pointData); // 로컬 캐시 수정
return true;
}
Debug.LogError($"SavePointToProgramAsync 실패: {await result.Content.ReadAsStringAsync()}");
return false;
}
catch (Exception e)
@@ -341,9 +384,23 @@ public class ProgramModel : IProgramModel
// 서버에 포인트 삭제 요청
public async Task<bool> DeletePointFromProgramAsync(int index)
{
if (CurrentProgram == null) return false;
if (CurrentProgram == null || index < 0 || index >= CurrentProgram.Steps.Count)
{
Debug.LogError($"DeletePointFromProgramAsync: 잘못된 인덱스 {index}");
return false;
}
var payload = new { programId = CurrentProgram.ProgramId, indexToDelete = index };
// sno_ref = 삭제할 스텝의 번호 (0-based index가 아님)
int sno_ref = CurrentProgram.Steps[index].StepNumber;
var payload = new
{
adjust_branch = true,
fno_ref = 0,
ofs = 0,
save_file = true,
sno_ref = sno_ref
};
string jsonPayload = JsonConvert.SerializeObject(payload);
HttpContent content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
@@ -354,10 +411,12 @@ public class ProgramModel : IProgramModel
HttpResponseMessage result = await httpClient.PostAsync(requestUri, content);
if (result.IsSuccessStatusCode)
{
// 서버 삭제 성공 시, 메모리에서도 삭제
// 서버 삭제 성공 시, 로컬 캐시에서도 삭제 및 재정렬
CurrentProgram.DeleteStep(index);
return true;
}
Debug.LogError($"DeletePointFromProgramAsync 실패: {await result.Content.ReadAsStringAsync()}");
return false;
}
catch (Exception e)

View File

@@ -1,3 +1,4 @@
using System.Text.RegularExpressions;
using UnityEngine;
public class RobotMoveStep
@@ -5,18 +6,73 @@ public class RobotMoveStep
public string FullLine { get; private set; }
public RobotPose Pose { get; private set; }
public int StepNumber { get; private set; }
/// <summary>
/// 좌표를 제외한 이동 명령 (예: "move P,spd=50%,accu=3,tool=1")
/// </summary>
public string MoveCommand { get; private set; }
// Regex로 S<번호>와 move <명령> [좌표]를 분리
// 그룹 1: (S([0-9]+)) -> "S1", "1"
// 그룹 3: (move.*?) -> "move P,spd=50%,accu=3,tool=1"
private static readonly Regex StepRegex = new Regex(@"^(S([0-9]+))\s+(move.*?)(\s+\[.*\])", RegexOptions.Compiled);
public RobotMoveStep(string line, string coordString)
{
this.FullLine = line;
string[] values = coordString.Split(',');
if (values.Length == 6)
if (values.Length >= 6)
{
this.Pose = new RobotPose(
float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]),
float.Parse(values[3]), float.Parse(values[4]), float.Parse(values[5])
);
}
else
{
Debug.LogError($"좌표 파싱 실패: {coordString}");
this.Pose = new RobotPose(0, 0, 0, 0, 0, 0);
}
Match match = StepRegex.Match(line);
if (match.Success)
{
this.StepNumber = int.Parse(match.Groups[2].Value);
this.MoveCommand = match.Groups[3].Value.Trim();
}
else
{
Debug.LogError($"스텝 라인 파싱 실패: {line}");
this.StepNumber = -1;
this.MoveCommand = "move P,spd=50%,accu=3,tool=0"; // 기본값
}
}
/// <summary>
/// DeleteStep 시, S<번호>를 업데이트하기 위한 헬퍼 함수
/// </summary>
public void UpdateStepNumber(int newStepNumber, string newMoveCommand = null)
{
this.StepNumber = newStepNumber;
if (newMoveCommand != null)
{
this.MoveCommand = newMoveCommand;
}
// FullLine을 새 번호와 Pose로 다시 조립
this.FullLine = $"S{this.StepNumber} {this.MoveCommand} {this.Pose.ToString()}";
}
/// <summary>
/// UpdateStep 시, Pose를 업데이트하기 위한 헬퍼 함수
/// </summary>
public void UpdatePose(RobotPose newPose)
{
this.Pose = newPose;
// FullLine을 새 Pose로 다시 조립
this.FullLine = $"S{this.StepNumber} {this.MoveCommand} {this.Pose.ToString()}";
}
}
@@ -28,4 +84,37 @@ public class RobotPose
this.x = x; this.y = y; this.z = z;
this.rx = rx; this.ry = ry; this.rz = rz;
}
/// <summary>
/// RobotData(Model)를 RobotPose(Program)로 변환
/// </summary>
public RobotPose(RobotData data)
{
this.x = data.x; this.y = data.y; this.z = data.z;
this.rx = data.rx; this.ry = data.ry; this.rz = data.rz;
}
/// <summary>
/// RobotPose(Program)를 RobotData(Model)로 변환
/// </summary>
public RobotData ToRobotData()
{
return new RobotData
{
x = this.x,
y = this.y,
z = this.z,
rx = this.rx,
ry = this.ry,
rz = this.rz
};
}
/// <summary>
/// API에서 요구하는 좌표 문자열 형식으로 변환
/// </summary>
public override string ToString()
{
return $"[{x},{y},{z},{rx},{ry},{rz},\"robot\"]";
}
}

View File

@@ -1,10 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System;
using UnityEngine;
public class RobotProgram
{
public string ProgramId { get; private set; }
public string Version { get; private set; }
public string MechType { get; private set; }
public List<RobotMoveStep> Steps { get; private set; }
public RobotProgram(string programId, string rawTextContent)
@@ -15,24 +16,27 @@ public class RobotProgram
ParseJobContent(rawTextContent);
}
/// <summary>
/// GET 응답(rawText)을 파싱하여 Steps 리스트를 채움
/// </summary>
private void ParseJobContent(string rawText)
{
// 헤더 파싱 (예: "Robot Job File; { version: 2.0, ... }")
// 정규식이나 Substring을 사용해 version, mech_type 등 추출
string[] lines = rawText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
// 스텝(S1, S2...) 파싱
string[] lines = rawText.Split('\n');
foreach (string line in lines)
{
if (line.StartsWith("S")) // (S1, S2... 같은 라인)
// S<번호>로 시작하고, [좌표]를 포함하는 라인만 파싱
if (line.StartsWith("S") && line.Contains("["))
{
string coordString = ExtractCoordinates(line);
// 좌표 문자열을 실제 Pose 데이터로 변환
RobotMoveStep step = new RobotMoveStep(line, coordString);
Steps.Add(step);
if (!string.IsNullOrEmpty(coordString))
{
Steps.Add(new RobotMoveStep(line, coordString));
}
}
}
Debug.Log($"프로그램 '{ProgramId}' 로드 완료. {Steps.Count}개의 스텝 파싱됨.");
}
private string ExtractCoordinates(string line)
@@ -41,34 +45,79 @@ public class RobotProgram
int end = line.IndexOf(']');
if (start != -1 && end != -1)
{
return line.Substring(start + 1, end - start - 1);
return line.Substring(start + 1, end - start -1);
}
return string.Empty;
}
public void AddStep(RobotData data)
/// <summary>
/// 새 포인트 로컬 캐시에 추가
/// </summary>
public void AddStep(RobotData data, int toolNum)
{
int newStepNum = (Steps.Count > 0) ? Steps.Last().StepNumber + 1 : 1;
string cmd = $"move P,spd=50%,accu=3,tool={toolNum}";
RobotPose newPose = new RobotPose(data);
string line = $"S{newStepNum} {cmd} {newPose.ToString()}";
Steps.Add(new RobotMoveStep(line, ExtractCoordinates(line)));
}
/// <summary>
/// 기존 포인트의 Pose 로컬 캐시에서 수정
/// </summary>
public void UpdateStep(int index, RobotData data)
{
if (index < 0 || index >= Steps.Count)
{
Debug.LogError($"UpdateStep: 잘못된 인덱스 {index}");
return;
}
Steps[index].UpdatePose(new RobotPose(data));
}
/// <summary>
/// 포인트를 로컬 캐시에서 삭제하고 S<번호> 재정렬
/// </summary>
public void DeleteStep(int index)
{
if (index < 0 || index >= Steps.Count)
{
Debug.LogError($"DeleteStep: 잘못된 인덱스 {index}");
return;
}
Steps.RemoveAt(index);
// 스텝 번호 재정렬 (S1, S2, S3...)
for (int i = 0; i < Steps.Count; i++)
{
// MoveCommand는 그대로 유지
Steps[i].UpdateStepNumber(i + 1);
}
}
/// <summary>
/// 특정 인덱스의 Pose를 RobotData로 반환
/// </summary>
public RobotData GetStepPose(int index)
{
RobotData data = null;
return data;
if (index < 0 || index >= Steps.Count)
{
Debug.LogError($"GetStepPose: 잘못된 인덱스 {index}");
return new RobotData(); // 빈 데이터 반환
}
return Steps[index].Pose.ToRobotData();
}
public void GetAllStepPoses()
/// <summary>
/// 모든 Pose를 List<RobotData>로 반환
/// </summary>
public List<RobotData> GetAllStepPoses()
{
return Steps.Select(step => step.Pose.ToRobotData()).ToList();
}
}

View File

@@ -40,6 +40,7 @@ public class ProgramPresenter
private CancellationTokenSource dragLoopCts;
private RobotData latestTargetPose; // 뷰가 갱신할 최신 목표 지점
private bool IsDragging = false;
private RobotData originalDragPose; // 취소 시 돌아갈 원본 위치
public ProgramPresenter(ProgramModel model, ProgramView view, TCPView tcpView,
InteractionView interactionView, PointManagerView pmView, PopupView popView, PathLineView pathLineView)
@@ -77,29 +78,6 @@ public class ProgramPresenter
popPos = controlledRobot.GetEndPoint();
}
//void Update()
//{
// if (isDragging && currentInteractor != null)
// {
// communicationScript.isMoving = false;
// // 1) Ray Interactor: 현재 3D Raycast 히트 포인트가 있으면 그대로 사용
// if (currentInteractor is XRRayInteractor ray &&
// ray.TryGetCurrent3DRaycastHit(out RaycastHit hit))
// {
// dragPosition = hit.point;
// }
// else
// {
// // 2) Direct Interactor 또는 Ray 히트가 없을 때: 컨트롤러(또는 attachTransform) 위치 사용
// var t = currentInteractor.transform;
// var attach = currentInteractor.GetAttachTransform(null);
// dragPosition = attach != null ? attach.position : t.position;
// }
// uiController?.UpdateCoordinates(dragPosition); // 기존 UI 갱신 유지 :contentReference[oaicite:2]{index=2}
// }
//}
public async Task UpdateMotorStateAsync()
{
try
@@ -164,6 +142,7 @@ public class ProgramPresenter
view.HideProgramList();
OnApplicationStart();
RedrawSceneFromModel(); // 뷰 갱신
_programId = null;
}
@@ -221,13 +200,16 @@ public class ProgramPresenter
return targetPose;
}
private Vector3 ConvertRobotDataToVector3(RobotData pose)
{
float x = Convert.ToSingle(pose.x / -1000.0);
float y = Convert.ToSingle(pose.z / 1000.0);
float z = Convert.ToSingle(pose.y / -1000.0);
return new Vector3(x, y, z);
}
private async void HandleRobotGrabbed(Vector3 newWorldPos, Quaternion newWorldRot)
{
//if (!IsDragging) return;
//this.latestTargetPose = ConvertPoseToRobotData(newWorldPos, newWorldRot);
//await model.MoveToPoseTcpAsync(newWorldPos);
try
{
if (!IsDragging)
@@ -250,8 +232,6 @@ public class ProgramPresenter
private void HandleRobotReleased(RobotData pose)
{
IsDragging = false;
StopDragMoveLoop();
controlledRobot.DisableIK();
pendingPointData = pose; // 임시 저장
currentPopupState = PopupState.ConfirmAddPoint; // 상태 설정
popupView.ShowConfirmPopup(popPos); // 팝업 요청
@@ -273,48 +253,44 @@ public class ProgramPresenter
}
// --- 포인트 드래그 ---
private RobotData originalDragPose; // 취소 시 돌아갈 원본 위치
private void HandlePointDragStart(int index)
{
IsDragging = true;
activePointIndex = index;
if (index > -1) // (포인트를 잡았을 때)
if (index > -1) // 포인트를 잡았을 때
{
originalDragPose = model.CurrentProgram.GetStepPose(index);
interactionView.ShowGhostRobot(originalDragPose);
Vector3 startPos = interactionView.GetCurrentRayPosition();
interactionView.ShowDragArrow(startPos);
interactionView.ShowGhostRobot();
// 반투명 로봇의 위치를 마우스 위치와 같도록 설정
pointManagerView.kinematicsNode.targetTransform.localPosition = startPos;
}
}
private async void HandlePointDragUpdate(int index, Vector3 newWorldPos, Quaternion newWorldRot)
private void HandlePointDragUpdate(int index, Vector3 newWorldPos, Quaternion newWorldRot)
{
if (!IsDragging) return;
RobotData newPose = ConvertPoseToRobotData(newWorldPos, newWorldRot);
await model.MoveToPoseTcpAsync(newWorldPos);
this.latestTargetPose = ConvertPoseToRobotData(newWorldPos, newWorldRot);
interactionView.ShowDragArrow(newWorldPos); // 마우스 이미지 변경
// 고스트 로봇, 포인트, 경로 실시간 이동
interactionView.ShowGhostRobot(newPose);
pointManagerView.UpdatePointPosition(index, newPose);
//pathLineView.DrawPath(GetFullPathOfProgramWithTempChange(index, newPose)); // 임시 경로 그리기
//await model.StreamPoseUdpAsync(newPose);
pointManagerView.kinematicsNode.targetTransform.localPosition = newWorldPos;
pointManagerView.UpdatePointPosition(index, this.latestTargetPose);
RedrawTemporaryPath(index, latestTargetPose);
}
private void HandlePointDragEnd(int index)
{
IsDragging = false;
StopDragMoveLoop(); // 루프 중지
controlledRobot.DisableIK();
interactionView.HideDragArrow();
interactionView.HideGhostRobot();
// 가상 로봇 위치 이동 로직
// robotController.SetRobotPosition(newPose);
//pendingPointData = ConvertPoseToRobotData(GetLastDragPosition()); // 임시 저장
pendingPointData = this.latestTargetPose;
currentPopupState = PopupState.ConfirmModifyPoint; // 상태 설정
popupView.ShowConfirmPopup(popPos);
}
@@ -356,7 +332,13 @@ public class ProgramPresenter
if (response == PopupResponse.Move)
{
RobotData targetPose = model.CurrentProgram.GetStepPose(activePointIndex);
//await model.MoveToPoseTcpAsync(targetPose);
Vector3 pos = ConvertRobotDataToVector3(targetPose);
// 알림 UI 표시
pointManagerView.movingAlert.SetActive(true);
await model.MoveToPoseTcpAsync(pos);
Debug.Log($"이동 중? : { await model.GetMovingState()}"); // TODO. 어떤 값을 받아오는지.
}
else if (response == PopupResponse.Delete)
{
@@ -380,18 +362,32 @@ public class ProgramPresenter
activePointIndex = -1;
}
// Model의 현재 상태를 읽어 모든 View(포인트, 경로)를 새로 고침
// Model의 현재 상태를 읽어 모든 View를 새로 고침
private void RedrawSceneFromModel()
{
if (model.CurrentProgram == null) return;
//(RobotProgram.Steps (List<RobotMoveStep>)를 List<RobotData>로 변환하는 로직
// RobotProgram.Steps (List<RobotMoveStep>)를 List<RobotData>로 변환
List<RobotData> poses = model.CurrentProgram.GetAllStepPoses();
pointManagerView.RedrawPoints(poses); // 포인트 다시 그림
pathLineView.DrawPath(poses); // 경로 다시 그림
}
// 실시간 경로 그리기
private void RedrawTemporaryPath(int modifiedIndex, RobotData tempPose)
{
if (model.CurrentProgram == null) return;
List<RobotData> poses = model.CurrentProgram.GetAllStepPoses();
if (poses == null || modifiedIndex < 0 || modifiedIndex >= poses.Count)
{
return;
}
pathLineView.DrawPath(poses, modifiedIndex, tempPose);
}
private void Destroy()
{
this.view.OnCreateProgramClicked -= async (id) => await HandleCreateProgram(id);

View File

@@ -0,0 +1,10 @@
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
[RequireComponent(typeof(Collider))]
[RequireComponent(typeof(XRSimpleInteractable))]
public class RobotPoint : MonoBehaviour
{
[Tooltip("Point Index")]
public int pointIndex = -1;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c9b277895d391194691ecc18b3d442eb

View File

@@ -24,6 +24,13 @@ public class InteractionView : MonoBehaviour, IInteractionView
private XRBaseInteractor baseInteractor;
private IXRRayProvider rayProvider;
[SerializeField]
[Tooltip("드래그 시 위치를 표시할 반투명 로봇 모델")]
private GameObject ghostRobot;
[SerializeField]
[Tooltip("드래그용 마우스 이미지")]
private GameObject dragArrow;
private bool isInitialized = false;
private bool isGrabbingPoint = false;
private int currentGrabbedPointIndex = -1;
@@ -92,8 +99,6 @@ public class InteractionView : MonoBehaviour, IInteractionView
// XRI 이벤트 구독
baseInteractor.selectEntered.AddListener(HandleGrabStart);
baseInteractor.selectExited.AddListener(HandleGrabEnd);
//interactor.activated.AddListener(OnActivated);
//interactor.deactivated.AddListener(OnDeactivated);
isInitialized = true;
AppManager.Instance.RegisterView(this);
@@ -112,57 +117,39 @@ public class InteractionView : MonoBehaviour, IInteractionView
// --- XRI 이벤트 핸들러 ---
// "잡기" 버튼을 눌렀을 때
private void HandleGrabStart(SelectEnterEventArgs args)
{
GameObject grabbedGO = args.interactableObject.transform.gameObject;
// 잡은 것이 "포인트"인지 확인
//RobotPoint point = grabbedGO.GetComponent<RobotPoint>();
//if (point != null)
//{
// isGrabbingPoint = true;
// isGrabbingRobot = false;
// currentGrabbedPointIndex = point.pointIndex;
RobotPoint point = grabbedGO.GetComponent<RobotPoint>();
if (point != null)
{
isGrabbingPoint = true;
isGrabbingRobot = false;
currentGrabbedPointIndex = point.pointIndex;
// // (Presenter의 HandlePointDragStart 호출)
// OnPointDragStart?.Invoke(currentGrabbedPointIndex);
//}
// 2. 잡은 것이 "로봇 핸들"인지 확인
if (grabbedGO.CompareTag("RobotArm"))
OnPointDragStart?.Invoke(currentGrabbedPointIndex);
}
else if (grabbedGO.CompareTag("RobotArm"))
{
isGrabbingPoint = false;
isGrabbingRobot = true;
// (로봇 자체를 잡는 것은 -1 인덱스로 Presenter에게 알림)
currentGrabbedPointIndex = -1;
// (로봇 잡기도 "PointDragStart" 이벤트로 통합하여 Presenter에 알림)
OnPointDragStart?.Invoke(currentGrabbedPointIndex);
}
//if (!enableSelectToDrag) return;
//BeginDrag(args.interactorObject);
}
// "잡기" 버튼을 뗐을 때
private void HandleGrabEnd(SelectExitEventArgs args)
{
//if (!enableSelectToDrag) return;
//EndDrag();
//// "포인트"를 놓고 있는 중이었다면
//if (isGrabbingPoint)
//{
// // Presenter에게 "드래그 끝" 이벤트 전송 (팝업 트리거용)
// OnPointDragEnd?.Invoke(currentGrabbedPointIndex);
//}
//// "로봇"을 놓고 있는 중이었다면
//else if (isGrabbingRobot)
//{
// // Presenter에게 "로봇 놓기" 이벤트 전송 (팝업 트리거용)
// RobotData currentPose = GetCurrentRobotPoseFromController();
// OnRobotReleased?.Invoke(currentPose);
//}
if (isGrabbingPoint)
{
OnPointDragEnd?.Invoke(currentGrabbedPointIndex);
}
else if (isGrabbingRobot)
{
OnRobotReleased?.Invoke(new RobotData());
}
// 상태 초기화
isGrabbingPoint = false;
@@ -170,128 +157,77 @@ public class InteractionView : MonoBehaviour, IInteractionView
currentGrabbedPointIndex = -1;
}
// ---- Drag lifecycle ----
//private void BeginDrag(IXRInteractor interactor)
//{
// currentInteractor = interactor;
// isDragging = true;
// startPosition = transform.position;
// //pathLine.enabled = true;
// uiController?.UpdateStatus("드래그 중...");
// if (communicationScript != null) communicationScript.isMoving = false;
// // ← 드래그 루프 시작
// StartDragMoveLoop();
//}
//private void EndDrag()
//{
// if (!isDragging) return;
// isDragging = false;
// uiController?.UpdateStatus("완료!");
// communicationScript.isMoving = false;
// // ← 루프 중지
// StopDragMoveLoop();
// currentInteractor = null;
//}
//private void StopDragMoveLoop()
//{
// if (dragLoopCts != null)
// {
// dragLoopCts.Cancel();
// dragLoopCts.Dispose();
// dragLoopCts = null;
// }
//}
//private void StartDragMoveLoop()
//{
// StopDragMoveLoop(); // 중복 방지
// dragLoopCts = new CancellationTokenSource();
// _ = DragMoveLoopAsync(dragLoopCts.Token);
//}
//private async Task DragMoveLoopAsync(CancellationToken token)
//{
// // 드래그 동안 100ms 주기로 전송
// while (!token.IsCancellationRequested && isDragging)
// {
// try
// {
// // 로봇이 아직 이동 중이 아니라면(대기 상태) 최신 dragPosition으로 지령 전송
// if (communicationScript != null && !communicationScript.isMoving)
// {
// await MovingTask(); // 내부에서 StratMovement(dragPosition) 호출 및 isMoving 갱신 :contentReference[oaicite:4]{index=4}
// }
// await Task.Delay(10, token); // 100ms 주기
// }
// catch (TaskCanceledException) { /* 정상 취소 */ }
// }
//}
//// ---- Per-frame ----
//void Update()
//{
// if (isDragging && currentInteractor != null)
// {
// communicationScript.isMoving = false;
// // 1) Ray Interactor: 현재 3D Raycast 히트 포인트가 있으면 그대로 사용
// if (currentInteractor is XRRayInteractor ray &&
// ray.TryGetCurrent3DRaycastHit(out RaycastHit hit))
// {
// dragPosition = hit.point;
// }
// else
// {
// // 2) Direct Interactor 또는 Ray 히트가 없을 때: 컨트롤러(또는 attachTransform) 위치 사용
// var t = currentInteractor.transform;
// var attach = currentInteractor.GetAttachTransform(null);
// dragPosition = attach != null ? attach.position : t.position;
// }
// uiController?.UpdateCoordinates(dragPosition); // 기존 UI 갱신 유지 :contentReference[oaicite:2]{index=2}
// }
//}
//private async Task MovingTask()
//{
// if (communicationScript == null) return;
// bool ok = await communicationScript.StratMovement(dragPosition); // 기존 호출 그대로 사용 :contentReference[oaicite:3]{index=3}
// if (ok) communicationScript.isMoving = true;
//}
private RobotData GetCurrentRobotPoseFromController()
// 로봇 좌표계(mm)를 Unity 월드 좌표계(m)로 변환
private Vector3 ConvertRobotDataToVector3(RobotData pose)
{
// 이 View는 Presenter의 변환 로직(ConvertVrToRobotPose)을 알 수 없으므로,
// 현재 컨트롤러 위치/회전을 기반으로 '가짜' RobotData를 만듦
// Presenter가 이 데이터를 받아 어차피 다시 변환(또는 무시)해야 함
return new RobotData(); // 임시 데이터
float x = Convert.ToSingle(pose.x / -1000.0);
float y = Convert.ToSingle(pose.z / 1000.0);
float z = Convert.ToSingle(pose.y / -1000.0);
return new Vector3(x, y, z);
}
// --- Presenter가 호출할 함수들 ---
public void ShowGhostRobot(RobotData pose)
{
/* 반투명 로봇2 활성화 및 위치 설정 */
// 로봇 오일러 각(rx,ry,rz)을 Unity 쿼터니언으로 변환
private Quaternion ConvertRobotDataToQuaternion(RobotData pose)
{
return Quaternion.Euler(pose.rx, pose.ry, pose.rz);
}
public void HideGhostRobot()
{
/* 반투명 로봇2 비활성화 */
// 고스트 로봇의 위치/회전 설정
public void ShowGhostRobot()
{
if (ghostRobot == null)
{
Debug.LogWarning("Ghost Robot이 Inspector에 할당되지 않았습니다.");
return;
}
ghostRobot.SetActive(true);
}
public void ShowDragArrow(Vector3 position)
{
/* 드래그용 화살표 UI 활성화 및 위치 설정 */
// 고스트 로봇 비활성화
public void HideGhostRobot()
{
if (ghostRobot != null)
{
ghostRobot.SetActive(false);
}
}
public void HideDragArrow()
{
/* 드래그용 화살표 UI 비활성화 */
// 드래그 화살표 활성화 및 위치 설정
public void ShowDragArrow(Vector3 position)
{
if (dragArrow == null)
{
Debug.LogWarning("Drag Arrow가 Inspector에 할당되지 않았습니다.");
return;
}
dragArrow.SetActive(true);
dragArrow.transform.position = position;
}
// 드래그 화살표 비활성화
public void HideDragArrow()
{
if (dragArrow != null)
{
dragArrow.SetActive(false);
}
}
// 광선 끝 위치 반환
public Vector3 GetCurrentRayPosition()
{
if (rayProvider != null)
{
return rayProvider.rayEndPoint;
}
if (baseInteractor != null)
{
return baseInteractor.attachTransform.position;
}
return transform.position;
}
}

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
// 인터페이스
public interface IPathLineView
{
void DrawPath(List<RobotData> poses); // (RobotProgram.Steps¿¡¼­ º¯È¯)
}
[RequireComponent(typeof(LineRenderer))]
@@ -15,21 +16,54 @@ public class PathLineView : MonoBehaviour, IPathLineView
void Awake()
{
lineRenderer = GetComponent<LineRenderer>();
lineRenderer.positionCount = 0;
// Line Renderer 기본 설정
lineRenderer.startWidth = 0.01f;
lineRenderer.endWidth = 0.01f;
lineRenderer.material = new Material(Shader.Find("Legacy Shaders/Particles/Alpha Blended Premultiply"));
lineRenderer.startColor = Color.cyan;
lineRenderer.endColor = Color.cyan;
}
private Vector3 ConvertRobotDataToVector3(RobotData pose)
{
float x = Convert.ToSingle(pose.x / -1000.0); // mm -> m
float y = Convert.ToSingle(pose.z / 1000.0); // Robot Z(mm) -> Unity Y(m)
float z = Convert.ToSingle(pose.y / -1000.0); // Robot Y(mm) -> Unity Z(m)
return new Vector3(x, y, z);
}
/// <summary>
/// 프로그램의 모든 포인트를 순서대로 잇는 선을 그림
/// </summary>
public void DrawPath(List<RobotData> poses)
{
if (poses == null || poses.Count < 2)
{
lineRenderer.positionCount = 0;
lineRenderer.positionCount = 0; // 포인트가 2개 미만이면 선을 지움
return;
}
lineRenderer.positionCount = poses.Count;
for (int i = 0; i < poses.Count; i++)
Vector3[] positions = poses.Select(ConvertRobotDataToVector3).ToArray();
lineRenderer.positionCount = positions.Length;
lineRenderer.SetPositions(positions);
}
// 실시간 경로 그리기
public void DrawPath(List<RobotData> poses, int modifiedIndex, RobotData tempPose)
{
if (poses == null || poses.Count < 2 ||
modifiedIndex < 0 || modifiedIndex >= poses.Count)
{
lineRenderer.SetPosition(i, new Vector3(poses[i].x, poses[i].y, poses[i].z));
DrawPath(poses);
return;
}
Vector3[] positions = poses.Select(ConvertRobotDataToVector3).ToArray();
positions[modifiedIndex] = ConvertRobotDataToVector3(tempPose);
lineRenderer.positionCount = positions.Length;
lineRenderer.SetPositions(positions);
}
}

View File

@@ -1,32 +1,51 @@
using System;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
// 인터페이스
public interface IPointManagerView
{
void CreatePoint(RobotData pose);
void UpdatePointPosition(int index, RobotData pose);
void DeletePoint(int index);
void RedrawPoints(List<RobotData> poses); // (RobotProgram.Steps에서 변환)
}
public class PointManagerView : MonoBehaviour, IPointManagerView
{
[SerializeField] private GameObject pointPrefab; // 인스펙터에서 포인트 프리팹 연결
[SerializeField] private GameObject pointPrefab;
private List<GameObject> activePoints = new List<GameObject>();
public void CreatePoint(RobotData pose)
[SerializeField] public GameObject movingAlert;
[SerializeField]
[Tooltip("반투명 로봇 모델의 IK")]
public HybridInverseKinematicsNode kinematicsNode;
private Vector3 ConvertRobotDataToVector3(RobotData pose)
{
Vector3 position = new Vector3(pose.x, pose.y, pose.z);
float x = Convert.ToSingle(pose.x / -1000.0); // mm -> m
float y = Convert.ToSingle(pose.z / 1000.0); // Robot Z(mm) -> Unity Y(m)
float z = Convert.ToSingle(pose.y / -1000.0); // Robot Y(mm) -> Unity Z(m)
return new Vector3(x, y, z);
}
public void CreatePoint(RobotData pose, int index)
{
Vector3 position = ConvertRobotDataToVector3(pose);
GameObject pointObj = Instantiate(pointPrefab, position, Quaternion.identity, this.transform);
activePoints.Add(pointObj);
// (참고: 이 pointObj에 'InteractionView'가 감지할 수 있는 콜라이더와 스크립트가 있어야 함)
RobotPoint pointComponent = pointObj.GetComponent<RobotPoint>();
if (pointComponent != null)
{
pointComponent.pointIndex = activePoints.Count - 1;
}
else
{
Debug.LogError("point프리팹에 RobotPoint스크립트가 없음");
}
}
public void UpdatePointPosition(int index, RobotData pose)
{
if (index < 0 || index >= activePoints.Count) return;
activePoints[index].transform.position = new Vector3(pose.x, pose.y, pose.z);
activePoints[index].transform.position = ConvertRobotDataToVector3(pose);
}
public void DeletePoint(int index)
@@ -38,10 +57,9 @@ public class PointManagerView : MonoBehaviour, IPointManagerView
public void RedrawPoints(List<RobotData> poses)
{
// 기존 포인트 모두 삭제
foreach (var point in activePoints) Destroy(point);
activePoints.Clear();
// 모든 포인트 새로 생성
foreach (var pose in poses) CreatePoint(pose);
if (poses == null) return;
for (int i= 0; i < poses.Count; i++) CreatePoint(poses[i], i);
}
}

View File

@@ -2,75 +2,83 @@ using System;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unity.XR.CoreUtils;
// 팝업 응답 타입
public enum PopupResponse
{
Confirm, // 확정
Cancel, // 취소
Option1, // (예: 여기로 이동)
Option2 // (예: 삭제)
InsConfirm, // 기록 확정
ModConfirm, // 수정 확정
Move, // 여기로 이동
Delete, // 삭제
DelConfirm, // 삭제 확정
Cancel // 취소
}
public interface IPopupView
{
event Action<PopupResponse> OnPopupResponse;
void ShowConfirmPopup(string title, string message); // 2, 5단계용 (확정/취소)
void ShowOptionPopup(string title, string message, string opt1Text, string opt2Text); // 8단계용 (이동/삭제)
void HidePopup();
}
public class PopupView : MonoBehaviour, IPopupView
{
public event Action<PopupResponse> OnPopupResponse;
[SerializeField] private GameObject popupPanel;
[SerializeField] private TextMeshProUGUI titleText;
[SerializeField] private TextMeshProUGUI messageText;
[SerializeField] private GameObject confirmPopupPanel;
[SerializeField] private GameObject modifyPopupPanel;
[SerializeField] private GameObject deletePopupPanel;
[SerializeField] private GameObject optionPopupPanel;
[SerializeField] private Button confirmButton; // '확정' 버튼
[SerializeField] private Button cancelButton; // '취소' 버튼
[SerializeField] private Button option1Button; // '옵션1(이동)' 버튼
[SerializeField] private Button option2Button; // '옵션2(삭제)' 버튼
[SerializeField] private Button ins_confirmButton; // '기록확정' 버튼
[SerializeField] private Button mod_confirmButton; // '수정확정' 버튼
[SerializeField] private Button moveButton; // '이동' 버튼
[SerializeField] private Button deleteButton; // '삭제' 버튼
[SerializeField] private Button del_confirmButton; // '삭제확정' 버튼
[SerializeField] private Button[] cancelButton; // '취소' 버튼
void Start()
{
// 각 버튼이 클릭되면 Presenter에게 응답 이벤트를 보냄
confirmButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Confirm));
cancelButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Cancel));
option1Button.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Option1));
option2Button.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Option2));
ins_confirmButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.InsConfirm));
mod_confirmButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.ModConfirm));
moveButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Move));
deleteButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Delete));
del_confirmButton.onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.DelConfirm));
for (int i = 0; i < cancelButton.Length; i++)
cancelButton[i].onClick.AddListener(() => OnPopupResponse?.Invoke(PopupResponse.Cancel));
popupPanel.SetActive(false);
confirmPopupPanel.SetActive(false);
modifyPopupPanel.SetActive(false);
deletePopupPanel.SetActive(false);
optionPopupPanel.SetActive(false);
}
public void ShowConfirmPopup(string title, string message)
public void ShowConfirmPopup(Transform popPose)
{
titleText.text = title;
messageText.text = message;
confirmButton.gameObject.SetActive(true);
cancelButton.gameObject.SetActive(true);
option1Button.gameObject.SetActive(false);
option2Button.gameObject.SetActive(false);
popupPanel.SetActive(true);
confirmPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity);
confirmPopupPanel.SetActive(true);
}
public void ShowOptionPopup(string title, string message, string opt1Text, string opt2Text)
public void ShowModifyPopup(Transform popPose)
{
titleText.text = title;
messageText.text = message;
option1Button.GetComponentInChildren<Text>().text = opt1Text;
option2Button.GetComponentInChildren<Text>().text = opt2Text;
modifyPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity);
modifyPopupPanel.SetActive(true);
}
confirmButton.gameObject.SetActive(false);
cancelButton.gameObject.SetActive(true); // 취소 버튼은 공용으로 사용
option1Button.gameObject.SetActive(true);
option2Button.gameObject.SetActive(true);
popupPanel.SetActive(true);
public void ShowDeletePopup(Transform popPose)
{
deletePopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity);
deletePopupPanel.SetActive(true);
}
public void ShowOptionPopup(Transform popPose)
{
optionPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity);
optionPopupPanel.SetActive(true);
}
public void HidePopup()
{
popupPanel.SetActive(false);
confirmPopupPanel.SetActive(false);
modifyPopupPanel.SetActive(false);
deletePopupPanel.SetActive(false);
optionPopupPanel.SetActive(false);
}
}

View File

@@ -109,7 +109,7 @@ public class ProgramView : MonoBehaviour, IProgramView
Debug.Log("No Program Loaded");
return;
}
Debug.Log($"연결된 프로그램: {programId}.job");
Debug.Log($"연결된 프로그램: {programId}");
}
public void ShowProgramList(List<string> programIds)