10 lives, game over for Valentines
This commit is contained in:
@@ -35,6 +35,13 @@ namespace Minigames.Airplane.Core
|
||||
[SerializeField] private UI.AirplaneSelectionUI selectionUI;
|
||||
[SerializeField] private UI.AirplaneAbilityButton abilityButton;
|
||||
|
||||
[Header("UI")]
|
||||
[SerializeField] private Minigames.CardSorting.UI.LivesDisplay livesDisplay;
|
||||
[SerializeField] private UI.GameOverScreen gameOverScreen;
|
||||
|
||||
[Header("Game Configuration")]
|
||||
[SerializeField] private int maxLives = 10;
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField] private bool showDebugLogs = true;
|
||||
|
||||
@@ -74,12 +81,16 @@ namespace Minigames.Airplane.Core
|
||||
private int _successCount;
|
||||
private int _failCount;
|
||||
private int _totalTurns;
|
||||
private int _targetsHit;
|
||||
private int _currentLives;
|
||||
private IAirplaneSettings _cachedSettings;
|
||||
|
||||
public AirplaneGameState CurrentState => _currentState;
|
||||
public Person CurrentPerson => _currentPerson;
|
||||
public int SuccessCount => _successCount;
|
||||
public int FailCount => _failCount;
|
||||
public int TargetsHit => _targetsHit;
|
||||
public int CurrentLives => _currentLives;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -196,6 +207,17 @@ namespace Minigames.Airplane.Core
|
||||
Logging.Warning("[AirplaneGameManager] ⚠️ AbilityButton not assigned! Player will not be able to use abilities.");
|
||||
Logging.Warning("[AirplaneGameManager] → Assign AirplaneAbilityButton GameObject in Inspector under 'Airplane Type Selection'");
|
||||
}
|
||||
|
||||
// Validate UI elements
|
||||
if (livesDisplay == null)
|
||||
{
|
||||
Logging.Warning("[AirplaneGameManager] ⚠️ LivesDisplay not assigned! Lives will not be displayed.");
|
||||
}
|
||||
|
||||
if (gameOverScreen == null)
|
||||
{
|
||||
Logging.Warning("[AirplaneGameManager] ⚠️ GameOverScreen not assigned! Game over screen will not be shown.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -223,6 +245,15 @@ namespace Minigames.Airplane.Core
|
||||
{
|
||||
if (showDebugLogs) Logging.Debug("[AirplaneGameManager] ===== GAME STARTING =====");
|
||||
|
||||
// Initialize lives
|
||||
_currentLives = maxLives;
|
||||
_targetsHit = 0;
|
||||
|
||||
if (livesDisplay != null)
|
||||
{
|
||||
livesDisplay.Initialize(maxLives);
|
||||
}
|
||||
|
||||
StartCoroutine(IntroSequence());
|
||||
}
|
||||
|
||||
@@ -693,6 +724,9 @@ namespace Minigames.Airplane.Core
|
||||
|
||||
_currentAirplane = airplane;
|
||||
|
||||
// Lose a life on each shot
|
||||
LoseLife();
|
||||
|
||||
// Disable launch controller
|
||||
if (launchController != null)
|
||||
{
|
||||
@@ -785,6 +819,7 @@ namespace Minigames.Airplane.Core
|
||||
{
|
||||
_lastShotHit = true;
|
||||
_successCount++;
|
||||
_targetsHit++;
|
||||
|
||||
// Hide target UI immediately on successful hit
|
||||
if (spawnManager != null)
|
||||
@@ -792,7 +827,7 @@ namespace Minigames.Airplane.Core
|
||||
spawnManager.HideTargetUI();
|
||||
}
|
||||
|
||||
if (showDebugLogs) Logging.Debug($"[AirplaneGameManager] ✓ SUCCESS! Hit correct target: {targetName}");
|
||||
if (showDebugLogs) Logging.Debug($"[AirplaneGameManager] ✓ SUCCESS! Hit correct target: {targetName} (Total targets hit: {_targetsHit})");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -859,7 +894,9 @@ namespace Minigames.Airplane.Core
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug($"[AirplaneGameManager] Turn result: {(success ? "SUCCESS" : "FAILURE")}" +
|
||||
$"\n Score: {_successCount} / {_totalTurns}");
|
||||
$"\n Score: {_successCount} / {_totalTurns}" +
|
||||
$"\n Targets Hit: {_targetsHit}" +
|
||||
$"\n Lives Remaining: {_currentLives}");
|
||||
}
|
||||
|
||||
OnPersonFinishTurn?.Invoke(_currentPerson, success);
|
||||
@@ -883,21 +920,138 @@ namespace Minigames.Airplane.Core
|
||||
launchController.ClearActiveAirplane();
|
||||
}
|
||||
|
||||
// Route to appropriate flow based on result
|
||||
if (success)
|
||||
// Check for game over conditions
|
||||
bool allTargetsHit = _targetsHit >= 3;
|
||||
bool outOfLives = _currentLives <= 0;
|
||||
|
||||
if (allTargetsHit || outOfLives)
|
||||
{
|
||||
// Success: Go to person shuffle flow
|
||||
StartCoroutine(ExecutePersonShuffleFlow());
|
||||
// Game over - trigger end game sequence
|
||||
if (showDebugLogs)
|
||||
{
|
||||
string reason = allTargetsHit ? "All 3 targets hit!" : "Out of lives!";
|
||||
Logging.Debug($"[AirplaneGameManager] Game ending: {reason}");
|
||||
}
|
||||
|
||||
StartCoroutine(EndGameSequence());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failure: Go to repeat shot flow
|
||||
StartCoroutine(ExecuteRepeatShotFlow());
|
||||
// Route to appropriate flow based on result
|
||||
if (success)
|
||||
{
|
||||
// Success: Go to person shuffle flow
|
||||
StartCoroutine(ExecutePersonShuffleFlow());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failure: Go to repeat shot flow
|
||||
StartCoroutine(ExecuteRepeatShotFlow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Game over - no more people
|
||||
/// Lose a life and update UI
|
||||
/// </summary>
|
||||
private void LoseLife()
|
||||
{
|
||||
_currentLives--;
|
||||
|
||||
if (livesDisplay != null)
|
||||
{
|
||||
livesDisplay.RemoveLife();
|
||||
}
|
||||
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug($"[AirplaneGameManager] Life lost! Remaining lives: {_currentLives}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End game sequence: award boosters, wait for completion, then show game over screen
|
||||
/// </summary>
|
||||
private IEnumerator EndGameSequence()
|
||||
{
|
||||
// Calculate booster reward
|
||||
int boosterReward = CalculateBoosterReward(_targetsHit);
|
||||
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug($"[AirplaneGameManager] Targets hit: {_targetsHit}, awarding {boosterReward} booster pack(s)");
|
||||
}
|
||||
|
||||
// Show booster pack reward UI and wait for completion
|
||||
if (boosterReward > 0)
|
||||
{
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug("[AirplaneGameManager] Starting booster giver sequence via GameManager");
|
||||
}
|
||||
|
||||
var task = GameManager.Instance.GiveBoosterPacksAsync(boosterReward);
|
||||
|
||||
// Wait for the task to complete
|
||||
while (!task.IsCompleted)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Check for exceptions
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
Logging.Warning($"[AirplaneGameManager] Booster pack reward failed: {task.Exception?.GetBaseException().Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug("[AirplaneGameManager] Booster giver sequence finished, proceeding to game over screen");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showDebugLogs)
|
||||
{
|
||||
Logging.Debug("[AirplaneGameManager] No boosters to award, proceeding directly to game over screen");
|
||||
}
|
||||
}
|
||||
|
||||
// Now show game over screen
|
||||
if (gameOverScreen != null)
|
||||
{
|
||||
gameOverScreen.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("[AirplaneGameManager] GameOverScreen reference missing!");
|
||||
}
|
||||
|
||||
// Transition to GameOver state
|
||||
yield return StartCoroutine(GameOver());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate booster pack reward based on targets hit.
|
||||
/// Rules:
|
||||
/// - 1 booster for participation (playing the game)
|
||||
/// - 1 additional booster per target hit
|
||||
/// </summary>
|
||||
private int CalculateBoosterReward(int targetsHit)
|
||||
{
|
||||
// Base reward: 1 booster for participation
|
||||
int reward = 1;
|
||||
|
||||
// Additional reward: 1 booster per target hit
|
||||
reward += targetsHit;
|
||||
|
||||
return reward;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Game over - final state
|
||||
/// </summary>
|
||||
private IEnumerator GameOver()
|
||||
{
|
||||
@@ -909,15 +1063,15 @@ namespace Minigames.Airplane.Core
|
||||
$"\n Total Turns: {_totalTurns}" +
|
||||
$"\n Success: {_successCount}" +
|
||||
$"\n Failures: {_failCount}" +
|
||||
$"\n Targets Hit: {_targetsHit}" +
|
||||
$"\n Success Rate: {(_totalTurns > 0 ? (_successCount * 100f / _totalTurns) : 0):F1}%");
|
||||
}
|
||||
|
||||
OnGameComplete?.Invoke();
|
||||
|
||||
// Stub: Show game over UI
|
||||
yield return new WaitForSeconds(2f);
|
||||
|
||||
if (showDebugLogs) Logging.Debug("[AirplaneGameManager] Game complete");
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
91
Assets/Scripts/Minigames/Airplane/UI/GameOverScreen.cs
Normal file
91
Assets/Scripts/Minigames/Airplane/UI/GameOverScreen.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Core;
|
||||
|
||||
namespace Minigames.Airplane.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Game over screen for Airplane minigame.
|
||||
/// Displays when the game ends (out of lives or all targets hit) and allows restarting the level.
|
||||
/// </summary>
|
||||
public class GameOverScreen : MonoBehaviour
|
||||
{
|
||||
[Header("UI References")]
|
||||
[SerializeField] private Button dismissButton;
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Subscribe to button click
|
||||
if (dismissButton != null)
|
||||
{
|
||||
dismissButton.onClick.AddListener(OnDismissClicked);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("[GameOverScreen] Dismiss button not assigned!");
|
||||
}
|
||||
|
||||
// Get or add CanvasGroup for fade effects
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
// Hide by default
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Unsubscribe from button
|
||||
if (dismissButton != null)
|
||||
{
|
||||
dismissButton.onClick.RemoveListener(OnDismissClicked);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the game over screen.
|
||||
/// </summary>
|
||||
public void Show()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
|
||||
// Set canvas group for interaction
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
}
|
||||
|
||||
Logging.Debug("[GameOverScreen] Game Over screen shown");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when dismiss button is clicked. Reloads the level.
|
||||
/// </summary>
|
||||
private async void OnDismissClicked()
|
||||
{
|
||||
Logging.Debug("[GameOverScreen] Dismiss button clicked - Reloading level");
|
||||
|
||||
// Hide this screen first
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
gameObject.SetActive(false);
|
||||
|
||||
var progress = new Progress<float>(p => Logging.Debug($"Loading progress: {p * 100:F0}%"));
|
||||
await SceneManagerService.Instance.ReloadCurrentScene(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8bd5b50856a416cb64619d99b26061f
|
||||
timeCreated: 1766159655
|
||||
Reference in New Issue
Block a user