cirnogodot/Scripts/PlayerMovement.cs
2025-02-11 13:47:31 +01:00

439 lines
9.1 KiB
C#

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;
public Weapon EquippedWeapon { get; set; }
public Array<Weapon> EquippedWeapons { get; set; } = new Array<Weapon>();
public int CurrentWeaponIndex { get; set; } = 0;
private float _currentHealth = 0f;
private bool _isDestroyed = false;
private GameManager _gameManager;
private InventoryManager _inventoryManager;
[Export] public Sprite2D HitboxSprite { get; set; }
private bool _isStrafing { get; set; }
private bool _canMove = true;
[Signal]
public delegate void HealthChangedEventHandler(float newHealth, float MaxHealth);
[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);
}
}
}
//private InventoryManager _inventoryManager;
public override void _Ready()
{
CurrentHealth = MaxHealth;
_animatedSprite = GetNode<AnimatedSprite2D>("./Smoothing2D/AnimatedSprite2D");
_crosshair = GetNode<Sprite2D>("./Smoothing2D/Crosshair");
//_inventoryManager = GetNode<InventoryManager>("/root/GameScene/InventoryManager");
_movementDirection = Vector2.Zero;
_facingDirection = Vector2.Zero;
_rightStickInput = Vector2.Zero;
_isStrafing = false;
_gameManager = this.GetGameManager(); //GetNode<GameManager>("/root/GameScene");
_inventoryManager = this.GetInventoryManager();
_gameManager.GameStateChange += GameManagerOnGameStateChange;
if (SelectorScene != null)
{
_selector = this.CreateSibling<Selector>(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;
}
}
/// <summary>
/// Requests disable movement
/// </summary>
/// <param name="disable">true disables false enables</param>
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 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<Bullet>();
// 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();
//FindInteractable();
}
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)
{
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)
{
GD.Print("Received damage manually");
this.Hit(bullet.Damage);
bullet.QueueFree();
}
}
}