diff --git a/Assets/Code/Scripts/Player/PlayerInputHandler.cs b/Assets/Code/Scripts/Player/PlayerInputHandler.cs index b768a2d..5ca9d8d 100644 --- a/Assets/Code/Scripts/Player/PlayerInputHandler.cs +++ b/Assets/Code/Scripts/Player/PlayerInputHandler.cs @@ -4,6 +4,7 @@ using UnityEngine.InputSystem; public class PlayerInputController : MonoBehaviour { public InputActionAsset InputActions; + public bool InputEnabled { get; private set; } = true; private InputAction m_moveAction; private InputAction m_lookAction; @@ -44,6 +45,17 @@ public class PlayerInputController : MonoBehaviour private void Update() { + if (!InputEnabled) + { + MoveAmount = Vector2.zero; + LookAmount = Vector2.zero; + ShiftPressed = false; + JumpPressed = false; + ThrowPressed = false; + HeadInteractionPressed = false; + return; + } + MoveAmount = m_moveAction.ReadValue(); LookAmount = m_lookAction.ReadValue(); @@ -52,4 +64,9 @@ public class PlayerInputController : MonoBehaviour ThrowPressed = m_throwAction.WasPressedThisFrame(); HeadInteractionPressed = m_headInteractAction.WasPressedThisFrame(); } + + public void SetInputEnabled(bool enabled) + { + InputEnabled = enabled; + } } \ No newline at end of file diff --git a/Assets/Code/Scripts/Player/RobotBootSequence.cs b/Assets/Code/Scripts/Player/RobotBootSequence.cs new file mode 100644 index 0000000..1b43a00 --- /dev/null +++ b/Assets/Code/Scripts/Player/RobotBootSequence.cs @@ -0,0 +1,264 @@ +using System.Collections; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class RobotBootSequence : MonoBehaviour +{ + [Header("References")] + public PlayerInputController InputController; + public Transform CameraTransform; + + [Header("Timing")] + public bool PlayOnStart = true; + [Min(0.1f)] public float BootDuration = 2.4f; + [Min(0.1f)] public float CharacterPerSecond = 40f; + [Min(0f)] public float LinePause = 0.35f; + [Min(0f)] public float DelayBeforeReveal = 0.4f; + + [Header("Motion")] + public Vector2 StartYawPitch = new Vector2(-30f, -20f); + public float RollWobble = 2.5f; + public float WobbleFrequency = 16f; + public AnimationCurve EaseCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + [Header("Boot Text")] + public Color BootTextColor = new Color(0.62f, 1f, 0.7f, 1f); + public string[] BootLines = + { + "UNIT SB-3954 | preparing startup . . .", + "verification of OS-5 . . . 4 . . . 3 . . . 2 . . . 1", + "system integrity: OK", + "motor bus: OK", + "vision pipeline: ONLINE", + "SYSTEM OK" + }; + + [Header("Optional Audio")] + public AudioSource BootAudioSource; + + private bool m_IsPlaying; + + private struct BootUI + { + public Canvas Canvas; + public RectTransform LeftPanel; + public RectTransform RightPanel; + public TextMeshProUGUI Text; + } + + private void Awake() + { + if (InputController == null) + { + InputController = GetComponent(); + } + } + + private void Start() + { + if (PlayOnStart) + { + StartCoroutine(PlayBootSequence()); + } + } + + [ContextMenu("Play Boot Sequence")] + public void PlayBootSequenceFromMenu() + { + if (!Application.isPlaying || m_IsPlaying) + { + return; + } + + StartCoroutine(PlayBootSequence()); + } + + public IEnumerator PlayBootSequence() + { + if (m_IsPlaying) + { + yield break; + } + + m_IsPlaying = true; + + if (InputController != null) + { + InputController.SetInputEnabled(false); + } + + if (BootAudioSource != null) + { + BootAudioSource.Play(); + } + + if (CameraTransform == null) + { + m_IsPlaying = false; + if (InputController != null) + { + InputController.SetInputEnabled(true); + } + yield break; + } + + Quaternion gameplayRotation = CameraTransform.localRotation; + Quaternion fromRotation = Quaternion.Euler(StartYawPitch.y, StartYawPitch.x, 0f) * gameplayRotation; + CameraTransform.localRotation = fromRotation; + + BootUI bootUI = CreateBootUI(); + + yield return StartCoroutine(PlayBootText(bootUI.Text)); + + if (DelayBeforeReveal > 0f) + { + yield return new WaitForSeconds(DelayBeforeReveal); + } + + float elapsed = 0f; + while (elapsed < BootDuration) + { + elapsed += Time.deltaTime; + float t = Mathf.Clamp01(elapsed / BootDuration); + float eased = EaseCurve.Evaluate(t); + + float wobbleFade = 1f - eased; + float roll = Mathf.Sin(Time.time * WobbleFrequency) * RollWobble * wobbleFade; + Quaternion wobbleRotation = Quaternion.Euler(0f, 0f, roll); + + CameraTransform.localRotation = Quaternion.Slerp(fromRotation, gameplayRotation, eased) * wobbleRotation; + + RectTransform rootRect = bootUI.Canvas.GetComponent(); + float halfWidth = rootRect.rect.width * 0.5f; + float leftTarget = -(halfWidth + 24f); + float rightTarget = halfWidth + 24f; + bootUI.LeftPanel.anchoredPosition = new Vector2(Mathf.Lerp(0f, leftTarget, eased), 0f); + bootUI.RightPanel.anchoredPosition = new Vector2(Mathf.Lerp(0f, rightTarget, eased), 0f); + + Color textColor = bootUI.Text.color; + textColor.a = 1f - eased; + bootUI.Text.color = textColor; + + yield return null; + } + + CameraTransform.localRotation = gameplayRotation; + + if (bootUI.Canvas != null) + { + Destroy(bootUI.Canvas.gameObject); + } + + if (InputController != null) + { + InputController.SetInputEnabled(true); + } + + m_IsPlaying = false; + } + + private IEnumerator PlayBootText(TextMeshProUGUI label) + { + if (label == null || BootLines == null || BootLines.Length == 0) + { + yield break; + } + + label.text = string.Empty; + float charDelay = CharacterPerSecond <= 0f ? 0f : 1f / CharacterPerSecond; + + for (int i = 0; i < BootLines.Length; i++) + { + string line = BootLines[i]; + for (int c = 0; c < line.Length; c++) + { + label.text += line[c]; + if (charDelay > 0f) + { + yield return new WaitForSeconds(charDelay); + } + } + + if (i < BootLines.Length - 1) + { + label.text += "\n"; + } + + if (LinePause > 0f) + { + yield return new WaitForSeconds(LinePause); + } + } + } + + private BootUI CreateBootUI() + { + BootUI ui = new BootUI(); + + GameObject canvasGO = new GameObject("RobotBootCanvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)); + Canvas canvas = canvasGO.GetComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + canvas.sortingOrder = 5000; + + CanvasScaler scaler = canvasGO.GetComponent(); + scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; + scaler.referenceResolution = new Vector2(1920f, 1080f); + scaler.matchWidthOrHeight = 0.5f; + + RectTransform root = canvasGO.GetComponent(); + root.anchorMin = Vector2.zero; + root.anchorMax = Vector2.one; + root.offsetMin = Vector2.zero; + root.offsetMax = Vector2.zero; + + RectTransform leftPanel = CreatePanel("LeftPanel", root, true); + RectTransform rightPanel = CreatePanel("RightPanel", root, false); + TextMeshProUGUI label = CreateBootLabel(root); + + ui.Canvas = canvas; + ui.LeftPanel = leftPanel; + ui.RightPanel = rightPanel; + ui.Text = label; + + return ui; + } + + private RectTransform CreatePanel(string panelName, RectTransform parent, bool isLeft) + { + GameObject panelGO = new GameObject(panelName, typeof(RectTransform), typeof(Image)); + RectTransform rect = panelGO.GetComponent(); + rect.SetParent(parent, false); + rect.anchorMin = isLeft ? new Vector2(0f, 0f) : new Vector2(0.5f, 0f); + rect.anchorMax = isLeft ? new Vector2(0.5f, 1f) : new Vector2(1f, 1f); + rect.pivot = new Vector2(0.5f, 0.5f); + rect.offsetMin = Vector2.zero; + rect.offsetMax = Vector2.zero; + rect.anchoredPosition = Vector2.zero; + + Image image = panelGO.GetComponent(); + image.color = Color.black; + + return rect; + } + + private TextMeshProUGUI CreateBootLabel(RectTransform parent) + { + GameObject textGO = new GameObject("BootText", typeof(RectTransform), typeof(TextMeshProUGUI)); + RectTransform rect = textGO.GetComponent(); + rect.SetParent(parent, false); + rect.anchorMin = new Vector2(0.13f, 0.5f); + rect.anchorMax = new Vector2(0.13f, 0.5f); + rect.pivot = new Vector2(0f, 0.5f); + rect.sizeDelta = new Vector2(980f, 380f); + + TextMeshProUGUI text = textGO.GetComponent(); + text.text = string.Empty; + text.fontSize = 40f; + text.alignment = TextAlignmentOptions.Left; + text.color = BootTextColor; + text.enableWordWrapping = true; + + return text; + } +} diff --git a/Assets/Code/Scripts/Player/RobotBootSequence.cs.meta b/Assets/Code/Scripts/Player/RobotBootSequence.cs.meta new file mode 100644 index 0000000..e0ad01c --- /dev/null +++ b/Assets/Code/Scripts/Player/RobotBootSequence.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ef6855cd57b4f94b47f410d47e89ff1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: