using Godot; using System; using System.Diagnostics; using System.Linq; using Cirno.Scripts; using Cirno.Scripts.Resources; using Godot.Collections; public partial class PlayerMovement : CharacterBody2D, IDestructible { [Export] public int Speed { get; set; } = 400; [Export] public int StrafeSpeed { get; set; } = 200; public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed; [Export] public float CrosshairDistance { get; set; } = 10f; [Export] public PackedScene SelectorScene { get; set; } [Export] public string GameOverScene { get; set; } private Selector _selector; //private Interactable _lastInteractable; [Export] public Marker2D Muzzle { get; set; } private AnimatedSprite2D _animatedSprite; private Vector2 _movementDirection { get; set; } private Vector2 _facingDirection { get; set; } private Vector2 _rightStickInput { get; set; } private Sprite2D _crosshair; [Export] public float MaxHealth = 32f; [Export] public float MaxShield = 32f; public Weapon EquippedWeapon { get; set; } public Array EquippedWeapons { get; set; } = new Array(); public int CurrentWeaponIndex { get; set; } = 0; private float _currentHealth = 0f; private float _currentShield = 0f; private bool _isDestroyed = false; private GameManager _gameManager; private InventoryManager _inventoryManager; [Export] public Sprite2D HitboxSprite { get; set; } [Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.Player; private bool _isStrafing { get; set; } private bool _canMove = true; [Signal] public delegate void HealthChangedEventHandler(float newHealth, float MaxHealth); [Signal] public delegate void ShieldChangedEventHandler(float newShield, float maxShield); [Signal] public delegate void InteractableAreaEnteredEventHandler(Interactable interactable); [Signal] public delegate void InteractableAreaExitedEventHandler(Interactable interactable); public float CurrentHealth { get => _currentHealth; set { if (_currentHealth != value) { _currentHealth = value; EmitSignal(nameof(HealthChanged), _currentHealth, MaxHealth); } } } public float CurrentShield { get => _currentShield; set { if (_currentShield != value) { _currentShield = value; EmitSignal(nameof(ShieldChanged), _currentShield, MaxShield); } } } //private InventoryManager _inventoryManager; public override void _Ready() { CurrentHealth = MaxHealth; CurrentShield = MaxShield; _animatedSprite = GetNode("./Smoothing2D/AnimatedSprite2D"); _crosshair = GetNode("./Smoothing2D/Crosshair"); //_inventoryManager = GetNode("/root/GameScene/InventoryManager"); _movementDirection = Vector2.Zero; _facingDirection = Vector2.Zero; _rightStickInput = Vector2.Zero; _isStrafing = false; _gameManager = this.GetGameManager(); //GetNode("/root/GameScene"); _inventoryManager = this.GetInventoryManager(); _gameManager.GameStateChange += GameManagerOnGameStateChange; if (SelectorScene != null) { _selector = this.CreateSibling(SelectorScene, this.GlobalPosition); _selector.Visible = false; } } private void GameManagerOnGameStateChange(GameState state) { switch (state) { case GameState.Menu: break; case GameState.Paused: _canMove = false; break; case GameState.Playing: _canMove = true; break; case GameState.Dialogue: _canMove = false; break; } } /// /// Requests disable movement /// /// true disables false enables public void RequestMovementDisable(bool disable) { if (disable) { _canMove = false; } else { _canMove = true; } } /*public override _Process(float _delta) { if (Input.IsActionPressed("ui_right")) { _animatedSprite.Play("run"); } else { _animatedSprite.Stop(); } }*/ // public void ItemAdded(LootItem item, int amount) // { // switch (item.Item) // { // case ItemTypes.Weapon: // AddWeapon(item.WeaponData); // break; // } // } public void AddWeapon(Weapon weapon) { EquippedWeapons.Add(weapon); } public void EquipWeapon(Weapon weapon) { EquippedWeapon = weapon; CurrentWeaponIndex = EquippedWeapons.IndexOf(weapon); } public void NextWeapon() { CurrentWeaponIndex += 1; if (CurrentWeaponIndex > EquippedWeapons.Count - 1) { CurrentWeaponIndex = EquippedWeapons.Count - 1; } EquipWeapon(EquippedWeapons[CurrentWeaponIndex]); } public void PreviousWeapon() { CurrentWeaponIndex -= 1; if (CurrentWeaponIndex < 0) { CurrentWeaponIndex = 0; } EquipWeapon(EquippedWeapons[CurrentWeaponIndex]); } public override void _Process(double delta) { SetAnimation(); if (!_canMove) return; HandleShoot(); FindInteractable(); if (Input.IsActionJustPressed("next_weapon")) { NextWeapon(); } if (Input.IsActionJustPressed("previous_weapon")) { PreviousWeapon(); } } private void FindInteractable() { if (!Input.IsActionJustPressed("Use") || _selector.SelectedInteractable == null) return; if (!_selector.SelectedInteractable.CanActivate()) return; bool success = _selector.SelectedInteractable.Activate(); if (success) { // Deselect and scan for next _selector.SelectedInteractable = null; _selector.SelectNext(); } //var spaceState = GetWorld2D().DirectSpaceState; //var query = PhysicsRayQueryParameters2D.Create(Vector2.Zero, ) } private void HandleShoot() { if (EquippedWeapon == null) return; if (!Input.IsActionPressed("shoot")) return; EquippedWeapon.ShootDirection = this._facingDirection; EquippedWeapon.Shoot(); // //Debug.WriteLine("Shoot"); // var bullet = BulletScene.Instantiate(); // Owner.AddChild(bullet); // bullet.Transform = Muzzle.GlobalTransform; // bullet.Position = this.Position; // bullet.SetDirection(this._facingDirection); } private void SetAnimation() { if (Velocity.X == 0 && Velocity.Y == 0) { _animatedSprite.SpeedScale = 0; } else { _animatedSprite.SpeedScale = 1; } if (Velocity.X > 0) { _animatedSprite.Play("walk_right"); } else if (Velocity.X < 0) { _animatedSprite.Play("walk_left"); } else if (Velocity.Y > 0) { _animatedSprite.Play("walk_down"); } else if (Velocity.Y < 0) { _animatedSprite.Play("walk_up"); } } public Vector2 GetInput() { return Input.GetVector("left", "right", "up", "down"); } private Vector2 GetRightStickInput() { return new Vector2( Input.GetAxis("aim_left","aim_right"), Input.GetAxis("aim_up", "aim_down") ); } private Vector2 CalculateCrosshairPosition() { return _facingDirection * CrosshairDistance;// + this.Position; //var angle = Mathf.Atan2(this.Position.X, this.Position.Y); //var cPos = new Vector2(this.Position.X + CrosshairDistance * Godot.Mathf.Cos(angle), this.Position.Y + CrosshairDistance * Godot.Mathf.Sin(angle)); } // public override void _Draw() // { // if (_isStrafing) // { // HitboxSprite.Visible = true; // } // else // { // HitboxSprite.Visible = false; // } // base._Draw(); // } public override void _PhysicsProcess(double delta) { if (!_canMove) return; _movementDirection = GetInput(); _isStrafing = Input.IsActionPressed("strafe"); // Toggle visibility of the hitbox sprite based on strafing if (HitboxSprite != null) { HitboxSprite.Visible = _isStrafing; } _rightStickInput = GetRightStickInput(); // Update Facing Direction if (!_isStrafing) { if (_rightStickInput.Length() > 0.1f) // If the right stick is moved { _facingDirection = _rightStickInput.Normalized(); } else if (_movementDirection != Vector2.Zero) // Fall back to movement direction { _facingDirection = _movementDirection; } } // if (_movementDirection != Vector2.Zero) // { // _facingDirection = _movementDirection; // } Velocity = _movementDirection * (float)( MovementSpeed/* * delta*/); MoveAndSlide(); _crosshair.Position = CalculateCrosshairPosition(); } private void _on_interaction_controller_area_entered(Area2D area) { if (!_canMove) return; // Replace with function body. if (area.IsInGroup("Interactable") && area is Interactable interactable && interactable.CanActivate()) { Debug.WriteLine($"Interactable {area.Name} Entered"); EmitSignal(nameof(InteractableAreaEntered), interactable); if (_selector == null) return; //_selector.Position = interactable.Position; _selector.SelectedInteractable = interactable; //_selector.AddInteractable(interactable); //_selector.Visible = true; //_lastInteractable = interactable; } } private void _on_interaction_controller_area_exited(Area2D area) { if (!_canMove) return; if (area.IsInGroup("Interactable") && area is Interactable interactable) { Debug.WriteLine($"Interactable {area.Name} Exited"); EmitSignal(nameof(InteractableAreaExited), interactable); if (_selector == null) return; _selector.RemoveInteractable(interactable); } } private void Explode() { Debug.WriteLine("Ded"); //CreateParticles(); //CreateDebris(); if (GameOverScene != null) { GetTree().ChangeSceneToFile(GameOverScene); } else { QueueFree(); } } public void Hit(float damage, DamageType type = DamageType.Neutral) { if (!_canMove) return; GD.Print($"Player damaged for {damage}"); if (_isDestroyed) return; CurrentHealth -= damage; if (!(CurrentHealth <= 0)) return; _isDestroyed = true; Explode(); } public bool IsDestroyed() { return _isDestroyed; } private void _on_damage_hit_box_area_entered(Area2D area) { if (!_canMove) return; if (area is Bullet bullet && bullet.BulletOwner != BulletGroup) { this.Hit(bullet.Damage, bullet.DamageType); bullet.QueueFree(); } } }