diff --git a/PongFE/Components/PaddleMoveSpeedComponent.cs b/PongFE/Components/PaddleMoveSpeedComponent.cs new file mode 100644 index 0000000..0eb4b1a --- /dev/null +++ b/PongFE/Components/PaddleMoveSpeedComponent.cs @@ -0,0 +1,14 @@ +using Encompass; + +namespace PongFE.Components +{ + public struct PaddleMoveSpeedComponent : IComponent + { + public float Speed { get; } + + public PaddleMoveSpeedComponent(float speed) + { + Speed = speed; + } + } +} diff --git a/PongFE/Components/PlayerInputComponent.cs b/PongFE/Components/PlayerInputComponent.cs new file mode 100644 index 0000000..04e07bb --- /dev/null +++ b/PongFE/Components/PlayerInputComponent.cs @@ -0,0 +1,20 @@ +using Encompass; + +namespace PongFE.Components +{ + public enum PlayerIndex + { + One, + Two + } + + public struct PlayerInputComponent : IComponent + { + public PlayerIndex PlayerIndex { get; } + + public PlayerInputComponent(PlayerIndex playerIndex) + { + PlayerIndex = playerIndex; + } + } +} diff --git a/PongFE/Engines/InputEngine.cs b/PongFE/Engines/InputEngine.cs new file mode 100644 index 0000000..26da613 --- /dev/null +++ b/PongFE/Engines/InputEngine.cs @@ -0,0 +1,44 @@ +using Encompass; +using Microsoft.Xna.Framework.Input; +using PongFE.Components; +using PongFE.Messages; + +namespace PongFE.Engines +{ + [Reads(typeof(PlayerInputComponent))] + [Sends(typeof(PaddleMoveMessage))] + public class InputEngine : Engine + { + public override void Update(double dt) + { + var keyboardState = Keyboard.GetState(); + + foreach (ref readonly var playerInputEntity in ReadEntities()) + { + ref readonly var playerInputComponent = ref GetComponent(playerInputEntity); + + if (playerInputComponent.PlayerIndex == PlayerIndex.One) + { + if (keyboardState.IsKeyDown(Keys.Down)) + { + SendMessage( + new PaddleMoveMessage( + playerInputEntity, + PaddleMoveDirection.Down + ) + ); + } + else if (keyboardState.IsKeyDown(Keys.Up)) + { + SendMessage( + new PaddleMoveMessage( + playerInputEntity, + PaddleMoveDirection.Up + ) + ); + } + } + } + } + } +} diff --git a/PongFE/Engines/MotionEngine.cs b/PongFE/Engines/MotionEngine.cs new file mode 100644 index 0000000..46f9b41 --- /dev/null +++ b/PongFE/Engines/MotionEngine.cs @@ -0,0 +1,25 @@ +using Encompass; +using PongFE.Components; +using PongFE.Messages; + +namespace PongFE.Engines +{ + [Reads(typeof(PositionComponent))] + [Receives(typeof(MotionMessage))] + [Writes(typeof(PositionComponent))] + public class MotionEngine : Engine + { + public override void Update(double dt) + { + foreach (ref readonly var motionMessage in ReadMessages()) + { + if (HasComponent(motionMessage.Entity)) + { + ref readonly var positionComponent = ref GetComponent(motionMessage.Entity); + var newPosition = positionComponent.Position + motionMessage.Movement; + SetComponent(motionMessage.Entity, new PositionComponent(newPosition)); + } + } + } + } +} diff --git a/PongFE/Engines/PaddleMovementEngine.cs b/PongFE/Engines/PaddleMovementEngine.cs new file mode 100644 index 0000000..6cc78ce --- /dev/null +++ b/PongFE/Engines/PaddleMovementEngine.cs @@ -0,0 +1,30 @@ +using Encompass; +using PongFE.Components; +using PongFE.Messages; + +namespace PongFE.Engines +{ + [Reads(typeof(PaddleMoveSpeedComponent))] + [Receives(typeof(PaddleMoveMessage))] + [Sends(typeof(MotionMessage))] + public class PaddleMovementEngine : Engine + { + public override void Update(double dt) + { + foreach (ref readonly var message in ReadMessages()) + { + if (HasComponent(message.Entity)) + { + var directionMultiplier = message.PaddleMoveDirection == PaddleMoveDirection.Down ? 1 : -1; + ref readonly var paddleMoveSpeedComponent = ref GetComponent(message.Entity); + SendMessage( + new MotionMessage( + message.Entity, + new System.Numerics.Vector2(0, paddleMoveSpeedComponent.Speed * directionMultiplier * (float)dt) + ) + ); + } + } + } + } +} diff --git a/PongFE/Engines/Spawners/BallSpawner.cs b/PongFE/Engines/Spawners/BallSpawner.cs new file mode 100644 index 0000000..f86a747 --- /dev/null +++ b/PongFE/Engines/Spawners/BallSpawner.cs @@ -0,0 +1,24 @@ +using Encompass; +using Microsoft.Xna.Framework.Graphics; +using PongFE.Components; +using PongFE.Messages; + +namespace PongFE.Spawners +{ + public class BallSpawner : Spawner + { + private Texture2D BallTexture { get; } + + public BallSpawner(Texture2D ballTexture) + { + BallTexture = ballTexture; + } + + protected override void Spawn(BallSpawnMessage message) + { + var ball = CreateEntity(); + AddComponent(ball, new PositionComponent(new MoonTools.Structs.Position2D(640, 360))); + AddComponent(ball, new Texture2DComponent(BallTexture, 0)); + } + } +} diff --git a/PongFE/Messages/BallSpawnMessage.cs b/PongFE/Messages/BallSpawnMessage.cs new file mode 100644 index 0000000..f918d0b --- /dev/null +++ b/PongFE/Messages/BallSpawnMessage.cs @@ -0,0 +1,15 @@ +using Encompass; +using MoonTools.Structs; + +namespace PongFE.Messages +{ + public struct BallSpawnMessage : IMessage + { + public Position2D Position { get; } + + public BallSpawnMessage(Position2D position) + { + Position = position; + } + } +} diff --git a/PongFE/Messages/MotionMessage.cs b/PongFE/Messages/MotionMessage.cs new file mode 100644 index 0000000..c1833a7 --- /dev/null +++ b/PongFE/Messages/MotionMessage.cs @@ -0,0 +1,17 @@ +using System.Numerics; +using Encompass; + +namespace PongFE.Messages +{ + public struct MotionMessage : IMessage, IHasEntity + { + public Entity Entity { get; } + public Vector2 Movement { get; } + + public MotionMessage(Entity entity, Vector2 movement) + { + Entity = entity; + Movement = movement; + } + } +} diff --git a/PongFE/Messages/PaddleMoveMessage.cs b/PongFE/Messages/PaddleMoveMessage.cs new file mode 100644 index 0000000..f3ebe56 --- /dev/null +++ b/PongFE/Messages/PaddleMoveMessage.cs @@ -0,0 +1,22 @@ +using Encompass; + +namespace PongFE.Messages +{ + public enum PaddleMoveDirection + { + Up, + Down + } + + public struct PaddleMoveMessage : IMessage, IHasEntity + { + public Entity Entity { get; } + public PaddleMoveDirection PaddleMoveDirection { get; } + + public PaddleMoveMessage(Entity entity, PaddleMoveDirection paddleMoveDirection) + { + Entity = entity; + PaddleMoveDirection = paddleMoveDirection; + } + } +} diff --git a/PongFE/PongFEGame.cs b/PongFE/PongFEGame.cs index e17cc71..71125e6 100644 --- a/PongFE/PongFEGame.cs +++ b/PongFE/PongFEGame.cs @@ -2,7 +2,10 @@ using Encompass; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using PongFE.Components; +using PongFE.Engines; +using PongFE.Messages; using PongFE.Renderers; +using PongFE.Spawners; namespace PongFE { @@ -16,6 +19,7 @@ namespace PongFE SpriteBatch SpriteBatch { get; set; } Texture2D WhitePixel { get; set; } RenderTarget2D PaddleTexture { get; set; } + RenderTarget2D BallTexture { get; set; } public PongFEGame() { @@ -27,6 +31,7 @@ namespace PongFE Window.AllowUserResizing = true; IsMouseVisible = true; + IsFixedTimeStep = true; } protected override void LoadContent() @@ -41,14 +46,28 @@ namespace PongFE SpriteBatch.Begin(); SpriteBatch.Draw(WhitePixel, new Rectangle(0, 0, 20, 80), Color.White); SpriteBatch.End(); + + BallTexture = new RenderTarget2D(GraphicsDevice, 16, 16); + GraphicsDevice.SetRenderTarget(BallTexture); + SpriteBatch.Begin(); + SpriteBatch.Draw(WhitePixel, new Rectangle(0, 0, 16, 16), Color.White); + SpriteBatch.End(); GraphicsDevice.SetRenderTarget(null); + WorldBuilder.AddEngine(new InputEngine()); + WorldBuilder.AddEngine(new PaddleMovementEngine()); + WorldBuilder.AddEngine(new MotionEngine()); + WorldBuilder.AddEngine(new BallSpawner(BallTexture)); WorldBuilder.AddOrderedRenderer(new Texture2DRenderer(SpriteBatch)); var paddle = WorldBuilder.CreateEntity(); + WorldBuilder.SetComponent(paddle, new PlayerInputComponent(PongFE.Components.PlayerIndex.One)); + WorldBuilder.SetComponent(paddle, new PaddleMoveSpeedComponent(400)); WorldBuilder.SetComponent(paddle, new PositionComponent(new MoonTools.Structs.Position2D(5, 5))); WorldBuilder.SetComponent(paddle, new Texture2DComponent(PaddleTexture, 0)); + WorldBuilder.SendMessage(new BallSpawnMessage(new MoonTools.Structs.Position2D(640, 360))); + World = WorldBuilder.Build(); } @@ -59,6 +78,7 @@ namespace PongFE protected override void Update(GameTime gameTime) { + System.Console.WriteLine(1 / gameTime.ElapsedGameTime.TotalSeconds); World.Update(gameTime.ElapsedGameTime.TotalSeconds); base.Update(gameTime);