Files
decay-grid/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs

251 lines
8.0 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Core.Domain;
using Core.Ports;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Infrastructure.Unity
{
public class GameBootstrap : MonoBehaviour
{
[Header("Infrastructure")]
[SerializeField] private LevelGenerator levelGenerator;
[SerializeField] private OrbViewAdapter orbPrefab;
[SerializeField] private PlayerController playerPrefab;
[SerializeField] private DeathPlaneAdapter deathPlanePrefab;
[SerializeField] private SoundManager soundManager;
[SerializeField] private CameraController cameraController;
[SerializeField] private NpcController npcPrefab;
[Header("Level Generation")]
[SerializeField] private int floorsCount = 3;
[SerializeField] private float floorHeightDistance = 15f;
[Header("Ui")]
[SerializeField] private TMP_Text scoreText;
[SerializeField] private TMP_Text highScoreText;
[SerializeField] private GameObject gameOverUi;
[SerializeField] private GameObject startScreenUi;
[Header("Settings")]
[SerializeField] private float restartTime = 3f;
[Header("Power Ups")]
[SerializeField] private PowerUpViewAdapter lightFootedPrefab;
[SerializeField] private PowerUpViewAdapter speedBoostPrefab;
private readonly List<Tile> _allTiles = new();
private readonly Dictionary<string, TileViewAdapter> _tileViews = new();
private GameSession _gameSession;
private IPersistenceService _persistenceService;
private InputSystem_Actions _actions;
private PlayerController _playerInstance;
private GameObject _currentOrbInstance;
private bool _isGameRunning;
private void OnEnable()
{
_actions = new InputSystem_Actions();
_actions.Player.Enable();
}
private void OnDisable()
{
_actions.Player.Disable();
}
private void Start()
{
if (levelGenerator) levelGenerator.Generate(soundManager, _allTiles, _tileViews);
SpawnDeathPlane();
SpawnPlayer();
if (gameOverUi) gameOverUi.SetActive(false);
if (startScreenUi) startScreenUi.SetActive(true);
_persistenceService = new PlayerPrefsPersistenceAdapter();
_gameSession = new GameSession(_allTiles, _persistenceService);
WireEvents();
UpdateScoreUi(_gameSession.Score);
}
private void Update()
{
if (!_isGameRunning)
{
if (_actions.Player.StartGame.triggered)
{
StartGameSequence();
}
return;
}
if (_playerInstance)
{
var playerY = _playerInstance.transform.position.y;
var currentFloor = Mathf.RoundToInt(-playerY / floorHeightDistance);
currentFloor = Mathf.Clamp(currentFloor, 0, floorsCount - 1);
_gameSession.SetPlayerFloor(currentFloor);
}
var dt = Time.deltaTime;
if (_isGameRunning) _gameSession.Tick(dt);
for (var i = _allTiles.Count - 1; i >= 0; i--)
{
_allTiles[i].Tick(dt);
}
}
private void SpawnVisualOrb(string tileId)
{
if (_currentOrbInstance) Destroy(_currentOrbInstance);
if (!_tileViews.TryGetValue(tileId, out var tileView)) return;
if (!tileView) return;
var spawnPos = tileView.transform.position + Vector3.up;
var orb = Instantiate(orbPrefab, spawnPos, Quaternion.identity);
orb.OnCollected += () => _gameSession.OrbCollected();
_currentOrbInstance = orb.gameObject;
}
private void HandleOrbReset()
{
if (_currentOrbInstance)
{
Destroy(_currentOrbInstance);
}
}
private void UpdateScoreUi(int newScore)
{
if (!scoreText) return;
scoreText.text = $"Data: {newScore}";
if (highScoreText) highScoreText.text = $"BEST: {_gameSession.HighScore}";
}
private void SpawnPlayer()
{
var spawnPos = new Vector3(0f, 5f, 0f);
_playerInstance = Instantiate(playerPrefab, spawnPos, Quaternion.identity);
_playerInstance.enabled = false;
_playerInstance.Rigidbody.isKinematic = true;
if (cameraController)
{
cameraController.SetTarget(_playerInstance.transform);
}
}
private void SpawnDeathPlane()
{
if (!levelGenerator) return;
var lowestY = -(levelGenerator.FloorsCount * levelGenerator.FloorHeightDistance) - 5f;
var pos = new Vector3(levelGenerator.GridSizeX / 2f, lowestY, levelGenerator.GridSizeY / 2f);
var plane = Instantiate(deathPlanePrefab, pos, Quaternion.identity);
plane.transform.localScale = new Vector3(levelGenerator.GridSizeX * 2f, 1f, levelGenerator.GridSizeY * 2f);
plane.OnPlayerFell += () => _gameSession.EndGame();
}
private void HandleGameOver()
{
_isGameRunning = false;
if (gameOverUi) gameOverUi.SetActive(true);
StartCoroutine(RestartRoutine());
}
private IEnumerator RestartRoutine()
{
yield return new WaitForSeconds(restartTime);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
private void WireEvents()
{
_gameSession.OnScoreChanged += UpdateScoreUi;
_gameSession.OnOrbSpawned += SpawnVisualOrb;
_gameSession.OnOrbReset += HandleOrbReset;
_gameSession.OnGameOver += HandleGameOver;
_gameSession.OnSpawnNpc += SpawnNpc;
_gameSession.OnSpawnPowerUp += SpawnPowerUp;
if (!soundManager) return;
_gameSession.OnScoreChanged += _ => soundManager.PlayScore();
_gameSession.OnGameOver += () =>
{
soundManager.StopMusic();
soundManager.PlayGameOver();
};
}
private void SpawnNpc()
{
if (!npcPrefab) return;
var spawnPos = new Vector3(levelGenerator.GridSizeX / 2f, 7f, levelGenerator.GridSizeY / 2f);
Instantiate(npcPrefab, spawnPos, Quaternion.identity);
soundManager.PlayNpcSpawn();
}
private void StartGameSequence()
{
_isGameRunning = true;
if (startScreenUi) startScreenUi.SetActive(false);
if (soundManager)
{
soundManager.PlayGameStart();
soundManager.PlayMusic();
}
if (_playerInstance)
{
_playerInstance.enabled = true;
_playerInstance.Rigidbody.isKinematic = false;
}
_gameSession.StartGame();
}
private void SpawnPowerUp(PowerUpType type, string tileId)
{
if (!_tileViews.TryGetValue(tileId, out var tileView)) return;
if (!tileView) return;
var spawnPos = tileView.transform.position + Vector3.up * 0.5f;
var prefabToSpawn = type == PowerUpType.LightFooted
? lightFootedPrefab
: speedBoostPrefab;
if (!prefabToSpawn) return;
var instance = Instantiate(prefabToSpawn, spawnPos, Quaternion.identity);
instance.Configure(type);
}
}
}