Files
Studio/Assets/Scripts/Studio/AssetTool/RenderObjectHandler.cs
2025-07-23 10:58:51 +09:00

395 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using Studio.AssetTool;
using Studio.Command;
using Studio.DataStructures;
using Studio.Interfaces;
using Studio.Manage;
using Studio.RuntimeGizmo;
using Studio.HierarchyTree;
namespace Studio.AssetTool
{
public class RenderObjectHandler : Manager, IModeController, IInputHandler
{
public ModePanel.ProgramMode mode => ModePanel.ProgramMode.ObjectLayout;
public List<CustomAssetRenderObject> selectedRenderObjects = new List<CustomAssetRenderObject>();
List<CustomAssetRenderObject> copyRenderObjects = new List<CustomAssetRenderObject>();
List<GameObject> selectedGameObjects = new List<GameObject>();
CustomAssetRenderObject prevSelectedObject;
public RTGController rtgController;
ConvexHullCalculator convexHullCalculator = new ConvexHullCalculator();
UserInputManager userInputManager;
Vector3 clickBeginPos;
float clickLengthThreshold = 5.0f;
int uiLayer;
int selectIndex;
bool lockHandler = false;
bool inputLockhandler = false;
public override void Init()
{
myHandler = GetInputHandler();
rtgController = new RTGController();
rtgController.onTransformBegin = OnTransformBegin;
rtgController.onTransformChanged = OnTransformChangedFromRTG;
uiLayer = LayerMask.NameToLayer("UI");
userInputManager = GameObject.FindAnyObjectByType<UserInputManager>();
var statusPanel = GameObject.FindFirstObjectByType<ModePanel>();
statusPanel.AddController(this);
selectIndex = 0;
}
private void OnMousePointerDown()
{
clickBeginPos = Input.mousePosition;
//ui를 선택했을 경우에는 오브젝트 선택을 멈춘다.
PointerEventData pointerData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, raycastResults);
if (raycastResults.Any(x => x.gameObject.layer == uiLayer))
{
lockHandler = true;
return;
}
CanvasManager.instance.GetCanvas<Canvas_DragArea>().panel_draghandler.OnBeginDrag(clickBeginPos);
}
private void OnMousePointerUp()
{
//rtg 컨트롤러가 조작중일때 락을 건다.
//rtg 컨트롤러 조작 후 포커스가 바뀌는 것을 방지하기 위한 용도
if (lockHandler == true)
{
lockHandler = false;
return;
}
//ui를 선택했을 경우에는 오브젝트 선택을 멈춘다.
PointerEventData pointerData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, raycastResults);
if (raycastResults.Any(x => x.gameObject.layer == uiLayer))
{
CanvasManager.instance.GetCanvas<Canvas_DragArea>().panel_draghandler.ForceEndDrag();
return;
}
//포인터 업 위치가 포인터 다운 위치에서 크게 벗어났을 경우는 클릭을 무시한다.
if ((clickBeginPos - Input.mousePosition).magnitude > clickLengthThreshold)
{
DeselectAll();
CanvasManager.instance.GetCanvas<Canvas_DragArea>().panel_draghandler.OnEndDrag(Input.mousePosition);
return;
}
List<CustomAssetRenderObject> raycastedTarget = new List<CustomAssetRenderObject>();
CustomAssetRenderObject renderObject = null;
foreach (var result in raycastResults)
{
renderObject = result.gameObject.GetComponent<CustomAssetRenderObject>();
if (renderObject != null)
{
raycastedTarget.Add(renderObject);
}
}
if (raycastedTarget.Count > 0)
{
//오브젝트가 여러개 겹쳐 있을 경우 뒤의 오브젝트를 순차적으로 선택해주기 위한 용도
if (selectIndex < raycastedTarget.Count && prevSelectedObject == raycastedTarget[selectIndex])
{
selectIndex++;
}
if (selectIndex >= raycastedTarget.Count)
{
selectIndex = 0;
}
renderObject = raycastedTarget[selectIndex];
//컨트롤이 눌려 있으면 오브젝트 선택을 토글한다. (유니티 기능과 일치)
if (Input.GetKey(KeyCode.LeftControl))
{
if (renderObject.ToggleSelect())
{
AddSelection(renderObject);
}
else
{
RemoveSelection(renderObject);
}
}
//시프트 키가 눌려 있는 경우 다중 선택 기능으로 작용한다.
else if (Input.GetKey(KeyCode.LeftShift))
{
AddSelection(renderObject);
}
//그 외는 선택된 아이템을 제외하고 다 비선택해준다.
else
{
RemoveAllSelections();
AddSelection(renderObject);
}
prevSelectedObject = renderObject;
OnSelect();
}
else
{
CommandInvoker.instance.Invoke(new ResetGizmoCommand());
DeselectAll();
}
CanvasManager.instance.GetCanvas<Canvas_DragArea>().panel_draghandler.ForceEndDrag();
}
public void DeselectAll()
{
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftShift))
{
return;
}
RemoveAllSelections();
var canvas_Popup = CanvasManager.instance.GetCanvas<Canvas_Popup>();
canvas_Popup.panel_dynamicobjectinfo.ResetObjectInfo();
ManagerHub.instance.Get<CustomAssetConnector>().OnDeselectAll();
}
public void AddSelection(CustomAssetRenderObject item)
{
if (selectedRenderObjects.Any(x => x == item))
{
return;
}
item.Select();
selectedRenderObjects.Add(item);
selectedGameObjects.Add(item.gameObject);
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
public void AddSelection(List<CustomAssetRenderObject> items)
{
for (int i = 0; i < items.Count; i++)
{
CustomAssetRenderObject item = items[i];
AddSelection(item);
}
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
public void RemoveAllSelections()
{
for (int i = 0; i < selectedRenderObjects.Count; i++)
{
selectedRenderObjects[i].Deselect();
}
selectedRenderObjects.Clear();
selectedGameObjects.Clear();
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
public void RemoveSelection(CustomAssetRenderObject item)
{
Debug.Log("RemoveSelection");
item.Deselect();
selectedRenderObjects.Remove(item);
selectedGameObjects.Remove(item.gameObject);
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
private void OnSelect()
{
OnSelectObjectFromObjectHandler(selectedRenderObjects);
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
public void OnSelectObjectFromObjectHandler(List<CustomAssetRenderObject> objects)
{
if (objects.Count == 0)
{
return;
}
string name = "";
List<GameObject> selectedObjects = new List<GameObject>();
List<HierarchyItem> selectedItems = new List<HierarchyItem>();
var connector = ManagerHub.instance.Get<CustomAssetConnector>();
for (int i = 0; i < objects.Count; i++)
{
ConnectedAsset searchAsset = connector.connectedAssets.Find((x) => x.renderObject == objects[i]);
selectedItems.Add(searchAsset.hierarchyItem);
name = i == 0 ? searchAsset.hierarchyItem.name : name.Equals(searchAsset.hierarchyItem.name) ? searchAsset.hierarchyItem.name : "-";
selectedObjects.Add(searchAsset.renderObject.gameObject);
}
connector.componentScrollView.OnSelect(selectedItems);
connector.OnSelectObjects(name, selectedObjects);
}
public void OnTransformBegin()
{
lockHandler = true;
}
public void OnTransformChangedFromRTG(List<GameObject> transformObjects)
{
OnTransformChanged(transformObjects);
CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_dynamicobjectinfo.OnTransformChanged(transformObjects);
CanvasManager.instance.GetCanvas<Canvas_DragArea>().panel_draghandler.ForceEndDrag();
}
public void OnTransformChanged(List<GameObject> transformObjects)
{
foreach (GameObject gb in transformObjects)
{
CustomAssetRenderObject renderObject = gb.GetComponent<CustomAssetRenderObject>();
if (renderObject != null)
{
renderObject.onTransformChanged?.Invoke();
}
}
}
public void SaveItemsToCopy()
{
copyRenderObjects.Clear();
copyRenderObjects.AddRange(selectedRenderObjects);
}
public void ResetGizmoTargetObjects()
{
rtgController.SetGizmoTargetObjects(selectedGameObjects);
}
public void AlignObjects(int row, int col, float spaceX, float spaceZ, int direction)
{
if (selectedRenderObjects.Count <= 1)
{
return;
}
ManagerHub.instance.Get<CustomAssetConnector>().OrderByHierarchy(selectedRenderObjects);
List<CustomAssetRenderObject> objectsToAlign = new List<CustomAssetRenderObject>(selectedRenderObjects);
List<Vector3> originalPos = objectsToAlign.Select(x => x.transform.position).ToList();
direction = ((direction % 8) + 8) % 8;
int primary = direction % 2 == 0 ? col : row;
Vector3 primaryDir = Vector3.zero;
Vector3 secondaryDir = Vector3.zero;
primaryDir = (direction == 0 || direction == 2) ? Vector3.right * spaceX :
(direction == 4 || direction == 6) ? -Vector3.right * spaceX :
(direction == 1 || direction == 7) ? Vector3.forward * spaceZ : -Vector3.forward * spaceZ;
secondaryDir = (direction == 1 || direction == 3) ? Vector3.right * spaceX :
(direction == 5 || direction == 7) ? -Vector3.right * spaceX :
(direction == 0 || direction == 6) ? Vector3.forward * spaceZ : -Vector3.forward * spaceZ;
ActionCommand command = new ActionCommand(
() => Align(objectsToAlign, primary, primaryDir, secondaryDir),
() => UndoAlign(objectsToAlign, originalPos));
CommandInvoker.instance.Invoke(command);
}
private void Align(List<CustomAssetRenderObject> objectsToAlign, int primary, Vector3 primaryDir, Vector3 secondaryDir)
{
int countP = 0;
int countS = 0;
Vector3 referencePoint = objectsToAlign[0].transform.position;
for (int i = 1; i < objectsToAlign.Count; i++)
{
CustomAssetRenderObject renderObject = objectsToAlign[i];
if (countP < primary - 1 || primary == 0)
{
countP++;
}
else
{
countS++;
countP = 0;
}
renderObject.transform.position = referencePoint + primaryDir * countP + secondaryDir * countS;
renderObject.onTransformChanged?.Invoke();
}
CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_dynamicobjectinfo.OnTransformChanged(objectsToAlign.Select(renderObject => renderObject.gameObject).ToList());
}
private void UndoAlign(List<CustomAssetRenderObject> objectsToAlign, List<Vector3> originalPos)
{
for (int i = 1; i < objectsToAlign.Count; i++)
{
CustomAssetRenderObject renderObject = objectsToAlign[i];
renderObject.transform.position = originalPos[i];
renderObject.onTransformChanged?.Invoke();
}
CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_dynamicobjectinfo.OnTransformChanged(objectsToAlign.Select(renderObject => renderObject.gameObject).ToList());
}
InputHandler myHandler;
public void StatusEnterEvent()
{
userInputManager.SetHandler(myHandler);
}
public void StatusExitEvent()
{
userInputManager .RemoveHandler(myHandler);
}
public InputHandler GetInputHandler()
{
var getKeyActions = new Dictionary<KeyCode, Action>();
var downKeyActions = new Dictionary<KeyCode, Action>();
var upKeyActions = new Dictionary<KeyCode, Action>();
downKeyActions.Add(KeyCode.Mouse0, OnMousePointerDown);
upKeyActions.Add(KeyCode.Mouse0, OnMousePointerUp);
downKeyActions.Add(KeyCode.Mouse1, OnMouseRightPointerDown);
upKeyActions.Add(KeyCode.Mouse1, OnMouseRightPointerUp);
downKeyActions.Add(KeyCode.W, () => SetGizmoChangedCommand(new ActivateMoveGizmoCommand()));
downKeyActions.Add(KeyCode.E, () => SetGizmoChangedCommand(new ActivateRotateGizmoCommand()));
downKeyActions.Add(KeyCode.R, () => SetGizmoChangedCommand(new ActivateScaleGizmoCommand()));
//downKeyActions.Add(KeyCode.R, () => SetGizmoChangedCommand(new ResetGizmoCommand()));
downKeyActions.Add(KeyCode.Delete, () => CommandInvoker.instance.Invoke(new RemoveSelectObjectCommand()));
var shortcutTable = new Dictionary<KeyCode, Dictionary<KeyCode, Action>>();
#if UNITY_EDITOR
shortcutTable.Add(KeyCode.LeftControl, new Dictionary<KeyCode, Action>());
//shortcutTable[KeyCode.LeftShift].Add(KeyCode.C, SaveItemsToCopy);
//shortcutTable[KeyCode.LeftShift].Add(KeyCode.V, () => CommandInvoker.instance.Invoke(new CopyObjectCommand()));
shortcutTable[KeyCode.LeftControl].Add(KeyCode.D, () =>
{
if (ManagerHub.instance.Get<RenderObjectHandler>().selectedRenderObjects.Count == 0)
return;
CommandInvoker.instance.Invoke(new CopyObjectCommand());
// CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_toastmessage.ActivateMessage("Copy");
});
#else
shortcutTable.Add(KeyCode.LeftControl, new Dictionary<KeyCode, Action>());
//shortcutTable[KeyCode.LeftControl].Add(KeyCode.C, SaveItemsToCopy);
//shortcutTable[KeyCode.LeftControl].Add(KeyCode.V, () => CommandInvoker.instance.Invoke(new CopyObjectCommand()));
shortcutTable[KeyCode.LeftControl].Add(KeyCode.D, () =>
{
if (ManagerHub.instance.Get<RenderObjectHandler>().selectedRenderObjects.Count == 0)
return;
CommandInvoker.instance.Invoke(new CopyObjectCommand());
// CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_toastmessage.ActivateMessage("Copy");
});
#endif
var handler = new InputHandler(getKeyActions, downKeyActions, upKeyActions, shortcutTable);
return handler;
}
private void OnMouseRightPointerDown()
{
inputLockhandler = true;
}
private void OnMouseRightPointerUp()
{
inputLockhandler = false;
}
private void SetGizmoChangedCommand(IIrreversibleCommand command)
{
if (!inputLockhandler)
{
CommandInvoker.instance.Invoke(command);
}
}
}
}