Mini demo with all features

This commit is contained in:
2026-02-23 14:10:46 +01:00
parent 5b1bdaeb90
commit d9326e48cc
176 changed files with 32668 additions and 564 deletions
@@ -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);
}
}