From d6912c67918d30f1fe18f62772d0aeb9ae439e9c Mon Sep 17 00:00:00 2001 From: Maxwell Edwards <93385879+MaxEdwards20@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:11:09 -0600 Subject: [PATCH] Mouse plumbing (#29) * Fixes crash * Adds mouse plumbing * Adds menu * Adds todos and defaults to using the keyboard --- src/Client/ClientMain.cs | 6 ++-- src/Client/GameModel.cs | 9 ++++-- src/Client/Menu/ControlSettingsView.cs | 7 +++-- src/Client/Systems/KeyboardInput.cs | 37 ++++++++--------------- src/Client/Systems/MouseInput.cs | 23 ++++++++++++-- src/Server/MessageQueueServer.cs | 2 +- src/Shared/Components/Controls.cs | 8 ++--- src/Shared/Systems/ControlsPersistence.cs | 7 ++--- 8 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/Client/ClientMain.cs b/src/Client/ClientMain.cs index 306579b..88b6729 100644 --- a/src/Client/ClientMain.cs +++ b/src/Client/ClientMain.cs @@ -26,7 +26,7 @@ public class ClientMain : Game private Texture2D m_background; private GameModel m_gameModel; private Controls m_controls; - private SettingsPersistence m_settingsPersistence; + private ControlsPersistence _mControlsPersistence; public ClientMain() { @@ -36,7 +36,7 @@ public ClientMain() IsMouseVisible = true; m_gameModel = new GameModel(); m_controls = new Controls(); - m_settingsPersistence = new SettingsPersistence(); + _mControlsPersistence = new ControlsPersistence(); } @@ -49,7 +49,7 @@ protected override void Initialize() // Load the controls // We pass in our own controls so we always have them as a default if they were not saved - m_settingsPersistence.LoadControls(m_controls); + _mControlsPersistence.LoadControls(m_controls); // Create all the game states here m_states = new Dictionary diff --git a/src/Client/GameModel.cs b/src/Client/GameModel.cs index 5a767d9..6745880 100644 --- a/src/Client/GameModel.cs +++ b/src/Client/GameModel.cs @@ -19,6 +19,7 @@ public class GameModel private Systems.Network m_systemNetwork; private Systems.Camera m_systemCamera; private Systems.KeyboardInput m_systemKeyboardInput; + private Systems.MouseInput m_systemMouseInput; private Systems.Interpolation m_systemInterpolation; private Systems.Renderer m_systemRenderer; private Controls m_controls; @@ -31,6 +32,7 @@ public void update(TimeSpan elapsedTime) { m_systemNetwork.update(elapsedTime, MessageQueueClient.instance.getMessages()); m_systemKeyboardInput.update(elapsedTime); + m_systemMouseInput.update(elapsedTime); m_systemInterpolation.update(elapsedTime); m_systemCamera.update(elapsedTime); } @@ -64,6 +66,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic m_systemKeyboardInput = new Systems.KeyboardInput(new List> { }, m_controls); + m_systemMouseInput = new Systems.MouseInput(m_controls); return true; } @@ -147,9 +150,10 @@ private void addEntity(Entity entity) { return; } - // TODO: Update the systems we use here + // NOTE: Update the systems we use here m_entities[entity.id] = entity; m_systemKeyboardInput.add(entity); + m_systemMouseInput.add(entity); m_systemRenderer.add(entity); m_systemNetwork.add(entity); m_systemInterpolation.add(entity); @@ -162,9 +166,10 @@ private void addEntity(Entity entity) /// private void removeEntity(uint id) { - // TODO: Update the systems we use here + // NOTE: Update the systems we use here m_entities.Remove(id); m_systemKeyboardInput.remove(id); + m_systemMouseInput.remove(id); m_systemNetwork.remove(id); m_systemRenderer.remove(id); m_systemInterpolation.remove(id); diff --git a/src/Client/Menu/ControlSettingsView.cs b/src/Client/Menu/ControlSettingsView.cs index b7e0170..5270fbf 100644 --- a/src/Client/Menu/ControlSettingsView.cs +++ b/src/Client/Menu/ControlSettingsView.cs @@ -21,7 +21,7 @@ public class ControlSettingsView : GameStateView private ControlStateEnum updatingKey = ControlStateEnum.None; private bool isUpdatingKey = false; private Controls m_controls; - private SettingsPersistence m_settingsPersistence = new SettingsPersistence(); + private ControlsPersistence _mControlsPersistence = new ControlsPersistence(); public enum ControlStateEnum { @@ -81,12 +81,15 @@ public override void update(GameTime gameTime) break; } // Now we persist any changes - m_settingsPersistence.SaveControls(m_controls); + _mControlsPersistence.SaveControls(m_controls); } } } } + // TODO: Add a pill toggle to change whether we are in keyboard or mouse mode + // TODO: Add a menu mouse input system to handle the mouse input + } public override void render(GameTime gameTime) { diff --git a/src/Client/Systems/KeyboardInput.cs b/src/Client/Systems/KeyboardInput.cs index 995a55d..f44c2d7 100644 --- a/src/Client/Systems/KeyboardInput.cs +++ b/src/Client/Systems/KeyboardInput.cs @@ -20,6 +20,10 @@ public KeyboardInput(List> mapping, Co public override void update(TimeSpan elapsedTime) { + if (!m_controls.UseKeyboard) + { + return; + } var keyboardState = Keyboard.GetState(); m_keysPressed.Clear(); @@ -32,18 +36,21 @@ public override void update(TimeSpan elapsedTime) foreach (var entity in m_entities) { var inputs = new List(); - inputs.Add(Input.Type.SnakeUp); if (keyPressed(m_controls.SnakeLeft.key)) { inputs.Add(Input.Type.RotateLeft); + Utility.rotateLeft(entity.Value, elapsedTime, m_entities); + } if (keyPressed(m_controls.SnakeRight.key)) { inputs.Add(Input.Type.RotateRight); + Utility.rotateRight(entity.Value, elapsedTime, m_entities); + } - - // Now we handle the input locally before sending the message to the server - performInputAction(entity.Value, elapsedTime, inputs); + // Always add thrust + inputs.Add(Input.Type.SnakeUp); + Utility.thrust(entity.Value, elapsedTime, m_entities); if (inputs.Count > 0) { @@ -55,27 +62,7 @@ public override void update(TimeSpan elapsedTime) m_statePrevious = keyboardState; } - private void performInputAction(Entity entity, TimeSpan elapsedTime, List inputs) - { - for (int i = 0; i < inputs.Count; i++) - { - var inputType = inputs[i]; - // Perform action based on inputType - // NOTE: Could do an optimization here where we have all of the combinations of possible inputs - switch (inputType) - { - case Input.Type.SnakeUp: - Utility.thrust(entity, elapsedTime, m_entities); - break; - case Input.Type.RotateLeft: - Utility.rotateLeft(entity, elapsedTime, m_entities); - break; - case Input.Type.RotateRight: - Utility.rotateRight(entity, elapsedTime, m_entities); - break; - } - } - } + public override bool add(Entity entity) { diff --git a/src/Client/Systems/MouseInput.cs b/src/Client/Systems/MouseInput.cs index 51b0980..114c59e 100644 --- a/src/Client/Systems/MouseInput.cs +++ b/src/Client/Systems/MouseInput.cs @@ -19,6 +19,11 @@ public MouseInput(Controls controls) : base(typeof(Shared.Components.Input)) public override void update(TimeSpan elapsedTime) { + if (m_controls.UseKeyboard) + { + return; + } + var mouseState = Mouse.GetState(); var currentPosition = new Vector2(mouseState.X, mouseState.Y); @@ -29,18 +34,30 @@ public override void update(TimeSpan elapsedTime) try { var positionComponent = entity.get(); - var wormHeadPosition = positionComponent.position; var direction = currentPosition - wormHeadPosition; + var inputs = new List(); // Check mouse movement relative to the worm head's position to decide on turn direction if (direction.X < 0 && currentPosition != previousMouseState.Position.ToVector2()) // Mouse moved left { HandleTurnLeft(entity, elapsedTime); + inputs.Add(Input.Type.RotateLeft); } else if (direction.X > 0 && currentPosition != previousMouseState.Position.ToVector2()) // Mouse moved right { HandleTurnRight(entity, elapsedTime); + inputs.Add(Input.Type.RotateLeft); + } + + // Always add thrust + inputs.Add(Input.Type.SnakeUp); + Utility.thrust(entity, elapsedTime, m_entities); + + if (inputs.Count > 0) + { + // Assuming you have a messaging system to handle input + MessageQueueClient.instance.sendMessageWithId(new Shared.Messages.Input(entityPair.Key, inputs, elapsedTime)); } } catch (KeyNotFoundException) @@ -54,12 +71,12 @@ public override void update(TimeSpan elapsedTime) private void HandleTurnLeft(Entity entity, TimeSpan elapsedTime) { - // Logic for left turn + Utility.rotateLeft(entity, elapsedTime, m_entities); } private void HandleTurnRight(Entity entity, TimeSpan elapsedTime) { - // Logic for right turn + Utility.rotateRight(entity, elapsedTime, m_entities); } } } diff --git a/src/Server/MessageQueueServer.cs b/src/Server/MessageQueueServer.cs index f925478..7c8b177 100644 --- a/src/Server/MessageQueueServer.cs +++ b/src/Server/MessageQueueServer.cs @@ -298,7 +298,7 @@ private void initializeReceiver() byte[] size = new byte[sizeof(int)]; List remove = new List(); - // TODO: This is a busy loop, would be nice to efficiently wait for an incoming message + // NOTE: This is a busy loop, would be nice to efficiently wait for an incoming message // from a client while (m_keepRunning) { diff --git a/src/Shared/Components/Controls.cs b/src/Shared/Components/Controls.cs index 6cd532f..0a877c3 100644 --- a/src/Shared/Components/Controls.cs +++ b/src/Shared/Components/Controls.cs @@ -13,16 +13,12 @@ namespace Shared.Components [DataContract(Name = "Controls")] public class Controls : Component { - [DataMember(Name = "SnakeUp")] - public Control SnakeUp = new Control(Keys.Up); [DataMember(Name = "SnakeLeft")] public Control SnakeLeft = new Control(Keys.Left); [DataMember(Name = "SnakeRight")] public Control SnakeRight = new Control(Keys.Right); - [DataMember(Name = "SnakeDown")] - public Control SnakeDown = new Control(Keys.Down); - [DataMember (Name = "SnakeBoost")] - public Control SnakeBoost = new Control(Keys.Space); + [DataMember (Name = "UseKeyboard")] + public bool UseKeyboard = true; } [DataContract(Name = "Control")] diff --git a/src/Shared/Systems/ControlsPersistence.cs b/src/Shared/Systems/ControlsPersistence.cs index 3e7b3b2..8876bab 100644 --- a/src/Shared/Systems/ControlsPersistence.cs +++ b/src/Shared/Systems/ControlsPersistence.cs @@ -6,7 +6,7 @@ namespace Shared.Systems; -public class SettingsPersistence: System +public class ControlsPersistence: System { // Now we want to make all of these control settings persist across game sessions. We will use the same serialization technique we used for the high scores. private bool saving = false; @@ -32,11 +32,10 @@ public void LoadControls(Controls controls) { var res = finalizeLoadControlsAsync(); res.Wait(); // we want to load the controls before letting the user start playing // All of them have a default value in case they were not saved - controls.SnakeUp = m_loadedState.SnakeUp == null? new Control(Keys.Up) : m_loadedState.SnakeUp; controls.SnakeLeft = m_loadedState.SnakeLeft == null? new Control(Keys.Left) : m_loadedState.SnakeLeft; controls.SnakeRight = m_loadedState.SnakeRight == null? new Control(Keys.Right) : m_loadedState.SnakeRight; - controls.SnakeDown = m_loadedState.SnakeDown == null ? new Control(Keys.Down) : m_loadedState.SnakeDown; - controls.SnakeBoost = m_loadedState.SnakeBoost == null ? new Control(Keys.Space): m_loadedState.SnakeBoost; + // controls.UseKeyboard = m_loadedState.UseKeyboard == null ? true: m_loadedState.UseKeyboard; // Real. + controls.UseKeyboard = true; // FOR TESTING. Allow us to switch keyboard on and off. } } private async Task finalizeSaveControlsAsync(Controls controls)