app.hypergames.hypersdk 1.8.19 → 1.8.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/HyperLoader.unity +3 -3
- package/Runtime/Internal/Managers/DataManager.cs +38 -2
- package/Runtime/Internal/Managers/GameManager.cs +34 -23
- package/Runtime/Internal/UI/Animation/SlideUp.cs +6 -1
- package/Runtime/Internal/UI/Components/RoundedRawImage.cs +146 -0
- package/Runtime/Internal/UI/Components/RoundedRawImage.cs.meta +11 -0
- package/Runtime/Internal/UI/Modals/GamePausedModal.cs +2 -0
- package/Runtime/Internal/UI/Modals/TutorialButton.cs +10 -0
- package/Runtime/Internal/UI/Modals/TutorialLoaderModal.cs +28 -2
- package/Runtime/Internal/UI/Modals/TutorialModal.cs +721 -47
- package/Runtime/Plugins/WebGL/HyperTutorialCachePlugin.jslib +35 -53
- package/Runtime/Resources/Materials/RoundedRawImage.mat +65 -0
- package/Runtime/Resources/Materials/RoundedRawImage.mat.meta +8 -0
- package/Runtime/Resources/Materials.meta +8 -0
- package/Runtime/Resources/RenderTextures/TutorialVideoTexture P.renderTexture +3 -3
- package/Runtime/Resources/Shaders/RoundedRawImage.shader +142 -0
- package/Runtime/Resources/Shaders/RoundedRawImage.shader.meta +10 -0
- package/Runtime/Resources/Shaders/RoundedStrip.shader +152 -0
- package/Runtime/Resources/Shaders/RoundedStrip.shader.meta +10 -0
- package/Runtime/Resources/Shaders.meta +8 -0
- package/Runtime/Resources/Sprites/Frames/Square.png +0 -0
- package/Runtime/Resources/Sprites/Frames/Square.png.meta +186 -0
- package/Runtime/Resources/Sprites/TutorialModal/Button_Back.png.meta +1 -1
- package/Runtime/Resources/Sprites/TutorialModal/Button_Next.png.meta +1 -1
- package/Runtime/Resources/Sprites/TutorialModal/Knob.png.meta +1 -1
- package/Runtime/Resources/Sprites/TutorialModal/Tutorial_Background_Portrait.png.meta +3 -3
- package/Runtime/Resources/UIPrefabs/Content.prefab +1672 -0
- package/Runtime/Resources/UIPrefabs/Content.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/IndicatorCircle.prefab +2 -2
- package/Runtime/Resources/UIPrefabs/TutorialLandscapeModal.prefab +121 -51
- package/Runtime/Resources/UIPrefabs/TutorialPortraitModal.prefab +497 -1469
- package/Runtime/Shared/DTOs/TutorialData.cs +18 -1
- package/package.json +1 -1
|
@@ -6,13 +6,22 @@ using UnityEngine;
|
|
|
6
6
|
using UnityEngine.UI;
|
|
7
7
|
using UnityEngine.Video;
|
|
8
8
|
using UnityEngine.Networking;
|
|
9
|
+
using Hyper.Internal.Animation;
|
|
9
10
|
using Hyper.Internal.Managers;
|
|
10
11
|
using Hyper.Shared;
|
|
12
|
+
using TMPro;
|
|
11
13
|
|
|
12
14
|
namespace Hyper.Internal
|
|
13
15
|
{
|
|
14
16
|
internal class TutorialModal : MonoBehaviour
|
|
15
17
|
{
|
|
18
|
+
// Keep the seek wiring available while the tutorial video uses a passive progress bar.
|
|
19
|
+
private const bool VideoSeekingEnabled = false;
|
|
20
|
+
private const float LoaderFadeOutDelay = 2.15f;
|
|
21
|
+
private const float SlideInDuration = 0.33f;
|
|
22
|
+
private const float ContentFadeInDuration = 0.28f;
|
|
23
|
+
private const float ContentFadeOutDuration = 0.18f;
|
|
24
|
+
private const float HiddenPreloadPlayDuration = 0.75f;
|
|
16
25
|
|
|
17
26
|
#if UNITY_WEBGL && !UNITY_EDITOR
|
|
18
27
|
[DllImport("__Internal")]
|
|
@@ -23,20 +32,25 @@ namespace Hyper.Internal
|
|
|
23
32
|
private CanvasGroup tutorialCG;
|
|
24
33
|
|
|
25
34
|
[SerializeField] TutorialLoaderModal tutorialLoaderModal;
|
|
35
|
+
[SerializeField] private CanvasGroup tutorialContentGroup;
|
|
26
36
|
|
|
27
37
|
[Header("Display Components")]
|
|
28
38
|
[SerializeField] private RawImage tutorialDisplayP;
|
|
29
39
|
[SerializeField] private RawImage tutorialDisplayL;
|
|
30
40
|
[SerializeField] private VideoPlayer videoPlayer;
|
|
41
|
+
[SerializeField] private RawImage tutorialImageDisplay;
|
|
42
|
+
[SerializeField] private TMP_Text descriptionText;
|
|
43
|
+
|
|
44
|
+
#if UNITY_EDITOR
|
|
45
|
+
[Header("Editor Tutorial Test")]
|
|
46
|
+
[SerializeField] private EditorTutorialCard[] editorTutorialCards;
|
|
47
|
+
[SerializeField] private Vector2 editorLoadDelayRange = new Vector2(1f, 2f);
|
|
48
|
+
#endif
|
|
31
49
|
|
|
32
50
|
[Header("Video Textures")]
|
|
33
51
|
[SerializeField] private RenderTexture tutorialVideoTextureP;
|
|
34
52
|
[SerializeField] private RenderTexture tutorialVideoTextureL;
|
|
35
53
|
|
|
36
|
-
[Header("Aspect Ratio Fitters")]
|
|
37
|
-
[SerializeField] private AspectRatioFitter aspectRatioFitterP;
|
|
38
|
-
[SerializeField] private AspectRatioFitter aspectRatioFitterL;
|
|
39
|
-
|
|
40
54
|
[Header("UI Controls")]
|
|
41
55
|
[SerializeField] private Slider timeSlider;
|
|
42
56
|
[SerializeField] private Button backButton;
|
|
@@ -46,16 +60,38 @@ namespace Hyper.Internal
|
|
|
46
60
|
[SerializeField] private Transform indicatorParent;
|
|
47
61
|
[SerializeField] private GameObject indicatorPrefab;
|
|
48
62
|
private Sprite[] tutorialImages;
|
|
63
|
+
private readonly List<TutorialCardData> tutorialCards = new List<TutorialCardData>();
|
|
49
64
|
private RawImage currentDisplay;
|
|
50
65
|
private int currentImageIndex = 0;
|
|
66
|
+
private int currentCardIndex = 0;
|
|
51
67
|
private bool isDraggingSlider = false;
|
|
52
68
|
private float cachedVideoLength = 0f;
|
|
53
69
|
private Coroutine updateVideoTimeCo = null;
|
|
70
|
+
private Coroutine editorTutorialLoadCo = null;
|
|
71
|
+
private Coroutine hiddenPreloadCloseCo = null;
|
|
54
72
|
private TutorialData tutorialData;
|
|
73
|
+
private bool isClosing;
|
|
74
|
+
private bool hasInvokedTutorialLoadComplete;
|
|
75
|
+
private bool hasPreparedTutorialContent;
|
|
76
|
+
private bool isDirectContentOpen;
|
|
77
|
+
private bool contentRevealScheduled;
|
|
78
|
+
private HyperTween.TweenHandle contentRevealDelayTween;
|
|
55
79
|
|
|
56
80
|
private EventManager _eventManager;
|
|
57
81
|
private DataManager _dataManager;
|
|
58
82
|
|
|
83
|
+
#if UNITY_EDITOR
|
|
84
|
+
[Serializable]
|
|
85
|
+
private class EditorTutorialCard
|
|
86
|
+
{
|
|
87
|
+
public TutorialType type = TutorialType.video;
|
|
88
|
+
public VideoClip videoClip;
|
|
89
|
+
public Sprite image;
|
|
90
|
+
[TextArea] public string description;
|
|
91
|
+
public int position;
|
|
92
|
+
}
|
|
93
|
+
#endif
|
|
94
|
+
|
|
59
95
|
private void Awake()
|
|
60
96
|
{
|
|
61
97
|
_eventManager = HyperRuntime.EventManager;
|
|
@@ -63,31 +99,32 @@ namespace Hyper.Internal
|
|
|
63
99
|
|
|
64
100
|
slideUp = GetComponent<SlideUp>();
|
|
65
101
|
tutorialCG = GetComponent<CanvasGroup>();
|
|
102
|
+
Hide();
|
|
66
103
|
|
|
67
104
|
tutorialLoaderModal.gameObject.SetActive(true);
|
|
68
105
|
|
|
69
106
|
_eventManager.OnTutorialResourcesReferenced += ShowTutorialBasedOnType;
|
|
107
|
+
_eventManager.OnTutorialLoadingComplete += HandleTutorialLoadingComplete;
|
|
70
108
|
}
|
|
71
109
|
|
|
72
110
|
void OnEnable()
|
|
73
111
|
{
|
|
74
112
|
SetupSliderControls();
|
|
75
113
|
|
|
114
|
+
if (hasPreparedTutorialContent) return;
|
|
115
|
+
|
|
76
116
|
if (_dataManager.HasReferencedTutorialResources)
|
|
77
117
|
{
|
|
78
|
-
|
|
79
|
-
if (tutorialData != null && tutorialData.type == TutorialType.video)
|
|
80
|
-
{
|
|
81
|
-
PlayCurrentVideo();
|
|
82
|
-
}
|
|
83
|
-
else if(tutorialData != null && tutorialData.type == TutorialType.images)
|
|
84
|
-
{
|
|
85
|
-
ShowImagesTutorial(tutorialData);
|
|
86
|
-
}
|
|
118
|
+
ShowTutorialData(_dataManager.TutorialData);
|
|
87
119
|
}
|
|
88
120
|
else
|
|
89
121
|
{
|
|
90
|
-
|
|
122
|
+
#if UNITY_EDITOR
|
|
123
|
+
if (TryStartEditorTutorialLoad())
|
|
124
|
+
{
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
#endif
|
|
91
128
|
}
|
|
92
129
|
}
|
|
93
130
|
|
|
@@ -99,11 +136,47 @@ namespace Hyper.Internal
|
|
|
99
136
|
|
|
100
137
|
public void Show()
|
|
101
138
|
{
|
|
139
|
+
isClosing = false;
|
|
140
|
+
isDirectContentOpen = false;
|
|
141
|
+
contentRevealScheduled = false;
|
|
142
|
+
CancelHiddenPreloadClose();
|
|
143
|
+
HideTutorialContent();
|
|
102
144
|
tutorialCG.alpha = 1f;
|
|
103
145
|
tutorialCG.interactable = true;
|
|
104
146
|
tutorialCG.blocksRaycasts = true;
|
|
105
147
|
|
|
106
|
-
slideUp.SlideUpAnimation();
|
|
148
|
+
slideUp.SlideUpAnimation(SlideInDuration);
|
|
149
|
+
|
|
150
|
+
if (CanShowPreparedTutorialImmediately())
|
|
151
|
+
{
|
|
152
|
+
ShowPreparedTutorialImmediately();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (tutorialLoaderModal != null)
|
|
157
|
+
{
|
|
158
|
+
tutorialLoaderModal.gameObject.SetActive(true);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (_dataManager != null && _dataManager.HasReferencedTutorialResources)
|
|
162
|
+
{
|
|
163
|
+
ShowTutorialData(_dataManager.TutorialData);
|
|
164
|
+
}
|
|
165
|
+
#if UNITY_EDITOR
|
|
166
|
+
else
|
|
167
|
+
{
|
|
168
|
+
if (!TryStartEditorTutorialLoad())
|
|
169
|
+
{
|
|
170
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
#endif
|
|
174
|
+
#if !UNITY_EDITOR
|
|
175
|
+
else
|
|
176
|
+
{
|
|
177
|
+
HyperRuntime.BackendManager.GetTutorial(() => { });
|
|
178
|
+
}
|
|
179
|
+
#endif
|
|
107
180
|
}
|
|
108
181
|
|
|
109
182
|
private void Hide()
|
|
@@ -111,6 +184,143 @@ namespace Hyper.Internal
|
|
|
111
184
|
tutorialCG.alpha = 0f;
|
|
112
185
|
tutorialCG.interactable = false;
|
|
113
186
|
tutorialCG.blocksRaycasts = false;
|
|
187
|
+
// HideTutorialContent();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private bool CanShowPreparedTutorialImmediately()
|
|
191
|
+
{
|
|
192
|
+
return hasPreparedTutorialContent && tutorialData != null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private void ShowPreparedTutorialImmediately()
|
|
196
|
+
{
|
|
197
|
+
isDirectContentOpen = true;
|
|
198
|
+
|
|
199
|
+
if (tutorialLoaderModal != null)
|
|
200
|
+
{
|
|
201
|
+
tutorialLoaderModal.gameObject.SetActive(false);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
FadeTutorialContentIn(SlideInDuration);
|
|
205
|
+
ShowTutorialData(tutorialData);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private void ShowTutorialContentImmediate()
|
|
209
|
+
{
|
|
210
|
+
if (tutorialContentGroup == null) return;
|
|
211
|
+
|
|
212
|
+
tutorialContentGroup.DOKill();
|
|
213
|
+
tutorialContentGroup.gameObject.SetActive(true);
|
|
214
|
+
tutorialContentGroup.alpha = 1f;
|
|
215
|
+
tutorialContentGroup.interactable = true;
|
|
216
|
+
tutorialContentGroup.blocksRaycasts = true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private void FadeTutorialContentIn(float delay = 0f)
|
|
220
|
+
{
|
|
221
|
+
if (tutorialContentGroup == null) return;
|
|
222
|
+
|
|
223
|
+
contentRevealScheduled = true;
|
|
224
|
+
contentRevealDelayTween?.Kill();
|
|
225
|
+
contentRevealDelayTween = null;
|
|
226
|
+
tutorialContentGroup.DOKill();
|
|
227
|
+
tutorialContentGroup.gameObject.SetActive(true);
|
|
228
|
+
tutorialContentGroup.alpha = 0f;
|
|
229
|
+
tutorialContentGroup.interactable = false;
|
|
230
|
+
tutorialContentGroup.blocksRaycasts = false;
|
|
231
|
+
|
|
232
|
+
if (delay > 0f)
|
|
233
|
+
{
|
|
234
|
+
contentRevealDelayTween = HyperTween.DelayedCall(delay, StartTutorialContentFade)
|
|
235
|
+
.SetUpdate(true);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
StartTutorialContentFade();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private void StartTutorialContentFade()
|
|
243
|
+
{
|
|
244
|
+
if (tutorialContentGroup == null) return;
|
|
245
|
+
|
|
246
|
+
contentRevealDelayTween = null;
|
|
247
|
+
tutorialContentGroup.DOKill();
|
|
248
|
+
tutorialContentGroup.gameObject.SetActive(true);
|
|
249
|
+
tutorialContentGroup.interactable = true;
|
|
250
|
+
tutorialContentGroup.blocksRaycasts = true;
|
|
251
|
+
var fadeTween = tutorialContentGroup.DOFade(1f, ContentFadeInDuration)
|
|
252
|
+
.SetEase(HyperTween.Ease.OutQuad)
|
|
253
|
+
.SetUpdate(true);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private void HandleTutorialLoadingComplete()
|
|
257
|
+
{
|
|
258
|
+
if (!isActiveAndEnabled || isClosing) return;
|
|
259
|
+
|
|
260
|
+
hasPreparedTutorialContent = true;
|
|
261
|
+
|
|
262
|
+
if (IsHiddenPreload())
|
|
263
|
+
{
|
|
264
|
+
ScheduleHiddenPreloadClose();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (isDirectContentOpen)
|
|
269
|
+
{
|
|
270
|
+
if (!contentRevealScheduled)
|
|
271
|
+
{
|
|
272
|
+
FadeTutorialContentIn(SlideInDuration);
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (tutorialContentGroup == null) return;
|
|
278
|
+
if (contentRevealScheduled) return;
|
|
279
|
+
|
|
280
|
+
FadeTutorialContentIn(LoaderFadeOutDelay);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private void HideTutorialContent()
|
|
284
|
+
{
|
|
285
|
+
if (tutorialContentGroup == null) return;
|
|
286
|
+
|
|
287
|
+
contentRevealScheduled = false;
|
|
288
|
+
contentRevealDelayTween?.Kill();
|
|
289
|
+
contentRevealDelayTween = null;
|
|
290
|
+
tutorialContentGroup.DOKill();
|
|
291
|
+
tutorialContentGroup.alpha = 0f;
|
|
292
|
+
tutorialContentGroup.interactable = false;
|
|
293
|
+
tutorialContentGroup.blocksRaycasts = false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private bool IsHiddenPreload()
|
|
297
|
+
{
|
|
298
|
+
return tutorialCG != null && tutorialCG.alpha <= 0.001f && !tutorialCG.blocksRaycasts && !tutorialCG.interactable;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private void ScheduleHiddenPreloadClose()
|
|
302
|
+
{
|
|
303
|
+
CancelHiddenPreloadClose();
|
|
304
|
+
hiddenPreloadCloseCo = StartCoroutine(CloseHiddenPreloadAfterPreview());
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private IEnumerator CloseHiddenPreloadAfterPreview()
|
|
308
|
+
{
|
|
309
|
+
yield return new WaitForSecondsRealtime(HiddenPreloadPlayDuration);
|
|
310
|
+
|
|
311
|
+
hiddenPreloadCloseCo = null;
|
|
312
|
+
|
|
313
|
+
if (!isActiveAndEnabled || isClosing || !IsHiddenPreload()) yield break;
|
|
314
|
+
|
|
315
|
+
FinishClose();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private void CancelHiddenPreloadClose()
|
|
319
|
+
{
|
|
320
|
+
if (hiddenPreloadCloseCo == null) return;
|
|
321
|
+
|
|
322
|
+
StopCoroutine(hiddenPreloadCloseCo);
|
|
323
|
+
hiddenPreloadCloseCo = null;
|
|
114
324
|
}
|
|
115
325
|
|
|
116
326
|
private void SetupSliderControls()
|
|
@@ -119,19 +329,25 @@ namespace Hyper.Internal
|
|
|
119
329
|
|
|
120
330
|
timeSlider.minValue = 0f;
|
|
121
331
|
timeSlider.wholeNumbers = false;
|
|
122
|
-
timeSlider.
|
|
332
|
+
timeSlider.interactable = VideoSeekingEnabled;
|
|
333
|
+
timeSlider.onValueChanged.RemoveListener(OnTimeSliderChanged);
|
|
123
334
|
|
|
124
|
-
// Add event triggers for drag detection
|
|
125
335
|
var eventTrigger = timeSlider.gameObject.GetComponent<UnityEngine.EventSystems.EventTrigger>();
|
|
336
|
+
if (eventTrigger != null)
|
|
337
|
+
{
|
|
338
|
+
eventTrigger.triggers.Clear();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!VideoSeekingEnabled) return;
|
|
342
|
+
|
|
343
|
+
timeSlider.onValueChanged.AddListener(OnTimeSliderChanged);
|
|
344
|
+
|
|
345
|
+
eventTrigger = timeSlider.gameObject.GetComponent<UnityEngine.EventSystems.EventTrigger>();
|
|
126
346
|
if (eventTrigger == null)
|
|
127
347
|
{
|
|
128
348
|
eventTrigger = timeSlider.gameObject.AddComponent<UnityEngine.EventSystems.EventTrigger>();
|
|
129
349
|
}
|
|
130
350
|
|
|
131
|
-
// Clear existing triggers
|
|
132
|
-
eventTrigger.triggers.Clear();
|
|
133
|
-
|
|
134
|
-
// Pointer down (begin drag)
|
|
135
351
|
var pointerDownEntry = new UnityEngine.EventSystems.EventTrigger.Entry
|
|
136
352
|
{
|
|
137
353
|
eventID = UnityEngine.EventSystems.EventTriggerType.PointerDown
|
|
@@ -139,7 +355,6 @@ namespace Hyper.Internal
|
|
|
139
355
|
pointerDownEntry.callback.AddListener((_) => OnSliderDragStart());
|
|
140
356
|
eventTrigger.triggers.Add(pointerDownEntry);
|
|
141
357
|
|
|
142
|
-
// Pointer up (end drag)
|
|
143
358
|
var pointerUpEntry = new UnityEngine.EventSystems.EventTrigger.Entry
|
|
144
359
|
{
|
|
145
360
|
eventID = UnityEngine.EventSystems.EventTriggerType.PointerUp
|
|
@@ -150,11 +365,15 @@ namespace Hyper.Internal
|
|
|
150
365
|
|
|
151
366
|
private void OnSliderDragStart()
|
|
152
367
|
{
|
|
368
|
+
if (!VideoSeekingEnabled) return;
|
|
369
|
+
|
|
153
370
|
isDraggingSlider = true;
|
|
154
371
|
}
|
|
155
372
|
|
|
156
373
|
private void OnSliderDragEnd()
|
|
157
374
|
{
|
|
375
|
+
if (!VideoSeekingEnabled) return;
|
|
376
|
+
|
|
158
377
|
isDraggingSlider = false;
|
|
159
378
|
|
|
160
379
|
if (videoPlayer != null && videoPlayer.isPrepared)
|
|
@@ -171,8 +390,24 @@ namespace Hyper.Internal
|
|
|
171
390
|
{
|
|
172
391
|
//Debug.Log("Showing tutorial based on type");
|
|
173
392
|
tutorialData = _dataManager.TutorialData;
|
|
393
|
+
ShowTutorialData(tutorialData);
|
|
394
|
+
}
|
|
174
395
|
|
|
175
|
-
|
|
396
|
+
private void ShowTutorialData(TutorialData data)
|
|
397
|
+
{
|
|
398
|
+
if (data == null)
|
|
399
|
+
{
|
|
400
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
tutorialData = data;
|
|
405
|
+
|
|
406
|
+
if (tutorialData.cards != null && tutorialData.cards.Length > 0)
|
|
407
|
+
{
|
|
408
|
+
ShowMixedTutorial(tutorialData);
|
|
409
|
+
}
|
|
410
|
+
else if (tutorialData.type == TutorialType.video)
|
|
176
411
|
{
|
|
177
412
|
ShowVideoTutorial(tutorialData);
|
|
178
413
|
}
|
|
@@ -187,6 +422,74 @@ namespace Hyper.Internal
|
|
|
187
422
|
}
|
|
188
423
|
}
|
|
189
424
|
|
|
425
|
+
#if UNITY_EDITOR
|
|
426
|
+
internal bool TryStartEditorTutorialLoad()
|
|
427
|
+
{
|
|
428
|
+
TutorialData editorData = CreateEditorTutorialData();
|
|
429
|
+
if (editorData == null) return false;
|
|
430
|
+
|
|
431
|
+
if (editorTutorialLoadCo != null)
|
|
432
|
+
{
|
|
433
|
+
StopCoroutine(editorTutorialLoadCo);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
editorTutorialLoadCo = StartCoroutine(LoadEditorTutorialAfterDelay(editorData));
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private TutorialData CreateEditorTutorialData()
|
|
441
|
+
{
|
|
442
|
+
if (editorTutorialCards == null || editorTutorialCards.Length == 0) return null;
|
|
443
|
+
|
|
444
|
+
List<TutorialCardData> editorCards = new List<TutorialCardData>();
|
|
445
|
+
|
|
446
|
+
for (int i = 0; i < editorTutorialCards.Length; i++)
|
|
447
|
+
{
|
|
448
|
+
EditorTutorialCard editorCard = editorTutorialCards[i];
|
|
449
|
+
if (editorCard == null || editorCard.type == TutorialType.None) continue;
|
|
450
|
+
|
|
451
|
+
if (editorCard.type == TutorialType.video && editorCard.videoClip == null) continue;
|
|
452
|
+
if (editorCard.type == TutorialType.images && editorCard.image == null) continue;
|
|
453
|
+
|
|
454
|
+
editorCards.Add(new TutorialCardData
|
|
455
|
+
{
|
|
456
|
+
type = editorCard.type,
|
|
457
|
+
videoClip = editorCard.videoClip,
|
|
458
|
+
image = editorCard.image,
|
|
459
|
+
description = editorCard.description,
|
|
460
|
+
position = editorCard.position > 0 ? editorCard.position : i + 1
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (editorCards.Count == 0) return null;
|
|
465
|
+
|
|
466
|
+
editorCards.Sort((a, b) => a.position.CompareTo(b.position));
|
|
467
|
+
|
|
468
|
+
return new TutorialData
|
|
469
|
+
{
|
|
470
|
+
type = editorCards[0].type,
|
|
471
|
+
cards = editorCards.ToArray()
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
private IEnumerator LoadEditorTutorialAfterDelay(TutorialData editorData)
|
|
476
|
+
{
|
|
477
|
+
tutorialLoaderModal.gameObject.SetActive(true);
|
|
478
|
+
tutorialDisplayP.gameObject.SetActive(false);
|
|
479
|
+
tutorialDisplayL.gameObject.SetActive(false);
|
|
480
|
+
videoPlayer.enabled = false;
|
|
481
|
+
|
|
482
|
+
float minDelay = Mathf.Max(0f, Mathf.Min(editorLoadDelayRange.x, editorLoadDelayRange.y));
|
|
483
|
+
float maxDelay = Mathf.Max(minDelay, Mathf.Max(editorLoadDelayRange.x, editorLoadDelayRange.y));
|
|
484
|
+
float delay = UnityEngine.Random.Range(minDelay, maxDelay);
|
|
485
|
+
|
|
486
|
+
yield return new WaitForSecondsRealtime(delay);
|
|
487
|
+
|
|
488
|
+
editorTutorialLoadCo = null;
|
|
489
|
+
ShowTutorialData(editorData);
|
|
490
|
+
}
|
|
491
|
+
#endif
|
|
492
|
+
|
|
190
493
|
private RawImage SelectOptimalDisplay(float aspectRatio)
|
|
191
494
|
{
|
|
192
495
|
bool isLandscape = aspectRatio > 1.0f;
|
|
@@ -196,20 +499,304 @@ namespace Hyper.Internal
|
|
|
196
499
|
|
|
197
500
|
if (isLandscape)
|
|
198
501
|
{
|
|
199
|
-
//Debug.Log($"Content is landscape (aspect: {aspectRatio:F2}), using landscape display");
|
|
200
502
|
tutorialDisplayL.gameObject.SetActive(true);
|
|
201
503
|
return tutorialDisplayL;
|
|
202
504
|
}
|
|
203
505
|
else
|
|
204
506
|
{
|
|
205
|
-
//Debug.Log($"Content is portrait (aspect: {aspectRatio:F2}), using portrait display");
|
|
206
507
|
tutorialDisplayP.gameObject.SetActive(true);
|
|
207
508
|
return tutorialDisplayP;
|
|
208
509
|
}
|
|
209
510
|
}
|
|
210
511
|
|
|
512
|
+
private void ShowMixedTutorial(TutorialData tutorialData)
|
|
513
|
+
{
|
|
514
|
+
if (tutorialData.cards == null || tutorialData.cards.Length == 0)
|
|
515
|
+
{
|
|
516
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
hasInvokedTutorialLoadComplete = false;
|
|
521
|
+
tutorialCards.Clear();
|
|
522
|
+
tutorialCards.AddRange(tutorialData.cards);
|
|
523
|
+
tutorialCards.Sort((a, b) => a.position.CompareTo(b.position));
|
|
524
|
+
currentCardIndex = 0;
|
|
525
|
+
currentImageIndex = 0;
|
|
526
|
+
|
|
527
|
+
if (tutorialDisplayP != null) tutorialDisplayP.gameObject.SetActive(false);
|
|
528
|
+
if (tutorialDisplayL != null) tutorialDisplayL.gameObject.SetActive(false);
|
|
529
|
+
|
|
530
|
+
if (TryLoadCardImagesFromUrls())
|
|
531
|
+
{
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
SetupMixedTutorialCards();
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private bool TryLoadCardImagesFromUrls()
|
|
539
|
+
{
|
|
540
|
+
bool hasRemoteImage = false;
|
|
541
|
+
|
|
542
|
+
for (int i = 0; i < tutorialCards.Count; i++)
|
|
543
|
+
{
|
|
544
|
+
TutorialCardData card = tutorialCards[i];
|
|
545
|
+
if (card.type == TutorialType.images && card.image == null && !string.IsNullOrEmpty(card.imageUrl))
|
|
546
|
+
{
|
|
547
|
+
hasRemoteImage = true;
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (!hasRemoteImage) return false;
|
|
553
|
+
|
|
554
|
+
StartCoroutine(LoadCardImagesFromUrlsCoroutine(SetupMixedTutorialCards));
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private IEnumerator LoadCardImagesFromUrlsCoroutine(Action onComplete)
|
|
559
|
+
{
|
|
560
|
+
for (int i = 0; i < tutorialCards.Count; i++)
|
|
561
|
+
{
|
|
562
|
+
TutorialCardData card = tutorialCards[i];
|
|
563
|
+
if (card.type != TutorialType.images || card.image != null || string.IsNullOrEmpty(card.imageUrl)) continue;
|
|
564
|
+
|
|
565
|
+
using (UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(card.imageUrl))
|
|
566
|
+
{
|
|
567
|
+
yield return webRequest.SendWebRequest();
|
|
568
|
+
|
|
569
|
+
if (webRequest.result == UnityWebRequest.Result.Success)
|
|
570
|
+
{
|
|
571
|
+
Texture2D texture = DownloadHandlerTexture.GetContent(webRequest);
|
|
572
|
+
texture.filterMode = FilterMode.Bilinear;
|
|
573
|
+
texture.Compress(false);
|
|
574
|
+
|
|
575
|
+
card.image = Sprite.Create(
|
|
576
|
+
texture,
|
|
577
|
+
new Rect(0, 0, texture.width, texture.height),
|
|
578
|
+
new Vector2(0.5f, 0.5f),
|
|
579
|
+
100f,
|
|
580
|
+
0,
|
|
581
|
+
SpriteMeshType.Tight
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
onComplete?.Invoke();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
private void SetupMixedTutorialCards()
|
|
591
|
+
{
|
|
592
|
+
RemoveInvalidTutorialCards();
|
|
593
|
+
|
|
594
|
+
if (tutorialCards.Count == 0)
|
|
595
|
+
{
|
|
596
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
backButton.gameObject.SetActive(true);
|
|
601
|
+
nextButton.gameObject.SetActive(true);
|
|
602
|
+
indicatorParent.gameObject.SetActive(true);
|
|
603
|
+
|
|
604
|
+
UpdateIndicators(tutorialCards.Count);
|
|
605
|
+
StartCoroutine(ApplyInitialIndicatorHighlightNextFrame());
|
|
606
|
+
DisplayCurrentCard(true);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
private void RemoveInvalidTutorialCards()
|
|
610
|
+
{
|
|
611
|
+
for (int i = tutorialCards.Count - 1; i >= 0; i--)
|
|
612
|
+
{
|
|
613
|
+
TutorialCardData card = tutorialCards[i];
|
|
614
|
+
bool hasVideo = card.type == TutorialType.video && (card.videoClip != null || !string.IsNullOrEmpty(card.videoUrl));
|
|
615
|
+
bool hasImage = card.type == TutorialType.images && card.image != null;
|
|
616
|
+
|
|
617
|
+
if (!hasVideo && !hasImage)
|
|
618
|
+
{
|
|
619
|
+
tutorialCards.RemoveAt(i);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
private void DisplayCurrentCard(bool isInitialDisplay)
|
|
627
|
+
{
|
|
628
|
+
if (currentCardIndex < 0 || currentCardIndex >= tutorialCards.Count) return;
|
|
629
|
+
|
|
630
|
+
StopVideoPlayback();
|
|
631
|
+
TutorialCardData card = tutorialCards[currentCardIndex];
|
|
632
|
+
|
|
633
|
+
if (descriptionText != null)
|
|
634
|
+
{
|
|
635
|
+
descriptionText.text = card.description ?? string.Empty;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (card.type == TutorialType.video)
|
|
639
|
+
{
|
|
640
|
+
DisplayVideoCard(card, isInitialDisplay);
|
|
641
|
+
}
|
|
642
|
+
else
|
|
643
|
+
{
|
|
644
|
+
DisplayImageCard(card, isInitialDisplay);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
HighlightIndicator(currentCardIndex);
|
|
648
|
+
UpdateNavigationButtons(tutorialCards.Count, currentCardIndex);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
private void DisplayVideoCard(TutorialCardData card, bool isInitialDisplay)
|
|
652
|
+
{
|
|
653
|
+
if (videoPlayer == null)
|
|
654
|
+
{
|
|
655
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (tutorialImageDisplay != null)
|
|
660
|
+
tutorialImageDisplay.gameObject.SetActive(false);
|
|
661
|
+
|
|
662
|
+
// Start with portrait display as default; will switch to landscape in OnCardVideoPrepared if needed
|
|
663
|
+
tutorialDisplayP.gameObject.SetActive(true);
|
|
664
|
+
tutorialDisplayL.gameObject.SetActive(false);
|
|
665
|
+
currentDisplay = tutorialDisplayP;
|
|
666
|
+
|
|
667
|
+
videoPlayer.enabled = true;
|
|
668
|
+
videoPlayer.isLooping = true;
|
|
669
|
+
videoPlayer.prepareCompleted -= OnVideoPrepared;
|
|
670
|
+
videoPlayer.prepareCompleted -= OnCardVideoPrepared;
|
|
671
|
+
videoPlayer.loopPointReached -= OnLoopPointReached;
|
|
672
|
+
videoPlayer.loopPointReached += OnLoopPointReached;
|
|
673
|
+
|
|
674
|
+
if (card.videoClip != null)
|
|
675
|
+
{
|
|
676
|
+
videoPlayer.source = VideoSource.VideoClip;
|
|
677
|
+
videoPlayer.clip = card.videoClip;
|
|
678
|
+
}
|
|
679
|
+
else if (!string.IsNullOrEmpty(card.videoUrl))
|
|
680
|
+
{
|
|
681
|
+
videoPlayer.source = VideoSource.Url;
|
|
682
|
+
videoPlayer.url = card.videoUrl;
|
|
683
|
+
}
|
|
684
|
+
else
|
|
685
|
+
{
|
|
686
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
videoPlayer.prepareCompleted += OnCardVideoPrepared;
|
|
691
|
+
videoPlayer.Prepare();
|
|
692
|
+
|
|
693
|
+
timeSlider.gameObject.SetActive(true);
|
|
694
|
+
timeSlider.interactable = VideoSeekingEnabled;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
private void OnCardVideoPrepared(VideoPlayer vp)
|
|
698
|
+
{
|
|
699
|
+
vp.prepareCompleted -= OnCardVideoPrepared;
|
|
700
|
+
PreventIOSFullscreen();
|
|
701
|
+
|
|
702
|
+
if (currentDisplay == null)
|
|
703
|
+
{
|
|
704
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
bool isLandscape = vp.width > vp.height;
|
|
709
|
+
RawImage targetDisplay = isLandscape ? tutorialDisplayL : tutorialDisplayP;
|
|
710
|
+
RenderTexture targetTexture = isLandscape ? tutorialVideoTextureL : tutorialVideoTextureP;
|
|
711
|
+
if (targetTexture == null) targetTexture = isLandscape ? tutorialVideoTextureP : tutorialVideoTextureL;
|
|
712
|
+
|
|
713
|
+
// Switch to the correct display
|
|
714
|
+
tutorialDisplayP.gameObject.SetActive(targetDisplay == tutorialDisplayP);
|
|
715
|
+
tutorialDisplayL.gameObject.SetActive(targetDisplay == tutorialDisplayL);
|
|
716
|
+
currentDisplay = targetDisplay;
|
|
717
|
+
|
|
718
|
+
if (targetTexture != null)
|
|
719
|
+
{
|
|
720
|
+
currentDisplay.texture = targetTexture;
|
|
721
|
+
videoPlayer.targetTexture = targetTexture;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
double len = videoPlayer.length;
|
|
725
|
+
if (len <= 0 && videoPlayer.clip != null) len = videoPlayer.clip.length;
|
|
726
|
+
cachedVideoLength = (float)Mathf.Max(0f, (float)len);
|
|
727
|
+
|
|
728
|
+
timeSlider.minValue = 0f;
|
|
729
|
+
timeSlider.maxValue = cachedVideoLength;
|
|
730
|
+
timeSlider.value = 0f;
|
|
731
|
+
|
|
732
|
+
if (updateVideoTimeCo != null) StopCoroutine(updateVideoTimeCo);
|
|
733
|
+
updateVideoTimeCo = StartCoroutine(UpdateVideoTime());
|
|
734
|
+
|
|
735
|
+
InvokeTutorialLoadingCompleteOnce();
|
|
736
|
+
videoPlayer.Play();
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
private void DisplayImageCard(TutorialCardData card, bool isInitialDisplay)
|
|
740
|
+
{
|
|
741
|
+
videoPlayer.enabled = false;
|
|
742
|
+
timeSlider.gameObject.SetActive(false);
|
|
743
|
+
|
|
744
|
+
if (tutorialDisplayP != null)
|
|
745
|
+
tutorialDisplayP.gameObject.SetActive(false);
|
|
746
|
+
if (tutorialDisplayL != null)
|
|
747
|
+
tutorialDisplayL.gameObject.SetActive(false);
|
|
748
|
+
|
|
749
|
+
if (tutorialImageDisplay == null || card.image == null)
|
|
750
|
+
{
|
|
751
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
tutorialImageDisplay.gameObject.SetActive(true);
|
|
756
|
+
tutorialImageDisplay.texture = card.image.texture;
|
|
757
|
+
|
|
758
|
+
if (isInitialDisplay)
|
|
759
|
+
{
|
|
760
|
+
InvokeTutorialLoadingCompleteOnce();
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private void InvokeTutorialLoadingCompleteOnce()
|
|
765
|
+
{
|
|
766
|
+
if (hasInvokedTutorialLoadComplete) return;
|
|
767
|
+
|
|
768
|
+
hasPreparedTutorialContent = true;
|
|
769
|
+
hasInvokedTutorialLoadComplete = true;
|
|
770
|
+
_eventManager.InvokeTutorialLoadingCompleteEvent();
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
private void StopVideoPlayback()
|
|
774
|
+
{
|
|
775
|
+
if (updateVideoTimeCo != null)
|
|
776
|
+
{
|
|
777
|
+
StopCoroutine(updateVideoTimeCo);
|
|
778
|
+
updateVideoTimeCo = null;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (videoPlayer == null) return;
|
|
782
|
+
|
|
783
|
+
videoPlayer.prepareCompleted -= OnCardVideoPrepared;
|
|
784
|
+
videoPlayer.Stop();
|
|
785
|
+
videoPlayer.targetTexture = null;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
211
790
|
private void ShowVideoTutorial(TutorialData tutorialData)
|
|
212
791
|
{
|
|
792
|
+
if (videoPlayer == null)
|
|
793
|
+
{
|
|
794
|
+
_eventManager.InvokeTutorialFetchFailedEvent();
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
videoPlayer.enabled = true;
|
|
799
|
+
|
|
213
800
|
bool videoFound = false;
|
|
214
801
|
|
|
215
802
|
if (tutorialData.videoClip != null)
|
|
@@ -234,6 +821,7 @@ namespace Hyper.Internal
|
|
|
234
821
|
|
|
235
822
|
else
|
|
236
823
|
{
|
|
824
|
+
videoPlayer.prepareCompleted -= OnCardVideoPrepared;
|
|
237
825
|
videoPlayer.prepareCompleted += OnVideoPrepared;
|
|
238
826
|
videoPlayer.loopPointReached += OnLoopPointReached;
|
|
239
827
|
}
|
|
@@ -258,15 +846,6 @@ namespace Hyper.Internal
|
|
|
258
846
|
currentDisplay.texture = targetTexture;
|
|
259
847
|
videoPlayer.targetTexture = targetTexture;
|
|
260
848
|
|
|
261
|
-
AspectRatioFitter fitter = (currentDisplay == tutorialDisplayL) ?
|
|
262
|
-
aspectRatioFitterL : aspectRatioFitterP;
|
|
263
|
-
|
|
264
|
-
if (fitter != null)
|
|
265
|
-
{
|
|
266
|
-
fitter.aspectRatio = Mathf.Max(0.01f, videoAspectRatio);
|
|
267
|
-
fitter.aspectMode = AspectRatioFitter.AspectMode.FitInParent;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
849
|
timeSlider.gameObject.SetActive(true);
|
|
271
850
|
backButton.gameObject.SetActive(false);
|
|
272
851
|
nextButton.gameObject.SetActive(false);
|
|
@@ -278,6 +857,7 @@ namespace Hyper.Internal
|
|
|
278
857
|
timeSlider.minValue = 0f;
|
|
279
858
|
timeSlider.maxValue = cachedVideoLength;
|
|
280
859
|
timeSlider.value = 0f;
|
|
860
|
+
timeSlider.interactable = VideoSeekingEnabled;
|
|
281
861
|
|
|
282
862
|
if (updateVideoTimeCo != null) StopCoroutine(updateVideoTimeCo);
|
|
283
863
|
updateVideoTimeCo = StartCoroutine(UpdateVideoTime());
|
|
@@ -324,6 +904,7 @@ namespace Hyper.Internal
|
|
|
324
904
|
{
|
|
325
905
|
tutorialImages = tutorialData.images;
|
|
326
906
|
SetupImageTutorial();
|
|
907
|
+
_eventManager.InvokeTutorialLoadingCompleteEvent();
|
|
327
908
|
}
|
|
328
909
|
else if (tutorialData.imageUrls != null && tutorialData.imageUrls.Length > 0)
|
|
329
910
|
{
|
|
@@ -377,15 +958,6 @@ namespace Hyper.Internal
|
|
|
377
958
|
float aspectRatio = (float)texture.width / texture.height;
|
|
378
959
|
|
|
379
960
|
currentDisplay = SelectOptimalDisplay(aspectRatio);
|
|
380
|
-
|
|
381
|
-
AspectRatioFitter fitter = (currentDisplay == tutorialDisplayL) ?
|
|
382
|
-
aspectRatioFitterL : aspectRatioFitterP;
|
|
383
|
-
|
|
384
|
-
if (fitter != null)
|
|
385
|
-
{
|
|
386
|
-
fitter.aspectRatio = Mathf.Max(0.01f, aspectRatio);
|
|
387
|
-
fitter.aspectMode = AspectRatioFitter.AspectMode.FitInParent;
|
|
388
|
-
}
|
|
389
961
|
}
|
|
390
962
|
|
|
391
963
|
private IEnumerator LoadImagesFromUrlsCoroutine(string[] urls, Action<Sprite[]> onComplete)
|
|
@@ -407,7 +979,7 @@ namespace Hyper.Internal
|
|
|
407
979
|
if (webRequest.result == UnityWebRequest.Result.Success)
|
|
408
980
|
{
|
|
409
981
|
Texture2D texture = DownloadHandlerTexture.GetContent(webRequest);
|
|
410
|
-
texture.filterMode = FilterMode.
|
|
982
|
+
texture.filterMode = FilterMode.Bilinear;
|
|
411
983
|
texture.Compress(false);
|
|
412
984
|
|
|
413
985
|
Sprite sprite = Sprite.Create(
|
|
@@ -447,6 +1019,20 @@ namespace Hyper.Internal
|
|
|
447
1019
|
|
|
448
1020
|
private void OnDisable()
|
|
449
1021
|
{
|
|
1022
|
+
isDirectContentOpen = false;
|
|
1023
|
+
contentRevealScheduled = false;
|
|
1024
|
+
isClosing = false;
|
|
1025
|
+
CancelHiddenPreloadClose();
|
|
1026
|
+
HideTutorialContent();
|
|
1027
|
+
|
|
1028
|
+
#if UNITY_EDITOR
|
|
1029
|
+
if (editorTutorialLoadCo != null)
|
|
1030
|
+
{
|
|
1031
|
+
StopCoroutine(editorTutorialLoadCo);
|
|
1032
|
+
editorTutorialLoadCo = null;
|
|
1033
|
+
}
|
|
1034
|
+
#endif
|
|
1035
|
+
|
|
450
1036
|
if (updateVideoTimeCo != null)
|
|
451
1037
|
{
|
|
452
1038
|
StopCoroutine(updateVideoTimeCo);
|
|
@@ -454,6 +1040,14 @@ namespace Hyper.Internal
|
|
|
454
1040
|
}
|
|
455
1041
|
}
|
|
456
1042
|
|
|
1043
|
+
private void OnDestroy()
|
|
1044
|
+
{
|
|
1045
|
+
if (_eventManager == null) return;
|
|
1046
|
+
|
|
1047
|
+
_eventManager.OnTutorialResourcesReferenced -= ShowTutorialBasedOnType;
|
|
1048
|
+
_eventManager.OnTutorialLoadingComplete -= HandleTutorialLoadingComplete;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
457
1051
|
private void DisplayImage(int index)
|
|
458
1052
|
{
|
|
459
1053
|
if (tutorialImages == null || index < 0 || index >= tutorialImages.Length)
|
|
@@ -471,6 +1065,12 @@ namespace Hyper.Internal
|
|
|
471
1065
|
|
|
472
1066
|
public void NextImage()
|
|
473
1067
|
{
|
|
1068
|
+
if (tutorialCards.Count > 0)
|
|
1069
|
+
{
|
|
1070
|
+
NextContent();
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
474
1074
|
if (currentImageIndex < tutorialImages.Length - 1)
|
|
475
1075
|
{
|
|
476
1076
|
currentImageIndex++;
|
|
@@ -480,6 +1080,12 @@ namespace Hyper.Internal
|
|
|
480
1080
|
|
|
481
1081
|
public void PreviousImage()
|
|
482
1082
|
{
|
|
1083
|
+
if (tutorialCards.Count > 0)
|
|
1084
|
+
{
|
|
1085
|
+
PreviousContent();
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
483
1089
|
if (currentImageIndex > 0)
|
|
484
1090
|
{
|
|
485
1091
|
currentImageIndex--;
|
|
@@ -487,19 +1093,77 @@ namespace Hyper.Internal
|
|
|
487
1093
|
}
|
|
488
1094
|
}
|
|
489
1095
|
|
|
1096
|
+
public void NextContent()
|
|
1097
|
+
{
|
|
1098
|
+
if (currentCardIndex >= tutorialCards.Count - 1) return;
|
|
1099
|
+
|
|
1100
|
+
currentCardIndex++;
|
|
1101
|
+
DisplayCurrentCard(false);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
public void PreviousContent()
|
|
1105
|
+
{
|
|
1106
|
+
if (currentCardIndex <= 0) return;
|
|
1107
|
+
|
|
1108
|
+
currentCardIndex--;
|
|
1109
|
+
DisplayCurrentCard(false);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
490
1112
|
public void Close()
|
|
491
1113
|
{
|
|
1114
|
+
if (isClosing) return;
|
|
1115
|
+
|
|
1116
|
+
isClosing = true;
|
|
1117
|
+
CancelHiddenPreloadClose();
|
|
1118
|
+
tutorialCG.interactable = false;
|
|
1119
|
+
tutorialCG.blocksRaycasts = false;
|
|
1120
|
+
|
|
1121
|
+
if (tutorialContentGroup == null || tutorialContentGroup.alpha <= 0.001f)
|
|
1122
|
+
{
|
|
1123
|
+
FinishClose();
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
tutorialContentGroup.DOKill();
|
|
1128
|
+
tutorialContentGroup.interactable = false;
|
|
1129
|
+
tutorialContentGroup.blocksRaycasts = false;
|
|
1130
|
+
tutorialContentGroup.DOFade(0f, ContentFadeOutDuration)
|
|
1131
|
+
.SetEase(HyperTween.Ease.InQuad)
|
|
1132
|
+
.SetUpdate(true)
|
|
1133
|
+
.OnComplete(FinishClose);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
private void FinishClose()
|
|
1137
|
+
{
|
|
1138
|
+
if (tutorialContentGroup != null)
|
|
1139
|
+
{
|
|
1140
|
+
tutorialContentGroup.alpha = 0f;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
492
1143
|
if (videoPlayer != null) videoPlayer.enabled = false;
|
|
493
1144
|
slideUp.SlideDownAnimation();
|
|
494
1145
|
}
|
|
495
1146
|
|
|
496
1147
|
private void UpdateNavigationButtons()
|
|
497
1148
|
{
|
|
498
|
-
|
|
499
|
-
|
|
1149
|
+
UpdateNavigationButtons(tutorialImages != null ? tutorialImages.Length : 0, currentImageIndex);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
private void UpdateNavigationButtons(int totalCount, int currentIndex)
|
|
1153
|
+
{
|
|
1154
|
+
bool hasMultipleCards = totalCount > 1;
|
|
1155
|
+
nextButton.gameObject.SetActive(hasMultipleCards);
|
|
1156
|
+
backButton.gameObject.SetActive(hasMultipleCards);
|
|
1157
|
+
nextButton.interactable = currentIndex < totalCount - 1;
|
|
1158
|
+
backButton.interactable = currentIndex > 0;
|
|
500
1159
|
}
|
|
501
1160
|
|
|
502
1161
|
private void UpdateIndicators()
|
|
1162
|
+
{
|
|
1163
|
+
UpdateIndicators(tutorialImages != null ? tutorialImages.Length : 0);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
private void UpdateIndicators(int totalCount)
|
|
503
1167
|
{
|
|
504
1168
|
|
|
505
1169
|
foreach (Transform child in indicatorParent)
|
|
@@ -507,10 +1171,18 @@ namespace Hyper.Internal
|
|
|
507
1171
|
Destroy(child.gameObject);
|
|
508
1172
|
}
|
|
509
1173
|
|
|
510
|
-
for (int i = 0; i <
|
|
1174
|
+
for (int i = 0; i < totalCount; i++)
|
|
511
1175
|
{
|
|
512
1176
|
Instantiate(indicatorPrefab, indicatorParent);
|
|
513
1177
|
}
|
|
1178
|
+
|
|
1179
|
+
indicatorParent.gameObject.SetActive(totalCount > 1);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
private IEnumerator ApplyInitialIndicatorHighlightNextFrame()
|
|
1183
|
+
{
|
|
1184
|
+
yield return null;
|
|
1185
|
+
HighlightIndicator(currentCardIndex);
|
|
514
1186
|
}
|
|
515
1187
|
|
|
516
1188
|
private void HighlightIndicator(int index)
|
|
@@ -559,6 +1231,8 @@ namespace Hyper.Internal
|
|
|
559
1231
|
|
|
560
1232
|
private void OnTimeSliderChanged(float value)
|
|
561
1233
|
{
|
|
1234
|
+
if (!VideoSeekingEnabled) return;
|
|
1235
|
+
|
|
562
1236
|
// var tutorialData = HyperRuntime.GameManager.IsPortrait()
|
|
563
1237
|
// ? HyperRuntime.DataManager.tutorialData
|
|
564
1238
|
// : HyperRuntime.DataManager.landscapeTutorial;
|