Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Assets/.DS_Store
Binary file not shown.
118 changes: 117 additions & 1 deletion Assets/Integration/TreeRhythmController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class TreeRhythmController : MonoBehaviour, IRhythmGameAdapter
[Tooltip("Unity layer for all nodes and edges created by this controller. Set to P1Tree or P2Tree in 2P mode.")]
[SerializeField] private string _treeLayerName = "Default";

[Header("Preview Nodes")]
[Tooltip("Ghost prefab for edge-direction hints and next-value indicator. Assign TreeNodePreview.prefab.")]
[SerializeField] private GameObject _previewNodePrefab;

[Header("Animation")]
[Tooltip("Sound effects and animation parameters for node reactions.")]
[SerializeField] private TreeAnimationConfig _animationConfig;
Expand Down Expand Up @@ -128,6 +132,11 @@ public class TreeRhythmController : MonoBehaviour, IRhythmGameAdapter
private bool _lastActionSucceeded;
private int _currentInsertValue;

private NodePreviewView _leftEdgePreview;
private NodePreviewView _rightEdgePreview;
private NodePreviewView _nextValuePreview;
private int _nextInsertValue;

#endregion

#region Lifecycle
Expand Down Expand Up @@ -158,6 +167,14 @@ private void Awake()
int layer = LayerMask.NameToLayer(_treeLayerName);
_layout = new TreeLayoutManager<int>(_nodePrefab, _config, _edgeContainer, layer < 0 ? 0 : layer);

if (_previewNodePrefab != null)
{
int prevLayer = LayerMask.NameToLayer(_treeLayerName);
_leftEdgePreview = CreatePreviewView(prevLayer);
_rightEdgePreview = CreatePreviewView(prevLayer);
_nextValuePreview = CreatePreviewView(prevLayer);
}

SubscribeNavigatorEvents();
SubscribeRhythmInput();

Expand Down Expand Up @@ -237,6 +254,9 @@ private void OnDestroy()
_p2InputActions.Dispose();
_p2InputActions = null;
}
if (_leftEdgePreview != null) Destroy(_leftEdgePreview.gameObject);
if (_rightEdgePreview != null) Destroy(_rightEdgePreview.gameObject);
if (_nextValuePreview != null) Destroy(_nextValuePreview.gameObject);
}

#endregion
Expand Down Expand Up @@ -395,6 +415,7 @@ private void BeginNextInsertion()
_generator.Max = _config.MaxValue;
int value = _generator.GenerateNext();
_currentInsertValue = value;
_nextInsertValue = _generator.PeekNext();
_navigator.BeginInsertion(value).Forget();
}

Expand All @@ -420,18 +441,25 @@ private void OnNavigationBegan(NavigationContext<int> context)
_activeComparisonNode = context.CurrentNode;
_layout.SetComparisonFocus(context.CurrentNode);
}

UpdateEdgePreviews(context);
}

private void OnMoved(NavigationContext<int> context)
{
ClearActiveComparisonFocus();

if (context.IsAtEmptySlot) return;
if (context.IsAtEmptySlot)
{
HideEdgePreviews();
return;
}

_activeComparisonNode = context.CurrentNode;
_layout.SetComparisonFocus(context.CurrentNode);

MoveCarrierAndCamera(context);
UpdateEdgePreviews(context);
}

private async UniTask OnReachedEmptySlotAsync(NavigationContext<int> context)
Expand All @@ -445,6 +473,9 @@ await UniTask.WhenAll(
_cameraRig.MoveToAsync(target),
_layout.PreviewLayout(_navigator.Root, context.Depth)
);

HideEdgePreviews();
ShowNextValuePreview();
}

private void OnInvalidAction(NavigationContext<int> context, NavigationAction attempted)
Expand All @@ -455,6 +486,7 @@ private void OnInvalidAction(NavigationContext<int> context, NavigationAction at

private async UniTask OnNodeInsertedAsync(TreeNode<int> node)
{
HideNextValuePreview();
ClearActiveComparisonFocus();

_carrierView.SetState(NodeVisualState.Normal);
Expand All @@ -477,6 +509,90 @@ private async UniTask OnNavigationCompleteAsync()

#endregion

#region Preview Nodes

private NodePreviewView CreatePreviewView(int layer)
{
var go = Instantiate(_previewNodePrefab);
int safe = layer < 0 ? 0 : layer;
SetLayerRecursive(go, safe);
var view = go.GetComponent<NodePreviewView>();
view.SetColor(_config.PreviewNodeColor);
go.SetActive(false);
return view;
}

private void UpdateEdgePreviews(NavigationContext<int> context)
{
if (_leftEdgePreview == null || _animationConfig == null) return;

if (context.IsAtEmptySlot || context.CurrentNode == null)
{
HideEdgePreviews();
return;
}

var node = context.CurrentNode;

if (node.Left?.View != null)
{
var leftStart = node.View.LeftConnectorPosition;
var leftDir = (node.Left.View.TopConnectorPosition - leftStart).normalized;
_leftEdgePreview.transform.position = leftStart + leftDir * _config.PreviewEdgeOffset;
_leftEdgePreview.SetValue(node.Left.Value.ToString());
_leftEdgePreview.ShowWithAnimation(
_animationConfig.PreviewShowDuration, _animationConfig.PreviewShowEase);
}
else
{
_leftEdgePreview.gameObject.SetActive(false);
}

if (node.Right?.View != null)
{
var rightStart = node.View.RightConnectorPosition;
var rightDir = (node.Right.View.TopConnectorPosition - rightStart).normalized;
_rightEdgePreview.transform.position = rightStart + rightDir * _config.PreviewEdgeOffset;
_rightEdgePreview.SetValue(node.Right.Value.ToString());
_rightEdgePreview.ShowWithAnimation(
_animationConfig.PreviewShowDuration, _animationConfig.PreviewShowEase);
}
else
{
_rightEdgePreview.gameObject.SetActive(false);
}
}

private void HideEdgePreviews()
{
_leftEdgePreview?.gameObject.SetActive(false);
_rightEdgePreview?.gameObject.SetActive(false);
}

private void ShowNextValuePreview()
{
if (_nextValuePreview == null || _carrierView == null || _animationConfig == null) return;
_nextValuePreview.SetValue(_nextInsertValue.ToString());
_nextValuePreview.transform.position =
_carrierView.transform.position + Vector3.down * _config.PreviewNextValueOffset;
_nextValuePreview.ShowWithAnimation(
_animationConfig.PreviewShowDuration, _animationConfig.PreviewShowEase);
}

private void HideNextValuePreview()
{
_nextValuePreview?.gameObject.SetActive(false);
}

private static void SetLayerRecursive(GameObject go, int layer)
{
go.layer = layer;
foreach (Transform child in go.transform)
SetLayerRecursive(child.gameObject, layer);
}

#endregion

#region Helpers

private void MoveCarrierAndCamera(NavigationContext<int> context)
Expand Down
Loading