diff --git a/DaggerFramework/Source/InputAction.cs b/DaggerFramework/Source/InputAction.cs index 33c7aec..256e57a 100644 --- a/DaggerFramework/Source/InputAction.cs +++ b/DaggerFramework/Source/InputAction.cs @@ -4,6 +4,7 @@ namespace DaggerFramework { public abstract bool IsDown(InputHandler inputHandler); public abstract bool IsPressed(InputHandler inputHandler); + public abstract bool IsReleased(InputHandler inputHandler); } public class KeyInputAction : InputAction @@ -24,6 +25,12 @@ namespace DaggerFramework return inputHandler.KeyboardKeyJustPressed(_keyboardKey); } + public override bool IsReleased(InputHandler inputHandler) + { + return inputHandler.KeyboardKeyJustReleased(_keyboardKey); + } + + private KeyboardKey _keyboardKey; } } \ No newline at end of file diff --git a/DaggerFramework/Source/InputHandler.cs b/DaggerFramework/Source/InputHandler.cs index 9742282..a6740f2 100644 --- a/DaggerFramework/Source/InputHandler.cs +++ b/DaggerFramework/Source/InputHandler.cs @@ -1,4 +1,6 @@ +using System.Diagnostics.CodeAnalysis; using System.Numerics; +using DaggerFramework.Utils; namespace DaggerFramework { @@ -7,16 +9,20 @@ namespace DaggerFramework public InputHandler() { inputMappings = new Dictionary>(); + CreateDefaultMappings(); } public Action OnInput; public bool Handled { get => _handled; set => _handled = value; } public abstract bool IsKeyboardKeyDown(KeyboardKey key); public abstract bool KeyboardKeyJustPressed(KeyboardKey key); + public abstract bool KeyboardKeyJustReleased(KeyboardKey key); public abstract Vector2 GetInputDirection(KeyboardKey leftKey, KeyboardKey rightKey, KeyboardKey upKey, KeyboardKey downKey); + public abstract Vector2 GetInputDirection(string leftAction, string rightAction, string upAction, string downAction); public abstract int GetCharPressed(); public abstract bool IsActionDown(string action); - public abstract bool IsActionJustPressed(string action); + public abstract bool IsActionPressed(string action); + public abstract bool IsActionReleased(string action); public abstract bool IsMouseButtonDown(MouseButton button); public abstract float GetMouseWheelMovement(); @@ -33,8 +39,46 @@ namespace DaggerFramework inputMappings.Add(actionName, inputActions); } + private void CreateDefaultMappings() + { + AddInputMapping("up", new InputAction[] { + new KeyInputAction(KeyboardKey.W), + new KeyInputAction(KeyboardKey.Up), + }); + AddInputMapping("down", new InputAction[] { + new KeyInputAction(KeyboardKey.S), + new KeyInputAction(KeyboardKey.Down), + }); + AddInputMapping("left", new InputAction[] { + new KeyInputAction(KeyboardKey.A), + new KeyInputAction(KeyboardKey.Left), + }); + AddInputMapping("right", new InputAction[] { + new KeyInputAction(KeyboardKey.D), + new KeyInputAction(KeyboardKey.Right), + }); + } + + protected bool TryGetInputMappings(string forAction, [NotNullWhen(true)] out IEnumerable? inputActions) + { + var contains = inputMappings.ContainsKey(forAction); + inputActions = null; + + if (!contains) + { + _logger.Error($"The action \"{forAction}\" is not present in the input mappings!"); + return false; + } + + inputActions = inputMappings[forAction]; + + return true; + } + private bool _handled; protected Dictionary> inputMappings; + + private Logger _logger = new(nameof(InputHandler)); } public enum KeyboardKey diff --git a/DaggerFramework/Source/RaylibInputHandler.cs b/DaggerFramework/Source/RaylibInputHandler.cs index eea84b6..b14f284 100644 --- a/DaggerFramework/Source/RaylibInputHandler.cs +++ b/DaggerFramework/Source/RaylibInputHandler.cs @@ -26,6 +26,23 @@ namespace DaggerFramework return dir == Vector2.Zero ? Vector2.Zero : Vector2.Normalize(dir); } + public override Vector2 GetInputDirection(string leftAction, string rightAction, string upAction, string downAction) + { + Vector2 dir = Vector2.Zero; + + if (IsActionDown(leftAction)) + dir += new Vector2(-1, 0); + if (IsActionDown(rightAction)) + dir += new Vector2(1, 0); + if (IsActionDown(upAction)) + dir += new Vector2(0, -1); + if (IsActionDown(downAction)) + dir += new Vector2(0, 1); + + + return dir == Vector2.Zero ? Vector2.Zero : Vector2.Normalize(dir); + } + public override Vector2 GetMousePosition() { return Raylib.GetMousePosition(); @@ -43,18 +60,39 @@ namespace DaggerFramework public override bool IsActionDown(string action) { - // throw new NotImplementedException(); - // return inputMappings[action].IsPressed(); - foreach (InputAction inputAction in inputMappings[action]) - if (inputAction.IsDown(this)) return true; + IEnumerable? mappings; + + if (TryGetInputMappings(action, out mappings)) + { + foreach (InputAction inputAction in mappings) + if (inputAction.IsDown(this)) return true; + } return false; } - public override bool IsActionJustPressed(string action) + public override bool IsActionPressed(string action) { - foreach (InputAction inputAction in inputMappings[action]) - if (inputAction.IsPressed(this)) return true; + IEnumerable? mappings; + + if (TryGetInputMappings(action, out mappings)) + { + foreach (InputAction inputAction in mappings) + if (inputAction.IsPressed(this)) return true; + } + + return false; + } + + public override bool IsActionReleased(string action) + { + IEnumerable? mappings; + + if (TryGetInputMappings(action, out mappings)) + { + foreach (InputAction inputAction in mappings) + if (inputAction.IsReleased(this)) return true; + } return false; } @@ -77,6 +115,11 @@ namespace DaggerFramework return Raylib.IsKeyPressed(rayKey); } + public override bool KeyboardKeyJustReleased(KeyboardKey key) + { + return Raylib.IsKeyReleased((Raylib_cs.KeyboardKey)key); + } + public override void SetMousePosition(Vector2 position) { Raylib.SetMousePosition((int)position.X, (int)position.Y); diff --git a/DaggerFramework/Source/SceneGraph/Entities/CircleShape2d.cs b/DaggerFramework/Source/SceneGraph/Entities/CircleShape2d.cs index 4f071c4..b659552 100644 --- a/DaggerFramework/Source/SceneGraph/Entities/CircleShape2d.cs +++ b/DaggerFramework/Source/SceneGraph/Entities/CircleShape2d.cs @@ -12,7 +12,7 @@ namespace DaggerFramework.SceneGraph renderer.DrawCircle(_radius, _color); } - private float _radius; - private Color _color; + private float _radius = 16; + private Color _color = Color.White; } } \ No newline at end of file diff --git a/DaggerFramework/Source/SceneGraph/Entities/RectangleShape2d.cs b/DaggerFramework/Source/SceneGraph/Entities/RectangleShape2d.cs new file mode 100644 index 0000000..4a8a07d --- /dev/null +++ b/DaggerFramework/Source/SceneGraph/Entities/RectangleShape2d.cs @@ -0,0 +1,14 @@ +using System.Numerics; +using DaggerFramework.Rendering; + +namespace DaggerFramework.SceneGraph; + +public class RectangleShape2d : Drawable2d +{ + public Vector2 Size { get; set; } = Vector2.One * 32; + public Color Color { get; set; } = Color.White; + public override void OnDraw(Renderer renderer) + { + renderer.DrawRectangle(Size, Color); + } +} \ No newline at end of file diff --git a/DaggerFramework/Source/SceneGraph/Entities/Text2d.cs b/DaggerFramework/Source/SceneGraph/Entities/Text2d.cs index 13443e1..79ec8de 100644 --- a/DaggerFramework/Source/SceneGraph/Entities/Text2d.cs +++ b/DaggerFramework/Source/SceneGraph/Entities/Text2d.cs @@ -5,17 +5,41 @@ namespace DaggerFramework.SceneGraph { public class Text2d : Drawable2d { - public string Contents { get => _contents; set => _contents = value; } + public string Text { get => _text; set => _text = value; } public int FontSize { get => _fontSize; set => _fontSize = value; } public Color FontColor { get => _fontColor; set => _fontColor = value; } + public Font Font + { + get => _font; set + { + _isDirty = true; + _font = value; + } + } public override void OnDraw(Renderer renderer) { - renderer.DrawDebugText(_contents, _fontSize, _fontColor); + if (_isDirty) + { + _fontHandle = renderer.LoadFont(_font); + _isDirty = false; + } + + if (_font == null) + { + renderer.DrawDebugText(_text, _fontSize, _fontColor); + } + else + { + renderer.DrawText(_fontHandle, _text, _fontSize, _fontColor); + } } - private string _contents = string.Empty; + private string _text = string.Empty; private int _fontSize = 16; private Color _fontColor = Color.White; + private Font _font; + private int _fontHandle; + private bool _isDirty; } } \ No newline at end of file diff --git a/DaggerFramework/Source/SceneGraph/Layer.cs b/DaggerFramework/Source/SceneGraph/Layer.cs index 5ef5870..6743e6b 100644 --- a/DaggerFramework/Source/SceneGraph/Layer.cs +++ b/DaggerFramework/Source/SceneGraph/Layer.cs @@ -1,3 +1,4 @@ +using DaggerFramework.Resources; using DaggerFramework.Rendering; namespace DaggerFramework.SceneGraph @@ -6,6 +7,7 @@ namespace DaggerFramework.SceneGraph { public Scene Scene { get; set; } public InputHandler Input { get; set; } + public ResourceManager ResourceManager => Scene.ResourceManager; public void Draw(Renderer renderer) => OnDraw(renderer); diff --git a/DaggerFramework/Source/SceneGraph/Scene.cs b/DaggerFramework/Source/SceneGraph/Scene.cs index c14b240..9399b09 100644 --- a/DaggerFramework/Source/SceneGraph/Scene.cs +++ b/DaggerFramework/Source/SceneGraph/Scene.cs @@ -1,7 +1,7 @@ -using System.Drawing; using System.Numerics; using DaggerFramework.Audio; using DaggerFramework.Rendering; +using DaggerFramework.Resources; namespace DaggerFramework.SceneGraph @@ -11,14 +11,17 @@ namespace DaggerFramework.SceneGraph public Renderer Renderer { get => _renderer; set => _renderer = value; } public InputHandler Input { get => _input; set => _input = value; } public AudioBackend Audio => _audioBackend; + public ResourceManager ResourceManager => _resourceManager; public double DeltaTime => Renderer.GetFrameTime(); - public Scene(Renderer renderer, InputHandler input, AudioBackend audioBackend) + public Scene(Renderer renderer, InputHandler input, AudioBackend audioBackend, ResourceManager resourceManager) { _renderer = renderer; _input = input; _audioBackend = audioBackend; + _resourceManager = resourceManager; + _layers = new Dictionary(); } @@ -43,6 +46,7 @@ namespace DaggerFramework.SceneGraph { layer.Value.Update(DeltaTime); } + Draw(); } @@ -58,10 +62,12 @@ namespace DaggerFramework.SceneGraph { Renderer.BeginFrame(); Renderer.ClearBackground(Color.Black); + foreach (var layer in _layers.Values) { layer.Draw(_renderer); } + Renderer.EndFrame(); Audio.Update(); @@ -78,5 +84,8 @@ namespace DaggerFramework.SceneGraph private Renderer _renderer; private AudioBackend _audioBackend; private InputHandler _input; + private ResourceManager _resourceManager; + + private bool _inputDirty; } } \ No newline at end of file diff --git a/DaggerFramework/Source/Utils/Logger.cs b/DaggerFramework/Source/Utils/Logger.cs index 74ee165..57b7c91 100644 --- a/DaggerFramework/Source/Utils/Logger.cs +++ b/DaggerFramework/Source/Utils/Logger.cs @@ -7,11 +7,18 @@ namespace DaggerFramework.Utils { _className = className; } + + public void Echo(object what) + { + LogConsole((string)what, LogType.Echo); + OnLog?.Invoke((string)what, LogType.Echo); + } + public void Info(object what) { LogType logType = LogType.Info; string message = $"({DateFormat}) [{logType.ToString().ToUpper()}/{_className}] {what}"; - LogConsole(message); + LogConsole(message, logType); OnLog?.Invoke(message, logType); } @@ -19,7 +26,7 @@ namespace DaggerFramework.Utils { LogType logType = LogType.Warn; string message = $"({DateFormat}) [{logType.ToString().ToUpper()}/{_className}] {what}"; - LogConsole(message); + LogConsole(message, logType); OnLog?.Invoke(message, logType); } @@ -27,19 +34,47 @@ namespace DaggerFramework.Utils { LogType logType = LogType.Error; string message = $"({DateFormat}) [{logType.ToString().ToUpper()}/{_className}] {what}"; - LogConsole(message); + LogConsole(message, logType); OnLog?.Invoke(message, logType); } private static string DateFormat => $"{DateTime.Now:t}"; - private static void LogConsole(string what) => Console.WriteLine(what); + private static void LogConsole(string what, LogType logType) + { + Console.ForegroundColor = GetConsoleColorForLog(logType); + Console.WriteLine(what); + Console.ForegroundColor = ConsoleColor.White; + } + + private static ConsoleColor GetConsoleColorForLog(LogType logType) + { + ConsoleColor color = ConsoleColor.White; + + switch (logType) + { + case LogType.Info: + color = ConsoleColor.Cyan; + break; + + case LogType.Warn: + color = ConsoleColor.Yellow; + break; + case LogType.Error: + color = ConsoleColor.Red; + break; + } + + return color; + } + private readonly string _className; } public enum LogType { + Echo, Info, Warn, Error diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index da9eb3e..8472cad 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -4,6 +4,7 @@ using DaggerFramework; using DaggerFramework.Rendering; using DaggerFramework.Audio; using DaggerFramework.Resources; +using DaggerFramework.SceneGraph; public class TestGame : Game @@ -20,56 +21,17 @@ public class TestGame : Game { Title = "Test Game", Size = new Vector2(1280, 720) - }, RendererSettings.Default); - _renderer.SetTargetFps(60); + }, new RendererSettings() + { + UseVSync = false + }); _audioBackend.Initialize(); - } - protected override void LoadResources() - { - if (_resourceManager.TryLoad("my_sound", "sounds/test_sound.ogg")) - { - _resourceManager.TryGetResource("my_sound", out _testSound); - } + _scene = new Scene(_renderer, _inputHandler, _audioBackend, _resourceManager); - if (_resourceManager.TryLoad("inter_regular", "fonts/Inter-Regular.ttf")) - { - _resourceManager.TryGetResource("inter_regular", out _font); - } - } - - protected override void Ready() - { - // _audioBackend.AddBusEffect(new AudioEffectReverb()); - _inputHandler.AddInputMapping("play", new InputAction[] { new KeyInputAction(KeyboardKey.Spacebar) }); - _fontHandle = _renderer.LoadFont(_font); - } - - protected override void Run() - { - while (_renderer.ShouldRun) - { - _renderer.BeginFrame(); - _renderer.ClearBackground(Color.Black); - - if (_inputHandler.IsActionJustPressed("play")) - { - var instance = _audioBackend.CreateInstance(_testSound) - .PitchVariation(min: 0.9f, max: 1.2f) - .VolumeVariation(min: 0.90f, max: 1.0f); - instance.Play(); - } - - _audioBackend.Update(); - - _renderer.SetTransform(new Vector2(640, 480)); - _renderer.DrawCircle(16f, Color.Chocolate); - - _renderer.DrawText(_fontHandle, "Hello World!", 24, Color.White); - - _renderer.EndFrame(); - } + _uiLayer = new UiLayer(); + _worldLayer = new EntityLayer(); } public override void Shutdown() @@ -78,6 +40,60 @@ public class TestGame : Game _audioBackend.Shutdown(); } + protected override void LoadResources() + { + if (_resourceManager.TryLoad("my_sound", "sounds/test_sound.ogg")) + { + _resourceManager.TryGetResource("my_sound", out _testSound); + } + + if (_resourceManager.TryLoad("inter_regular", "fonts/Inter-Regular.ttf")) + { + _resourceManager.TryGetResource("inter_regular", out _font); + } + } + + protected override void Ready() + { + _inputHandler.AddInputMapping("play", new InputAction[] { new KeyInputAction(KeyboardKey.Spacebar) }); + _inputHandler.AddInputMapping("sprint", new InputAction[] { new KeyInputAction(KeyboardKey.LeftShift) }); + + _fontHandle = _renderer.LoadFont(_font); + + _scene.AddLayer("World", _worldLayer); + _scene.AddLayer("UI", _uiLayer); + _worldLayer.AddEntity(new TestPlayer()); + + _scene.Start(); + } + + protected override void Run() + { + while (!_scene.ShouldStop()) + { + // _renderer.BeginFrame(); + // _renderer.ClearBackground(Color.Black); + + // if (_inputHandler.IsActionJustPressed("play")) + // { + // var instance = _audioBackend.CreateInstance(_testSound) + // .PitchVariation(min: 0.9f, max: 1.2f) + // .VolumeVariation(min: 0.90f, max: 1.0f); + // instance.Play(); + // } + + // _audioBackend.Update(); + + // _renderer.SetTransform(new Vector2(32, 32)); + // _renderer.DrawCircle(16f, Color.Chocolate); + + // _renderer.DrawText(_fontHandle, $"{(int)(1 / _renderer.GetFrameTime())} FPS", 20, Color.White); + + // _renderer.EndFrame(); + _scene.Update(); + } + } + private Renderer _renderer; private ResourceManager _resourceManager = new(); private Sound? _testSound; @@ -85,4 +101,8 @@ public class TestGame : Game private int _fontHandle; private FmodAudioBackend _audioBackend; private InputHandler _inputHandler; + private Scene _scene; + + private UiLayer _uiLayer; + private EntityLayer _worldLayer; } \ No newline at end of file diff --git a/TestGame/TestPlayer.cs b/TestGame/TestPlayer.cs new file mode 100644 index 0000000..df0186c --- /dev/null +++ b/TestGame/TestPlayer.cs @@ -0,0 +1,25 @@ +using DaggerFramework; +using DaggerFramework.SceneGraph; +using DaggerFramework.Utils; + +public class TestPlayer : RectangleShape2d +{ + protected override void OnStart() + { + base.OnStart(); + Color = Color.Cyan; + } + + protected override void OnUpdate(double dt) + { + base.OnUpdate(dt); + + var sprinting = Input.IsActionDown("sprint"); + _speed = sprinting ? 400f : 200f; + + var velocity = Input.GetInputDirection("left", "right", "up", "down") * _speed; + Position += velocity * (float)dt; + } + + private float _speed = 200f; +} \ No newline at end of file diff --git a/TestGame/UiLayer.cs b/TestGame/UiLayer.cs index 4c1cf8f..2f162b2 100644 --- a/TestGame/UiLayer.cs +++ b/TestGame/UiLayer.cs @@ -1,23 +1,41 @@ using System.Numerics; - using DaggerFramework; -using DaggerFramework.Rendering; using DaggerFramework.SceneGraph; -public class UiLayer : Layer +public class UiLayer : EntityLayer { + protected override void OnStart() + { + base.OnStart(); + + GetResources(); + CreateAndAddEntities(); + } + protected override void OnUpdate(double dt) { base.OnUpdate(dt); - _time += dt; - } - protected override void OnDraw(Renderer renderer) - { - renderer.SetTransform(Vector2.Zero); - renderer.DrawRectangle(new Vector2(720 / 2, 1280), Color.Green); - renderer.SetTransform(new Vector2(720 / 4 - 24, 64)); - renderer.DrawDebugText("UI :)", 24, Color.White); + + _fpsText.Text = $"{MathF.Round(1 / (float)dt)} FPS"; } - private double _time; + private void CreateAndAddEntities() + { + _fpsText = new Text2d() + { + Font = _defaultFont, + Position = Vector2.One * 16, + FontSize = 20 + }; + + AddEntity(_fpsText); + } + + private void GetResources() + { + ResourceManager.TryGetResource("inter_regular", out _defaultFont); + } + + private Text2d _fpsText; + private Font _defaultFont; } \ No newline at end of file