Mini demo with all features
This commit is contained in:
@@ -3,22 +3,41 @@ using UnityEngine.UI;
|
||||
|
||||
namespace Unheimlich.UI.DetectiveBoard
|
||||
{
|
||||
public enum LineColorState
|
||||
{
|
||||
Green = 0,
|
||||
Orange = 1,
|
||||
Red = 2
|
||||
}
|
||||
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class ConnectionLine : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Image _lineImage;
|
||||
[SerializeField] private Image _outlineImage;
|
||||
[SerializeField] private RectTransform _rectTransform;
|
||||
|
||||
private RectTransform _lineRectTransform;
|
||||
private RectTransform _outlineRectTransform;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private float _lineThickness = 3f;
|
||||
[SerializeField] private Color _lineColor = Color.white;
|
||||
[SerializeField] private Color _outlineColor = Color.yellow;
|
||||
|
||||
[Header("Color States")]
|
||||
[SerializeField] private Color _greenColor = Color.green;
|
||||
[SerializeField] private Color _orangeColor = new Color(1f, 0.5f, 0f);
|
||||
[SerializeField] private Color _redColor = Color.red;
|
||||
|
||||
private PostItNode _startNode;
|
||||
private PostItNode _endNode;
|
||||
private LineColorState _colorState = LineColorState.Green;
|
||||
private bool _isHovered;
|
||||
|
||||
public PostItNode StartNode => _startNode;
|
||||
public PostItNode EndNode => _endNode;
|
||||
public LineColorState ColorState => _colorState;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -26,20 +45,54 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
|
||||
if (_lineImage == null)
|
||||
_lineImage = GetComponent<Image>();
|
||||
_lineImage = GetComponentInChildren<Image>();
|
||||
|
||||
if (_lineImage != null)
|
||||
{
|
||||
_lineRectTransform = _lineImage.GetComponent<RectTransform>();
|
||||
_lineImage.raycastTarget = true;
|
||||
}
|
||||
|
||||
if (_rectTransform != null)
|
||||
{
|
||||
_rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
_rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
_rectTransform.pivot = new Vector2(0f, 0.5f);
|
||||
}
|
||||
|
||||
if (_lineRectTransform != null)
|
||||
{
|
||||
_lineRectTransform.anchorMin = new Vector2(0f, 0.5f);
|
||||
_lineRectTransform.anchorMax = new Vector2(0f, 0.5f);
|
||||
_lineRectTransform.pivot = new Vector2(0f, 0.5f);
|
||||
}
|
||||
|
||||
if (_outlineImage == null)
|
||||
{
|
||||
_outlineImage = transform.Find("Outline")?.GetComponent<Image>();
|
||||
}
|
||||
|
||||
if (_outlineImage != null)
|
||||
{
|
||||
_outlineRectTransform = _outlineImage.GetComponent<RectTransform>();
|
||||
if (_outlineRectTransform != null)
|
||||
{
|
||||
_outlineRectTransform.anchorMin = new Vector2(0f, 0.5f);
|
||||
_outlineRectTransform.anchorMax = new Vector2(0f, 0.5f);
|
||||
_outlineRectTransform.pivot = new Vector2(0f, 0.5f);
|
||||
}
|
||||
_outlineImage.raycastTarget = false;
|
||||
_outlineImage.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(PostItNode startNode, PostItNode endNode, Color? color = null)
|
||||
public void Initialize(PostItNode startNode, PostItNode endNode)
|
||||
{
|
||||
_startNode = startNode;
|
||||
_endNode = endNode;
|
||||
_colorState = LineColorState.Green;
|
||||
|
||||
if (color.HasValue)
|
||||
_lineColor = color.Value;
|
||||
|
||||
if (_lineImage != null)
|
||||
_lineImage.color = _lineColor;
|
||||
|
||||
UpdateColorState();
|
||||
UpdateLine();
|
||||
}
|
||||
|
||||
@@ -55,19 +108,57 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
float distance = direction.magnitude;
|
||||
|
||||
_rectTransform.anchoredPosition = startPos;
|
||||
_rectTransform.sizeDelta = new Vector2(distance, _lineThickness);
|
||||
|
||||
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
|
||||
_rectTransform.rotation = Quaternion.Euler(0, 0, angle);
|
||||
_rectTransform.localRotation = Quaternion.Euler(0, 0, angle);
|
||||
|
||||
_rectTransform.pivot = new Vector2(0, 0.5f);
|
||||
if (_lineRectTransform != null)
|
||||
{
|
||||
_lineRectTransform.sizeDelta = new Vector2(distance, _lineThickness);
|
||||
}
|
||||
|
||||
if (_outlineRectTransform != null)
|
||||
{
|
||||
_outlineRectTransform.sizeDelta = new Vector2(distance, _lineThickness + 3f);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetColor(Color color)
|
||||
public void CycleColorState()
|
||||
{
|
||||
_lineColor = color;
|
||||
if (_lineImage != null)
|
||||
_lineImage.color = color;
|
||||
_colorState = (LineColorState)(((int)_colorState + 1) % 3);
|
||||
UpdateColorState();
|
||||
}
|
||||
|
||||
public void SetColorState(LineColorState state)
|
||||
{
|
||||
_colorState = state;
|
||||
UpdateColorState();
|
||||
}
|
||||
|
||||
private void UpdateColorState()
|
||||
{
|
||||
if (_lineImage == null)
|
||||
return;
|
||||
|
||||
Color targetColor = _colorState switch
|
||||
{
|
||||
LineColorState.Green => _greenColor,
|
||||
LineColorState.Orange => _orangeColor,
|
||||
LineColorState.Red => _redColor,
|
||||
_ => _greenColor
|
||||
};
|
||||
|
||||
_lineImage.color = targetColor;
|
||||
}
|
||||
|
||||
public void SetHovered(bool hovered)
|
||||
{
|
||||
_isHovered = hovered;
|
||||
|
||||
if (_outlineImage != null)
|
||||
{
|
||||
_outlineImage.gameObject.SetActive(hovered);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ConnectsNodes(PostItNode nodeA, PostItNode nodeB)
|
||||
|
||||
@@ -5,35 +5,85 @@ using System.Linq;
|
||||
using Unheimlich.Data.DetectiveBoard;
|
||||
using Unheimlich.Managers;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Gameplay.Player;
|
||||
|
||||
namespace Unheimlich.UI.DetectiveBoard
|
||||
{
|
||||
public class DetectiveBoardCanvas : Singleton<DetectiveBoardCanvas>
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Canvas _canvas;
|
||||
[SerializeField] private RectTransform _boardArea;
|
||||
[Header("Prefabs")]
|
||||
[SerializeField] private GameObject _postItNodePrefab;
|
||||
[SerializeField] private GameObject _connectionLinePrefab;
|
||||
|
||||
[Header("World Space Setup")]
|
||||
[SerializeField] private Camera _targetCamera;
|
||||
[Header("Layout References")]
|
||||
[SerializeField] private RectTransform _boardArea;
|
||||
|
||||
[Header("Connection Settings")]
|
||||
[SerializeField] private Color _connectionColor = Color.white;
|
||||
[SerializeField] private bool _allowFreeConnections = false;
|
||||
[Header("Auto-Placement Settings")]
|
||||
[SerializeField] private float _leftMargin = 50f;
|
||||
[SerializeField] private float _topMargin = 50f;
|
||||
[SerializeField] private float _nodeSpacing = 20f;
|
||||
[SerializeField] private float _randomRotationRange = 10f;
|
||||
|
||||
[Header("Input")]
|
||||
[SerializeField] private Key _connectModeKey = Key.LeftCtrl;
|
||||
[SerializeField] private Key _eliminateKey = Key.X;
|
||||
|
||||
private Canvas _canvas;
|
||||
private Camera _targetCamera;
|
||||
private Dictionary<string, PostItNode> _activeNodes = new Dictionary<string, PostItNode>();
|
||||
private List<ConnectionLine> _activeConnections = new List<ConnectionLine>();
|
||||
private PostItNode _selectedNode;
|
||||
private ConnectionLine _hoveredLine;
|
||||
private bool _isConnectMode;
|
||||
private DetectiveBoardSaveData _saveData;
|
||||
private float _currentColumnYOffset = 0f;
|
||||
|
||||
public bool IsConnectMode => _isConnectMode;
|
||||
public RectTransform BoardArea => _boardArea;
|
||||
|
||||
public void OnLineClicked(ConnectionLine line)
|
||||
{
|
||||
if (line != null)
|
||||
{
|
||||
line.CycleColorState();
|
||||
SaveConnectionColorState(line);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveConnectionColorState(ConnectionLine line)
|
||||
{
|
||||
if (line.StartNode == null || line.EndNode == null)
|
||||
return;
|
||||
|
||||
ConnectionData startNodeConnection = line.StartNode.NodeData.Connections.Find(c => c.TargetNodeID == line.EndNode.NodeID);
|
||||
if (startNodeConnection != null)
|
||||
{
|
||||
startNodeConnection.ColorState = line.ColorState;
|
||||
}
|
||||
|
||||
ConnectionData endNodeConnection = line.EndNode.NodeData.Connections.Find(c => c.TargetNodeID == line.StartNode.NodeID);
|
||||
if (endNodeConnection != null)
|
||||
{
|
||||
endNodeConnection.ColorState = line.ColorState;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHoveredLine(ConnectionLine line)
|
||||
{
|
||||
if (_hoveredLine == line)
|
||||
return;
|
||||
|
||||
if (_hoveredLine != null)
|
||||
{
|
||||
_hoveredLine.SetHovered(false);
|
||||
}
|
||||
|
||||
_hoveredLine = line;
|
||||
|
||||
if (_hoveredLine != null)
|
||||
{
|
||||
_hoveredLine.SetHovered(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by DetectiveBoardInteraction when a node is left-clicked.
|
||||
@@ -63,11 +113,13 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (_canvas == null)
|
||||
_canvas = GetComponent<Canvas>();
|
||||
_canvas = GetComponent<Canvas>();
|
||||
|
||||
if (_canvas != null && _canvas.renderMode == RenderMode.WorldSpace)
|
||||
{
|
||||
if (PlayerController.Instance != null)
|
||||
_targetCamera = PlayerController.Instance.PlayerCamera;
|
||||
|
||||
if (_targetCamera == null)
|
||||
_targetCamera = Camera.main;
|
||||
|
||||
@@ -120,7 +172,6 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
private void Update()
|
||||
{
|
||||
HandleConnectModeInput();
|
||||
HandleEliminateInput();
|
||||
}
|
||||
|
||||
private void HandleConnectModeInput()
|
||||
@@ -138,17 +189,6 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEliminateInput()
|
||||
{
|
||||
if (Keyboard.current == null)
|
||||
return;
|
||||
|
||||
if (Keyboard.current[_eliminateKey].wasPressedThisFrame && _selectedNode != null)
|
||||
{
|
||||
ToggleNodeEliminated(_selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddClueNode(ClueData clueData)
|
||||
{
|
||||
if (_activeNodes.ContainsKey(clueData.ClueID))
|
||||
@@ -169,12 +209,8 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
PostItNodeData nodeData = _saveData.GetNodeData(clueData.ClueID);
|
||||
if (nodeData == null)
|
||||
{
|
||||
Vector2 canvasSize = _boardArea.rect.size;
|
||||
Vector2 randomPos = new Vector2(
|
||||
Random.Range(-canvasSize.x * 0.4f, canvasSize.x * 0.4f),
|
||||
Random.Range(-canvasSize.y * 0.4f, canvasSize.y * 0.4f)
|
||||
);
|
||||
nodeData = new PostItNodeData(clueData.ClueID, randomPos);
|
||||
Vector2 autoPlacedPos = CalculateAutoPlacementPosition();
|
||||
nodeData = new PostItNodeData(clueData.ClueID, autoPlacedPos);
|
||||
_saveData.AddOrUpdateNode(nodeData);
|
||||
}
|
||||
|
||||
@@ -191,11 +227,40 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
node.Initialize(clueData, nodeData);
|
||||
|
||||
float savedRotation = nodeData.Rotation;
|
||||
if (savedRotation == 0f)
|
||||
{
|
||||
savedRotation = Random.Range(-_randomRotationRange, _randomRotationRange);
|
||||
nodeData.Rotation = savedRotation;
|
||||
}
|
||||
node.SetRotation(savedRotation);
|
||||
|
||||
_activeNodes.Add(clueData.ClueID, node);
|
||||
|
||||
RestoreConnectionsForNode(node);
|
||||
}
|
||||
|
||||
private Vector2 CalculateAutoPlacementPosition()
|
||||
{
|
||||
Vector2 canvasSize = _boardArea.rect.size;
|
||||
|
||||
float startX = -canvasSize.x * 0.5f + _leftMargin;
|
||||
float startY = canvasSize.y * 0.5f - _topMargin;
|
||||
|
||||
float estimatedNodeHeight = 150f;
|
||||
|
||||
Vector2 position = new Vector2(startX, startY - _currentColumnYOffset);
|
||||
|
||||
_currentColumnYOffset += estimatedNodeHeight + _nodeSpacing;
|
||||
|
||||
if (_currentColumnYOffset > canvasSize.y - _topMargin * 2)
|
||||
{
|
||||
_currentColumnYOffset = 0f;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
public void RemoveClueNode(string clueID)
|
||||
{
|
||||
if (!_activeNodes.TryGetValue(clueID, out PostItNode node))
|
||||
@@ -229,9 +294,6 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
private void ToggleConnection(PostItNode nodeA, PostItNode nodeB)
|
||||
{
|
||||
if (!CanConnect(nodeA, nodeB))
|
||||
return;
|
||||
|
||||
ConnectionLine existingConnection = _activeConnections.Find(c => c.ConnectsNodes(nodeA, nodeB));
|
||||
|
||||
if (existingConnection != null)
|
||||
@@ -244,20 +306,6 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanConnect(PostItNode nodeA, PostItNode nodeB)
|
||||
{
|
||||
if (nodeA == null || nodeB == null)
|
||||
return false;
|
||||
|
||||
if (_allowFreeConnections)
|
||||
return true;
|
||||
|
||||
if (nodeA.ClueData.PossibleConnections == null || nodeA.ClueData.PossibleConnections.Length == 0)
|
||||
return true;
|
||||
|
||||
return nodeA.ClueData.PossibleConnections.Contains(nodeB.NodeID);
|
||||
}
|
||||
|
||||
private void CreateConnection(PostItNode startNode, PostItNode endNode)
|
||||
{
|
||||
GameObject lineObj = Instantiate(_connectionLinePrefab, _boardArea);
|
||||
@@ -271,22 +319,34 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
return;
|
||||
}
|
||||
|
||||
line.Initialize(startNode, endNode, _connectionColor);
|
||||
line.Initialize(startNode, endNode);
|
||||
|
||||
ConnectionData existingConnectionData = startNode.NodeData.Connections.Find(c => c.TargetNodeID == endNode.NodeID);
|
||||
if (existingConnectionData != null)
|
||||
{
|
||||
line.SetColorState(existingConnectionData.ColorState);
|
||||
}
|
||||
|
||||
_activeConnections.Add(line);
|
||||
|
||||
if (!startNode.NodeData.ConnectedNodeIDs.Contains(endNode.NodeID))
|
||||
startNode.NodeData.ConnectedNodeIDs.Add(endNode.NodeID);
|
||||
if (existingConnectionData == null)
|
||||
{
|
||||
startNode.NodeData.Connections.Add(new ConnectionData(endNode.NodeID));
|
||||
}
|
||||
|
||||
if (!endNode.NodeData.ConnectedNodeIDs.Contains(startNode.NodeID))
|
||||
endNode.NodeData.ConnectedNodeIDs.Add(startNode.NodeID);
|
||||
ConnectionData reverseConnectionData = endNode.NodeData.Connections.Find(c => c.TargetNodeID == startNode.NodeID);
|
||||
if (reverseConnectionData == null)
|
||||
{
|
||||
endNode.NodeData.Connections.Add(new ConnectionData(startNode.NodeID));
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveConnection(ConnectionLine connection)
|
||||
{
|
||||
if (connection.StartNode != null && connection.EndNode != null)
|
||||
{
|
||||
connection.StartNode.NodeData.ConnectedNodeIDs.Remove(connection.EndNode.NodeID);
|
||||
connection.EndNode.NodeData.ConnectedNodeIDs.Remove(connection.StartNode.NodeID);
|
||||
connection.StartNode.NodeData.Connections.RemoveAll(c => c.TargetNodeID == connection.EndNode.NodeID);
|
||||
connection.EndNode.NodeData.Connections.RemoveAll(c => c.TargetNodeID == connection.StartNode.NodeID);
|
||||
}
|
||||
|
||||
_activeConnections.Remove(connection);
|
||||
@@ -322,12 +382,12 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
private void RestoreConnectionsForNode(PostItNode node)
|
||||
{
|
||||
if (node.NodeData.ConnectedNodeIDs == null || node.NodeData.ConnectedNodeIDs.Count == 0)
|
||||
if (node.NodeData.Connections == null || node.NodeData.Connections.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (string connectedID in node.NodeData.ConnectedNodeIDs)
|
||||
foreach (ConnectionData connectionData in node.NodeData.Connections)
|
||||
{
|
||||
if (_activeNodes.TryGetValue(connectedID, out PostItNode otherNode))
|
||||
if (_activeNodes.TryGetValue(connectionData.TargetNodeID, out PostItNode otherNode))
|
||||
{
|
||||
bool connectionExists = _activeConnections.Any(c => c.ConnectsNodes(node, otherNode));
|
||||
if (!connectionExists)
|
||||
@@ -366,6 +426,7 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
if (nodeData != null)
|
||||
{
|
||||
node.SetPosition(nodeData.Position);
|
||||
node.SetRotation(nodeData.Rotation);
|
||||
node.SetEliminated(nodeData.IsEliminated);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.UI;
|
||||
using Unheimlich.Gameplay.DetectiveBoard;
|
||||
using Unheimlich.Gameplay.Player;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
@@ -14,35 +15,38 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
/// </summary>
|
||||
public class DetectiveBoardInteraction : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Camera _camera;
|
||||
[SerializeField] private Canvas _boardCanvas;
|
||||
[SerializeField] private RectTransform _boardArea;
|
||||
[SerializeField] private LayerMask _boardLayer;
|
||||
[SerializeField] private DetectiveBoardController _boardController;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private LayerMask _boardLayer;
|
||||
[SerializeField] private float _minInteractionDistance = 0.1f;
|
||||
[SerializeField] private float _maxInteractionDistance = 10f;
|
||||
|
||||
private Camera _camera;
|
||||
private Canvas _boardCanvas;
|
||||
private RectTransform _boardArea;
|
||||
private DetectiveBoardController _boardController;
|
||||
private DetectiveBoardCanvas _canvasManager;
|
||||
private PostItNode _hoveredNode;
|
||||
private PostItNode _selectedNode;
|
||||
private ConnectionLine _hoveredLine;
|
||||
private bool _isDragging;
|
||||
private Plane _canvasPlane;
|
||||
private Vector3 _dragOffset;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_boardCanvas = GetComponent<Canvas>();
|
||||
_canvasManager = GetComponent<DetectiveBoardCanvas>();
|
||||
_boardController = DetectiveBoardController.Instance;
|
||||
|
||||
if (_canvasManager != null && _canvasManager.BoardArea != null)
|
||||
_boardArea = _canvasManager.BoardArea;
|
||||
|
||||
if (PlayerController.Instance != null)
|
||||
_camera = PlayerController.Instance.PlayerCamera;
|
||||
|
||||
if (_camera == null)
|
||||
_camera = Camera.main;
|
||||
|
||||
if (_boardController == null)
|
||||
_boardController = FindFirstObjectByType<DetectiveBoardController>();
|
||||
|
||||
if (_canvasManager == null)
|
||||
_canvasManager = GetComponent<DetectiveBoardCanvas>();
|
||||
|
||||
UpdateCanvasPlane();
|
||||
}
|
||||
|
||||
@@ -63,6 +67,7 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
else
|
||||
{
|
||||
HandleHover();
|
||||
HandleLineHover();
|
||||
}
|
||||
|
||||
HandleClick();
|
||||
@@ -70,7 +75,9 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
private bool IsInBoardInteractionMode()
|
||||
{
|
||||
return _boardController != null && _boardController.IsBoardActive;
|
||||
bool isActive = _boardController != null && _boardController.IsBoardActive;
|
||||
|
||||
return isActive;
|
||||
}
|
||||
|
||||
private void ClearInteractionState()
|
||||
@@ -81,6 +88,12 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
_hoveredNode = null;
|
||||
}
|
||||
|
||||
if (_hoveredLine != null && _canvasManager != null)
|
||||
{
|
||||
_canvasManager.SetHoveredLine(null);
|
||||
_hoveredLine = null;
|
||||
}
|
||||
|
||||
if (_selectedNode != null && _isDragging)
|
||||
{
|
||||
_selectedNode.SetSelected(false);
|
||||
@@ -119,6 +132,59 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleLineHover()
|
||||
{
|
||||
if (_canvasManager == null || Mouse.current == null)
|
||||
return;
|
||||
|
||||
if (_hoveredNode != null)
|
||||
{
|
||||
if (_hoveredLine != null)
|
||||
{
|
||||
_canvasManager.SetHoveredLine(null);
|
||||
_hoveredLine = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionLine hitLine = RaycastForLine();
|
||||
|
||||
if (hitLine != _hoveredLine)
|
||||
{
|
||||
_canvasManager.SetHoveredLine(hitLine);
|
||||
_hoveredLine = hitLine;
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionLine RaycastForLine()
|
||||
{
|
||||
if (_camera == null || Mouse.current == null)
|
||||
return null;
|
||||
|
||||
Vector2 mousePos = Mouse.current.position.ReadValue();
|
||||
|
||||
GraphicRaycaster raycaster = _boardCanvas?.GetComponent<GraphicRaycaster>();
|
||||
if (raycaster != null && EventSystem.current != null)
|
||||
{
|
||||
var pointerEventData = new PointerEventData(EventSystem.current)
|
||||
{
|
||||
position = mousePos
|
||||
};
|
||||
|
||||
var results = new List<RaycastResult>();
|
||||
raycaster.Raycast(pointerEventData, results);
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
ConnectionLine line = result.gameObject.GetComponentInParent<ConnectionLine>();
|
||||
if (line != null)
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
if (Mouse.current == null)
|
||||
@@ -128,7 +194,18 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
HandleLeftClick(hitNode);
|
||||
if (hitNode != null)
|
||||
{
|
||||
HandleLeftClick(hitNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectionLine hitLine = RaycastForLine();
|
||||
if (hitLine != null && _canvasManager != null)
|
||||
{
|
||||
_canvasManager.OnLineClicked(hitLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Mouse.current.rightButton.wasPressedThisFrame && hitNode != null && _canvasManager != null)
|
||||
{
|
||||
|
||||
@@ -13,9 +13,11 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
[SerializeField] private TextMeshProUGUI _titleText;
|
||||
[SerializeField] private TextMeshProUGUI _descriptionText;
|
||||
[SerializeField] private Image _iconImage;
|
||||
[SerializeField] private GameObject _strikethroughLine;
|
||||
[SerializeField] private Image _selectionOutline;
|
||||
|
||||
[Header("Effects")]
|
||||
[SerializeField] private PostItScribbleEffect _scribbleEffect;
|
||||
|
||||
[Header("Connection Points")]
|
||||
[SerializeField] private RectTransform _connectionPoint;
|
||||
|
||||
@@ -27,7 +29,7 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
|
||||
public string NodeID => _clueData?.ClueID;
|
||||
public RectTransform RectTransform => _rectTransform;
|
||||
public RectTransform ConnectionPoint => _connectionPoint;
|
||||
public RectTransform ConnectionPoint => _rectTransform;
|
||||
public ClueData ClueData => _clueData;
|
||||
public PostItNodeData NodeData => _nodeData;
|
||||
public bool IsEliminated => _isEliminated;
|
||||
@@ -38,8 +40,8 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
if (_rectTransform == null)
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
|
||||
if (_strikethroughLine != null)
|
||||
_strikethroughLine.SetActive(false);
|
||||
if (_scribbleEffect == null)
|
||||
_scribbleEffect = GetComponent<PostItScribbleEffect>();
|
||||
|
||||
if (_selectionOutline != null)
|
||||
_selectionOutline.enabled = false;
|
||||
@@ -72,11 +74,6 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
_background.color = _originalColor;
|
||||
}
|
||||
|
||||
if (_connectionPoint == null)
|
||||
{
|
||||
_connectionPoint = _rectTransform;
|
||||
}
|
||||
|
||||
SetPosition(nodeData.Position);
|
||||
SetEliminated(nodeData.IsEliminated);
|
||||
}
|
||||
@@ -91,16 +88,28 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRotation(float rotation)
|
||||
{
|
||||
if (_rectTransform != null)
|
||||
{
|
||||
_rectTransform.localRotation = Quaternion.Euler(0, 0, rotation);
|
||||
if (_nodeData != null)
|
||||
_nodeData.Rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetRotation()
|
||||
{
|
||||
return _rectTransform != null ? _rectTransform.localEulerAngles.z : 0f;
|
||||
}
|
||||
|
||||
public void SetEliminated(bool eliminated)
|
||||
{
|
||||
_isEliminated = eliminated;
|
||||
|
||||
if (_strikethroughLine != null)
|
||||
_strikethroughLine.SetActive(eliminated);
|
||||
|
||||
if (_background != null)
|
||||
if (_scribbleEffect != null)
|
||||
{
|
||||
_background.color = eliminated ? new Color(0.5f, 0.5f, 0.5f, 0.8f) : _originalColor;
|
||||
_scribbleEffect.SetEliminated(eliminated);
|
||||
}
|
||||
|
||||
if (_nodeData != null)
|
||||
@@ -110,18 +119,13 @@ namespace Unheimlich.UI.DetectiveBoard
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
_isSelected = selected;
|
||||
|
||||
if (_selectionOutline != null)
|
||||
{
|
||||
_selectionOutline.enabled = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHovered(bool hovered)
|
||||
{
|
||||
if (_selectionOutline != null)
|
||||
{
|
||||
_selectionOutline.enabled = hovered || _isSelected;
|
||||
_selectionOutline.enabled = hovered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.UI.DetectiveBoard
|
||||
{
|
||||
public class PostItScribbleEffect : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Material _scribbleMaterialTemplate;
|
||||
[SerializeField] private RectTransform _targetRectTransform;
|
||||
|
||||
private Image _scribbleOverlay;
|
||||
private Material _scribbleMaterialInstance;
|
||||
private bool _overlayCreated = false;
|
||||
private bool _isEliminated = false;
|
||||
|
||||
private static readonly int ProgressID = Shader.PropertyToID("_Progress");
|
||||
private int _scribbleTweenId = -1;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_targetRectTransform == null)
|
||||
_targetRectTransform = GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
private void CreateScribbleOverlay()
|
||||
{
|
||||
if (_overlayCreated || _scribbleMaterialTemplate == null || _targetRectTransform == null)
|
||||
return;
|
||||
|
||||
GameObject overlayObject = new GameObject("ScribbleOverlay");
|
||||
overlayObject.transform.SetParent(_targetRectTransform, false);
|
||||
|
||||
_scribbleOverlay = overlayObject.AddComponent<Image>();
|
||||
_scribbleOverlay.raycastTarget = false;
|
||||
|
||||
RectTransform overlayRect = overlayObject.GetComponent<RectTransform>();
|
||||
|
||||
overlayRect.anchorMin = Vector2.zero;
|
||||
overlayRect.anchorMax = Vector2.one;
|
||||
overlayRect.sizeDelta = Vector2.zero;
|
||||
overlayRect.anchoredPosition = Vector2.zero;
|
||||
|
||||
_scribbleMaterialInstance = new Material(_scribbleMaterialTemplate);
|
||||
_scribbleMaterialInstance.SetFloat(ProgressID, 0f);
|
||||
_scribbleOverlay.material = _scribbleMaterialInstance;
|
||||
|
||||
_scribbleOverlay.gameObject.SetActive(false);
|
||||
|
||||
_overlayCreated = true;
|
||||
}
|
||||
|
||||
public void SetEliminated(bool eliminated)
|
||||
{
|
||||
if (_isEliminated == eliminated)
|
||||
return;
|
||||
|
||||
_isEliminated = eliminated;
|
||||
|
||||
if (eliminated)
|
||||
{
|
||||
ApplyScribble();
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveScribble();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyScribble()
|
||||
{
|
||||
CancelActiveTweens();
|
||||
CreateScribbleOverlay();
|
||||
|
||||
if (_scribbleOverlay == null || _scribbleMaterialInstance == null)
|
||||
return;
|
||||
|
||||
_scribbleOverlay.gameObject.SetActive(true);
|
||||
|
||||
_scribbleTweenId = LeanTween.value(gameObject, 0f, 1f, 0.4f)
|
||||
.setEase(LeanTweenType.easeInOutQuad)
|
||||
.setOnUpdate((float val) => {
|
||||
if (_scribbleMaterialInstance != null)
|
||||
_scribbleMaterialInstance.SetFloat(ProgressID, val);
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_scribbleTweenId = -1;
|
||||
}).id;
|
||||
}
|
||||
|
||||
private void RemoveScribble()
|
||||
{
|
||||
if (!_overlayCreated || _scribbleOverlay == null)
|
||||
return;
|
||||
|
||||
if (!_scribbleOverlay.gameObject.activeSelf)
|
||||
return;
|
||||
|
||||
CancelActiveTweens();
|
||||
|
||||
if (_scribbleMaterialInstance != null)
|
||||
{
|
||||
float currentProgress = _scribbleMaterialInstance.GetFloat(ProgressID);
|
||||
|
||||
_scribbleTweenId = LeanTween.value(gameObject, currentProgress, 0f, 0.3f)
|
||||
.setEase(LeanTweenType.easeOutQuad)
|
||||
.setOnUpdate((float val) => {
|
||||
if (_scribbleMaterialInstance != null)
|
||||
_scribbleMaterialInstance.SetFloat(ProgressID, val);
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_scribbleTweenId = -1;
|
||||
if (_scribbleOverlay != null)
|
||||
_scribbleOverlay.gameObject.SetActive(false);
|
||||
}).id;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelActiveTweens()
|
||||
{
|
||||
TweenHelper.CancelTween(ref _scribbleTweenId);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
CancelActiveTweens();
|
||||
|
||||
if (_scribbleMaterialInstance != null)
|
||||
Destroy(_scribbleMaterialInstance);
|
||||
|
||||
if (_scribbleOverlay != null)
|
||||
Destroy(_scribbleOverlay.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 009173206d77d184d86915685410c7d8
|
||||
Reference in New Issue
Block a user