Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/SalesSystem/CrankController.cs
T

776 lines
29 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Linq;
using AibisDream.Framework;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using DG.Tweening;
using System.Collections;
namespace AibisDream.MiniGame.HuoShan
{
/// <summary>
/// 发条控制器 - 实现发条的拖拽旋转交互
/// 功能:拖拽旋转,最大260°,缓慢回位,触发事件
/// 交互通过 EventTriggerEx 统一管理,支持 EventSystemEx.isLocked 和 IInteraction 状态
/// 在发条 GameObject 上添加 EventTriggerEx + Collider2D 即可接入;未添加则回退到 Input+Raycast
/// </summary>
public class CrankController : MonoBehaviour, IInteraction
{
[Header("发条配置")]
[Tooltip("最大旋转角度(度)")]
[SerializeField] private float maxRotationAngle = 260f;
[Tooltip("回位时长(秒),从满弦回到 0 的匀速时间,与滑片滑动时长匹配")]
[SerializeField] private float returnDuration = 3f;
[Tooltip("触发事件的最小角度(度)")]
[SerializeField] private float triggerAngle = 240f;
[Tooltip("拖拽阻力,值越大越难拖动")]
[SerializeField] private float dragResistance = 0.1f;
[Tooltip("是否自动返回初始位置")]
[SerializeField] private bool autoReturn = true;
[Header("事件" )]
[Tooltip("发条达到最大角度并释放时触发")]
public UnityEvent onCrankComplete;
[Tooltip("发条旋转时触发(参数:当前角度0-1)")]
public UnityEvent<float> onCrankRotate;
[Tooltip("发条开始拖拽时触发")]
public UnityEvent onCrankStartDrag;
[Header("逆时针转圈表现")]
[Tooltip("逆时针转一圈的动画时长(秒)")]
[SerializeField] private float spinOnceDuration = 1f;
[Tooltip("逆时针转一圈完成后触发")]
public UnityEvent onSpinOnceComplete;
[Header("圆环/中心配置")]
[Tooltip("环中心(内环旋转中心),配置后发条将沿环轨道移动;不填则原地旋转")]
[SerializeField] private Transform ringCenter;
[Tooltip("环半径(发条到中心的距离),0 则从初始位置自动计算")]
[SerializeField] private float ringRadius = 0f;
[Tooltip("起始角度偏移(度),0=右侧3点钟方向")]
[SerializeField] private float startAngleOffset = 0f;
[Tooltip("面向圆心时的旋转偏移(度),用于调整图片朝向,不同 sprite 的正面方向不同")]
[SerializeField] private float facingRotationOffset = 0f;
[Tooltip("角度正方向:勾选=顺时针为正,不勾选=逆时针为正")]
[SerializeField] private bool clockwisePositive = false;
[Header("视觉反馈")]
[Tooltip("发条旋转的 Transform(手柄 visuals")]
[SerializeField] private Transform crankTransform;
[Tooltip("用于检测点击的 Collider2D,不填则尝试从 crankTransform 获取")]
[SerializeField] private Collider2D interactionCollider;
[Tooltip("拖拽时的缩放效果")]
[SerializeField] private float dragScale = 1.05f;
[Tooltip("缩放动画时长")]
[SerializeField] private float scaleDuration = 0.1f;
[Header("交互提示")]
[Tooltip("高亮目标:发条 Sprite(材质需含 _ShineFade);不填则使用 crankTransform 上 SpriteRenderer")]
[SerializeField] private SpriteRenderer interactionHighlightSprite;
[Tooltip("开始拖拽发条时是否自动关闭高亮")]
[SerializeField] private bool clearHighlightWhenDragStarts = true;
[Header("上弦判定")]
[Tooltip("进入成功范围后吸附到终点的时长")]
[SerializeField] private float completionSnapDuration = 0.15f;
[Tooltip("当前轮未上满多少次后显示 Yarn 文本提示")]
[SerializeField] private int failedAttemptHintThreshold = 2;
[Tooltip("连续未上满后调用的 Yarn 节点")]
[SerializeField] private string failedAttemptHintNode = "发条操作提示";
private static readonly int ShineFadeId = Shader.PropertyToID("_ShineFade");
private SpriteRenderer _shineHighlightSprite;
private Vector3 _dragStartPosition;
private float _dragStartAngle; // 按下时鼠标相对中心的角度
private float _dragStartRotation; // 按下时发条的角度
private float _lastMouseAngle; // 上一帧鼠标角度,用于累计增量
private float _currentRotation = 0f;
private bool _isDragging = false;
private bool _hasTriggered = false;
private Camera _mainCamera;
private Vector3 _initialScale;
private Tweener _scaleTween;
private Tweener _returnTween;
private Tweener _spinTween;
private Tweener _completeTween;
private float _spinAngleOffset; // 逆时针转圈时的附加角度(0~360)
private bool _isSpinning; // 正在播放逆时针转圈
private float _effectiveRadius; // 实际使用的环半径
private bool _isReturning;
private bool _isCompleting;
private float _returnSpeedPerSec; // 回位时的度/秒,匀速
private int _failedAttemptCount;
private bool _failedAttemptHintShown;
private EventTriggerEx _eventTrigger;
private bool _useEventTrigger;
#region 生命周期
private void Awake()
{
_mainCamera = Camera.main;
if (crankTransform != null)
{
_initialScale = crankTransform.localScale;
}
else
{
_initialScale = transform.localScale;
crankTransform = transform;
}
maxRotationAngle = Mathf.Max(0.01f, maxRotationAngle);
dragResistance = Mathf.Clamp01(dragResistance);
// 完成判定不能超过画面上的旋转终点。
// 旧逻辑会在配置越界时悄悄改为 80%,导致画面、手感和判定使用不同的角度。
if (triggerAngle > maxRotationAngle)
{
Debug.LogWarning($"[CrankController] triggerAngle ({triggerAngle}°) 超过 maxRotationAngle ({maxRotationAngle}°),已对齐到旋转终点", this);
triggerAngle = maxRotationAngle;
}
triggerAngle = Mathf.Clamp(triggerAngle, 0f, maxRotationAngle);
// 未配置交互碰撞体时,尝试从 crankTransform 获取
if (interactionCollider == null && crankTransform != null)
{
interactionCollider = crankTransform.GetComponent<Collider2D>();
#if UNITY_EDITOR
if (interactionCollider == null)
{
Debug.LogWarning($"[CrankController] 未找到 Collider2D!请在「发条」或其父物体上添加 Collider2D(如 CircleCollider2D),或在 interactionCollider 中手动指定。", this);
}
#endif
}
// 计算环半径:优先使用配置值,否则从发条到 ringCenter 的距离
if (ringCenter != null && crankTransform != null)
{
_effectiveRadius = ringRadius > 0f
? ringRadius
: Vector2.Distance(
new Vector2(crankTransform.position.x, crankTransform.position.y),
new Vector2(ringCenter.position.x, ringCenter.position.y));
if (_effectiveRadius < 0.01f) _effectiveRadius = 1f; // 防止除零
}
else
{
_effectiveRadius = 0f; // 原地旋转模式
}
// 事件目标:Collider 所在的对象(可能与 CrankController 不同,如手柄在子物体)
var eventTargetGo = interactionCollider != null ? interactionCollider.gameObject : (crankTransform != null ? crankTransform.gameObject : gameObject);
_eventTrigger = eventTargetGo.GetComponent<EventTriggerEx>();
if (_eventTrigger == null && eventTargetGo.GetComponent<Collider2D>() != null)
{
if (eventTargetGo != gameObject)
{
var bridge = eventTargetGo.GetComponent<CrankInteractionBridge>();
if (bridge == null) eventTargetGo.AddComponent<CrankInteractionBridge>();
}
_eventTrigger = eventTargetGo.AddComponent<EventTriggerEx>();
}
if (_eventTrigger != null)
{
_useEventTrigger = true;
EnsureEventTriggerEntries();
_eventTrigger.Register(EventTriggerType.PointerDown, OnEventPointerDown);
_eventTrigger.Register(EventTriggerType.PointerUp, OnEventPointerUp);
_eventTrigger.Register(EventTriggerType.Drag, OnEventDrag);
}
EnsureInteractionHighlightSprite();
SetInteractionHighlightVisible(false);
}
private void EnsureInteractionHighlightSprite()
{
if (interactionHighlightSprite != null)
{
_shineHighlightSprite = interactionHighlightSprite;
return;
}
if (crankTransform != null)
_shineHighlightSprite = crankTransform.GetComponent<SpriteRenderer>()
?? crankTransform.GetComponentInChildren<SpriteRenderer>(true);
}
/// <summary>
/// 控制发条交互提示高亮(材质 _ShineFade)。由外部脚本、Yarn 命令等在合适时机调用。
/// </summary>
public void SetInteractionHighlightVisible(bool visible)
{
EnsureInteractionHighlightSprite();
if (_shineHighlightSprite == null) return;
var mat = _shineHighlightSprite.material;
if (mat == null || !mat.HasProperty(ShineFadeId)) return;
mat.SetFloat(ShineFadeId, visible ? 1f : 0f);
}
/// <summary>
/// 确保 EventTrigger 有需要的触发类型(若使用 EventTriggerEx 管理交互)
/// </summary>
private void EnsureEventTriggerEntries()
{
if (_eventTrigger == null) return;
var triggers = _eventTrigger.triggers;
var needed = new[] { EventTriggerType.PointerDown, EventTriggerType.PointerUp, EventTriggerType.Drag };
foreach (var t in needed)
{
if (triggers.Any(e => e.eventID == t)) continue;
triggers.Add(new EventTrigger.Entry { eventID = t });
}
}
private void OnEnable()
{
ResetFailedAttempts();
ResetCrank();
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (ringCenter == null) return;
float r = ringRadius > 0f ? ringRadius : 0f;
if (r <= 0f && crankTransform != null && !Application.isPlaying)
{
r = Vector2.Distance(
new Vector2(crankTransform.position.x, crankTransform.position.y),
new Vector2(ringCenter.position.x, ringCenter.position.y));
}
if (r < 0.01f) return;
Vector3 center = ringCenter.position;
Gizmos.color = new Color(0.3f, 0.9f, 0.55f, 0.6f);
const int segments = 64;
for (int i = 0; i < segments; i++)
{
float a0 = (float)i / segments * 2f * Mathf.PI;
float a1 = (float)(i + 1) / segments * 2f * Mathf.PI;
Vector3 p0 = center + new Vector3(Mathf.Cos(a0) * r, Mathf.Sin(a0) * r, center.z);
Vector3 p1 = center + new Vector3(Mathf.Cos(a1) * r, Mathf.Sin(a1) * r, center.z);
Gizmos.DrawLine(p0, p1);
}
// 起点 / 终点标记(红=起点,橙=终点)
float startVisual = startAngleOffset;
float endVisual = clockwisePositive
? startAngleOffset - maxRotationAngle
: startAngleOffset + maxRotationAngle;
float startRadian = startVisual * Mathf.Deg2Rad;
float endRadian = endVisual * Mathf.Deg2Rad;
Vector3 startPos = center + new Vector3(Mathf.Cos(startRadian) * r, Mathf.Sin(startRadian) * r, center.z);
Vector3 endPos = center + new Vector3(Mathf.Cos(endRadian) * r, Mathf.Sin(endRadian) * r, center.z);
Gizmos.color = new Color(1f, 0f, 0f, 0.9f);
Gizmos.DrawWireSphere(startPos, 0.08f);
Gizmos.color = new Color(1f, 0.55f, 0f, 0.9f);
Gizmos.DrawWireSphere(endPos, 0.08f);
Gizmos.color = new Color(1f, 0.5f, 0f, 0.8f);
Gizmos.DrawWireSphere(center, 0.05f);
}
#endif
private void Update()
{
if (_useEventTrigger)
{
// 交互由 EventTriggerEx 驱动,此处仅处理回位
}
else
{
HandleMouseInputFallback();
}
HandleReturn();
}
#endregion
#region 输入处理(EventTriggerEx 驱动 / 回退)
private void OnEventPointerDown(BaseEventData eventData)
{
if (eventData is PointerEventData { button: PointerEventData.InputButton.Left })
StartDrag();
}
private void OnEventPointerUp(BaseEventData eventData)
{
if (eventData is PointerEventData { button: PointerEventData.InputButton.Left })
EndDrag();
}
private void OnEventDrag(BaseEventData eventData)
{
if (_isDragging && eventData is PointerEventData pointerData)
ContinueDrag(pointerData.position);
}
/// <summary>
/// 回退:无 EventTriggerEx 时使用 Input + Raycast(如 prefab 未迁移场景)
/// </summary>
private void HandleMouseInputFallback()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.GetRayIntersection(ray, float.MaxValue);
if (hit.collider != null && IsValidHitTarget(hit.collider.gameObject))
{
StartDrag();
}
}
if (_isDragging)
{
if (Input.GetMouseButton(0))
{
ContinueDrag(Input.mousePosition);
}
else if (Input.GetMouseButtonUp(0))
{
EndDrag();
}
}
}
/// <summary>
/// 获取旋转中心(环中心优先,否则用发条父节点)
/// </summary>
private Vector3 GetRotationPivot()
{
if (ringCenter != null) return ringCenter.position;
if (crankTransform != null && crankTransform.parent != null) return crankTransform.parent.position;
return crankTransform != null ? crankTransform.position : transform.position;
}
/// <summary>
/// 应用发条的位置和旋转。配置了 ringCenter 时沿环轨道移动,否则原地旋转。
/// </summary>
private void ApplyCrankTransform(float angle)
{
if (crankTransform == null) return;
// 顺时针为正时,视觉上角度取反(数学角度逆时针为正)
float visualAngle = clockwisePositive ? -angle : angle;
float positionAngle = startAngleOffset + visualAngle + _spinAngleOffset;
if (ringCenter != null && _effectiveRadius > 0f)
{
// 沿环轨道移动:更新世界坐标位置
float radian = positionAngle * Mathf.Deg2Rad;
Vector3 center = ringCenter.position;
float z = crankTransform.position.z;
Vector3 position = center + new Vector3(
Mathf.Cos(radian) * _effectiveRadius,
Mathf.Sin(radian) * _effectiveRadius,
z
);
crankTransform.position = position;
// 始终面向圆心(径向朝内),加 offset 调整 sprite 正面朝向
Vector3 toCenter = center - position;
float radialAngle = Mathf.Atan2(toCenter.y, toCenter.x) * Mathf.Rad2Deg;
crankTransform.rotation = Quaternion.Euler(0f, 0f, radialAngle + facingRotationOffset);
}
else
{
// 原地旋转:-visualAngle 为基础朝向,+_spinAngleOffset 为逆时针转圈叠加
crankTransform.localRotation = Quaternion.Euler(0f, 0f, -visualAngle + _spinAngleOffset);
}
}
/// <summary>
/// 检查点击目标是否有效(本物体、发条、交互碰撞体或其子物体)
/// </summary>
private bool IsValidHitTarget(GameObject hitGo)
{
if (hitGo == gameObject) return true;
if (crankTransform != null && (hitGo == crankTransform.gameObject || hitGo.transform.IsChildOf(crankTransform))) return true;
if (interactionCollider != null && hitGo == interactionCollider.gameObject) return true;
return false;
}
#endregion
#region 拖拽逻辑
private void StartDrag()
{
if (clearHighlightWhenDragStarts)
SetInteractionHighlightVisible(false);
_isDragging = true;
_dragStartPosition = Input.mousePosition;
_dragStartRotation = _currentRotation;
_dragStartAngle = GetMouseAngle();
_lastMouseAngle = _dragStartAngle;
_hasTriggered = false;
if (_returnTween != null)
{
_returnTween.Kill();
_returnTween = null;
}
if (_spinTween != null)
{
_spinTween.Kill();
_spinTween = null;
_spinAngleOffset = 0f;
_isSpinning = false;
}
_isReturning = false;
// 拖拽缩放效果
if (_scaleTween != null) _scaleTween.Kill();
_scaleTween = crankTransform.DOScale(_initialScale * dragScale, scaleDuration)
.SetEase(Ease.OutQuad);
onCrankStartDrag?.Invoke();
}
/// <summary>
/// 获取鼠标相对环中心的角度(0-360)
/// </summary>
private float GetMouseAngle(Vector3? screenPos = null)
{
Vector3 pivotWorld = GetRotationPivot();
Vector3 screenCenter = _mainCamera.WorldToScreenPoint(pivotWorld);
Vector3 pos = screenPos ?? Input.mousePosition;
float a = Mathf.Atan2(pos.y - screenCenter.y, pos.x - screenCenter.x) * Mathf.Rad2Deg;
return a < 0f ? a + 360f : a;
}
private void ContinueDrag(Vector3 screenPosition)
{
if (_isCompleting) return;
// 每帧累计角度增量,支持超过 180° 的拖拽(原先用总 delta 会在 180° 处反转)
float currentAngle = GetMouseAngle(screenPosition);
float frameDelta = currentAngle - _lastMouseAngle;
// 仅对单帧小增量做 0/360 边界 wrap
if (frameDelta > 180f) frameDelta -= 360f;
else if (frameDelta < -180f) frameDelta += 360f;
_lastMouseAngle = currentAngle;
if (clockwisePositive) frameDelta = -frameDelta;
float targetRotation = _currentRotation + frameDelta * (1f - dragResistance);
// 拖拽一帧跨过起点/终点时直接夹到边界。
// 若拒绝越界的整帧移动,当触发角度等于最大角度时就可能永远到不了终点。
_currentRotation = Mathf.Clamp(targetRotation, 0f, maxRotationAngle);
ApplyCrankTransform(_currentRotation);
float normalizedRotation = _currentRotation / maxRotationAngle;
onCrankRotate?.Invoke(normalizedRotation);
// 检查是否达到触发角度
if (_currentRotation >= triggerAngle && !_hasTriggered)
{
_hasTriggered = true;
Debug.Log($"[CrankController] 达到触发角度!当前角度: {_currentRotation:F1}°, 触发角度: {triggerAngle}°", this);
BeginAutoComplete();
}
}
private void BeginAutoComplete()
{
if (_isCompleting) return;
_isCompleting = true;
_isDragging = false;
_isReturning = false;
_failedAttemptCount = 0;
_failedAttemptHintShown = false;
_scaleTween?.Kill();
_scaleTween = crankTransform.DOScale(_initialScale, scaleDuration).SetEase(Ease.OutQuad);
_completeTween?.Kill();
_completeTween = DOTween.To(
() => _currentRotation,
value =>
{
_currentRotation = value;
ApplyCrankTransform(_currentRotation);
onCrankRotate?.Invoke(_currentRotation / maxRotationAngle);
},
maxRotationAngle,
Mathf.Max(0.01f, completionSnapDuration))
// OutBack 会超过 maxRotationAngle,导致实际画面角度大于配置上限。
.SetEase(Ease.OutCubic)
.OnComplete(() =>
{
_completeTween = null;
_isCompleting = false;
onCrankComplete?.Invoke();
});
}
private void EndDrag()
{
if (_isCompleting) return;
_isDragging = false;
// 恢复缩放
if (_scaleTween != null) _scaleTween.Kill();
_scaleTween = crankTransform.DOScale(_initialScale, scaleDuration)
.SetEase(Ease.OutQuad);
if (!_hasTriggered || _currentRotation < triggerAngle)
{
_failedAttemptCount++;
Debug.Log($"[CrankController] EndDrag 未触发:hasTriggered={_hasTriggered}, currentRotation={_currentRotation:F1}°, triggerAngle={triggerAngle}°", this);
if (!_failedAttemptHintShown && _failedAttemptCount >= Mathf.Max(1, failedAttemptHintThreshold))
{
_failedAttemptHintShown = true;
if (!string.IsNullOrEmpty(failedAttemptHintNode))
DialogController.Instance?.StartDialogNode(failedAttemptHintNode);
}
}
}
#endregion
#region 回位逻辑
private void HandleReturn()
{
if (_isCompleting) return;
if (!_isDragging && autoReturn && _currentRotation > 0f && !_isReturning && !_isSpinning)
{
_isReturning = true;
_returnSpeedPerSec = maxRotationAngle / Mathf.Max(0.01f, returnDuration);
}
if (_isReturning && !_isDragging)
{
float step = _returnSpeedPerSec * Time.deltaTime;
_currentRotation = Mathf.MoveTowards(_currentRotation, 0f, step);
ApplyCrankTransform(_currentRotation);
onCrankRotate?.Invoke(_currentRotation / maxRotationAngle);
if (_currentRotation <= 0f)
{
_currentRotation = 0f;
_isReturning = false;
}
}
}
#endregion
#region 公共方法
public void ResetCrank()
{
if (_returnTween != null)
{
_returnTween.Kill();
_returnTween = null;
}
if (_spinTween != null)
{
_spinTween.Kill();
_spinTween = null;
}
if (_completeTween != null)
{
_completeTween.Kill();
_completeTween = null;
}
_spinAngleOffset = 0f;
_isSpinning = false;
_isReturning = false;
_isCompleting = false;
_isDragging = false;
_hasTriggered = false;
ResetFailedAttempts();
_currentRotation = 0f;
if (crankTransform != null)
{
ApplyCrankTransform(0f);
crankTransform.localScale = _initialScale;
}
}
private void ResetFailedAttempts()
{
_failedAttemptCount = 0;
_failedAttemptHintShown = false;
}
private void OnDestroy()
{
_scaleTween?.Kill();
_returnTween?.Kill();
_spinTween?.Kill();
_completeTween?.Kill();
}
/// <summary>
/// 逆时针转一圈的表现(可被 Yarn 命令、事件等触发)
/// </summary>
/// <param name="duration">动画时长,不传则使用 spinOnceDuration</param>
public void PlaySpinCounterClockwise(float? duration = null)
{
float d = duration ?? spinOnceDuration;
if (d <= 0f) d = 0.5f;
if (_spinTween != null)
{
_spinTween.Kill();
_spinTween = null;
}
_spinAngleOffset = 0f;
_isSpinning = true;
_spinTween = DOTween.To(
() => _spinAngleOffset,
value =>
{
_spinAngleOffset = value;
ApplyCrankTransform(_currentRotation);
},
360f,
d
).SetEase(Ease.Linear).OnComplete(() =>
{
_spinAngleOffset = 0f;
_spinTween = null;
_isSpinning = false;
ApplyCrankTransform(_currentRotation);
onSpinOnceComplete?.Invoke();
});
}
/// <summary>
/// 手动旋转到指定角度(用于动画或程序化控制)
/// </summary>
public void RotateTo(float angle, float duration = 0.5f)
{
angle = Mathf.Clamp(angle, 0f, maxRotationAngle);
if (_returnTween != null)
{
_returnTween.Kill();
_returnTween = null;
}
DOTween.To(
() => _currentRotation,
value => {
_currentRotation = value;
ApplyCrankTransform(_currentRotation);
float normalizedRotation = _currentRotation / maxRotationAngle;
onCrankRotate?.Invoke(normalizedRotation);
},
angle,
duration
).SetEase(Ease.OutCubic);
}
/// <summary>
/// 获取当前旋转角度(0-1标准化)
/// </summary>
public float GetNormalizedRotation()
{
return _currentRotation / maxRotationAngle;
}
/// <summary>
/// 获取当前旋转角度(度)
/// </summary>
public float GetCurrentAngle()
{
return _currentRotation;
}
/// <summary>
/// 是否正在拖拽中
/// </summary>
public bool IsDragging => _isDragging;
/// <summary>
/// 是否已达到触发角度
/// </summary>
public bool HasTriggered => _hasTriggered;
/// <summary>
/// 是否正在播放逆时针转圈
/// </summary>
public bool IsSpinning => _isSpinning;
/// <summary>
/// 回位时长(秒),供滑片等配合使用
/// </summary>
public float ReturnDuration => returnDuration;
/// <summary>
/// 设置回位时长(由 SalesManager 同步每次转动时间)
/// </summary>
public void SetReturnDuration(float duration)
{
returnDuration = Mathf.Max(0.01f, duration);
}
#endregion
#region IInteractionEventTriggerEx 统一交互)
public bool IsActive => true;
public bool IsAvailable => true;
public GameObject GetGameObject() => gameObject;
#endregion
}
/// <summary>
/// 发条交互桥接:挂在 Collider 所在子物体上,将 IInteraction 转交给父级 CrankController
/// </summary>
public class CrankInteractionBridge : MonoBehaviour, IInteraction
{
private CrankController _controller;
private void Awake()
{
_controller = GetComponentInParent<CrankController>();
}
public bool IsActive => _controller?.IsActive ?? true;
public bool IsAvailable => _controller?.IsAvailable ?? true;
public GameObject GetGameObject() => gameObject;
}
}