Initial commit: Unity WordConnect project
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51726f82dad7405dbff26d0cd8974025
|
||||
timeCreated: 1745821654
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce27424fabf24a21a7c79ef4b949a233
|
||||
timeCreated: 1727533261
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 549c3179f3434c0b818fa99432205a43
|
||||
timeCreated: 1745821637
|
||||
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4994490efe84783a1374aaa5135c3c4
|
||||
timeCreated: 1729094280
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e40a00e9a36a45f0bbc7a894cfab08c1
|
||||
timeCreated: 1727346788
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 630490a36ddd4c0581994f1efaf73255
|
||||
timeCreated: 1731134799
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c9e6cfe060f541efae6bffd5b37c316
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 2000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user