diff --git a/src/Client/GameModel.cs b/src/Client/GameModel.cs index 0cc0550..880156b 100644 --- a/src/Client/GameModel.cs +++ b/src/Client/GameModel.cs @@ -1,177 +1,185 @@ -using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; -using Shared.Entities; + using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Client.Menu; -using Microsoft.Xna.Framework; + using Shared.Components; -using Shared.Components.Appearance; +using Shared.Entities; + +namespace Client; -namespace Client +public class GameModel { - public class GameModel + private ContentManager m_contentManager; + private Dictionary m_entities; + private Systems.Network m_systemNetwork; + private Systems.Camera m_systemCamera; + private Systems.KeyboardInput m_systemKeyboardInput; + private Systems.Interpolation m_systemInterpolation; + private Systems.Renderer m_systemRenderer; + private Controls m_controls; + private GraphicsDeviceManager m_graphics; + + /// + /// This is where everything performs its update. + /// + public void update(TimeSpan elapsedTime) { - private ContentManager m_contentManager; - private Dictionary m_entities; - private Systems.Network m_systemNetwork; - private Systems.KeyboardInput m_systemKeyboardInput; - private Systems.Interpolation m_systemInterpolation; - private Systems.Renderer m_systemRenderer; - private Controls m_controls; - - /// - /// This is where everything performs its update. - /// - public void update(TimeSpan elapsedTime) - { - m_systemNetwork.update(elapsedTime, MessageQueueClient.instance.getMessages()); - m_systemKeyboardInput.update(elapsedTime); - m_systemInterpolation.update(elapsedTime); - } + m_systemNetwork.update(elapsedTime, MessageQueueClient.instance.getMessages()); + m_systemKeyboardInput.update(elapsedTime); + m_systemInterpolation.update(elapsedTime); + m_systemCamera.update(elapsedTime); + } - /// - /// Where we render everything - /// + /// + /// Where we render everything + /// - public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch) - { - m_systemRenderer.render(elapsedTime, spriteBatch); - } + public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch) + { + m_systemRenderer.render(elapsedTime, spriteBatch); + } + + /// + /// This is where all game model initialization occurs. In the case + /// of this "game', start by initializing the systems and then + /// loading the art assets. + /// + public bool initialize(ContentManager contentManager, Controls controls, GraphicsDeviceManager graphics) + { + m_contentManager = contentManager; + m_entities = new Dictionary(); + m_systemInterpolation = new Systems.Interpolation(); + m_systemCamera = new Systems.Camera(); + m_systemRenderer = new Systems.Renderer(m_systemCamera, graphics); + m_systemNetwork = new Systems.Network(); + + m_systemNetwork.registerNewEntityHandler(handleNewEntity); + m_systemNetwork.registerRemoveEntityHandler(handleRemoveEntity); + m_controls = controls; + + m_systemKeyboardInput = new Systems.KeyboardInput(new List> + { }, m_controls); - /// - /// This is where all game model initialization occurs. In the case - /// of this "game', start by initializing the systems and then - /// loading the art assets. - /// - public bool initialize(ContentManager contentManager, Controls controls) + return true; + } + + public void shutdown() + { + + } + + /// + /// Based upon an Entity received from the server, create the + /// entity at the client. + /// + private Entity createEntity(Shared.Messages.NewEntity message) + { + Entity entity = new Entity(message.id); + + if (message.hasAppearance) { - m_contentManager = contentManager; - m_entities = new Dictionary(); - m_systemInterpolation = new Systems.Interpolation(); - m_systemRenderer = new Systems.Renderer(); - m_systemNetwork = new Systems.Network(); - - m_systemNetwork.registerNewEntityHandler(handleNewEntity); - m_systemNetwork.registerRemoveEntityHandler(handleRemoveEntity); - m_controls = controls; - - m_systemKeyboardInput = new Systems.KeyboardInput(new List> - { }, m_controls); - - return true; + Texture2D texture = m_contentManager.Load(message.texture); + entity.add(new Components.Sprite(texture)); } - - public void shutdown() + if (message.hasPosition) { - + entity.add(new Shared.Components.Position(message.position, message.orientation)); } - /// - /// Based upon an Entity received from the server, create the - /// entity at the client. - /// - private Entity createEntity(Shared.Messages.NewEntity message) + if (message.hasSize) { - Entity entity = new Entity(message.id); - - if (message.hasAppearance) - { - Texture2D texture = m_contentManager.Load(message.texture); - entity.add(new Components.Sprite(texture)); - } - if (message.hasPosition) - { - entity.add(new Shared.Components.Position(message.position, message.orientation)); - } - - if (message.hasSize) - { - entity.add(new Shared.Components.Size(message.size)); - } - - if (message.hasMovement) - { - entity.add(new Shared.Components.Movement(message.moveRate, message.rotateRate)); - } - - if (message.hasInput) - { - entity.add(new Shared.Components.Input(message.inputs)); - } - - return entity; + entity.add(new Shared.Components.Size(message.size)); } - /// - /// As entities are added to the game model, they are run by the systems - /// to see if they are interested in knowing about them during their - /// updates. - /// - private void addEntity(Entity entity) + if (message.hasMovement) { - if (entity == null) - { - return; - } - // TODO: Update the systems we use here - m_entities[entity.id] = entity; - m_systemKeyboardInput.add(entity); - m_systemRenderer.add(entity); - m_systemNetwork.add(entity); - m_systemInterpolation.add(entity); + entity.add(new Shared.Components.Movement(message.moveRate, message.rotateRate)); } - /// - /// All entity lists for the systems must be given a chance to remove - /// the entity. - /// - private void removeEntity(uint id) + if (message.hasInput) { - // TODO: Update the systems we use here - m_entities.Remove(id); - m_systemKeyboardInput.remove(id); - m_systemNetwork.remove(id); - m_systemRenderer.remove(id); - m_systemInterpolation.remove(id); + entity.add(new Shared.Components.Input(message.inputs)); } - private void handleNewEntity(Shared.Messages.NewEntity message) + return entity; + } + + /// + /// As entities are added to the game model, they are run by the systems + /// to see if they are interested in knowing about them during their + /// updates. + /// + private void addEntity(Entity entity) + { + if (entity == null) { - Entity entity = createEntity(message); - addEntity(entity); + return; } + // TODO: Update the systems we use here + m_entities[entity.id] = entity; + m_systemKeyboardInput.add(entity); + m_systemRenderer.add(entity); + m_systemNetwork.add(entity); + m_systemInterpolation.add(entity); + m_systemCamera.add(entity); + } + + /// + /// All entity lists for the systems must be given a chance to remove + /// the entity. + /// + private void removeEntity(uint id) + { + // TODO: Update the systems we use here + m_entities.Remove(id); + m_systemKeyboardInput.remove(id); + m_systemNetwork.remove(id); + m_systemRenderer.remove(id); + m_systemInterpolation.remove(id); + m_systemCamera.remove(id); + } + + private void handleNewEntity(Shared.Messages.NewEntity message) + { + Entity entity = createEntity(message); + addEntity(entity); + } - /// - /// Handler for the RemoveEntity message. It removes the entity from - /// the client game model (that's us!). - /// - private void handleRemoveEntity(Shared.Messages.RemoveEntity message) + /// + /// Handler for the RemoveEntity message. It removes the entity from + /// the client game model (that's us!). + /// + private void handleRemoveEntity(Shared.Messages.RemoveEntity message) + { + removeEntity(message.id); + } + + private Color parseColor(string color) + { + // Pattern to extract the RGBA values from the string + var pattern = @"\{R:(\d+)\sG:(\d+)\sB:(\d+)\sA:(\d+)\}"; + var match = Regex.Match(color, pattern); + if (match.Success) { - removeEntity(message.id); + // Extracting the RGBA values + int r = int.Parse(match.Groups[1].Value); + int g = int.Parse(match.Groups[2].Value); + int b = int.Parse(match.Groups[3].Value); + int a = int.Parse(match.Groups[4].Value); + + // Creating a new Color object with the extracted values + return new Color(r, g, b, a); } - - private Color parseColor(string color) + else { - // Pattern to extract the RGBA values from the string - var pattern = @"\{R:(\d+)\sG:(\d+)\sB:(\d+)\sA:(\d+)\}"; - var match = Regex.Match(color, pattern); - if (match.Success) - { - // Extracting the RGBA values - int r = int.Parse(match.Groups[1].Value); - int g = int.Parse(match.Groups[2].Value); - int b = int.Parse(match.Groups[3].Value); - int a = int.Parse(match.Groups[4].Value); - - // Creating a new Color object with the extracted values - return new Color(r, g, b, a); - }else{ - // If the string does not match the pattern, return a default color - return Color.White; - } + // If the string does not match the pattern, return a default color + return Color.White; } } } + diff --git a/src/Client/Menu/GamePlayView.cs b/src/Client/Menu/GamePlayView.cs index ceea940..f104896 100644 --- a/src/Client/Menu/GamePlayView.cs +++ b/src/Client/Menu/GamePlayView.cs @@ -21,7 +21,6 @@ public class GamePlayView : GameStateView private TimeSpan m_connectToServerTime = TimeSpan.Zero; private Controls m_controls; - public GamePlayView(Controls controls) { m_controls = controls; @@ -30,7 +29,7 @@ public GamePlayView(Controls controls) public override void initialize() { m_gameModel = new GameModel(); - m_gameModel.initialize(m_contentManager, m_controls); + m_gameModel.initialize(m_contentManager, m_controls, m_graphics); m_isSetup = false; m_isKeyboardRegistered = false; m_newState = MenuStateEnum.GamePlay; diff --git a/src/Client/Systems/Camera.cs b/src/Client/Systems/Camera.cs index e41cf34..ffbd305 100644 --- a/src/Client/Systems/Camera.cs +++ b/src/Client/Systems/Camera.cs @@ -1,11 +1,38 @@ +using Microsoft.Xna.Framework; +using Shared.Entities; using System; +using System.Diagnostics; +using System.Linq; namespace Client.Systems; public class Camera : Shared.Systems.System { + private Rectangle m_viewport = new(); + public Rectangle Viewport { get { return m_viewport; } } + + public Camera() : + base( + typeof(Shared.Components.Position), + typeof(Shared.Components.Movement), + typeof(Shared.Components.Input) + ) + { } + public override void update(TimeSpan elapsedTime) { - throw new NotImplementedException(); + if (m_entities.Count > 1) + throw new Exception("Got an invalid number of players on the client side."); + + if (m_entities.Count < 1) + { + Debug.WriteLine("No Player Found"); + return; + } + + Entity player = m_entities.Values.ToArray()[0]; + Point pos = player.get().position.ToPoint(); + + m_viewport.Location = pos; } } \ No newline at end of file diff --git a/src/Client/Systems/Renderer.cs b/src/Client/Systems/Renderer.cs index 11acd71..2c30f9e 100644 --- a/src/Client/Systems/Renderer.cs +++ b/src/Client/Systems/Renderer.cs @@ -1,65 +1,72 @@ - -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Shared.Entities; -using System; using Microsoft.Xna.Framework.Content; + +using Shared.Entities; using Shared.Components; using Shared.Components.Appearance; -namespace Client.Systems +using System; + +namespace Client.Systems; + +public class Renderer : Shared.Systems.System { - public class Renderer : Shared.Systems.System + private Systems.Camera m_camera; + private GraphicsDeviceManager m_graphics; + + public Renderer(Systems.Camera camera, GraphicsDeviceManager graphics) : + base( + typeof(Client.Components.Sprite), + typeof(Shared.Components.Position), + typeof(Shared.Components.Size) + ) { - public Renderer() : - base( - typeof(Client.Components.Sprite), - typeof(Shared.Components.Position), - typeof(Shared.Components.Size) - ) - { - - } + m_camera = camera; + m_graphics = graphics; + } + + public override void update(TimeSpan elapsedTime) { } + + public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch) + { + Matrix matrix = Matrix.Identity; + Vector2 offset = -m_camera.Viewport.Location.ToVector2() + + new Vector2(m_graphics.PreferredBackBufferWidth / 2, m_graphics.PreferredBackBufferHeight / 2); + matrix.Translation = new Vector3(offset, 0); - public override void update(TimeSpan elapsedTime) - { - } + // TODO: Account for viewport width and height - public void render(TimeSpan elapsedTime, SpriteBatch spriteBatch) - { - spriteBatch.Begin(); - foreach (Entity entity in m_entities.Values) - { - renderEntity(elapsedTime, spriteBatch, entity); - } - spriteBatch.End(); - } - - private void renderEntity(TimeSpan elapsedTime, SpriteBatch spriteBatch, Entity entity) - { - var position = entity.get().position; - var orientation = entity.get().orientation; - var size = entity.get().size; - var texCenter = entity.get().center; - var texture = entity.get().texture; + spriteBatch.Begin(transformMatrix: matrix); + foreach (Entity entity in m_entities.Values) + renderEntity(elapsedTime, spriteBatch, entity); + spriteBatch.End(); + } + + private void renderEntity(TimeSpan elapsedTime, SpriteBatch spriteBatch, Entity entity) + { + var position = entity.get().position; + var orientation = entity.get().orientation; + var size = entity.get().size; + var texCenter = entity.get().center; + var texture = entity.get().texture; - // Build a rectangle centered at position, with width/height of size - Rectangle rectangle = new Rectangle( - (int)(position.X - size.X / 2), - (int)(position.Y - size.Y / 2), - (int)size.X, - (int)size.Y); + // Build a rectangle centered at position, with width/height of size + Rectangle rectangle = new Rectangle( + (int)(position.X - size.X / 2), + (int)(position.Y - size.Y / 2), + (int)size.X, + (int)size.Y); - spriteBatch.Draw( - texture, - rectangle, - null, - Color.White, - orientation, - texCenter, - SpriteEffects.None, - 0); - } - + spriteBatch.Draw( + texture, + rectangle, + null, + Color.White, + orientation, + texCenter, + SpriteEffects.None, + 0); } + }