Initial Checkin of Code

This commit is contained in:
Mario Steele 2025-04-11 13:35:55 -05:00
parent 19b557ee9b
commit 0bee2ee47b
44 changed files with 7965 additions and 0 deletions

View file

@ -0,0 +1,69 @@
using Godot;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Characters;
[GlobalClass]
public partial class CharacterAnimation : AnimatedSprite2D
{
[ExportCategory("Nodes")]
[Export] public CharacterInput CharacterInput;
[Export] public CharacterMovement CharacterMovement;
[ExportCategory("Animation Vars")]
[Export] public ECharacterAnimation ECharacterAnimation = ECharacterAnimation.IdleDown;
public override void _Ready()
{
CharacterMovement.Animation += PlayAnimation;
Logger.Info("Loading player animation component ...");
}
public void PlayAnimation(string animationType)
{
ECharacterAnimation previousAnimation = ECharacterAnimation;
if (CharacterMovement.IsMoving()) return;
switch (animationType)
{
case "walk":
if (CharacterInput.Direction == Vector2.Up)
ECharacterAnimation = ECharacterAnimation.WalkUp;
else if (CharacterInput.Direction == Vector2.Left)
ECharacterAnimation = ECharacterAnimation.WalkLeft;
else if (CharacterInput.Direction == Vector2.Right)
ECharacterAnimation = ECharacterAnimation.WalkRight;
else if (CharacterInput.Direction == Vector2.Down)
ECharacterAnimation = ECharacterAnimation.WalkDown;
break;
case "turn":
if (CharacterInput.Direction == Vector2.Up)
ECharacterAnimation = ECharacterAnimation.TurnUp;
else if (CharacterInput.Direction == Vector2.Left)
ECharacterAnimation = ECharacterAnimation.TurnLeft;
else if (CharacterInput.Direction == Vector2.Right)
ECharacterAnimation = ECharacterAnimation.TurnRight;
else if (CharacterInput.Direction == Vector2.Down)
ECharacterAnimation = ECharacterAnimation.TurnDown;
break;
case "idle":
if (CharacterInput.Direction == Vector2.Up)
ECharacterAnimation = ECharacterAnimation.IdleUp;
else if (CharacterInput.Direction == Vector2.Left)
ECharacterAnimation = ECharacterAnimation.IdleLeft;
else if (CharacterInput.Direction == Vector2.Right)
ECharacterAnimation = ECharacterAnimation.IdleRight;
else if (CharacterInput.Direction == Vector2.Down)
ECharacterAnimation = ECharacterAnimation.IdleDown;
break;
}
if (previousAnimation != ECharacterAnimation)
{
Logger.Debug($"Playing animation {ECharacterAnimation}");
Play(ECharacterAnimation.ToString().ToSnakeCase());
}
}
}

View file

@ -0,0 +1 @@
uid://bfijr6flufatm

View file

@ -0,0 +1,18 @@
using Godot;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Characters;
[GlobalClass]
public abstract partial class CharacterInput : Node
{
[Signal]
public delegate void WalkEventHandler();
[Signal]
public delegate void TurnEventHandler();
[ExportCategory("Common Input")]
[Export] public Vector2 Direction = Vector2.Zero;
[Export] public Vector2 TargetPosition = Vector2.Zero;
}

View file

@ -0,0 +1 @@
uid://cwyvrfqhe4k74

View file

@ -0,0 +1,83 @@
using Godot;
using System;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Characters;
[GlobalClass]
public partial class CharacterMovement : Node
{
[Signal]
public delegate void AnimationEventHandler(string animationType);
[ExportCategory("Nodes")]
[Export] public CharacterBody2D Character;
[Export] public CharacterInput CharacterInput;
[ExportCategory("Movement")]
[Export] public Vector2 TargetPosition = Vector2.Zero;
[Export] public bool IsWalking = false;
public override void _Ready()
{
CharacterInput.Walk += StartWalking;
CharacterInput.Turn += Turn;
Logger.Info("Loading player movement component ...");
}
public override void _Process(double delta)
{
Walk(delta);
}
public bool IsMoving() => IsWalking;
public void StartWalking()
{
if (!IsMoving())
{
EmitSignal(SignalName.Animation, "walk");
TargetPosition = Character.Position + CharacterInput.Direction * Globals.Instance.GRID_SIZE;
Logger.Debug($"Moving from {Character.Position} to {TargetPosition}");
IsWalking = true;
}
}
public void Walk(double delta)
{
if (IsWalking)
{
Character.Position =
Character.Position.MoveToward(TargetPosition, (float)delta * Globals.Instance.GRID_SIZE * 4);
if (Character.Position.DistanceTo(TargetPosition) < 1f)
{
StopWalking();
}
}
else
{
EmitSignal(SignalName.Animation, "idle");
}
}
public void StopWalking()
{
IsWalking = false;
SnapPositionToGrid();
}
public void Turn()
{
EmitSignal(SignalName.Animation, "turn");
}
public void SnapPositionToGrid()
{
Character.Position = new Vector2(
Mathf.Round(Character.Position.X / Globals.Instance.GRID_SIZE) * Globals.Instance.GRID_SIZE,
Mathf.Round(Character.Position.Y / Globals.Instance.GRID_SIZE) * Globals.Instance.GRID_SIZE
);
}
}

