using Godot; using System; using System.Linq; using System.Threading.Tasks; using Cirno.Scripts; using Cirno.Scripts.Resources; using Godot.Collections; using Cirno.Scripts.Utils; public partial class GameManager : Node2D { public static GameManager Instance { get; private set;} private Hud _hud; private PlayerMovement _player; public GameState GameState { get; private set; } public PlayerMovement Player => _player; private Node2D _cameraTarget; public Vector2? PlayerPosition => _player?.GlobalPosition ?? null; [Export] public PackedScene PlayerTemplate { get; set; } [Export] public Dictionary SpawnMarkers { get; private set; } = new(); //[Export] public Marker2D PlayerSpawnMarker { get; set; } [Export] public PackedScene WeaponTemplate { get; private set; } [Export] public Array StartingEquipment { get; private set; } = new(); private InventoryManager _inventoryManager { get; set; } [Export] public MapStartDataResource MapStartData { get; private set; } //private AlarmManager _alarmManager { get; set; } //public InventoryManager Inventory => _inventoryManager; //public AlarmManager AlarmManager => _alarmManager; private Node2D _bulletsContainer; public Node2D BulletsContainer => _bulletsContainer; [Signal] public delegate void GameStateChangeEventHandler(GameState state); [Signal] public delegate void PlayerRespawnedEventHandler(); // Called when the node enters the scene tree for the first time. public override void _Ready() { Instance = this; _hud = GetNodeOrNull("HUD"); if (_hud == null) GD.Print("No HUD in scene."); _cameraTarget = GetNodeOrNull("CameraTarget"); if (_cameraTarget == null) GD.Print("No camera target in scene."); _inventoryManager = GetNodeOrNull("InventoryManager"); if (_inventoryManager == null) GD.Print("No inventory manager in scene."); //_alarmManager = GetNode("AlarmManager"); SpawnBulletsContainer(); if (_hud != null) { this.GameStateChange += _hud.OnGameStateChanged; } if (_inventoryManager != null && _hud != null) { _inventoryManager.ItemAdded += (item, currentAmount) => _hud.AddInventoryItem(item, currentAmount); _inventoryManager.ItemRemoved += (item, currentAmount) => _hud.RemoveInventoryItem(item, currentAmount); } PlayerRespawned += OnPlayerRespawned; GameState = GameState.Playing; //_ = DelayPlayerSpawn(); CallDeferred(MethodName.DelayPlayerSpawn); } private void OnPlayerRespawned() { this.ClearBullets(); } public void ApplyMapStartData(MapStartDataResource mapStartData) { MapStartData = mapStartData; StartingEquipment.AddRange(mapStartData.StartingEquipment); } public void ApplySessionState(SessionSettings settings) { } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { if (GameState is GameState.Playing && Input.IsActionJustPressed("pause")) { TogglePause(); } } private void DelayPlayerSpawn() { //await Task.Delay(500); if (SpawnMarkers.Any()) { SpawnPlayer(); } else { GD.Print("No player spawn marker in scene."); return; } if (_player != null && _hud != null) { _player.HealthChanged += (newHealth, maxHealth) => _hud.UpdateHealth(newHealth, maxHealth); _player.ShieldChanged += (newShield, maxShield) => _hud.UpdateShield(newShield, maxShield); _player.InteractableAreaEntered += (interactable) => _hud.UpdateInteractable(interactable); _player.Death += () => { // Show Game Over _hud.ShowGameOver(); }; } else { GD.Print("No player and hud in scene"); return; } if (_inventoryManager is not null) { _inventoryManager.ItemAdded += (LootItem item, int amount) => { if (item.Item == ItemTypes.Weapon) { SpawnPlayerWeapon(item); } }; _inventoryManager.WeaponEquip += _player.EquipWeapon; } SpawnWeapons(); } public void SpawnPlayer() { if (_player != null) return; //_player = this.CreateChild(PlayerTemplate, PlayerSpawnMarker.Position ); _player = PlayerTemplate.Instantiate(); this.CallDeferred("add_child", _player); _player.Transform = this.GlobalTransform; _player.GlobalPosition = GetStartPosition(); //_player.GlobalPosition = PlayerSpawnMarker.Position; CameraTargetPlayer(); // // if (_cameraTarget != null) // { // _cameraTarget.Reparent(_player, true); // _cameraTarget.GlobalPosition = _player.Position; // } } private Vector2 GetStartPosition() { if (MapStartData != null) { if (SpawnMarkers.TryGetValue(MapStartData.EggIndex, out var spawnMarker)) { var marker = GetNode(spawnMarker); return marker.Position; // Why position and not globalposition? I have no idea } } var m = GetNode(SpawnMarkers.First().Value); return m.GlobalPosition; } public void CameraTargetPlayer() { if (_player is null) return; CameraTargetObject(_player); } public void CameraTargetObject(Node2D target, Vector2? offset = null) { if (_cameraTarget is null) return; _cameraTarget.Reparent(target, true); _cameraTarget.GlobalPosition = target.GlobalPosition; if (offset.HasValue) { _cameraTarget.Position += offset.Value; } } private void SpawnWeapons() { if (!StartingEquipment.Any()) { GD.Print("No items to spawn on Player"); return; } foreach (var startingItem in StartingEquipment) { // Now automatically taken care of by the event // switch (startingItem.Item) // { // case ItemTypes.Weapon: // SpawnPlayerWeapon(startingItem); // // //_player.EquippedWeapon ??= weapon; // break; // } _inventoryManager.AddItem(startingItem); } } private void SpawnPlayerWeapon(LootItem startingItem) { if (WeaponTemplate == null) { GD.Print("Could not spawn weapon because template is null"); return; } var weapon = _player.CreateChild(WeaponTemplate); weapon.WeaponData = startingItem.WeaponData; _player.AddWeapon(weapon); if (_player.EquippedWeapon == null) { _player.EquipWeapon(weapon); } } private void SpawnBulletsContainer() { _bulletsContainer = new Node2D(); _bulletsContainer.Name = "BulletsContainer"; _bulletsContainer.ProcessMode = ProcessModeEnum.Pausable; AddChild(_bulletsContainer); } public void TogglePause() { if (GameState == GameState.Paused) { Unpause(); } else if (GameState == GameState.Playing) { Pause(); } } public void Pause() { if (GameState == GameState.Playing) { ChangeState(GameState.Paused); } } public void Unpause() { if (GameState == GameState.Paused) { ChangeState(GameState.Playing); } } public GameState ToggleControlMode() { if (GameState is GameState.Playing) { ChangeState(GameState.Controlling); } else if (GameState is GameState.Controlling) { ChangeState(GameState.Playing); } return GameState; } public void ChangeState(GameState state) { if (state == GameState) return; GameState = state; EmitSignal(nameof(GameStateChange), (int)GameState); GD.Print($"Game state changed to {state}"); switch (state) { case GameState.Menu: GetTree().SetPause(false); break; case GameState.Paused: case GameState.Dialogue: GetTree().SetPause(true); break; case GameState.Playing: GetTree().SetPause(false); break; case GameState.Controlling: GetTree().SetPause(false); break; } } public void ClearBullets() { if (_bulletsContainer is null) return; foreach (var node in _bulletsContainer.GetChildren()) { node.QueueFree(); } } } public enum GameState { Menu, Paused, Playing, Dialogue, Controlling }