SummerGame/Assets/Scripts/FurnitureController.cs

333 lines
13 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;
public class FurnitureController : MonoBehaviour
{
public enum EditTool { Move, Rotate }
[Header("Настройки")]
public GameObject currentPrefab;
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 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;
private void Start()
{
_cam = Camera.main;
if (cameraController == null && _cam != null)
cameraController = _cam.GetComponent("CameraController") as MonoBehaviour;
currentPrefab = null;
editPanel.SetActive(false);
if (rotate90Button != null) rotate90Button.SetActive(false);
}
void Update()
{
if (_activeFurniture != null)
{
HandleEditing();
}
else if (currentPrefab != null)
{
if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI())
TryPlaceFurniture();
}
else
{
if (Input.GetMouseButtonDown(0) && !shopPanel.activeSelf && !IsPointerOverUI())
TrySelectPlacedFurniture();
}
}
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;
// Настенные предметы крутим вокруг своей оси 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;
}
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);
_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);
// Определяем, куда пускать луч при установке в зависимости от типа предмета
FurnitureObject prefabScript = currentPrefab.GetComponent<FurnitureObject>();
LayerMask targetLayer = prefabScript.isWallObject ? wallLayer : floorLayer;
if (Physics.Raycast(ray, out RaycastHit hit, 100f, targetLayer))
{
_activeFurniture = Instantiate(currentPrefab, hit.point, Quaternion.identity);
// Если это стена - сразу поворачиваем спиной к ней
if (prefabScript.isWallObject)
{
_activeFurniture.transform.rotation = Quaternion.LookRotation(hit.normal);
}
_activeFurnitureScript = _activeFurniture.GetComponent<FurnitureObject>();
_activeFurnitureScript.SetEditMode(true);
_currentTool = EditTool.Move;
if (rotate90Button != null) rotate90Button.SetActive(false);
currentPrefab = null;
_isInteracting = false;
LockCamera(false);
UpdateUIPosition();
}
}
public void Rotate90Degrees()
{
if (_activeFurniture != null)
{
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 ConfirmPlacement()
{
if (_activeFurnitureScript != null && _activeFurnitureScript.IsPlacementValid)
{
_activeFurnitureScript.SetEditMode(false);
_activeFurniture = null;
_activeFurnitureScript = null;
editPanel.SetActive(false);
LockCamera(false);
}
}
public void CancelPlacement()
{
if (_activeFurniture != null)
{
Destroy(_activeFurniture);
_activeFurniture = null;
_activeFurnitureScript = null;
editPanel.SetActive(false);
LockCamera(false);
}
}
public void SelectFurnitureAndCloseShop(GameObject prefabToSelect)
{
currentPrefab = prefabToSelect;
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;
}
}