View file

@ -0,0 +1 @@
uid://bytos0ecojls1

View file

@ -0,0 +1,15 @@
using Godot;
using PokemonLike.Library.Utilities;
namespace PokemonLike.Library.Characters;
[GlobalClass]
public partial class Player : CharacterBody2D
{
[Export] public StateMachine StateMachine;
public override void _Ready()
{
StateMachine.ChangeState(StateMachine.GetNode<State>("Roam"));
}
}

View file

@ -0,0 +1 @@
uid://b4thjem54fyfl

View file

@ -0,0 +1,17 @@
using Godot;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Characters;
[GlobalClass]
public partial class PlayerInput : CharacterInput
{
[ExportCategory("Player Input")]
[Export] public double HoldThreshold = 0.1f;
[Export] public double HoldTime = 0.0f;
public override void _Ready()
{
Logger.Info("Loading player input component ...");
}
}

View file

@ -0,0 +1 @@
uid://b70ubhqc16nw4

View file

@ -0,0 +1,63 @@
using Godot;
using PokemonLike.Library.Support;
using PokemonLike.Library.Utilities;
namespace PokemonLike.Library.Characters.States;
[GlobalClass]
public partial class PlayerRoamState : State
{
[ExportCategory("State Vars")]
[Export] public PlayerInput PlayerInput;
public override void _Process(double delta)
{
GetInputDirection();
GetInput(delta);
}
public void GetInputDirection()
{
if (Input.IsActionJustPressed("move_up"))
{
PlayerInput.Direction = Vector2.Up;
PlayerInput.TargetPosition = new Vector2(0, -Globals.Instance.GRID_SIZE);
}
else if (Input.IsActionJustPressed("move_down"))
{
PlayerInput.Direction = Vector2.Down;
PlayerInput.TargetPosition = new Vector2(0, Globals.Instance.GRID_SIZE);
}
else if (Input.IsActionJustPressed("move_left"))
{
PlayerInput.Direction = Vector2.Left;
PlayerInput.TargetPosition = new Vector2(-Globals.Instance.GRID_SIZE, 0);
}
else if (Input.IsActionJustPressed("move_right"))
{
PlayerInput.Direction = Vector2.Right;
PlayerInput.TargetPosition = new Vector2(Globals.Instance.GRID_SIZE, 0);
}
}
public void GetInput(double delta)
{
if (Modules.IsActionJustReleased())
{
if (PlayerInput.HoldTime > PlayerInput.HoldThreshold)
PlayerInput.EmitSignal(CharacterInput.SignalName.Walk);
else
PlayerInput.EmitSignal(CharacterInput.SignalName.Turn);
PlayerInput.HoldThreshold = 0.0f;
}
if (Modules.IsActionPressed())
{
PlayerInput.HoldTime += delta;
if (PlayerInput.HoldTime > PlayerInput.HoldThreshold)
PlayerInput.EmitSignal(CharacterInput.SignalName.Walk);
}
}
}

View file

@ -0,0 +1 @@
uid://c5nu12q4or8pw

26
Library/Support/Enums.cs Normal file
View file

@ -0,0 +1,26 @@
namespace PokemonLike.Library.Support;
public enum LogLevel
{
None,
Error,
Info,
Warn,
Debug,
}
public enum ECharacterAnimation
{
IdleDown,
IdleUp,
IdleLeft,
IdleRight,
TurnDown,
TurnUp,
TurnLeft,
TurnRight,
WalkDown,
WalkUp,
WalkLeft,
WalkRight,
}

View file

@ -0,0 +1 @@
uid://b0tdcpfs7kdnl

