Commit a7f8360f authored by Yousef Sameh's avatar Yousef Sameh

Merge remote-tracking branch 'origin/pt_minigames' into NewUI

# Conflicts:
#	My project/Assets/AppUI/NewAppUI/Scene/Login.unity
#	My project/Assets/ScienceStreet/Features/Challenge/ChallengeManager.cs
parents 9807f3e4 0652cde1
fileFormatVersion: 2
guid: 745e9c17df962b24a80a69d5da8e5d38
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: d308d9efe86ef6242a75802e1f37de49
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: e5036f96e3c15ea49b96f7ee989dd3c1
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 9e9f7f46a1ba34c338eb95b193ae1327
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: b18b93d4b5d00384ba417df18aeac5a3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 92a80e6f6cd90464b8f87b98fc72999a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
This diff is collapsed.
This diff is collapsed.
...@@ -7,10 +7,8 @@ using UnityEngine.Events; ...@@ -7,10 +7,8 @@ using UnityEngine.Events;
namespace com.al_arcade.cs namespace com.al_arcade.cs
{ {
using System.Linq;
using shared; using shared;
using Unity.Cinemachine; using Unity.Cinemachine;
using UnityEngine.SceneManagement;
public enum CsGameState public enum CsGameState
{ {
...@@ -151,8 +149,16 @@ namespace com.al_arcade.cs ...@@ -151,8 +149,16 @@ namespace com.al_arcade.cs
if (uiManager != null) if (uiManager != null)
{ {
uiManager.ShowGameUI(); uiManager.ShowGameUI();
uiManager.SetScore(0);
uiManager.SetProgress(0, _questions.Length); uiManager.SetProgress(0, _questions.Length);
uiManager.EnableScore(IsChallengeMode);
if (IsChallengeMode && ChallengeManager.Instance != null)
{
uiManager.SetScore(ChallengeManager.Instance.TimeSaved);
}
else
{
uiManager.SetScore(0);
}
} }
onGameStart?.Invoke(); onGameStart?.Invoke();
...@@ -316,7 +322,6 @@ namespace com.al_arcade.cs ...@@ -316,7 +322,6 @@ namespace com.al_arcade.cs
if (uiManager != null) if (uiManager != null)
{ {
uiManager.ShowFeedback($"ممتاز! {points}+", true); uiManager.ShowFeedback($"ممتاز! {points}+", true);
uiManager.SetScore(_score);
uiManager.SetStreak(_streak); uiManager.SetStreak(_streak);
} }
......
...@@ -198,7 +198,6 @@ namespace com.al_arcade.cs ...@@ -198,7 +198,6 @@ namespace com.al_arcade.cs
Debug.LogError("[CS] Canvas prefab is missing CsUIManager!"); Debug.LogError("[CS] Canvas prefab is missing CsUIManager!");
yield break; yield break;
} }
} }
else else
{ {
......
...@@ -20,7 +20,7 @@ namespace com.al_arcade.cs ...@@ -20,7 +20,7 @@ namespace com.al_arcade.cs
[SerializeField] protected CanvasGroup _optionsPanel, _feedbackGroup; [SerializeField] protected CanvasGroup _optionsPanel, _feedbackGroup;
[SerializeField] protected UniText _progressText; [SerializeField] protected UniText _progressText;
[SerializeField] protected UniText _hintText, _scoreText, _streakText; [SerializeField] protected UniText _hintText, _scoreText, _streakText , _scoreLbl;
[SerializeField] protected UniText _feedbackText; [SerializeField] protected UniText _feedbackText;
[SerializeField] protected Image _feedbackBg, _timerFill; [SerializeField] protected Image _feedbackBg, _timerFill;
...@@ -508,7 +508,19 @@ namespace com.al_arcade.cs ...@@ -508,7 +508,19 @@ namespace com.al_arcade.cs
_timerSlider.value = time / 30f; _timerSlider.value = time / 30f;
_timerFill.color = time > 4f ? _timerDefaultColor : SSColorPalette.Danger; _timerFill.color = time > 4f ? _timerDefaultColor : SSColorPalette.Danger;
} }
public void EnableScore(bool value)
{
_scoreText.enabled = value;
_scoreLbl.enabled = value;
if (value)
{
_scoreLbl.Text = "الوقت الموفر";
}
else
{
_scoreLbl.Text = "النقاط";
}
}
public void UpdateTimer(float time, bool pos) public void UpdateTimer(float time, bool pos)
{ {
isTweening = true; isTweening = true;
...@@ -548,6 +560,7 @@ namespace com.al_arcade.cs ...@@ -548,6 +560,7 @@ namespace com.al_arcade.cs
TickPoints(0); TickPoints(0);
SetStreak(0); SetStreak(0);
ClearOptions(); ClearOptions();
_scoreLbl.enabled = false;
} }
public void TickPoints(int count) public void TickPoints(int count)
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using com.al_arcade.shared; using com.al_arcade.shared;
...@@ -7,10 +7,11 @@ using EasyTransition; ...@@ -7,10 +7,11 @@ using EasyTransition;
using Unity.VisualScripting; using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
// Spawns three games one after the other.
// Move to next game when the current game is won, if lost end the challenge and show results.
public class ChallengeManager : MonoBehaviour public class ChallengeManager : MonoBehaviour
{ {
// ✅ NEW: Singleton
public static ChallengeManager Instance { get; private set; }
[SerializeField] private List<string> gameSceneNames = new(); [SerializeField] private List<string> gameSceneNames = new();
[SerializeField] private TransitionSettings transitionSettings; [SerializeField] private TransitionSettings transitionSettings;
...@@ -18,51 +19,63 @@ public class ChallengeManager : MonoBehaviour ...@@ -18,51 +19,63 @@ public class ChallengeManager : MonoBehaviour
[SerializeField] private int timeSavedBonusMultiplier = 2; [SerializeField] private int timeSavedBonusMultiplier = 2;
[SerializeField] private List<int> penaltiesPerGame = new() { 200, 150, 100 }; [SerializeField] private List<int> penaltiesPerGame = new() { 200, 150, 100 };
[SerializeField] private AudioClip transitionSFX;
// Time saved for bonus if won the challenge
private int timeSaved = 0; private int timeSaved = 0;
private int currentGameIndex = 0; private int currentGameIndex = 0;
private DateTime startTime; private DateTime startTime;
IChallengeGame currentGame = null; IChallengeGame currentGame = null;
BaseGameManager baseGameManager = null; BaseGameManager baseGameManager = null;
private UniTaskCompletionSource transitionEndCompletionSource = null;
[SerializeField] private ChallengeCanvas challengeCanvas; [SerializeField] private ChallengeCanvas challengeCanvas;
// ✅ NEW: public read-only accessor so any game can read time saved
public int TimeSaved => timeSaved;
// ✅ NEW: time bonus from the PREVIOUS game to give to the NEXT game
// this is the timeLeft value passed from OnGameCompleted
private float _lastGameTimeLeft = 0f;
public float LastGameTimeLeft => _lastGameTimeLeft;
void Awake() // ─── Singleton ────────────────────────────────────────────────────────
private void Awake()
{ {
// ✅ NEW: singleton guard — only one ChallengeManager ever exists
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
} }
[ContextMenu("Start Challenge")] private void OnDestroy()
public void StartChallengeButton()
{ {
StartChallenge().Forget(); // ✅ NEW: clear singleton ref when destroyed
if (Instance == this)
Instance = null;
} }
// ─── Context Menu helpers ─────────────────────────────────────────────
[ContextMenu("Start Challenge")]
public void StartChallengeButton() => StartChallenge().Forget();
[ContextMenu("Load Next")] [ContextMenu("Load Next")]
public void LoadNextButton() public void LoadNextButton() => LoadNextGameAndListen().Forget();
{
LoadNextGameAndListen().Forget();
}
[ContextMenu("Fake win")] [ContextMenu("Fake win")]
public void Fakewin() public void Fakewin() => OnGameCompleted(true, 30, 100);
{
OnGameCompleted(true, 30, 100);
}
// ─── Challenge flow ───────────────────────────────────────────────────
public async UniTask StartChallenge() public async UniTask StartChallenge()
{ {
startTime = DateTime.UtcNow; startTime = DateTime.UtcNow;
currentGameIndex = 0; currentGameIndex = 0;
timeSaved = 0; timeSaved = 0;
// ✅ NEW: reset last game time left at start of fresh challenge
_lastGameTimeLeft = 0f;
currentGame = null; currentGame = null;
await LoadNextGameAndListen(); await LoadNextGameAndListen();
...@@ -80,14 +93,16 @@ public class ChallengeManager : MonoBehaviour ...@@ -80,14 +93,16 @@ public class ChallengeManager : MonoBehaviour
return; return;
} }
// Add time left to the saved time for the next game // ✅ NEW: store timeLeft so the next game can use it as a bonus
_lastGameTimeLeft = timeLeft;
// Add time left to total saved time
timeSaved += Mathf.RoundToInt(timeLeft); timeSaved += Mathf.RoundToInt(timeLeft);
currentGameIndex++; currentGameIndex++;
if (currentGameIndex >= gameSceneNames.Count) if (currentGameIndex >= gameSceneNames.Count)
{ {
var pointsEarnedTotal = winningPoints + (timeSaved * timeSavedBonusMultiplier); var pointsEarnedTotal = winningPoints + (timeSaved * timeSavedBonusMultiplier);
WonChallenge(timeSaved, pointsEarnedTotal).Forget(); WonChallenge(timeSaved, pointsEarnedTotal).Forget();
return; return;
} }
...@@ -97,29 +112,27 @@ public class ChallengeManager : MonoBehaviour ...@@ -97,29 +112,27 @@ public class ChallengeManager : MonoBehaviour
private async UniTask LoadNextGameAndListen() private async UniTask LoadNextGameAndListen()
{ {
if (transitionSFX != null) TransitionManager.Instance().Transition(
{ gameSceneNames[currentGameIndex], transitionSettings, 0);
SSAudioManager.EnsureInstance();
SSAudioManager.Instance.Play(transitionSFX);
}
TransitionManager.Instance().Transition(gameSceneNames[currentGameIndex], transitionSettings, 0); await UniTask.WaitUntil(() =>
baseGameManager == null || baseGameManager.IsDestroyed());
// Wait until the old game is destroyed and the new game is loaded and ready
await UniTask.WaitUntil(() => baseGameManager == null || baseGameManager.IsDestroyed());
await UniTask.WaitUntil(() => await UniTask.WaitUntil(() =>
{ {
currentGame = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None) currentGame = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None)
.OfType<IChallengeGame>() .OfType<IChallengeGame>()
.FirstOrDefault(); .FirstOrDefault();
return currentGame != null; return currentGame != null;
}); });
baseGameManager = currentGame as BaseGameManager; baseGameManager = currentGame as BaseGameManager;
print("Current game: " + baseGameManager.name);
await UniTask.WaitForSeconds(0.5f); await UniTask.WaitForSeconds(0.5f);
// ✅ NEW: pass the saved time bonus to the game before starting it
// each game type checks ChallengeManager.Instance.LastGameTimeLeft
// in their own BeginGameplay() — no casting needed here
baseGameManager.StartGame(); baseGameManager.StartGame();
currentGame.OnGameCompleted += OnGameCompleted; currentGame.OnGameCompleted += OnGameCompleted;
} }
...@@ -127,24 +140,22 @@ public class ChallengeManager : MonoBehaviour ...@@ -127,24 +140,22 @@ public class ChallengeManager : MonoBehaviour
private async UniTask LostChallenge() private async UniTask LostChallenge()
{ {
Debug.Log("Challenge failed."); Debug.Log("Challenge failed.");
// Show results, reset challenge, etc. challengeCanvas.ShowChallengeResult(
false, 0, penaltiesPerGame[currentGameIndex]);
challengeCanvas.ShowChallengeResult(false, 0, penaltiesPerGame[currentGameIndex]); await ChallengeService.Instance.AddChallenge(
await ChallengeService.Instance.AddChallenge(false, 0, -penaltiesPerGame[currentGameIndex], startTime, DateTime.UtcNow); false, 0, -penaltiesPerGame[currentGameIndex], startTime, DateTime.UtcNow);
} }
private async UniTask WonChallenge(int timeSaved, int pointsEarned) private async UniTask WonChallenge(int timeSaved, int pointsEarned)
{ {
Debug.Log("Challenge completed! Total time saved: " + timeSaved); Debug.Log("Challenge completed! Total time saved: " + timeSaved);
challengeCanvas.ShowChallengeResult(true, timeSaved, pointsEarned); challengeCanvas.ShowChallengeResult(true, timeSaved, pointsEarned);
await ChallengeService.Instance.AddChallenge(true, timeSaved, pointsEarned, startTime, DateTime.UtcNow); await ChallengeService.Instance.AddChallenge(
true, timeSaved, pointsEarned, startTime, DateTime.UtcNow);
} }
public void EndChallenge() public void EndChallenge()
{ {
Destroy(gameObject, 2); Destroy(gameObject, 5);
} }
} }
\ No newline at end of file
...@@ -52,6 +52,7 @@ public class McqCompetitor : MonoBehaviour ...@@ -52,6 +52,7 @@ public class McqCompetitor : MonoBehaviour
_manager = manager; _manager = manager;
manager.onAnswerGiven?.AddListener(ChangeZLevel); manager.onAnswerGiven?.AddListener(ChangeZLevel);
manager.onGameOver.AddListener(Stop); manager.onGameOver.AddListener(Stop);
manager.onWin?.AddListener(Stop);
} }
private void ChangeZLevel(bool correct) private void ChangeZLevel(bool correct)
......
...@@ -60,6 +60,7 @@ namespace com.al_arcade.mcq ...@@ -60,6 +60,7 @@ namespace com.al_arcade.mcq
_manager = manager; _manager = manager;
manager.onAnswerGiven?.AddListener(PlayAnimation); manager.onAnswerGiven?.AddListener(PlayAnimation);
manager.onGameOver?.AddListener(Stop); manager.onGameOver?.AddListener(Stop);
manager.onWin?.AddListener(Stop);
} }
private void PlayAnimation(bool correct) private void PlayAnimation(bool correct)
......
...@@ -7,12 +7,14 @@ using TMPro; ...@@ -7,12 +7,14 @@ using TMPro;
namespace com.al_arcade.mcq namespace com.al_arcade.mcq
{ {
using com.al_arcade.cs;
using shared; using shared;
[AddComponentMenu("Science Street/MCQ Prefab Builder")] [AddComponentMenu("Science Street/MCQ Prefab Builder")]
public class McqPrefabBuilder : MonoBehaviour public class McqPrefabBuilder : MonoBehaviour
{ {
public static McqPrefabBuilder Instance { get; private set; }
[Header("Scene Environment")] [Header("Scene Environment")]
[Tooltip("Your full road/environment prefab. Spawned at origin.")] [Tooltip("Your full road/environment prefab. Spawned at origin.")]
...@@ -92,6 +94,11 @@ namespace com.al_arcade.mcq ...@@ -92,6 +94,11 @@ namespace com.al_arcade.mcq
[SerializeField] private float runSpeed = 12f; [SerializeField] private float runSpeed = 12f;
[SerializeField] private int lives = 3; [SerializeField] private int lives = 3;
[Header("Timer Settings")]
public int startTime = 30;
public int correctAnswerBonusTime = 3;
public int wrongAnswerPenaltyTime = 2;
[Header("Debug")] [Header("Debug")]
[SerializeField] private bool useOfflineTestData = false; [SerializeField] private bool useOfflineTestData = false;
...@@ -104,6 +111,7 @@ namespace com.al_arcade.mcq ...@@ -104,6 +111,7 @@ namespace com.al_arcade.mcq
private void Start() private void Start()
{ {
Instance = this;
DOTween.Init(); DOTween.Init();
if (arabicFont != null) SSFontManager.Font = arabicFont; if (arabicFont != null) SSFontManager.Font = arabicFont;
StartCoroutine(BuildEverything()); StartCoroutine(BuildEverything());
......
...@@ -102,7 +102,15 @@ namespace com.al_arcade.tf ...@@ -102,7 +102,15 @@ namespace com.al_arcade.tf
{ {
uiManager.ShowGameUI(); uiManager.ShowGameUI();
uiManager.SetProgress(0, stepsToWin); uiManager.SetProgress(0, stepsToWin);
uiManager.SetScore(0); uiManager.EnableScore(IsChallengeMode);
if (IsChallengeMode && ChallengeManager.Instance != null)
{
uiManager.SetScore(ChallengeManager.Instance.TimeSaved);
}
else
{
uiManager.SetScore(0);
}
} }
onGameStart?.Invoke(); onGameStart?.Invoke();
...@@ -226,7 +234,6 @@ namespace com.al_arcade.tf ...@@ -226,7 +234,6 @@ namespace com.al_arcade.tf
if (uiManager != null) if (uiManager != null)
{ {
uiManager.SetProgress(_progress, stepsToWin); uiManager.SetProgress(_progress, stepsToWin);
uiManager.SetScore(_score);
uiManager.SetStreak(_streak); uiManager.SetStreak(_streak);
} }
......
...@@ -15,7 +15,7 @@ namespace com.al_arcade.tf ...@@ -15,7 +15,7 @@ namespace com.al_arcade.tf
{ {
[SerializeField] private Canvas _canvas; [SerializeField] private Canvas _canvas;
[SerializeField] private CanvasGroup _gameUI, _loadingUI, _errorUI, _resultsUI; [SerializeField] private CanvasGroup _gameUI, _loadingUI, _errorUI, _resultsUI;
[SerializeField] private UniText _scoreText, _streakText; [SerializeField] private UniText _scoreText, _streakText , _scoreLbl;
[SerializeField] private ArabicTextMeshProUGUI _loadingText, _errorText; [SerializeField] private ArabicTextMeshProUGUI _loadingText, _errorText;
[SerializeField] private UniText _progressLabel; [SerializeField] private UniText _progressLabel;
[SerializeField] private UniText _resultTitle, _resultScore, _resultStats; [SerializeField] private UniText _resultTitle, _resultScore, _resultStats;
...@@ -338,7 +338,19 @@ namespace com.al_arcade.tf ...@@ -338,7 +338,19 @@ namespace com.al_arcade.tf
.DOPunchScale(Vector3.one * 0.12f, 0.2f, 4, 0.2f) .DOPunchScale(Vector3.one * 0.12f, 0.2f, 4, 0.2f)
.SetId("sp"); .SetId("sp");
} }
public void EnableScore(bool value)
{
_scoreText.enabled = value;
_scoreLbl.enabled = value;
if (value)
{
_scoreLbl.Text = "الوقت الموفر";
}
else
{
_scoreLbl.Text = "النقاط";
}
}
public void SetStreak(int s) public void SetStreak(int s)
{ {
if (_streakText == null) return; if (_streakText == null) return;
...@@ -415,6 +427,7 @@ namespace com.al_arcade.tf ...@@ -415,6 +427,7 @@ namespace com.al_arcade.tf
if (_loadingUI != null) _loadingUI.gameObject.SetActive(false); if (_loadingUI != null) _loadingUI.gameObject.SetActive(false);
if (_errorUI != null) _errorUI.gameObject.SetActive(false); if (_errorUI != null) _errorUI.gameObject.SetActive(false);
if (_resultsUI != null) _resultsUI.gameObject.SetActive(false); if (_resultsUI != null) _resultsUI.gameObject.SetActive(false);
// --- ADDED: Reset timer UI --- // --- ADDED: Reset timer UI ---
if (_timerSlider != null) if (_timerSlider != null)
_timerSlider.value = 1f; _timerSlider.value = 1f;
...@@ -423,6 +436,7 @@ namespace com.al_arcade.tf ...@@ -423,6 +436,7 @@ namespace com.al_arcade.tf
_timerFill.color = _timerDefaultColor; _timerFill.color = _timerDefaultColor;
_isTweening = false; _isTweening = false;
_scoreLbl.enabled = false;
} }
private GameObject MkPanel(Transform p, string n) private GameObject MkPanel(Transform p, string n)
......
This diff is collapsed.
fileFormatVersion: 2 fileFormatVersion: 2
guid: b9d0cd1c5778d1b479da3c3b554ed822 guid: c180291be00c6ac4091f2e5f8b379018
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
......
...@@ -66,14 +66,14 @@ ...@@ -66,14 +66,14 @@
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.collections": { "com.unity.collections": {
"version": "2.6.5", "version": "2.6.2",
"depth": 1, "depth": 1,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
"com.unity.burst": "1.8.27", "com.unity.burst": "1.8.23",
"com.unity.mathematics": "1.3.2", "com.unity.mathematics": "1.3.2",
"com.unity.test-framework": "1.4.6", "com.unity.test-framework": "1.4.6",
"com.unity.nuget.mono-cecil": "1.11.6", "com.unity.nuget.mono-cecil": "1.11.5",
"com.unity.test-framework.performance": "3.0.3" "com.unity.test-framework.performance": "3.0.3"
}, },
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
...@@ -217,7 +217,7 @@ ...@@ -217,7 +217,7 @@
} }
}, },
"com.unity.splines": { "com.unity.splines": {
"version": "2.8.4", "version": "2.8.2",
"depth": 1, "depth": 1,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
......
m_EditorVersion: 6000.3.12f1 m_EditorVersion: 6000.3.9f1
m_EditorVersionWithRevision: 6000.3.12f1 (fca03ac9b0d5) m_EditorVersionWithRevision: 6000.3.9f1 (7a9955a4f2fa)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment