Add detective board

This commit is contained in:
2026-02-10 03:00:41 +01:00
parent d4a728a150
commit b172762d4f
51 changed files with 1502 additions and 92 deletions
@@ -0,0 +1,93 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unheimlich.Data.DetectiveBoard;
namespace Unheimlich.UI.DetectiveBoard
{
/// <summary>
/// Visual representation of a clue node on the detective board.
/// Displays as a post-it/card with title, description, and icon.
/// Supports visual states: unlocked, eliminated, highlighted.
/// </summary>
public class ClueNodeUI : MonoBehaviour
{
[Header("References")]
[SerializeField] private Image _nodeImage;
[SerializeField] private TextMeshProUGUI _titleText;
[SerializeField] private Image _iconImage;
[SerializeField] private GameObject _eliminatedOverlay;
private ClueData _clueData;
private bool _isEliminated;
private Color _originalColor;
public ClueData ClueData => _clueData;
public bool IsEliminated => _isEliminated;
/// <summary>
/// Initializes the node with clue data.
/// </summary>
public void Initialize(ClueData clueData)
{
_clueData = clueData;
if (_titleText != null)
_titleText.text = clueData.Title;
if (_iconImage != null && clueData.Icon != null)
{
_iconImage.sprite = clueData.Icon;
_iconImage.enabled = true;
}
else if (_iconImage != null)
{
_iconImage.enabled = false;
}
if (_nodeImage != null)
{
_originalColor = clueData.NodeColor;
_nodeImage.color = _originalColor;
}
if (_eliminatedOverlay != null)
_eliminatedOverlay.SetActive(false);
}
/// <summary>
/// Marks this node as eliminated (incorrect hypothesis).
/// </summary>
public void SetEliminated(bool eliminated)
{
_isEliminated = eliminated;
if (_eliminatedOverlay != null)
_eliminatedOverlay.SetActive(eliminated);
if (_nodeImage != null)
{
_nodeImage.color = eliminated ? Color.gray : _originalColor;
}
}
/// <summary>
/// Highlights the node when hovered.
/// </summary>
public void SetHighlighted(bool highlighted, Color highlightColor)
{
if (_nodeImage != null && !_isEliminated)
{
_nodeImage.color = highlighted ? highlightColor : _originalColor;
}
}
/// <summary>
/// Updates the position of this node on the board (world space or canvas).
/// </summary>
public void SetPosition(Vector3 position)
{
transform.position = position;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a7086ec4620627b458b08500e412ee90
@@ -0,0 +1,90 @@
using UnityEngine;
using Unheimlich.Managers;
namespace Unheimlich.UI.DetectiveBoard
{
/// <summary>
/// Renders a connection line between two clue nodes on the detective board.
/// Visual style changes based on certainty level and elimination state.
/// </summary>
[RequireComponent(typeof(LineRenderer))]
public class ConnectionLineRenderer : MonoBehaviour
{
private LineRenderer _lineRenderer;
private string _fromClueID;
private string _toClueID;
private DetectiveBoardManager.CertaintyLevel _certainty;
private bool _isEliminated;
public string FromClueID => _fromClueID;
public string ToClueID => _toClueID;
private void Awake()
{
_lineRenderer = GetComponent<LineRenderer>();
}
/// <summary>
/// Initializes the connection line between two nodes.
/// </summary>
public void Initialize(string fromClueID, string toClueID,
DetectiveBoardManager.CertaintyLevel certainty, Color color, float width)
{
_fromClueID = fromClueID;
_toClueID = toClueID;
_certainty = certainty;
if (_lineRenderer != null)
{
_lineRenderer.startWidth = width;
_lineRenderer.endWidth = width;
_lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
_lineRenderer.startColor = color;
_lineRenderer.endColor = color;
}
}
/// <summary>
/// Updates the line positions based on node transforms.
/// </summary>
public void UpdateLine(Vector3 startPos, Vector3 endPos)
{
if (_lineRenderer != null)
{
_lineRenderer.SetPosition(0, startPos);
_lineRenderer.SetPosition(1, endPos);
}
}
/// <summary>
/// Updates the certainty level and visual appearance.
/// </summary>
public void SetCertainty(DetectiveBoardManager.CertaintyLevel certainty, Color color)
{
_certainty = certainty;
if (_lineRenderer != null)
{
_lineRenderer.startColor = color;
_lineRenderer.endColor = color;
}
}
/// <summary>
/// Marks this connection as eliminated.
/// </summary>
public void SetEliminated(bool eliminated)
{
_isEliminated = eliminated;
if (_lineRenderer != null)
{
float alpha = eliminated ? 0.3f : 1f;
Color color = _lineRenderer.startColor;
color.a = alpha;
_lineRenderer.startColor = color;
_lineRenderer.endColor = color;
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8d829d9811842b241b980bd64ab73bff