View file

@ -0,0 +1,18 @@
using Godot;
namespace PokemonLike.Library.Support;
public partial class Globals : Node
{
public static Globals Instance { get; private set; }
[ExportCategory("Gameplay")]
[Export] public int GRID_SIZE = 16;
public override void _Ready()
{
Instance = this;
Logger.Info("Loading Globals ... ");
}
}

View file

@ -0,0 +1 @@
uid://dwiq8oy8sm0o3

35
Library/Support/Logger.cs Normal file
View file

@ -0,0 +1,35 @@
using System;
using System.Diagnostics;
namespace PokemonLike.Library.Support;
public static class Logger
{
public static string ColorTable(LogLevel level) => level switch
{
LogLevel.None => "white",
LogLevel.Error => "firebrick",
LogLevel.Info => "white",
LogLevel.Warn => "gold",
LogLevel.Debug => "green",
};
public static LogLevel LogLevel { get; set; } = LogLevel.Debug;
public static void Log(LogLevel level, params object[] message)
{
if (level > LogLevel) return;
var timeStamp = $"[lb]{DateTime.Now:yyyy-MM-dd HH:mm:ss}[rb]";
var callingMethod = new StackTrace().GetFrame(2)?.GetMethod();
var lvl = $"{level}".ToUpper();
var clsName = callingMethod?.DeclaringType?.Name == null ? "UnknownClass" : callingMethod!.DeclaringType!.Name;
var mthdName = callingMethod?.Name == null ? "UnknownMethod" : callingMethod!.Name;
var msg = $"{timeStamp} [lb][color={ColorTable(level)}]{lvl}[/color][rb] [color=cyan][lb]{clsName}->{mthdName}[rb][/color] ";
Godot.GD.PrintRich([msg, ..message]);
}
public static void Info(params object[] message) => Log(LogLevel.Info, message);
public static void Warn(params object[] message) => Log(LogLevel.Warn, message);
public static void Debug(params object[] message) => Log(LogLevel.Debug, message);
public static void Error(params object[] message) => Log(LogLevel.Error, message);
}

View file

@ -0,0 +1 @@
uid://dhh1dnlsq1yfp

View file

@ -0,0 +1,28 @@
using Godot;
namespace PokemonLike.Library.Support;
public static class Modules
{
public static bool IsActionJustPressed() => (
Input.IsActionJustPressed("move_up") ||
Input.IsActionJustPressed("move_down") ||
Input.IsActionJustPressed("move_left") ||
Input.IsActionJustPressed("move_right")
);
public static bool IsActionPressed() => (
Input.IsActionPressed("move_up") ||
Input.IsActionPressed("move_down") ||
Input.IsActionPressed("move_left") ||
Input.IsActionPressed("move_right")
);
public static bool IsActionJustReleased() => (
Input.IsActionJustReleased("move_up") ||
Input.IsActionJustReleased("move_down") ||
Input.IsActionJustReleased("move_left") ||
Input.IsActionJustReleased("move_right")
);
}

View file

@ -0,0 +1 @@
uid://b4t7lcjfe10mc

View file

@ -0,0 +1,20 @@
using Godot;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Utilities;
[GlobalClass]
public abstract partial class State : Node
{
[Export] public Node StateOwner;
public virtual void EnterState()
{
Logger.Info($"Entering {GetType().Name} state ...");
}
public virtual void ExitState()
{
Logger.Info($"Exiting {GetType().Name} state ...");
}
}

View file

@ -0,0 +1 @@
uid://drebiluk2m8ft

View file

@ -0,0 +1,37 @@
using Godot;
using PokemonLike.Library.Support;
namespace PokemonLike.Library.Utilities;
[GlobalClass]
public partial class StateMachine : Node
{
[ExportCategory("State Machine Vars")]
[Export] public Node Customer;
[Export] public State CurrentState;
public override void _Ready()
{
Logger.Info("Loading state machine...");
foreach (Node child in GetChildren())
{
if (child is State state)
{
state.StateOwner = Customer;
state.SetProcess(false);
}
}
}
public string GetCurrentState() => CurrentState.Name.ToString();
public void ChangeState(State newState)
{
CurrentState?.ExitState();
CurrentState = newState;
CurrentState?.EnterState();
foreach (Node child in GetChildren())
if (child is State state)
state.SetProcess(state == CurrentState);
}
}

View file

@ -0,0 +1 @@
uid://dxo0eunwolubm