Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -0,0 +1,36 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public class DefaultGameStateManager : IGameStateManager
{
private readonly GameManager gameManager;
private readonly Level levelData;
public DefaultGameStateManager(GameManager gameManager, Level levelData)
{
this.gameManager = gameManager;
this.levelData = levelData;
}
public string CurrentLanguage => gameManager?.language;
public string[] GetLevelWords()
{
return levelData?.GetWords(CurrentLanguage);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 51726f82dad7405dbff26d0cd8974025
timeCreated: 1745821654

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ce27424fabf24a21a7c79ef4b949a233
timeCreated: 1727533261

View File

@ -0,0 +1,20 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public interface IGameStateManager
{
string CurrentLanguage { get; }
string[] GetLevelWords();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 549c3179f3434c0b818fa99432205a43
timeCreated: 1745821637

View File

@ -0,0 +1,105 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.System;
using DG.Tweening;
using VContainer;
using WordsToolkit.Scripts.Levels;
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public partial class LevelManager
{
[Inject]
private MenuManager menuManager;
private void HandleGameStateChange(EGameState newState)
{
switch (newState)
{
case EGameState.PrepareGame:
EventManager.GameStatus = EGameState.Playing;
break;
case EGameState.Playing:
if (HasTimer)
{
StartTimer();
}
break;
case EGameState.PreWin:
DOVirtual.DelayedCall(0.5f, () =>
{
ShowPreWinPopup();
});
break;
case EGameState.Win:
if (_levelData.GroupIsFinished())
ShowMenuFinished();
else
ShowMenuPlay();
break;
case EGameState.PreFailed:
menuManager.ShowPopup<PreFailed>(null, PrefailedResult);
break;
default:
break;
}
}
private void ShowMenuFinished()
{
menuManager.ShowPopup<Finish>(null, _=>ShowMenuPlay());
}
private void PrefailedResult(EPopupResult obj)
{
if (obj == EPopupResult.Continue)
{
TimerLimit += gameSettings.continueTime;
EventManager.GameStatus = EGameState.Playing;
}
else if(obj == EPopupResult.Cancel)
{
sceneLoader.GoMain();
}
}
private void ShowPreWinPopup()
{
var p = menuManager.ShowPopup<PreWin>(null, _ =>
{
PanelWinAnimation();
DOVirtual.DelayedCall(1f, () =>
{
EventManager.GameStatus = EGameState.Win;
});
});
p.transform.position = bubbleAnchor.position;
}
private void ShowMenuPlay()
{
if (Resources.LoadAll<Level>("Levels").Length <= _levelData.number)
{
menuManager.ShowPopup<ComingSoon>();
}
else
{
menuManager.ShowPopup<MenuPlay>();
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a4994490efe84783a1374aaa5135c3c4
timeCreated: 1729094280

View File

@ -0,0 +1,390 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.System;
using Object = UnityEngine.Object;
using VContainer;
using WordsToolkit.Scripts.GUI.Buttons;
using WordsToolkit.Scripts.Infrastructure.Service;
using WordsToolkit.Scripts.NLP;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public partial class LevelManager : MonoBehaviour
{
public int currentLevel;
private Level _levelData;
private FieldManager field;
public UnityEvent<Level> OnLevelLoaded;
protected float gameTimer = 0f;
private bool isTimerRunning = false;
// Dictionary to store special items in the level
private Dictionary<Vector2Int, GameObject> specialItems = new Dictionary<Vector2Int, GameObject>();
// Event that fires when a special item is collected
public UnityEvent<Vector2Int> OnSpecialItemCollected = new UnityEvent<Vector2Int>();
[SerializeField]
private Transform giftButton;
public bool hammerMode;
public float GameTime { get => gameTimer; private set => gameTimer = value; }
public bool HasTimer { get; private set; }
// Timer limit in seconds, -1 means unlimited time
public float TimerLimit { get; private set; } = -1f;
// Event that fires when the timer runs out
public UnityEvent OnTimerExpired = new UnityEvent();
private StateManager stateManager;
private SceneLoader sceneLoader;
private GameManager gameManager;
private DebugSettings debugSettings;
private ILevelLoaderService levelLoaderService;
private ButtonViewController buttonController;
private GameSettings gameSettings;
[SerializeField]
private Transform bubbleAnchor;
private ICustomWordRepository customWordRepository;
// Debug panel for web demo
private bool showDebugPanel = true;
private bool isDebugPanelExpanded = false;
private Vector2 scrollPosition = Vector2.zero;
[Inject]
public void Construct(FieldManager fieldManager, StateManager stateManager,
SceneLoader sceneLoader, GameManager gameManager, DebugSettings debugSettings, ILevelLoaderService levelLoaderService, ButtonViewController buttonController, GameSettings gameSettings, ICustomWordRepository customWordRepository)
{
this.debugSettings = debugSettings;
this.gameManager = gameManager;
this.field = fieldManager;
this.stateManager = stateManager;
this.sceneLoader = sceneLoader;
this.levelLoaderService = levelLoaderService;
this.buttonController = buttonController;
this.gameSettings = gameSettings;
this.customWordRepository = customWordRepository;
}
private void OnEnable()
{
EventManager.GameStatus = EGameState.PrepareGame;
EventManager.GetEvent(EGameEvent.RestartLevel).Subscribe(RestartLevel);
EventManager.OnGameStateChanged += HandleGameStateChange;
if (field != null)
{
field.OnAllTilesOpened.AddListener(HandleAllTilesOpened);
field.OnAllRequiredWordsFound.AddListener(HandleAllRequiredWordsFound);
}
Load();
}
private void OnDisable()
{
EventManager.GetEvent(EGameEvent.RestartLevel).Unsubscribe(RestartLevel);
EventManager.OnGameStateChanged -= HandleGameStateChange;
if (field != null)
{
field.OnAllTilesOpened.RemoveListener(HandleAllTilesOpened);
field.OnAllRequiredWordsFound.RemoveListener(HandleAllRequiredWordsFound);
}
if (stateManager != null)
{
stateManager.OnStateChanged.RemoveListener(HandleStateChanged);
}
}
private void HandleAllTilesOpened()
{
SetWin();
}
private void RestartLevel()
{
GameDataManager.SetLevel(_levelData);
sceneLoader.StartGameScene();
}
public void Load()
{
// check the level is loaded
if (EventManager.GameStatus == EGameState.Playing)
{
return;
}
field.Clear();
// currentLevel = GameDataManager.GetLevelNum();
_levelData = GameDataManager.GetLevel();
currentLevel = _levelData.number;
if (_levelData == null)
{
// Try to find previous level
int previousLevel = currentLevel - 1;
while (previousLevel > 0)
{
GameDataManager.SetLevelNum(previousLevel);
_levelData = GameDataManager.GetLevel();
if (_levelData != null)
{
currentLevel = previousLevel;
break;
}
previousLevel--;
}
// If still null after trying previous levels
if (_levelData == null)
{
return;
}
}
// Clear special items collection when loading a new level
ClearSpecialItems();
levelLoaderService.NotifyBeforeLevelLoaded(_levelData);
LoadLevel(_levelData);
Invoke(nameof(StartGame), 0.5f);
}
private void StartGame()
{
buttonController.ShowButtons();
levelLoaderService.NotifyLevelLoaded(_levelData);
EventManager.GameStatus = EGameState.Playing;
EventManager.GetEvent<Level>(EGameEvent.Play).Invoke(_levelData);
if (stateManager != null)
{
stateManager.OnStateChanged.RemoveListener(HandleStateChanged);
stateManager.OnStateChanged.AddListener(HandleStateChanged);
}
}
public void LoadLevel(Level levelData)
{
// Get the current language setting
string language = gameManager.language;
// Check if level data contains saved crossword for this language
var languageData = levelData.GetLanguageData(language);
// Generate the field with level data
// Use the new specialItems list instead of filtering placements
var specialItems = languageData?.crosswordData?.specialItems ?? new List<SerializableSpecialItem>();
field.GenerateWithSpecialItems(levelData, language, specialItems);
// Initialize timer settings from level data
HasTimer = levelData.enableTimer;
TimerLimit = levelData.enableTimer ? levelData.timerDuration : -1f;
// Reset timer for new level
ResetTimer();
}
public void SetWin()
{
customWordRepository.ClearExtraWords();
GameDataManager.UnlockLevel(currentLevel + 1);
EventManager.GameStatus = EGameState.PreWin;
}
private void PanelWinAnimation()
{
buttonController.HideAllForWin();
}
private void SetLose()
{
EventManager.GameStatus = EGameState.PreFailed;
}
private void Update()
{
if (Keyboard.current != null)
{
if (Keyboard.current[debugSettings.Win].wasPressedThisFrame)
{
SetWin();
}
if (Keyboard.current[debugSettings.Lose].wasPressedThisFrame)
{
SetLose();
}
if (Keyboard.current[debugSettings.Restart].wasPressedThisFrame)
{
gameManager.RestartLevel();
}
#if UNITY_WEBGL && !UNITY_EDITOR
// Quick win shortcut for web demo testing
if (Keyboard.current[Key.W].wasPressedThisFrame)
{
SetWin();
}
// Toggle debug panel with T key
if (Keyboard.current[Key.T].wasPressedThisFrame)
{
showDebugPanel = !showDebugPanel;
}
#endif
}
// Update timer if it's running
if (isTimerRunning && HasTimer && !menuManager.IsAnyPopupOpened())
{
// Timer now decreases instead of increases
gameTimer += Time.deltaTime;
// Check if timer has expired (if there's a limit)
if (TimerLimit > 0 && gameTimer >= TimerLimit)
{
TimerExpired();
}
}
}
private void StartTimer()
{
isTimerRunning = true;
}
private void StopTimer()
{
isTimerRunning = false;
}
private void ResetTimer()
{
gameTimer = 0f;
isTimerRunning = false;
}
private void TimerExpired()
{
// Stop the timer
StopTimer();
// Notify listeners that the timer has expired
OnTimerExpired.Invoke();
// Just check if all tiles are opened
if (field != null && field.AreAllTilesOpen())
{
SetWin();
return;
}
// If not all tiles are opened, player loses
SetLose();
}
public Level GetCurrentLevel()
{
return _levelData;
}
public string GetCurrentLanguage()
{
return gameManager?.language ?? "en";
}
private void HandleAllRequiredWordsFound()
{
EventManager.GameStatus = EGameState.PreWin;
}
// Register a special item instance with its position
public void RegisterSpecialItem(Vector2Int position, GameObject itemInstance)
{
if (itemInstance == null)
return;
specialItems[position] = itemInstance;
}
// Collect a special item at the given position
public bool CollectSpecialItem(Vector2Int position)
{
if (specialItems.TryGetValue(position, out GameObject item))
{
// Fire event before removing the item
OnSpecialItemCollected.Invoke(position);
// Remove from dictionary and destroy the instance
specialItems.Remove(position);
Destroy(item);
return true;
}
return false;
}
// Clear all special items
private void ClearSpecialItems()
{
foreach (var item in specialItems.Values)
{
if (item != null)
{
Destroy(item);
}
}
specialItems.Clear();
}
// Keep the SerializableStringArray class as it might be used elsewhere or for future serialization
[Serializable]
private class SerializableStringArray
{
public string[] words;
}
public Vector3 GetSpecialItemCollectionPoint()
{
return this.giftButton.transform.position;
}
private void HandleStateChanged(EScreenStates newState)
{
if (newState == EScreenStates.Game)
{
Load();
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e40a00e9a36a45f0bbc7a894cfab08c1
timeCreated: 1727346788

View File

@ -0,0 +1,69 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using UnityEngine;
using WordsToolkit.Scripts.System;
using VContainer;
using UnityEngine.Events;
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public class StateManager : MonoBehaviour
{
[SerializeField]
private GameObject[] mainMenus;
[SerializeField]
private GameObject[] maps;
[SerializeField]
private GameObject[] games;
private EScreenStates _currentState;
public UnityEvent<EScreenStates> OnStateChanged = new UnityEvent<EScreenStates>();
public EScreenStates CurrentState
{
get => _currentState;
set
{
_currentState = value;
SetActiveState(mainMenus, _currentState == EScreenStates.MainMenu);
SetActiveState(games, _currentState == EScreenStates.Game);
OnStateChanged?.Invoke(_currentState);
}
}
public void HideMain()
{
SetActiveState(mainMenus, false);
}
private void SetActiveState(GameObject[] gameObjects, bool isActive)
{
foreach (var gameObject in gameObjects)
{
if (gameObject != null && gameObject.activeSelf != isActive)
{
gameObject.SetActive(isActive);
}
}
}
}
public enum EScreenStates
{
MainMenu,
Game
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 630490a36ddd4c0581994f1efaf73255
timeCreated: 1731134799

View File

@ -0,0 +1,178 @@
// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Linq;
using DG.Tweening;
using UnityEngine;
using VContainer;
using VContainer.Unity;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.GUI.Buttons;
using WordsToolkit.Scripts.GUI.Tutorials;
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.Localization;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Settings;
using WordsToolkit.Scripts.System;
namespace WordsToolkit.Scripts.Gameplay.Managers
{
public class TutorialManager : IStartable, IDisposable
{
private readonly TutorialSettings settings;
private readonly MenuManager menuManager;
private readonly ILocalizationService localizationManager;
private readonly GameManager gameManager;
private readonly IObjectResolver _resolver;
private TutorialPopupBase tutorial;
public TutorialManager(
TutorialSettings settings,
MenuManager menuManager,
ILocalizationService localizationManager,
GameManager gameManager,
IObjectResolver resolver)
{
this.settings = settings;
this.menuManager = menuManager;
this.localizationManager = localizationManager;
this.gameManager = gameManager;
this._resolver = resolver;
}
public void Start()
{
EventManager.GetEvent<Level>( EGameEvent.Play).Subscribe(OnLevelLoaded);
EventManager.GetEvent(EGameEvent.WordAnimated).Subscribe(OnWordOpened);
EventManager.GetEvent<string>(EGameEvent.ExtraWordFound).Subscribe(ExtraWordFound);
EventManager.GetEvent(EGameEvent.SpecialItemCollected).Subscribe(OnSpecialItemCollected);
EventManager.GetEvent<CustomButton>( EGameEvent.ButtonClicked).Subscribe(OnCustomButtonClicked);
}
public void Dispose()
{
EventManager.GetEvent<Level>( EGameEvent.Play).Unsubscribe(OnLevelLoaded);
EventManager.GetEvent(EGameEvent.WordAnimated).Unsubscribe(OnWordOpened);
EventManager.GetEvent<string>(EGameEvent.ExtraWordFound).Unsubscribe(ExtraWordFound);
EventManager.GetEvent(EGameEvent.SpecialItemCollected).Unsubscribe(OnSpecialItemCollected);
EventManager.GetEvent<CustomButton>( EGameEvent.ButtonClicked).Unsubscribe(OnCustomButtonClicked);
if (tutorial != null)
{
tutorial.OnCloseAction -= OnTutorialClosed;
tutorial = null;
}
}
private void OnSpecialItemCollected()
{
ShowTutorialPopup(t => t.showCondition.showCondition == ETutorialShowCondition.Event && t.kind == TutorialKind.GiftButton);
}
private void OnCustomButtonClicked(CustomButton obj)
{
CloseTutorial();
}
private void CloseTutorial()
{
if (tutorial != null)
{
tutorial.Close();
}
}
private void ExtraWordFound(string obj)
{
ShowTutorialPopup(t => t.showCondition.showCondition == ETutorialShowCondition.Event && t.kind == TutorialKind.ExtraWordsButton);
}
private void OnLevelLoaded(Level obj)
{
DOVirtual.DelayedCall(0.2f, () => UpdateTutorialAppearance(obj), false);
}
private void UpdateTutorialAppearance(Level obj)
{
var tutorialShown = ShowTutorialPopup(t => t.showCondition.showCondition == ETutorialShowCondition.Level && t.showCondition.level == obj.number|| t.showCondition.showCondition == ETutorialShowCondition.FirstAppearance);
if (tutorialShown)
return;
var hasSpecialItem = obj.GetLanguageData(gameManager.language).crosswordData.placements.Any(i => i.isSpecialItem);
if (hasSpecialItem)
{
ShowTutorialPopup(t => t.showCondition.showCondition == ETutorialShowCondition.FirstAppearance && t.kind == TutorialKind.RedGem);
}
}
private void OnWordOpened()
{
UpdateTutorialAppearance(GameDataManager.GetLevel());
}
private bool ShowTutorialPopup(Func<TutorialSettingsData, bool> predicate)
{
// Only show tutorials when game is in playing state
if (EventManager.GameStatus != EGameState.Playing)
return false;
var tutorialDatas = settings.tutorialSettings.Where(predicate);
foreach (var tutorialData in tutorialDatas)
{
bool notShow = false;
foreach (var tag in tutorialData.tagsToShow)
{
var obj = GameObject.FindGameObjectWithTag(tag);
if (obj == null || !obj.activeSelf || (obj.TryGetComponent(out CanvasGroup cg) && cg.alpha <= 0))
{
notShow = true;
break; // If any tag is not active, do not show the tutorial
}
}
if (notShow)
continue; // Skip to the next tutorial if any tag is not active
if (!PlayerPrefs.HasKey(tutorialData.GetID()) || PlayerPrefs.GetInt(tutorialData.GetID()) != 1)
{
ShowTutorial(tutorialData);
return true; // Indicate that a tutorial was shown
}
}
return false; // No tutorial was shown
}
private void ShowTutorial(TutorialSettingsData tutorialData)
{
if (tutorialData != null)
{
tutorial = (TutorialPopupBase)menuManager.ShowPopup(tutorialData.popup);
tutorial.SetData(tutorialData);
tutorial.SetTitle(localizationManager.GetText(tutorialData.kind.ToString(), "Use this booster"));
tutorial.OnCloseAction += OnTutorialClosed;
}
}
private void OnTutorialClosed(EPopupResult obj)
{
if (tutorial != null)
{
PlayerPrefs.SetInt(tutorial.GetData().GetID(), 1); // Mark as shown
PlayerPrefs.Save();
tutorial.OnCloseAction -= OnTutorialClosed;
if (tutorial)
{
tutorial = null; // Clear the reference
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c9e6cfe060f541efae6bffd5b37c316
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 2000
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: