Add Hunter NPC and Teleporter features with associated prefabs and effects
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Infrastructure.Unity
|
||||
{
|
||||
public class GameBootstrap : MonoBehaviour
|
||||
{
|
||||
[Header("Infrastructure")]
|
||||
[Header("Infrastructure")]
|
||||
[SerializeField] private LevelGenerator levelGenerator;
|
||||
[SerializeField] private OrbViewAdapter orbPrefab;
|
||||
[SerializeField] private PlayerController playerPrefab;
|
||||
@@ -18,23 +18,23 @@ namespace Infrastructure.Unity
|
||||
[SerializeField] private SoundManager soundManager;
|
||||
[SerializeField] private CameraController cameraController;
|
||||
[SerializeField] private NpcController npcPrefab;
|
||||
|
||||
[SerializeField] private HunterNpcController hunterNpcPrefab;
|
||||
|
||||
[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;
|
||||
[SerializeField] private PowerUpViewAdapter powerUpPrefab;
|
||||
|
||||
private readonly List<Tile> _allTiles = new();
|
||||
private readonly Dictionary<string, TileViewAdapter> _tileViews = new();
|
||||
@@ -59,17 +59,20 @@ namespace Infrastructure.Unity
|
||||
|
||||
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);
|
||||
|
||||
// Set Theme based on High Score
|
||||
ThemeManager.CurrentTheme = ThemeManager.GetTheme(_gameSession.HighScore);
|
||||
|
||||
if (levelGenerator) levelGenerator.Generate(soundManager, _allTiles, _tileViews, cameraController);
|
||||
|
||||
SpawnDeathPlane();
|
||||
SpawnPlayer();
|
||||
|
||||
if (gameOverUi) gameOverUi.SetActive(false);
|
||||
if (startScreenUi) startScreenUi.SetActive(true);
|
||||
|
||||
WireEvents();
|
||||
UpdateScoreUi(_gameSession.Score);
|
||||
}
|
||||
@@ -90,34 +93,39 @@ namespace Infrastructure.Unity
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
var dilation = _gameSession.TimeDilation;
|
||||
|
||||
// Hard Mode: Decay faster as score increases
|
||||
var decayMultiplier = 1.0f + (_gameSession.Score / 500f);
|
||||
|
||||
for (var i = _allTiles.Count - 1; i >= 0; i--)
|
||||
{
|
||||
_allTiles[i].Tick(dt);
|
||||
_allTiles[i].Tick(dt * dilation * decayMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -132,22 +140,25 @@ namespace Infrastructure.Unity
|
||||
private void UpdateScoreUi(int newScore)
|
||||
{
|
||||
if (!scoreText) return;
|
||||
|
||||
scoreText.text = $"Data: {newScore}";
|
||||
|
||||
if (highScoreText) highScoreText.text = $"BEST: {_gameSession.HighScore}";
|
||||
|
||||
var combo = _gameSession?.ComboMultiplier ?? 1;
|
||||
var comboText = combo > 1 ? $" (x{combo})" : "";
|
||||
|
||||
scoreText.text = $"Data: {newScore}{comboText}";
|
||||
|
||||
if (highScoreText && _gameSession != null) 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);
|
||||
@@ -162,7 +173,7 @@ namespace Infrastructure.Unity
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -177,7 +188,7 @@ namespace Infrastructure.Unity
|
||||
private IEnumerator RestartRoutine()
|
||||
{
|
||||
yield return new WaitForSeconds(restartTime);
|
||||
|
||||
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
|
||||
}
|
||||
|
||||
@@ -191,7 +202,7 @@ namespace Infrastructure.Unity
|
||||
_gameSession.OnSpawnPowerUp += SpawnPowerUp;
|
||||
|
||||
if (!soundManager) return;
|
||||
|
||||
|
||||
_gameSession.OnScoreChanged += _ => soundManager.PlayScore();
|
||||
_gameSession.OnGameOver += () =>
|
||||
{
|
||||
@@ -202,18 +213,26 @@ namespace Infrastructure.Unity
|
||||
|
||||
private void SpawnNpc()
|
||||
{
|
||||
if (!npcPrefab) return;
|
||||
|
||||
var spawnPos = new Vector3(levelGenerator.GridSizeX / 2f, 7f, levelGenerator.GridSizeY / 2f);
|
||||
Instantiate(npcPrefab, spawnPos, Quaternion.identity);
|
||||
|
||||
|
||||
// 30% chance for Hunter if player available
|
||||
if (_playerInstance && hunterNpcPrefab && Random.value < 0.3f)
|
||||
{
|
||||
var hunter = Instantiate(hunterNpcPrefab, spawnPos, Quaternion.identity);
|
||||
hunter.Initialize(_playerInstance);
|
||||
}
|
||||
else if (npcPrefab)
|
||||
{
|
||||
Instantiate(npcPrefab, spawnPos, Quaternion.identity);
|
||||
}
|
||||
|
||||
soundManager.PlayNpcSpawn();
|
||||
}
|
||||
|
||||
private void StartGameSequence()
|
||||
{
|
||||
_isGameRunning = true;
|
||||
|
||||
|
||||
if (startScreenUi) startScreenUi.SetActive(false);
|
||||
|
||||
if (soundManager)
|
||||
@@ -227,7 +246,7 @@ namespace Infrastructure.Unity
|
||||
_playerInstance.enabled = true;
|
||||
_playerInstance.Rigidbody.isKinematic = false;
|
||||
}
|
||||
|
||||
|
||||
_gameSession.StartGame();
|
||||
}
|
||||
|
||||
@@ -237,15 +256,17 @@ namespace Infrastructure.Unity
|
||||
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(powerUpPrefab, spawnPos, Quaternion.identity);
|
||||
|
||||
var instance = Instantiate(prefabToSpawn, spawnPos, Quaternion.identity);
|
||||
instance.Configure(type);
|
||||
|
||||
instance.OnCollected += (t) =>
|
||||
{
|
||||
if (t == PowerUpType.TimeSlow)
|
||||
{
|
||||
_gameSession.ActivateTimeSlow(10f);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user