SummerGame/Assets/_Project/Scripts/MetaPart/FurnitureController.cs

378 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class FurnitureController : MonoBehaviour
{
public enum EditTool { Move, Rotate }
[Header("Настройки")]
public FurnitureItemSO currentItemData; // Заменили GameObject на SO
public LayerMask floorLayer;
public LayerMask wallLayer;
public LayerMask furnitureLayer;
[SerializeField] private GameObject shopPanel;
[Header("Режим редактирования (UI)")]
[SerializeField] private GameObject editPanel;
[SerializeField] private GameObject rotate90Button;
public float rotationSpeed = 5f;
[Header("Настройки двойного клика")]
public float doubleClickThreshold = 0.3f;
[Header("Связь с камерой")]
public MonoBehaviour cameraController;
private GameObject _activeFurniture;
private FurnitureObject _activeFurnitureScript;
private EditTool _currentTool = EditTool.Move;
private Camera _cam;
private bool _isInteracting = false;
private Vector3 _lastInputPos;
private Vector3 _dragOffset;
[Header("Связь с UI Цветов")]
public FurniturePaletteUI paletteUI; // Ссылка на новый скрипт
private float _lastClickTime = 0f;
private void Start()
{
_cam = Camera.main;
if (cameraController == null && _cam != null)
cameraController = _cam.GetComponent("CameraController") as MonoBehaviour;
currentItemData = null;
editPanel.SetActive(false);
if (rotate90Button != null) rotate90Button.SetActive(false);
}
void Update()
{
if (_activeFurniture != null)
{
HandleEditing();
}
else if (currentItemData != null)
{
if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI())
TryPlaceFurniture();
}
else
{
if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI())
{
float timeSinceLastClick = Time.time - _lastClickTime;
if (timeSinceLastClick <= doubleClickThreshold)
{
TrySelectPlacedFurniture();
}
_lastClickTime = Time.time;
}
}
}
private void HandleEditing()
{
if (Input.GetMouseButtonDown(0) && !IsPointerOverUI())
{
_lastInputPos = Input.mousePosition;
if (_currentTool == EditTool.Move)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
RaycastHit[] hits = Physics.SphereCastAll(ray, 0.5f, 100f);
bool foundFurniture = false;
foreach (var hit in hits)
{
if (hit.transform.IsChildOf(_activeFurniture.transform) || hit.transform == _activeFurniture.transform)
{
foundFurniture = true;
break;
}
}
if (foundFurniture)
{
if (!_activeFurnitureScript.isWallObject && Physics.Raycast(ray, out RaycastHit floorHit, 100f, floorLayer))
{
_dragOffset = _activeFurniture.transform.position - floorHit.point;
_dragOffset.y = 0;
}
else _dragOffset = Vector3.zero;
StartInteraction();
}
}
else if (_currentTool == EditTool.Rotate)
{
StartInteraction();
}
}
if (Input.GetMouseButton(0) && _isInteracting)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (_currentTool == EditTool.Move)
{
if (_activeFurnitureScript.isWallObject)
{
if (Physics.Raycast(ray, out RaycastHit hit, 100f, wallLayer))
{
_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)
{
BoxCollider box = _activeFurniture.GetComponent<BoxCollider>();
if (box != null)
{
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))
{
float safeDist = Mathf.Max(0f, wallHit.distance - 0.01f);
Vector3 remainingMove = moveDir - (moveDir.normalized * safeDist);
Vector3 slideMove = Vector3.ProjectOnPlane(remainingMove, wallHit.normal);
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;
}
}
}
else if (_currentTool == EditTool.Rotate)
{
float deltaX = Input.mousePosition.x - _lastInputPos.x;
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;
}
if (Input.GetMouseButtonUp(0) && _isInteracting) EndInteraction();
if (!_isInteracting) UpdateUIPosition();
}
private void TrySelectPlacedFurniture()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f, furnitureLayer, QueryTriggerInteraction.Collide))
{
FurnitureObject furnScript = hit.collider.GetComponentInParent<FurnitureObject>();
if (furnScript != null)
{
_activeFurniture = furnScript.gameObject;
_activeFurnitureScript = furnScript;
_activeFurnitureScript.SetEditMode(true);
_currentTool = EditTool.Move;
if (rotate90Button != null) rotate90Button.SetActive(false);
// Показываем панель цветов при выборе предмета
if (paletteUI != null) paletteUI.ShowColors(_activeFurnitureScript);
_isInteracting = false;
LockCamera(false);
UpdateUIPosition();
}
}
}
private void StartInteraction()
{
_isInteracting = true;
if (editPanel.activeSelf) editPanel.SetActive(false);
if (_currentTool == EditTool.Move) LockCamera(true);
}
private void EndInteraction()
{
_isInteracting = false;
UpdateUIPosition();
editPanel.SetActive(true);
if (_currentTool == EditTool.Move) LockCamera(false);
}
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;
RectTransform rect = editPanel.GetComponent<RectTransform>();
if (rect != null)
{
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);
}
void TryPlaceFurniture()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
// Берем слой для первичной установки из карточки товара SO!
LayerMask targetLayer = currentItemData.isWallObject ? wallLayer : floorLayer;
if (Physics.Raycast(ray, out RaycastHit hit, 100f, targetLayer))
{
// Блокируем новые клики, пока грузится ассет
_isInteracting = true;
Quaternion spawnRot = Quaternion.identity;
if (currentItemData.isWallObject)
spawnRot = Quaternion.LookRotation(hit.normal);
// Запускаем асинхронную загрузку из Addressables
currentItemData.prefabRef.InstantiateAsync(hit.point, spawnRot).Completed += handle =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
_activeFurniture = handle.Result;
_activeFurnitureScript = _activeFurniture.GetComponent<FurnitureObject>();
// --- МАГИЯ АРХИТЕКТУРЫ ---
// Инъекция карточки товара в объект на сцене!
_activeFurnitureScript.runtimeItemData = currentItemData;
FurnitureVisuals visuals = _activeFurniture.GetComponent<FurnitureVisuals>();
if (visuals != null && currentItemData.availablePresets != null && currentItemData.availablePresets.Count > 0)
{
visuals.ApplyPreset(currentItemData.availablePresets[0]);
}
// Показываем панель цветов для только что заспавненного объекта
if (paletteUI != null) paletteUI.ShowColors(_activeFurnitureScript);
// -------------------------
_activeFurnitureScript.SetEditMode(true);
_currentTool = EditTool.Move;
if (rotate90Button != null) rotate90Button.SetActive(false);
currentItemData = null; // Сбрасываем карточку из буфера
_isInteracting = false;
LockCamera(false);
UpdateUIPosition();
}
else
{
Debug.LogError($"Не удалось загрузить {currentItemData.itemName}. Проверьте галочку Addressables на префабе!");
_isInteracting = false;
}
};
}
}
public void Rotate90Degrees()
{
if (_activeFurniture != null)
{
if (_activeFurnitureScript.isWallObject)
{
_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 ConfirmPlacement()
{
if (_activeFurnitureScript != null && _activeFurnitureScript.IsPlacementValid)
{
_activeFurnitureScript.SetEditMode(false);
_activeFurniture = null;
_activeFurnitureScript = null;
editPanel.SetActive(false);
if (paletteUI != null) paletteUI.HideColors();
LockCamera(false);
}
}
public void CancelPlacement()
{
if (_activeFurniture != null)
{
// ПРАВИЛЬНОЕ удаление объекта, заспавненного через Addressables
Addressables.ReleaseInstance(_activeFurniture);
_activeFurniture = null;
_activeFurnitureScript = null;
editPanel.SetActive(false);
if (paletteUI != null) paletteUI.HideColors();
LockCamera(false);
}
}
// Эта функция вызывается из ShopManager
public void SelectFurnitureAndCloseShop(FurnitureItemSO itemToSelect)
{
currentItemData = itemToSelect;
shopPanel.SetActive(false);
}
private void LockCamera(bool isLocked) { if (cameraController != null) cameraController.enabled = !isLocked; }
private bool IsPointerOverUI()
{
if (EventSystem.current != null)
{
if (EventSystem.current.IsPointerOverGameObject()) return true;
if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return true;
}
return false;
}
}