@@ -17,6 +17,7 @@ public class UITutorialManager : MonoBehaviour
1717 private Action currentlyFocusedButtonCallback ; // Callback for the currently focused button
1818 private GameObject currentTooltip ; // The currently active tooltip
1919 private TooltipUI tooltip ;
20+ private Button overlayButton ;
2021
2122 [ Header ( "Debug" ) ]
2223 public SequenceID testSequenceID ;
@@ -25,6 +26,7 @@ public class UITutorialManager : MonoBehaviour
2526 public int currentStepIndex = 0 ;
2627 private TutorialSequence currentSequence ;
2728 private Dictionary < ButtonID , UIButton > buttonDictionary = new Dictionary < ButtonID , UIButton > ( ) ;
29+ private Dictionary < Button , UnityEngine . Events . UnityAction > tutorialClickActions = new ( ) ;
2830
2931 void Awake ( )
3032 {
@@ -44,6 +46,7 @@ private void CacheAllButtons()
4446 buttonDictionary [ button . buttonID ] = button ;
4547 }
4648 }
49+ ResetButtonAction ( ) ;
4750 }
4851
4952 [ Button ]
@@ -84,44 +87,78 @@ public void FocusOnNextButton()
8487
8588 var step = currentSequence . steps [ currentStepIndex ] ;
8689
87- // Enable overlay panel
88- if ( overlayPanel != null ) overlayPanel . SetActive ( true ) ;
89-
90- // Find target button
91- UIButton targetButton = FindButton ( step . buttonID ) ;
92- if ( targetButton == null )
90+ // Enable overlay panel ad add a button to it for skipping panels without buttons
91+ if ( overlayPanel != null )
9392 {
94- Debug . LogError ( $ "Button with ID { step . buttonID } not found!") ;
95- return ;
93+ overlayPanel . SetActive ( true ) ;
94+ if ( overlayPanel . GetComponent < Button > ( ) == null )
95+ {
96+ overlayButton = overlayPanel . AddComponent < Button > ( ) ;
97+ }
98+ else
99+ {
100+ overlayButton = overlayPanel . GetComponent < Button > ( ) ;
101+ }
102+ overlayButton . interactable = false ;
96103 }
97104
98- // Activate parent if it's inactive
99- if ( ! targetButton . gameObject . activeInHierarchy )
105+ // Find target button
106+ if ( step . focusButtonID != ButtonID . None )
100107 {
101- Transform parent = targetButton . transform . parent ;
102- while ( parent != null )
108+ UIButton targetButton = FindButton ( step . focusButtonID ) ;
109+ if ( targetButton == null )
110+ {
111+ Debug . LogError ( $ "Button with ID { step . focusButtonID } not found!") ;
112+ return ;
113+ }
114+
115+ // Activate parent if it's inactive
116+ if ( ! targetButton . gameObject . activeInHierarchy )
103117 {
104- if ( ! parent . gameObject . activeSelf )
118+ Transform parent = targetButton . transform . parent ;
119+ while ( parent != null )
105120 {
106- parent . gameObject . SetActive ( true ) ;
121+ if ( ! parent . gameObject . activeSelf )
122+ {
123+ parent . gameObject . SetActive ( true ) ;
124+ }
125+ parent = parent . parent ;
107126 }
108- parent = parent . parent ;
109127 }
110- }
111128
112- // Highlight button
113- OnButtonFocus ? . Invoke ( step . buttonID ) ;
129+ // Highlight button
130+ OnButtonFocus ? . Invoke ( step . focusButtonID ) ;
131+
132+ // Get the Button component and remove any previous listeners to avoid stacking events
133+ Button buttonComponent = targetButton . GetComponent < Button > ( ) ;
134+ if ( tutorialClickActions . TryGetValue ( buttonComponent , out var existingAction ) )
135+ {
136+ buttonComponent . onClick . RemoveListener ( existingAction ) ;
137+ tutorialClickActions . Remove ( buttonComponent ) ;
138+ }
139+
140+ // Create a new action for this step
141+ UnityEngine . Events . UnityAction clickAction = ( ) => OnStepCompleted ( step ) ;
142+
143+ // Add and store it
144+ buttonComponent . onClick . AddListener ( clickAction ) ;
145+ tutorialClickActions [ buttonComponent ] = clickAction ;
146+ }
147+ else
148+ {
149+ // Move to next step when we tap on the overlay panel
150+ if ( overlayButton )
151+ {
152+ overlayButton . interactable = true ;
153+ overlayButton . onClick . RemoveAllListeners ( ) ; // Add this before adding new one
154+ overlayButton . onClick . AddListener ( ( ) => OnStepCompleted ( step ) ) ;
155+ }
156+ }
114157
115158 // Show tooltip
116- ShowTooltip ( step . buttonID , step . message ) ;
117-
118- // Get the Button component and remove any previous listeners to avoid stacking events
119- Button buttonComponent = targetButton . GetComponent < Button > ( ) ;
120- buttonComponent . onClick . RemoveAllListeners ( ) ; // Remove previous tutorial event listeners
121- buttonComponent . onClick . AddListener ( ( ) => OnStepCompleted ( step ) ) ; // Move to next step on click
159+ ShowTooltip ( step . focusButtonID , step . message ) ;
122160 }
123161
124-
125162 // Called when a tutorial step is completed
126163 private void OnStepCompleted ( UITutorialStep step )
127164 {
@@ -136,6 +173,7 @@ public void EndTutorial()
136173 isTutorialActive = false ;
137174 if ( overlayPanel != null ) overlayPanel . SetActive ( false ) ;
138175 Debug . Log ( "Tutorial Completed." ) ;
176+ ResetButtonAction ( ) ;
139177 }
140178
141179 // Focus on a specific button by its ButtonID and provide a callback for when it's clicked
@@ -168,18 +206,50 @@ private void ShowTooltip(ButtonID buttonID, string tooltipText)
168206 currentTooltip = Instantiate ( tooltipPrefab , overlayPanel . transform ) ;
169207 tooltip = currentTooltip . GetComponent < TooltipUI > ( ) ;
170208 }
209+ else
210+ {
211+ tooltip . gameObject . SetActive ( false ) ;
212+ }
171213
172214 // Find the target button
173- UIButton targetButton = FindButton ( buttonID ) ;
174- if ( targetButton == null )
215+ if ( buttonID != ButtonID . None )
175216 {
176- Debug . LogError ( $ "Button with ID { buttonID } not found!") ;
177- return ;
178- }
217+ UIButton targetButton = FindButton ( buttonID ) ;
218+ if ( targetButton == null )
219+ {
220+ Debug . LogError ( $ "Button with ID { buttonID } not found!") ;
221+ return ;
222+ }
179223
180- // Set tooltip text and position
224+ // Set tooltip position
225+ PositionNearButton ( targetButton . GetComponent < RectTransform > ( ) ) ;
226+ }
227+ else
228+ {
229+ // Set tooltip position to the center of the screen
230+ PositionAtCenter ( ) ;
231+ }
181232 tooltip . SetText ( tooltipText ) ;
182- PositionNearButton ( targetButton . GetComponent < RectTransform > ( ) ) ;
233+ tooltip . gameObject . SetActive ( true ) ;
234+ }
235+
236+ private void PositionAtCenter ( )
237+ {
238+ RectTransform toolTipRect = tooltip . GetComponent < RectTransform > ( ) ;
239+
240+ // Ensure the tooltip anchors and pivot are centered
241+ toolTipRect . anchorMin = new Vector2 ( 0.5f , 0.5f ) ;
242+ toolTipRect . anchorMax = new Vector2 ( 0.5f , 0.5f ) ;
243+ toolTipRect . pivot = new Vector2 ( 0.5f , 0.5f ) ;
244+
245+ // Center it relative to the parent (canvas/overlayPanel)
246+ toolTipRect . anchoredPosition = Vector2 . zero ;
247+
248+ // Hide arrow if it exists
249+ if ( tooltip . arrowImage != null )
250+ {
251+ tooltip . arrowImage . gameObject . SetActive ( false ) ;
252+ }
183253 }
184254
185255 public void PositionNearButton ( RectTransform targetButtonRect )
@@ -229,11 +299,11 @@ public void PositionNearButton(RectTransform targetButtonRect)
229299
230300 // Apply tooltip position
231301 toolTipRect . anchoredPosition = new Vector2 ( desiredX , desiredY ) ;
232- toolTipRect . gameObject . SetActive ( true ) ;
233302
234303 // Position arrow
235304 if ( tooltip . arrowImage != null )
236305 {
306+ tooltip . arrowImage . gameObject . SetActive ( true ) ;
237307 RectTransform arrowRect = tooltip . arrowImage ;
238308
239309 // Calculate horizontal offset to maintain arrow pointing at button
@@ -264,6 +334,7 @@ public void PositionNearButton(RectTransform targetButtonRect)
264334 }
265335 }
266336 }
337+
267338 // Call this method to stop focusing on any button
268339 public void StopFocus ( )
269340 {
@@ -312,4 +383,13 @@ private UIButton FindButton(ButtonID id)
312383 }
313384 return null ; // Button not found
314385 }
315- }
386+
387+ void ResetButtonAction ( )
388+ {
389+ foreach ( var pair in tutorialClickActions )
390+ {
391+ pair . Key . onClick . RemoveListener ( pair . Value ) ;
392+ }
393+ tutorialClickActions . Clear ( ) ;
394+ }
395+ }
0 commit comments