From 17794207341c1a39de7d60d74f1dad4a4c164319 Mon Sep 17 00:00:00 2001 From: vladislove Date: Sat, 11 Jul 2026 18:05:11 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BD=D0=B0=20=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Furniture Models/Lamp/LampMaterial.mat | 68 ++++- Assets/Prefabs/Ready/Lamp.prefab | 259 ++++++++++++++++++ Assets/Prefabs/Ready/Lamp.prefab.meta | 7 + Assets/Scenes/RoomEditor.unity | 3 + Assets/Scripts/FurnitureController.cs | 185 ++++++------- Assets/Scripts/FurnitureObject.cs | 19 +- 6 files changed, 419 insertions(+), 122 deletions(-) create mode 100644 Assets/Prefabs/Ready/Lamp.prefab create mode 100644 Assets/Prefabs/Ready/Lamp.prefab.meta diff --git a/Assets/Downloaded/Furniture Models/Lamp/LampMaterial.mat b/Assets/Downloaded/Furniture Models/Lamp/LampMaterial.mat index c0b1420..f66a207 100644 --- a/Assets/Downloaded/Furniture Models/Lamp/LampMaterial.mat +++ b/Assets/Downloaded/Furniture Models/Lamp/LampMaterial.mat @@ -8,23 +8,31 @@ Material: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: LampMaterial - m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0} + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 m_ValidKeywords: + - _EMISSION + - _METALLICSPECGLOSSMAP - _NORMALMAP - - _SPECGLOSSMAP + - _OCCLUSIONMAP m_InvalidKeywords: [] - m_LightmapFlags: 5 + m_LightmapFlags: 1 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 - stringTagMap: {} - disabledShaderPasses: [] + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS m_LockedProperties: m_SavedProperties: serializedVersion: 3 m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 2800000, guid: 588acb0ca4024e34fbe692759004f613, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} - _BumpMap: m_Texture: {fileID: 2800000, guid: 48a0b8445aca0ea4cae75f565eed45a7, type: 3} m_Scale: {x: 1, y: 1} @@ -50,7 +58,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MetallicGlossMap: - m_Texture: {fileID: 0} + m_Texture: {fileID: 2800000, guid: 1c9e7814519efd042805678bce6c815d, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _OcclusionMap: @@ -65,23 +73,71 @@ Material: m_Texture: {fileID: 2800000, guid: 83ff1830cd2b9ad43b851e77df8ee36c, type: 3} 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: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 - _Glossiness: 0.741 + - _GlossyReflections: 1 - _Metallic: 0 - _Mode: 0 - _OcclusionStrength: 0.796 - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 - _UVSec: 0 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 - _ZWrite: 1 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.2, g: 0.2, b: 0.2, a: 1} m_BuildTextureStacks: [] m_AllowLocking: 1 +--- !u!114 &6250963627482809503 +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: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 diff --git a/Assets/Prefabs/Ready/Lamp.prefab b/Assets/Prefabs/Ready/Lamp.prefab new file mode 100644 index 0000000..4cd521c --- /dev/null +++ b/Assets/Prefabs/Ready/Lamp.prefab @@ -0,0 +1,259 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2307210997937809716 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8685994162877849489} + - component: {fileID: 3535353084307057529} + - component: {fileID: 530835854457807048} + - component: {fileID: 6750779239247170543} + - component: {fileID: 7958023738411863053} + m_Layer: 0 + m_Name: Lamp + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8685994162877849489 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2307210997937809716} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.4598788, y: 1.2676696, z: -2.6999989} + m_LocalScale: {x: 1.2241421, y: 1.2241421, z: 1.2241421} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5098634111614699637} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3535353084307057529 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2307210997937809716} + m_Mesh: {fileID: 4300000, guid: ef8377edf1ca14f40bb6414ab806e21d, type: 3} +--- !u!23 &530835854457807048 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2307210997937809716} + 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_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9e1e78f7bc649164598b3a3a8b57b15a, 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_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &6750779239247170543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2307210997937809716} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7196b5f65c7bcd143b0f035424936bef, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::FurnitureObject + isWallObject: 1 + obstacleLayers: + serializedVersion: 2 + m_Bits: 64 +--- !u!65 &7958023738411863053 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2307210997937809716} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 1 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 0.16, y: 0.21218802, z: 0.33694533} + m_Center: {x: 0, y: -0.011500888, z: 0.16847266} +--- !u!1 &4044746772867638992 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5098634111614699637} + - component: {fileID: 4643961889072012291} + - component: {fileID: 8678921170633064640} + m_Layer: 0 + m_Name: Spot Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5098634111614699637 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4044746772867638992} + serializedVersion: 2 + m_LocalRotation: {x: 0.62185633, y: -0, z: -0, w: 0.7831314} + m_LocalPosition: {x: 0.001, y: 0.012, z: 0.259} + m_LocalScale: {x: 0.81689864, y: 0.81689864, z: 0.81689864} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8685994162877849489} + m_LocalEulerAnglesHint: {x: 76.904, y: 0, z: 0} +--- !u!108 &4643961889072012291 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4044746772867638992} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 5 + m_Range: 20 + m_SpotAngle: 133.80692 + m_InnerSpotAngle: 34.78564 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 4500 + m_UseColorTemperature: 1 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!114 &8678921170633064640 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4044746772867638992} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 diff --git a/Assets/Prefabs/Ready/Lamp.prefab.meta b/Assets/Prefabs/Ready/Lamp.prefab.meta new file mode 100644 index 0000000..e35b368 --- /dev/null +++ b/Assets/Prefabs/Ready/Lamp.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1de5126b7e5d69e419afb3918a718672 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/RoomEditor.unity b/Assets/Scenes/RoomEditor.unity index 96bae90..a09c856 100644 --- a/Assets/Scenes/RoomEditor.unity +++ b/Assets/Scenes/RoomEditor.unity @@ -2967,6 +2967,9 @@ MonoBehaviour: - itemName: Shkaf icon: {fileID: 21300000, guid: 438857afb61d71545a9e4eb529a8b2df, type: 3} prefab: {fileID: 1516859676564360999, guid: 6b309dac6143e8b40a6c7ab1b8656f2f, type: 3} + - itemName: Lamp + icon: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + prefab: {fileID: 2307210997937809716, guid: 1de5126b7e5d69e419afb3918a718672, type: 3} --- !u!1 &1124212139 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/FurnitureController.cs b/Assets/Scripts/FurnitureController.cs index 7c757b5..cf19dbb 100644 --- a/Assets/Scripts/FurnitureController.cs +++ b/Assets/Scripts/FurnitureController.cs @@ -9,9 +9,7 @@ public class FurnitureController : MonoBehaviour public GameObject currentPrefab; public LayerMask floorLayer; public LayerMask wallLayer; - - [Tooltip("Слой мебели (чтобы кликать по уже стоящим объектам)")] - public LayerMask furnitureLayer; // НОВАЯ ПЕРЕМЕННАЯ + public LayerMask furnitureLayer; [SerializeField] private GameObject shopPanel; @@ -36,9 +34,7 @@ public class FurnitureController : MonoBehaviour { _cam = Camera.main; if (cameraController == null && _cam != null) - { cameraController = _cam.GetComponent("CameraController") as MonoBehaviour; - } currentPrefab = null; editPanel.SetActive(false); @@ -47,32 +43,24 @@ public class FurnitureController : MonoBehaviour void Update() { - // 1. Если мы УЖЕ редактируем объект if (_activeFurniture != null) { HandleEditing(); } - // 2. Если мы выбрали НОВУЮ мебель в магазине и хотим её поставить else if (currentPrefab != null) { if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI()) - { TryPlaceFurniture(); - } } - // 3. НОВОЕ: Если ничего не выбрано, пытаемся кликнуть по УЖЕ СТОЯЩЕЙ мебели else { if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI()) - { TrySelectPlacedFurniture(); - } } } private void HandleEditing() { - // 1. НАЧАЛО ВЗАИМОДЕЙСТВИЯ if (Input.GetMouseButtonDown(0) && !IsPointerOverUI()) { _lastInputPos = Input.mousePosition; @@ -94,7 +82,8 @@ public class FurnitureController : MonoBehaviour if (foundFurniture) { - if (Physics.Raycast(ray, out RaycastHit floorHit, 100f, floorLayer)) + // Для пола считаем смещение, настенные предметы просто цепляем к курсору + if (!_activeFurnitureScript.isWallObject && Physics.Raycast(ray, out RaycastHit floorHit, 100f, floorLayer)) { _dragOffset = _activeFurniture.transform.position - floorHit.point; _dragOffset.y = 0; @@ -110,101 +99,101 @@ public class FurnitureController : MonoBehaviour } } - // 2. ПРОЦЕСС if (Input.GetMouseButton(0) && _isInteracting) { + Ray ray = _cam.ScreenPointToRay(Input.mousePosition); + if (_currentTool == EditTool.Move) { - Ray ray = _cam.ScreenPointToRay(Input.mousePosition); - if (Physics.Raycast(ray, out RaycastHit hit, 100f, floorLayer)) + // === ЛОГИКА ДЛЯ НАСТЕННЫХ ПРЕДМЕТОВ === + if (_activeFurnitureScript.isWallObject) { - Vector3 currentPos = _activeFurniture.transform.position; - Vector3 targetPos = hit.point + _dragOffset; - targetPos.y = currentPos.y; - - Vector3 moveDir = targetPos - currentPos; - float moveDist = moveDir.magnitude; - - if (moveDist > 0.001f) + if (Physics.Raycast(ray, out RaycastHit hit, 100f, wallLayer)) { - BoxCollider box = _activeFurniture.GetComponent(); - if (box != null) + _activeFurniture.transform.position = hit.point; + // Магия: Поворачиваем объект "лицом" от стены + _activeFurniture.transform.rotation = Quaternion.LookRotation(hit.normal); + } + } + // === ЛОГИКА ДЛЯ НАПОЛЬНЫХ ПРЕДМЕТОВ (Старая) === + else + { + if (Physics.Raycast(ray, out RaycastHit hit, 100f, floorLayer)) + { + Vector3 currentPos = _activeFurniture.transform.position; + Vector3 targetPos = hit.point + _dragOffset; + targetPos.y = currentPos.y; + + Vector3 moveDir = targetPos - currentPos; + float moveDist = moveDir.magnitude; + + if (moveDist > 0.001f) { - Vector3 center = _activeFurniture.transform.TransformPoint(box.center); - Vector3 halfExtents = Vector3.Scale(box.size, _activeFurniture.transform.lossyScale) * 0.49f; - - if (Physics.BoxCast(center, halfExtents, moveDir.normalized, out RaycastHit wallHit, _activeFurniture.transform.rotation, moveDist, wallLayer)) + BoxCollider box = _activeFurniture.GetComponent(); + if (box != null) { - float safeDist = Mathf.Max(0f, wallHit.distance - 0.01f); - Vector3 remainingMove = moveDir - (moveDir.normalized * safeDist); - Vector3 slideMove = Vector3.ProjectOnPlane(remainingMove, wallHit.normal); + Vector3 center = _activeFurniture.transform.TransformPoint(box.center); + Vector3 halfExtents = Vector3.Scale(box.size, _activeFurniture.transform.lossyScale) * 0.49f; - if (slideMove.magnitude > 0.001f) + if (Physics.BoxCast(center, halfExtents, moveDir.normalized, out RaycastHit wallHit, _activeFurniture.transform.rotation, moveDist, wallLayer)) { - Vector3 newCenter = center + moveDir.normalized * safeDist; - if (Physics.BoxCast(newCenter, halfExtents, slideMove.normalized, out RaycastHit slideHit, _activeFurniture.transform.rotation, slideMove.magnitude, wallLayer)) - { - slideMove = slideMove.normalized * Mathf.Max(0f, slideHit.distance - 0.01f); - } - } + float safeDist = Mathf.Max(0f, wallHit.distance - 0.01f); + Vector3 remainingMove = moveDir - (moveDir.normalized * safeDist); + Vector3 slideMove = Vector3.ProjectOnPlane(remainingMove, wallHit.normal); - targetPos = currentPos + (moveDir.normalized * safeDist) + slideMove; + if (slideMove.magnitude > 0.001f) + { + Vector3 newCenter = center + moveDir.normalized * safeDist; + if (Physics.BoxCast(newCenter, halfExtents, slideMove.normalized, out RaycastHit slideHit, _activeFurniture.transform.rotation, slideMove.magnitude, wallLayer)) + { + slideMove = slideMove.normalized * Mathf.Max(0f, slideHit.distance - 0.01f); + } + } + + targetPos = currentPos + (moveDir.normalized * safeDist) + slideMove; + } } } + targetPos.y = currentPos.y; + _activeFurniture.transform.position = targetPos; } - - targetPos.y = currentPos.y; - _activeFurniture.transform.position = targetPos; } } else if (_currentTool == EditTool.Rotate) { float deltaX = Input.mousePosition.x - _lastInputPos.x; - _activeFurniture.transform.Rotate(Vector3.up, -deltaX * rotationSpeed * 0.2f); + + // Настенные предметы крутим вокруг своей оси Z (по циферблату), а напольные - вокруг мировой Y + if (_activeFurnitureScript.isWallObject) + _activeFurniture.transform.Rotate(Vector3.forward, -deltaX * rotationSpeed * 0.2f, Space.Self); + else + _activeFurniture.transform.Rotate(Vector3.up, -deltaX * rotationSpeed * 0.2f, Space.World); } _lastInputPos = Input.mousePosition; } - // 3. КОНЕЦ ВЗАИМОДЕЙСТВИЯ - if (Input.GetMouseButtonUp(0) && _isInteracting) - { - EndInteraction(); - } - - // 4. ПОЗИЦИОНИРОВАНИЕ UI - if (!_isInteracting) - { - UpdateUIPosition(); - } + if (Input.GetMouseButtonUp(0) && _isInteracting) EndInteraction(); + if (!_isInteracting) UpdateUIPosition(); } - // === НОВЫЙ МЕТОД: Выделение уже стоящей мебели === private void TrySelectPlacedFurniture() { Ray ray = _cam.ScreenPointToRay(Input.mousePosition); - - // Пускаем луч, который ищет ТОЛЬКО объекты на слое FurnitureLayer - if (Physics.Raycast(ray, out RaycastHit hit, 100f, furnitureLayer)) + if (Physics.Raycast(ray, out RaycastHit hit, 1000f, furnitureLayer, QueryTriggerInteraction.Collide)) { - // Ищем скрипт FurnitureObject на объекте (или его родителях) FurnitureObject furnScript = hit.collider.GetComponentInParent(); if (furnScript != null) { _activeFurniture = furnScript.gameObject; _activeFurnitureScript = furnScript; - - // Включаем зеленую подсветку _activeFurnitureScript.SetEditMode(true); - // Сбрасываем инструмент на Move _currentTool = EditTool.Move; if (rotate90Button != null) rotate90Button.SetActive(false); _isInteracting = false; LockCamera(false); - - // Моментально показываем меню над мебелью UpdateUIPosition(); } } @@ -228,11 +217,9 @@ public class FurnitureController : MonoBehaviour private void UpdateUIPosition() { Vector3 screenPos = _cam.WorldToScreenPoint(_activeFurniture.transform.position); - if (screenPos.z > 0) { if (!editPanel.activeSelf) editPanel.SetActive(true); - float yOffset = Screen.height * 0.15f; float targetX = screenPos.x; float targetY = screenPos.y + yOffset; @@ -242,27 +229,33 @@ public class FurnitureController : MonoBehaviour { float paddingX = (rect.rect.width / 2f) * editPanel.transform.lossyScale.x; float paddingY = (rect.rect.height / 2f) * editPanel.transform.lossyScale.y; - targetX = Mathf.Clamp(targetX, paddingX, Screen.width - paddingX); targetY = Mathf.Clamp(targetY, paddingY, Screen.height - paddingY); } - editPanel.transform.position = new Vector3(targetX, targetY, editPanel.transform.position.z); } - else - { - if (editPanel.activeSelf) editPanel.SetActive(false); - } + else if (editPanel.activeSelf) editPanel.SetActive(false); } void TryPlaceFurniture() { Ray ray = _cam.ScreenPointToRay(Input.mousePosition); - if (Physics.Raycast(ray, out RaycastHit hit, 100f, floorLayer)) + + // Определяем, куда пускать луч при установке в зависимости от типа предмета + FurnitureObject prefabScript = currentPrefab.GetComponent(); + LayerMask targetLayer = prefabScript.isWallObject ? wallLayer : floorLayer; + + if (Physics.Raycast(ray, out RaycastHit hit, 100f, targetLayer)) { _activeFurniture = Instantiate(currentPrefab, hit.point, Quaternion.identity); - _activeFurnitureScript = _activeFurniture.GetComponent(); + // Если это стена - сразу поворачиваем спиной к ней + if (prefabScript.isWallObject) + { + _activeFurniture.transform.rotation = Quaternion.LookRotation(hit.normal); + } + + _activeFurnitureScript = _activeFurniture.GetComponent(); _activeFurnitureScript.SetEditMode(true); _currentTool = EditTool.Move; @@ -271,7 +264,6 @@ public class FurnitureController : MonoBehaviour currentPrefab = null; _isInteracting = false; LockCamera(false); - UpdateUIPosition(); } } @@ -280,25 +272,22 @@ public class FurnitureController : MonoBehaviour { if (_activeFurniture != null) { - float currentY = _activeFurniture.transform.eulerAngles.y; - float snappedY = Mathf.Round(currentY / 90f) * 90f; - _activeFurniture.transform.rotation = Quaternion.Euler(0, snappedY + 90f, 0); + if (_activeFurnitureScript.isWallObject) + { + // Настенные объекты поворачиваем по их локальной оси Z (как часы) + _activeFurniture.transform.Rotate(0, 0, 90f, Space.Self); + } + else + { + float currentY = _activeFurniture.transform.eulerAngles.y; + float snappedY = Mathf.Round(currentY / 90f) * 90f; + _activeFurniture.transform.rotation = Quaternion.Euler(0, snappedY + 90f, 0); + } } } - public void SelectMoveTool() - { - _currentTool = EditTool.Move; - if (rotate90Button != null) rotate90Button.SetActive(false); - LockCamera(false); - } - - public void SelectRotateTool() - { - _currentTool = EditTool.Rotate; - if (rotate90Button != null) rotate90Button.SetActive(true); - LockCamera(true); - } + public void SelectMoveTool() { _currentTool = EditTool.Move; if (rotate90Button != null) rotate90Button.SetActive(false); LockCamera(false); } + public void SelectRotateTool() { _currentTool = EditTool.Rotate; if (rotate90Button != null) rotate90Button.SetActive(true); LockCamera(true); } public void ConfirmPlacement() { @@ -330,13 +319,7 @@ public class FurnitureController : MonoBehaviour shopPanel.SetActive(false); } - private void LockCamera(bool isLocked) - { - if (cameraController != null) - { - cameraController.enabled = !isLocked; - } - } + private void LockCamera(bool isLocked) { if (cameraController != null) cameraController.enabled = !isLocked; } private bool IsPointerOverUI() { diff --git a/Assets/Scripts/FurnitureObject.cs b/Assets/Scripts/FurnitureObject.cs index 410e15c..347bd41 100644 --- a/Assets/Scripts/FurnitureObject.cs +++ b/Assets/Scripts/FurnitureObject.cs @@ -2,13 +2,15 @@ using UnityEngine; public class FurnitureObject : MonoBehaviour { + [Header("Тип объекта")] + public bool isWallObject = false; // ГАЛОЧКА: Это настенный предмет? + [Header("Настройки")] public LayerMask obstacleLayers; private int _obstaclesCount = 0; public bool IsPlacementValid => _obstaclesCount == 0; - // Переменные для нашей "коробки" private GameObject _highlightBox; private Material _highlightMaterial; @@ -20,30 +22,18 @@ public class FurnitureObject : MonoBehaviour private void CreateHighlightBox() { BoxCollider col = GetComponent(); - if (col == null) - { - Debug.LogError("На префабе мебели нет BoxCollider! Коробка не появится."); - return; - } + if (col == null) return; - // 1. Создаем обычный куб _highlightBox = GameObject.CreatePrimitive(PrimitiveType.Cube); - - // 2. Удаляем с него коллайдер, чтобы он не мешал физике Destroy(_highlightBox.GetComponent()); - // 3. Делаем куб дочерним к мебели и задаем размеры коллайдера _highlightBox.transform.SetParent(transform); _highlightBox.transform.localPosition = col.center; _highlightBox.transform.localRotation = Quaternion.identity; _highlightBox.transform.localScale = col.size; - // 4. Магия: Создаем прозрачный материал через код. - // Шейдер "Sprites/Default" есть в Unity всегда, он светится в темноте и поддерживает прозрачность. _highlightMaterial = new Material(Shader.Find("Sprites/Default")); _highlightBox.GetComponent().material = _highlightMaterial; - - // Выключаем куб при старте _highlightBox.SetActive(false); } @@ -78,7 +68,6 @@ public class FurnitureObject : MonoBehaviour { if (_highlightMaterial != null) { - // Зеленый или красный цвет (0.4f - это степень прозрачности) Color targetColor = IsPlacementValid ? new Color(0, 1, 0, 0.4f) : new Color(1, 0, 0, 0.4f); _highlightMaterial.color = targetColor; }