diff --git a/.idea/.idea.SpringJam2026/.idea/workspace.xml b/.idea/.idea.SpringJam2026/.idea/workspace.xml
index 0a6a2e9..7893228 100644
--- a/.idea/.idea.SpringJam2026/.idea/workspace.xml
+++ b/.idea/.idea.SpringJam2026/.idea/workspace.xml
@@ -6,20 +6,11 @@
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
@@ -150,7 +141,7 @@
1777050991106
-
+
diff --git a/Assets/Prefabs/UI/Tutorial.prefab b/Assets/Prefabs/UI/Tutorial.prefab
new file mode 100644
index 0000000..129fd9b
--- /dev/null
+++ b/Assets/Prefabs/UI/Tutorial.prefab
@@ -0,0 +1,57 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &5909805567631671246
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 8934231714310863213}
+ - component: {fileID: 6093062084808708927}
+ m_Layer: 0
+ m_Name: Tutorial
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &8934231714310863213
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5909805567631671246}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 3.18688, y: 0.12234, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &6093062084808708927
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5909805567631671246}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
+ m_PanelSettings: {fileID: 11400000, guid: 4f01bbaf43abd294b9e7341d0530a9aa, type: 2}
+ m_ParentUI: {fileID: 0}
+ sourceAsset: {fileID: 9197481963319205126, guid: 5814a7920f5bfc44fa2409bc30e6e23f, type: 3}
+ m_SortingOrder: 0
+ m_Position: 0
+ m_WorldSpaceSizeMode: 1
+ m_WorldSpaceWidth: 1920
+ m_WorldSpaceHeight: 1080
+ m_PivotReferenceSize: 0
+ m_Pivot: 0
+ m_WorldSpaceCollider: {fileID: 0}
diff --git a/Assets/Prefabs/UI/Tutorial.prefab.meta b/Assets/Prefabs/UI/Tutorial.prefab.meta
new file mode 100644
index 0000000..cb3549a
--- /dev/null
+++ b/Assets/Prefabs/UI/Tutorial.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c7e2163f311728348a296fc3229df7a3
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scenes/Bootstrap.unity b/Assets/Scenes/Bootstrap.unity
index 2ec7558..ea674b5 100644
--- a/Assets/Scenes/Bootstrap.unity
+++ b/Assets/Scenes/Bootstrap.unity
@@ -508,6 +508,7 @@ MonoBehaviour:
fruitsPrefab: {fileID: 3648719755775049102, guid: 067c711b87e00ef4d9158c92377f44a6, type: 3}
deathScreenPrefab: {fileID: 6072795237519443946, guid: 439eaa80d7eac8d4db6eace5ddaf3489, type: 3}
deathSound: {fileID: 8300000, guid: 9abfcb38929cf1241a742680b5fcf017, type: 3}
+ tutorialPrefab: {fileID: 0}
--- !u!4 &1469922751
Transform:
m_ObjectHideFlags: 0
diff --git a/Assets/Scenes/Game.unity b/Assets/Scenes/Game.unity
index c73e1cb..8f070c3 100644
--- a/Assets/Scenes/Game.unity
+++ b/Assets/Scenes/Game.unity
@@ -567,6 +567,61 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::Cam
camSpeed: 20
yOffset: 1
+--- !u!1 &1131679838
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1131679840}
+ - component: {fileID: 1131679839}
+ m_Layer: 0
+ m_Name: Tutorial
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1131679839
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1131679838}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
+ m_PanelSettings: {fileID: 11400000, guid: 4f01bbaf43abd294b9e7341d0530a9aa, type: 2}
+ m_ParentUI: {fileID: 0}
+ sourceAsset: {fileID: 9197481963319205126, guid: 5814a7920f5bfc44fa2409bc30e6e23f, type: 3}
+ m_SortingOrder: 0
+ m_Position: 0
+ m_WorldSpaceSizeMode: 1
+ m_WorldSpaceWidth: 1920
+ m_WorldSpaceHeight: 1080
+ m_PivotReferenceSize: 0
+ m_Pivot: 0
+ m_WorldSpaceCollider: {fileID: 0}
+--- !u!4 &1131679840
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1131679838}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 3.18688, y: 0.12234, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1454353600
GameObject:
m_ObjectHideFlags: 0
@@ -6517,3 +6572,4 @@ SceneRoots:
- {fileID: 1454353602}
- {fileID: 219800105}
- {fileID: 1814193807}
+ - {fileID: 1131679840}
diff --git a/Assets/Scripts/Player/Movement.cs b/Assets/Scripts/Player/Movement.cs
index eb1d3e8..70b639d 100644
--- a/Assets/Scripts/Player/Movement.cs
+++ b/Assets/Scripts/Player/Movement.cs
@@ -11,6 +11,8 @@ namespace Player
public class Movement : MonoBehaviour
{
public event Action OnDeath;
+ public event Action EnterSpring;
+ public event Action GetPickup;
private static readonly int Spring = Animator.StringToHash("spring");
private static readonly int Grounded = Animator.StringToHash("grounded");
@@ -184,11 +186,16 @@ namespace Player
HandleDeath();
return;
}
-
+
if (other.gameObject.layer == LayerMask.NameToLayer("Spring"))
+ {
+ EnterSpring?.Invoke();
_springAnimator = other.gameObject.GetComponent();
+ }
+
if (other.gameObject.layer == LayerMask.NameToLayer("Pickup"))
{
+ GetPickup?.Invoke();
Services.Instance.SFX.PlayOneShot(pickupSound);
_airJumpCharges++;
Destroy(other.gameObject);
diff --git a/Assets/Scripts/State/Game/GameRunningState.cs b/Assets/Scripts/State/Game/GameRunningState.cs
index a421700..2118bb8 100644
--- a/Assets/Scripts/State/Game/GameRunningState.cs
+++ b/Assets/Scripts/State/Game/GameRunningState.cs
@@ -11,6 +11,13 @@ namespace State.Game
base.OnEnter(machine);
MainStateMachine.Respawn();
MainStateMachine.PlayerMovement.OnDeath += HandleDeath;
+ MainStateMachine.PlayerMovement.GetPickup += HandleTutorial;
+ MainStateMachine.PlayerMovement.EnterSpring += HandleTutorial;
+ }
+
+ private void HandleTutorial()
+ {
+ MainStateMachine.ShowTutorial(true);
}
private void HandleDeath()
@@ -26,10 +33,14 @@ namespace State.Game
// Cleanup before we remove player and fruits
MainStateMachine.PlayerMovement.OnDeath -= HandleDeath;
+ MainStateMachine.PlayerMovement.GetPickup -= HandleTutorial;
+ MainStateMachine.PlayerMovement.EnterSpring -= HandleTutorial;
MainStateMachine.Respawn();
// Reregister events
MainStateMachine.PlayerMovement.OnDeath += HandleDeath;
+ MainStateMachine.PlayerMovement.GetPickup += HandleTutorial;
+ MainStateMachine.PlayerMovement.EnterSpring += HandleTutorial;
// Wait a moment then restart the game
yield return new WaitForSeconds(2f);
diff --git a/Assets/Scripts/State/Game/MainStateMachine.cs b/Assets/Scripts/State/Game/MainStateMachine.cs
index e20f65b..1a218cd 100644
--- a/Assets/Scripts/State/Game/MainStateMachine.cs
+++ b/Assets/Scripts/State/Game/MainStateMachine.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections;
+using Management;
using Player;
using UnityEngine;
using UnityEngine.UIElements;
@@ -19,15 +21,21 @@ namespace State.Game
[SerializeField] private GameObject fruitsPrefab;
[SerializeField] private GameObject deathScreenPrefab;
[SerializeField] private AudioClip deathSound;
+ [SerializeField] private GameObject tutorialPrefab;
private GameObject _playerInstance;
private GameObject _fruitsInstance;
private GameObject _deathScreenInstance;
-
+ private GameObject _tutorialScreenInstance;
+ private bool _tutorial1Done;
+ private bool _tutorial2Done;
+
private void Awake()
{
_deathScreenInstance = Instantiate(deathScreenPrefab);
ShowDeathScreen(false);
+ _tutorialScreenInstance = Instantiate(tutorialPrefab);
+ ShowTutorial(false);
}
public void Respawn()
@@ -51,5 +59,46 @@ namespace State.Game
{
_deathScreenInstance.GetComponent().rootVisualElement.Q().visible = show;
}
+
+ public void ShowTutorial(bool show)
+ {
+ if (show)
+ {
+ if (!_tutorial1Done)
+ {
+ StartCoroutine(DelayTutorial());
+ return;
+ }
+
+ if (!_tutorial2Done)
+ {
+ Time.timeScale = 0;
+ Services.Instance.InputRouter.OnInteract += HandleClearTutorial;
+ _tutorial2Done = true;
+ _tutorialScreenInstance.GetComponent().rootVisualElement.Q("Tutorial2").style.display = DisplayStyle.Flex;;
+ }
+ }
+ else
+ {
+ Time.timeScale = 1;
+ _tutorialScreenInstance.GetComponent().rootVisualElement.Q("Tutorial1").style.display = DisplayStyle.None;Time.timeScale = 1;
+ _tutorialScreenInstance.GetComponent().rootVisualElement.Q("Tutorial2").style.display = DisplayStyle.None;
+ }
+ }
+
+ private IEnumerator DelayTutorial()
+ {
+ yield return new WaitForSeconds(0.25f);
+ Time.timeScale = 0;
+ Services.Instance.InputRouter.OnInteract += HandleClearTutorial;
+ _tutorialScreenInstance.GetComponent().rootVisualElement.Q("Tutorial1").style.display = DisplayStyle.Flex;;
+ _tutorial1Done = true;
+ }
+
+ private void HandleClearTutorial(bool obj)
+ {
+ Services.Instance.InputRouter.OnInteract -= HandleClearTutorial;
+ ShowTutorial(false);
+ }
}
}
\ No newline at end of file
diff --git a/Assets/UI/Tutorial.uxml b/Assets/UI/Tutorial.uxml
new file mode 100644
index 0000000..2682b59
--- /dev/null
+++ b/Assets/UI/Tutorial.uxml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/UI/Tutorial.uxml.meta b/Assets/UI/Tutorial.uxml.meta
new file mode 100644
index 0000000..1a31563
--- /dev/null
+++ b/Assets/UI/Tutorial.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 5814a7920f5bfc44fa2409bc30e6e23f
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}