summaryrefslogtreecommitdiff
path: root/source/game/systems
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/systems')
-rw-r--r--source/game/systems/CameraRenderSystem.cs43
-rw-r--r--source/game/systems/CameraSystem.cs39
-rw-r--r--source/game/systems/ChunkMapRenderSystem.cs63
-rw-r--r--source/game/systems/EntityDebugSystem.cs44
-rw-r--r--source/game/systems/LightingSystem.cs100
-rw-r--r--source/game/systems/LocalPlayerSystem.cs246
-rw-r--r--source/game/systems/TargetPositionSystem.cs37
-rw-r--r--source/game/systems/mainmenu/MainMenuBackgroundSystem.cs33
-rw-r--r--source/game/systems/mainmenu/MainMenuRenderSystem.cs43
-rw-r--r--source/game/systems/physics/PhysicsCollisionDebugSystem.cs61
-rw-r--r--source/game/systems/physics/PhysicsSystem.cs42
-rw-r--r--source/game/systems/physics/PhysicsWorldCollisionSystem.cs83
-rw-r--r--source/game/systems/ui/GameGUIDrawSystem.cs12
13 files changed, 846 insertions, 0 deletions
diff --git a/source/game/systems/CameraRenderSystem.cs b/source/game/systems/CameraRenderSystem.cs
new file mode 100644
index 0000000..2846fa7
--- /dev/null
+++ b/source/game/systems/CameraRenderSystem.cs
@@ -0,0 +1,43 @@
+using Celesteia.Graphics;
+using Celesteia.Resources.Sprites;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class CameraRenderSystem : EntityDrawSystem
+ {
+ private readonly Camera2D _camera;
+ private readonly SpriteBatch _spriteBatch;
+
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<EntityFrames> entityFramesMapper;
+
+ public CameraRenderSystem(Camera2D camera, SpriteBatch spriteBatch) : base(Aspect.All(typeof(Transform2), typeof(EntityFrames))) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ }
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ entityFramesMapper = mapperService.GetMapper<EntityFrames>();
+ }
+
+ public override void Draw(GameTime gameTime)
+ {
+ _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, _camera.GetViewMatrix());
+
+ foreach (int entityId in ActiveEntities) {
+ Transform2 transform = transformMapper.Get(entityId);
+ EntityFrames entityFrames = entityFramesMapper.Get(entityId);
+
+ entityFrames.Draw(0, _spriteBatch, transform.Position, transform.Scale, Color.White);
+ }
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/CameraSystem.cs b/source/game/systems/CameraSystem.cs
new file mode 100644
index 0000000..be121a5
--- /dev/null
+++ b/source/game/systems/CameraSystem.cs
@@ -0,0 +1,39 @@
+using System;
+using Celesteia.Game.Components;
+using Celesteia.Game.Input;
+using Celesteia.Graphics;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class CameraSystem : EntityUpdateSystem
+ {
+ private Camera2D _camera;
+ private float smoothing = 128f;
+
+ private ComponentMapper<Transform2> transformMapper;
+
+ public CameraSystem(Camera2D camera) : base(Aspect.All(typeof(Transform2), typeof(CameraFollow)))
+ => _camera = camera;
+
+ public override void Initialize(IComponentMapperService mapperService)
+ => transformMapper = mapperService.GetMapper<Transform2>();
+
+ Vector2 pos;
+ public override void Update(GameTime gameTime)
+ {
+ foreach (int entityId in ActiveEntities) {
+ pos = transformMapper.Get(entityId).Position * smoothing;
+ pos.X = MathF.Round(pos.X) / smoothing;
+ pos.Y = MathF.Round(pos.Y) / smoothing;
+ _camera.Center = pos;
+ break;
+ }
+
+ if (KeyboardHelper.IsDown(Keys.LeftControl)) _camera.Zoom += (int) Math.Clamp(MouseHelper.ScrollDelta, -1f, 1f);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/ChunkMapRenderSystem.cs b/source/game/systems/ChunkMapRenderSystem.cs
new file mode 100644
index 0000000..afb867c
--- /dev/null
+++ b/source/game/systems/ChunkMapRenderSystem.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+using Celesteia.Game.Planets;
+using Celesteia.Graphics;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class ChunkMapRenderSystem : IUpdateSystem, IDrawSystem
+ {
+ private readonly Camera2D _camera;
+ private readonly SpriteBatch _spriteBatch;
+ private ChunkVector _lastChunkPos;
+ private ChunkVector _pivotChunkPos => ChunkVector.FromVector2(_camera.Center);
+ public int RenderDistance = 4;
+ private ChunkMap _chunkMap;
+
+ public ChunkMapRenderSystem(Camera2D camera, SpriteBatch spriteBatch, ChunkMap chunkMap) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ _chunkMap = chunkMap;
+ }
+
+ public void Initialize(MonoGame.Extended.Entities.World world) {}
+
+ private ChunkVector _v;
+ private List<ChunkVector> activeChunks = new List<ChunkVector>();
+ public void Update(GameTime gameTime)
+ {
+ if (_lastChunkPos != _pivotChunkPos) {
+ activeChunks.Clear();
+ for (int i = -RenderDistance; i <= RenderDistance; i++) {
+ _v.X = _pivotChunkPos.X + i;
+ for (int j = -RenderDistance; j <= RenderDistance; j++) {
+ _v.Y = _pivotChunkPos.Y + j;
+
+ if (!_chunkMap.ChunkIsInMap(_v)) continue;
+ activeChunks.Add(_v);
+ }
+ }
+
+ _lastChunkPos = _pivotChunkPos;
+ }
+ }
+
+ public void Draw(GameTime gameTime) {
+ _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointWrap, null, null, null, _camera.GetViewMatrix());
+
+ // Draw every chunk in view.
+ foreach (ChunkVector cv in activeChunks) DrawChunk(cv, gameTime, _spriteBatch);
+
+ _spriteBatch.End();
+ }
+
+ private void DrawChunk(ChunkVector cv, GameTime gameTime, SpriteBatch spriteBatch) {
+ Chunk c = _chunkMap.GetChunk(cv);
+
+ if (c != null) c.Draw(gameTime, spriteBatch);
+ }
+
+ public void Dispose() {}
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/EntityDebugSystem.cs b/source/game/systems/EntityDebugSystem.cs
new file mode 100644
index 0000000..9b7914a
--- /dev/null
+++ b/source/game/systems/EntityDebugSystem.cs
@@ -0,0 +1,44 @@
+using Celesteia.Graphics;
+using Celesteia.Resources;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class EntityDebugSystem : EntityDrawSystem
+ {
+ private readonly Camera2D _camera;
+ private readonly SpriteBatch _spriteBatch;
+
+ private ComponentMapper<Transform2> transformMapper;
+
+ private SpriteFont _font;
+
+ public EntityDebugSystem(Camera2D camera, SpriteBatch spriteBatch) : base(Aspect.All(typeof(Transform2))) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ }
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+
+ _font = ResourceManager.Fonts.GetFontType("Hobo").Font;
+ }
+
+ public override void Draw(GameTime gameTime)
+ {
+ _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, SamplerState.PointClamp, null, null, null, _camera.GetViewMatrix());
+
+ foreach (int entityId in ActiveEntities) {
+ Transform2 transform = transformMapper.Get(entityId);
+
+ _spriteBatch.DrawString(_font, transform.Position.ToString(), transform.Position, Color.White, 0f, new Vector2(0.5f, 0.5f), .12f, SpriteEffects.None, 0f);
+ }
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/LightingSystem.cs b/source/game/systems/LightingSystem.cs
new file mode 100644
index 0000000..73c6cf8
--- /dev/null
+++ b/source/game/systems/LightingSystem.cs
@@ -0,0 +1,100 @@
+using Celesteia.Graphics;
+using Celesteia.Graphics.Lighting;
+using Celesteia.Resources;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Entities.Systems;
+using Celesteia.Resources.Types;
+using Celesteia.Game.Planets;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace Celesteia.Game.Systems {
+ public class LightingSystem : IUpdateSystem, IDrawSystem
+ {
+ private readonly Camera2D _camera;
+ private readonly SpriteBatch _spriteBatch;
+ private readonly ChunkMap _chunkMap;
+
+ public LightingSystem(Camera2D camera, SpriteBatch spriteBatch, ChunkMap chunkMap) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ _chunkMap = chunkMap;
+ }
+ public void Dispose() { }
+
+ private int _lightRenderDistance = 5;
+
+ private Dictionary<byte, BlockLightProperties> lightingDictionary;
+ public void Initialize(MonoGame.Extended.Entities.World world) {
+ int _size = 2 * _lightRenderDistance * Chunk.CHUNK_SIZE;
+
+ _lightMap = new LightMap(_size, _size);
+ _texture = new Texture2D(_spriteBatch.GraphicsDevice, _size, _size);
+
+ lightingDictionary = new Dictionary<byte, BlockLightProperties>();
+ }
+
+ private LightMap _lightMap;
+ private Texture2D _texture;
+
+ private bool drawTexture = false;
+ private Task _lightUpdate;
+ public void Update(GameTime gameTime)
+ {
+ if (_lightUpdate == null || (_lightUpdate != null && _lightUpdate.IsCompleted))
+ _lightUpdate = Task.Factory.StartNew(() => UpdateLight());
+
+ if (drawTexture) UpdateTexture();
+ }
+
+ private Point _position;
+ private void UpdatePosition() {
+ _position = ChunkVector.FromVector2(_camera.Center).Resolve() - new Point(_lightRenderDistance * Chunk.CHUNK_SIZE);
+ }
+
+ private void UpdateTexture() {
+ _drawPosition = _position.ToVector2();
+ _texture.SetData<Color>(_lightMap.GetColors(), 0, _lightMap.GetColorCount());
+ drawTexture = false;
+ }
+
+ private void UpdateLight() {
+ UpdatePosition();
+
+ UpdateEmission();
+ _lightMap.Propagate();
+ _lightMap.CreateColorMap();
+
+ drawTexture = true;
+ }
+
+ private BlockState _block;
+ private void UpdateEmission() {
+ for (int i = 0; i < _lightMap.Width; i++) {
+ for (int j = 0; j < _lightMap.Height; j++) {
+ if (!(_block = _chunkMap.GetForeground(i + _position.X, j + _position.Y)).Empty && _lightMap.AddForeground(i, j, _block.Type.Light)) continue;
+ if (!(_block = _chunkMap.GetBackground(i + _position.X, j + _position.Y)).Empty && _lightMap.AddBackground(i, j, _block.Type.Light)) continue;
+
+ _lightMap.AddLight(i, j, true, LightColor.ambient, 4);
+ }
+ }
+ }
+
+ private BlendState multiply = new BlendState() {
+ ColorBlendFunction = BlendFunction.Add,
+ ColorSourceBlend = Blend.DestinationColor,
+ ColorDestinationBlend = Blend.Zero,
+ };
+
+ private Vector2 _drawPosition;
+ public void Draw(GameTime gameTime)
+ {
+ _spriteBatch.Begin(SpriteSortMode.Immediate, multiply, SamplerState.LinearClamp, null, null, null, _camera.GetViewMatrix());
+
+ _spriteBatch.Draw(_texture, _drawPosition, Color.White);
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/LocalPlayerSystem.cs b/source/game/systems/LocalPlayerSystem.cs
new file mode 100644
index 0000000..5c17cb4
--- /dev/null
+++ b/source/game/systems/LocalPlayerSystem.cs
@@ -0,0 +1,246 @@
+using System;
+using System.Collections.Generic;
+using Celesteia.Game.Components;
+using Celesteia.Game.Components.Items;
+using Celesteia.Game.Components.Physics;
+using Celesteia.Game.Components.Player;
+using Celesteia.Game.Input;
+using Celesteia.Game.Items;
+using Celesteia.Game.Planets;
+using Celesteia.Graphics;
+using Celesteia.GUIs.Game;
+using Celesteia.Resources;
+using Celesteia.Resources.Sprites;
+using Celesteia.Resources.Types;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class LocalPlayerSystem : UpdateSystem, IDrawSystem
+ {
+ private GameInstance _game;
+ private GameGUI _gameGui;
+ private Camera2D _camera;
+ private ChunkMap _chunkMap;
+
+ private Entity _player;
+ public Entity Player {
+ get => _player;
+ set {
+ _player = value;
+
+ localPlayer = _player.Get<LocalPlayer>();
+ targetPosition = _player.Get<TargetPosition>();
+ physicsEntity = _player.Get<PhysicsEntity>();
+ frames = _player.Get<EntityFrames>();
+ attributes = _player.Get<EntityAttributes>();
+ input = _player.Get<PlayerInput>();
+ inventory = _player.Get<Inventory>();
+ }
+ }
+ private LocalPlayer localPlayer;
+ private PlayerInput input;
+ private PhysicsEntity physicsEntity;
+ private EntityFrames frames;
+ private EntityAttributes attributes;
+ private TargetPosition targetPosition;
+ private Inventory inventory;
+
+ private SpriteBatch _spriteBatch;
+
+ private BlockFrame _selectionSprite;
+
+ public LocalPlayerSystem(GameInstance game, ChunkMap chunkMap, Camera2D camera, SpriteBatch spriteBatch, GameGUI gameGui) {
+ _game = game;
+ _chunkMap = chunkMap;
+ _camera = camera;
+ _gameGui = gameGui;
+ _spriteBatch = spriteBatch;
+
+ _selectionSprite = ResourceManager.Blocks.Selection.GetFrame(0);
+ }
+
+ private bool IsGameActive => !_gameGui.Paused && (int)_gameGui.State < 1 && _game.IsActive;
+
+ public override void Update(GameTime gameTime)
+ {
+ if (_player == null) return;
+
+ bool clicked = false;
+ UpdateGUI(gameTime, input, out clicked);
+
+ if (IsGameActive) {
+ UpdateSelectedItem();
+
+ UpdateMouse(gameTime, input);
+ UpdateMovement(gameTime, input, physicsEntity, frames, attributes.Attributes, targetPosition);
+ UpdateJump(gameTime, localPlayer, input, physicsEntity, attributes.Attributes);
+
+ if (!clicked) UpdateClick(gameTime, input);
+ } else SelectionColor = Color.Transparent;
+ }
+
+ private static Dictionary<int, int> hotbarMappings = new Dictionary<int, int>() {
+ { (int)Keys.D1, 0 },
+ { (int)Keys.D2, 1 },
+ { (int)Keys.D3, 2 },
+ { (int)Keys.D4, 3 },
+ { (int)Keys.D5, 4 },
+ { (int)Keys.D6, 5 },
+ { (int)Keys.D7, 6 },
+ { (int)Keys.D8, 7 },
+ { (int)Keys.D9, 8 }
+ };
+
+ private void UpdateSelectedItem() {
+ foreach (int keys in hotbarMappings.Keys) {
+ if (KeyboardHelper.Pressed((Keys) keys)) {
+ _gameGui.HotbarSelection = hotbarMappings[keys];
+ }
+ }
+
+ if (!KeyboardHelper.IsDown(Keys.LeftControl) && MouseHelper.ScrollDelta != 0f) {
+ int change = (int) -Math.Clamp(MouseHelper.ScrollDelta, -1f, 1f);
+ int selection = _gameGui.HotbarSelection;
+
+ selection += change;
+
+ if (selection < 0) selection = _gameGui.HotbarSlots - 1;
+ if (selection >= _gameGui.HotbarSlots) selection = 0;
+
+ _gameGui.HotbarSelection = selection;
+ }
+ }
+
+ bool _inventoryPress;
+ bool _craftingPress;
+ bool _pausePress;
+ private void UpdateGUI(GameTime gameTime, PlayerInput input, out bool clicked) {
+ _inventoryPress = input.Inventory.Poll();
+ _craftingPress = input.Crafting.Poll();
+ _pausePress = input.Pause.Poll();
+
+ if (_inventoryPress || _craftingPress || _pausePress) {
+ switch (_gameGui.State) {
+ case InventoryScreenState.Closed:
+ if (_craftingPress) _gameGui.State = InventoryScreenState.Crafting;
+ else if (_inventoryPress) _gameGui.State = InventoryScreenState.Inventory;
+ else if (_pausePress) _gameGui.TogglePause();
+ break;
+ case InventoryScreenState.Inventory:
+ if (_craftingPress) _gameGui.State = InventoryScreenState.Crafting;
+ else _gameGui.State = InventoryScreenState.Closed;
+ break;
+ case InventoryScreenState.Crafting:
+ _gameGui.State = InventoryScreenState.Closed;
+ break;
+ default: break;
+ }
+ }
+
+ _gameGui.Update(gameTime, out clicked);
+ }
+
+ float h;
+ private bool _moving;
+ private double _startedMoving;
+ private void UpdateMovement(GameTime gameTime, PlayerInput input, PhysicsEntity physicsEntity, EntityFrames frames, EntityAttributes.EntityAttributeMap attributes, TargetPosition targetPosition) {
+ h = input.Horizontal.Poll();
+
+ if (h != 0f) {
+ // Player has started moving, animate.
+ if (!_moving) _startedMoving = gameTime.TotalGameTime.TotalSeconds;
+
+ // Flip sprite according to horizontal movement float.
+ frames.Effects = h < 0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
+ }
+
+ _moving = h != 0f;
+
+ // If the player is moving, change the frame every .25 seconds, else return the standing frame.
+ frames.Frame = _moving ? (int)((gameTime.TotalGameTime.TotalSeconds - _startedMoving) / 0.25) : 0;
+
+ if (h == 0f) return;
+
+ h *= 1f + (input.Run.Poll() ? 1.5f : 0);
+ h *= attributes.Get(EntityAttribute.MovementSpeed);
+ h *= gameTime.GetElapsedSeconds();
+
+ targetPosition.Target.X += h;
+ }
+
+ private void UpdateJump(GameTime gameTime, LocalPlayer localPlayer, PlayerInput input, PhysicsEntity physicsEntity, EntityAttributes.EntityAttributeMap attributes)
+ {
+ if (localPlayer.JumpRemaining > 0f) {
+ if (input.Jump.Poll()) {
+ physicsEntity.SetVelocity(physicsEntity.Velocity.X, -attributes.Get(EntityAttribute.JumpForce));
+ localPlayer.JumpRemaining -= gameTime.GetElapsedSeconds();
+ }
+ } else if (physicsEntity.CollidingDown) localPlayer.JumpRemaining = attributes.Get(EntityAttribute.JumpFuel);
+ }
+
+ private Point? Selection;
+ private BlockState SelectedBlock;
+ private Color SelectionColor;
+ public void SetSelection(Point? selection) {
+ if (selection == Selection) return;
+
+ Selection = selection;
+ if (!selection.HasValue) {
+ SelectionColor = Color.Transparent;
+ return;
+ }
+
+ SelectedBlock = _chunkMap.GetForeground(Selection.Value);
+ if (!SelectedBlock.Draw) SelectedBlock = _chunkMap.GetBackground(Selection.Value);
+
+ SelectionColor = (SelectedBlock.Type.Strength >= 0 ? Color.White : Color.Black);
+ }
+
+ Vector2 pointV = Vector2.Zero;
+ Point point = Point.Zero;
+ private void UpdateMouse(GameTime gameTime, PlayerInput input) {
+ pointV = _camera.ScreenToWorld(MouseHelper.Position);
+ pointV.Floor();
+ point = pointV.ToPoint();
+
+ SetSelection(point);
+ }
+
+
+ bool success = false;
+ ItemStack stack = null;
+ IItemActions actions = null;
+ private void UpdateClick(GameTime gameTime, PlayerInput input) {
+ if (!input.PrimaryUse.Poll() && !input.SecondaryUse.Poll()) return;
+ if (_gameGui.GetSelectedItem() == null) return;
+
+ stack = _gameGui.GetSelectedItem();
+ if(stack.Type == null || stack.Type.Actions == null) return;
+
+ actions = stack.Type.Actions;
+
+ if (input.PrimaryUse.Poll()) success = actions.Primary(gameTime, _chunkMap, point, _player);
+ if (input.SecondaryUse.Poll()) success = stack.Type.Actions.Secondary(gameTime, _chunkMap, point, _player);
+
+ if (success && stack.Type.ConsumeOnUse) stack.Amount -= 1;
+
+ inventory.AssertAmounts();
+ }
+
+ public void Draw(GameTime gameTime)
+ {
+ if (!UIReferences.GUIEnabled) return;
+
+ _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, _camera.GetViewMatrix());
+
+ _selectionSprite.Draw(0, _spriteBatch, pointV, SelectionColor);
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/TargetPositionSystem.cs b/source/game/systems/TargetPositionSystem.cs
new file mode 100644
index 0000000..7089bc1
--- /dev/null
+++ b/source/game/systems/TargetPositionSystem.cs
@@ -0,0 +1,37 @@
+using Celesteia.Game.Components;
+using Celesteia.Game.Planets;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems {
+ public class TargetPositionSystem : EntityUpdateSystem {
+ private ChunkMap _chunkMap;
+
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<TargetPosition> targetPositionMapper;
+
+ public TargetPositionSystem(ChunkMap chunkMap) : base(Aspect.All(typeof(Transform2), typeof(TargetPosition)))
+ => _chunkMap = chunkMap;
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ targetPositionMapper = mapperService.GetMapper<TargetPosition>();
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (int entityId in ActiveEntities) {
+ TargetPosition targetPosition = targetPositionMapper.Get(entityId);
+ Transform2 transform = transformMapper.Get(entityId);
+
+ if (targetPosition.Target.X < 0 || targetPosition.Target.X > _chunkMap.BlockWidth)
+ targetPosition.Target.X = MathHelper.Clamp(targetPosition.Target.X, 0f, _chunkMap.BlockWidth);
+
+ transform.Position = targetPosition.Target;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/mainmenu/MainMenuBackgroundSystem.cs b/source/game/systems/mainmenu/MainMenuBackgroundSystem.cs
new file mode 100644
index 0000000..e4d5e28
--- /dev/null
+++ b/source/game/systems/mainmenu/MainMenuBackgroundSystem.cs
@@ -0,0 +1,33 @@
+using Celesteia.Game.Components.Skybox;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.MainMenu {
+ public class MainMenuBackgroundSystem : EntityUpdateSystem
+ {
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<SkyboxRotateZ> rotatorMapper;
+
+ public MainMenuBackgroundSystem() : base(Aspect.All(typeof(Transform2), typeof(SkyboxRotateZ))) {}
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ rotatorMapper = mapperService.GetMapper<SkyboxRotateZ>();
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (int entityId in ActiveEntities) {
+ SkyboxRotateZ rotator = rotatorMapper.Get(entityId);
+ Transform2 transform = transformMapper.Get(entityId);
+
+ rotator.Current += rotator.Magnitude * (gameTime.GetElapsedSeconds() / 1000f) * 20f;
+
+ transform.Rotation = rotator.Current;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/mainmenu/MainMenuRenderSystem.cs b/source/game/systems/mainmenu/MainMenuRenderSystem.cs
new file mode 100644
index 0000000..ada6a77
--- /dev/null
+++ b/source/game/systems/mainmenu/MainMenuRenderSystem.cs
@@ -0,0 +1,43 @@
+using Celesteia.Graphics;
+using Celesteia.Resources.Sprites;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.MainMenu {
+ public class MainMenuRenderSystem : EntityDrawSystem
+ {
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<SkyboxPortionFrames> framesMapper;
+
+ private Camera2D _camera;
+ private SpriteBatch _spriteBatch;
+
+ public MainMenuRenderSystem(Camera2D camera, SpriteBatch spriteBatch) : base(Aspect.All(typeof(Transform2), typeof(SkyboxPortionFrames))) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ }
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ framesMapper = mapperService.GetMapper<SkyboxPortionFrames>();
+ }
+
+ public override void Draw(GameTime gameTime)
+ {
+ _spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.PointClamp, null, RasterizerState.CullNone, null, _camera.GetViewMatrix());
+
+ foreach (int entityId in ActiveEntities) {
+ SkyboxPortionFrames frames = framesMapper.Get(entityId);
+ Transform2 transform = transformMapper.Get(entityId);
+
+ frames.Draw(0, _spriteBatch, transform.Position, transform.Rotation, transform.Scale);
+ }
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/physics/PhysicsCollisionDebugSystem.cs b/source/game/systems/physics/PhysicsCollisionDebugSystem.cs
new file mode 100644
index 0000000..f605c30
--- /dev/null
+++ b/source/game/systems/physics/PhysicsCollisionDebugSystem.cs
@@ -0,0 +1,61 @@
+using Celesteia.Game.Components.Physics;
+using Celesteia.Game.Planets;
+using Celesteia.Graphics;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.Physics {
+ public class PhysicsCollisionDebugSystem : EntityDrawSystem
+ {
+ private readonly Camera2D _camera;
+ private readonly SpriteBatch _spriteBatch;
+ private readonly ChunkMap _chunkMap;
+
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<CollisionBox> collisionBoxMapper;
+
+ public PhysicsCollisionDebugSystem(Camera2D camera, SpriteBatch spriteBatch, ChunkMap chunkMap) : base(Aspect.All(typeof(Transform2), typeof(CollisionBox))) {
+ _camera = camera;
+ _spriteBatch = spriteBatch;
+ _chunkMap = chunkMap;
+ }
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ collisionBoxMapper = mapperService.GetMapper<CollisionBox>();
+ }
+
+ public override void Draw(GameTime gameTime)
+ {
+ if (!GameInstance.DebugMode) return;
+
+ _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, SamplerState.PointClamp, null, null, null, _camera.GetViewMatrix());
+
+ foreach (int entityId in ActiveEntities) {
+ Rectangle box = collisionBoxMapper.Get(entityId).Rounded;
+
+ int minX = box.X;
+ int maxX = box.X + box.Width;
+
+ int minY = box.Y;
+ int maxY = box.Y + box.Height;
+
+ for (int i = minX; i < maxX; i++)
+ for (int j = minY; j < maxY; j++) {
+ RectangleF? blockBox = _chunkMap.TestBoundingBox(i, j);
+ if (blockBox.HasValue) {
+ _spriteBatch.DrawRectangle(new RectangleF(i, j, blockBox.Value.Width, blockBox.Value.Height), Color.Red, .05f, 0f);
+ } else {
+ _spriteBatch.DrawRectangle(new RectangleF(i, j, 1f, 1f), Color.Green, .05f, 0f);
+ }
+ }
+ }
+
+ _spriteBatch.End();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/physics/PhysicsSystem.cs b/source/game/systems/physics/PhysicsSystem.cs
new file mode 100644
index 0000000..3963cc1
--- /dev/null
+++ b/source/game/systems/physics/PhysicsSystem.cs
@@ -0,0 +1,42 @@
+using Celesteia.Game.Components;
+using Celesteia.Game.Components.Physics;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.Physics {
+ public class PhysicsSystem : EntityUpdateSystem {
+ public const float GRAVITY_CONSTANT = 9.7f;
+
+ public PhysicsSystem() : base(Aspect.All(typeof(PhysicsEntity), typeof(TargetPosition))) {}
+
+ private ComponentMapper<TargetPosition> targetPositionMapper;
+ private ComponentMapper<PhysicsEntity> physicsEntityMapper;
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ targetPositionMapper = mapperService.GetMapper<TargetPosition>();
+ physicsEntityMapper = mapperService.GetMapper<PhysicsEntity>();
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (int entityId in ActiveEntities) {
+ TargetPosition targetPosition = targetPositionMapper.Get(entityId);
+ PhysicsEntity physicsEntity = physicsEntityMapper.Get(entityId);
+
+ // Apply gravity if applicable
+ if (physicsEntity.Gravity) {
+ if (physicsEntity.CollidingDown && physicsEntity.Velocity.Y > 0f) {
+ physicsEntity.SetVelocity(physicsEntity.Velocity.X, 0.1f);
+ }
+
+ physicsEntity.AddVelocity(0f, physicsEntity.Mass * PhysicsSystem.GRAVITY_CONSTANT * gameTime.GetElapsedSeconds());
+ }
+
+ targetPosition.Target += physicsEntity.Velocity * gameTime.GetElapsedSeconds();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/physics/PhysicsWorldCollisionSystem.cs b/source/game/systems/physics/PhysicsWorldCollisionSystem.cs
new file mode 100644
index 0000000..ba8da22
--- /dev/null
+++ b/source/game/systems/physics/PhysicsWorldCollisionSystem.cs
@@ -0,0 +1,83 @@
+using System;
+using Celesteia.Game.Components;
+using Celesteia.Game.Components.Physics;
+using Celesteia.Game.Planets;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended;
+using MonoGame.Extended.Entities;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.Physics {
+ public class PhysicsWorldCollisionSystem : EntityUpdateSystem {
+ private ChunkMap _chunkMap;
+
+ public PhysicsWorldCollisionSystem(ChunkMap chunkMap) : base(Aspect.All(typeof(TargetPosition), typeof(PhysicsEntity), typeof(CollisionBox))) {
+ _chunkMap = chunkMap;
+ }
+
+ private ComponentMapper<Transform2> transformMapper;
+ private ComponentMapper<TargetPosition> targetPositionMapper;
+ private ComponentMapper<PhysicsEntity> physicsEntityMapper;
+ private ComponentMapper<CollisionBox> collisionBoxMapper;
+
+ public override void Initialize(IComponentMapperService mapperService)
+ {
+ transformMapper = mapperService.GetMapper<Transform2>();
+ targetPositionMapper = mapperService.GetMapper<TargetPosition>();
+ physicsEntityMapper = mapperService.GetMapper<PhysicsEntity>();
+ collisionBoxMapper = mapperService.GetMapper<CollisionBox>();
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ foreach (int entityId in ActiveEntities) {
+ Transform2 transform = transformMapper.Get(entityId);
+ TargetPosition targetPosition = targetPositionMapper.Get(entityId);
+ PhysicsEntity physicsEntity = physicsEntityMapper.Get(entityId);
+ CollisionBox collisionBox = collisionBoxMapper.Get(entityId);
+
+ collisionBox.Update(targetPosition.Target);
+
+ int minX = (int)MathF.Floor(collisionBox.Bounds.Center.X - (collisionBox.Bounds.Width / 2f));
+ int maxX = (int)MathF.Ceiling(collisionBox.Bounds.Center.X + (collisionBox.Bounds.Width / 2f));
+
+ int minY = (int)MathF.Floor(collisionBox.Bounds.Center.Y - (collisionBox.Bounds.Height / 2f));
+ int maxY = (int)MathF.Ceiling(collisionBox.Bounds.Center.Y + (collisionBox.Bounds.Height / 2f));
+
+ bool collLeft = false;
+ bool collRight = false;
+ bool collUp = false;
+ bool collDown = false;
+
+ for (int i = minX; i < maxX; i++)
+ for (int j = minY; j < maxY; j++) {
+ RectangleF? blockBox = _chunkMap.TestBoundingBox(i, j);
+ if (blockBox.HasValue) {
+ RectangleF inter = RectangleF.Intersection(collisionBox.Bounds, blockBox.Value);
+
+ if (inter.IsEmpty) continue;
+
+ if (inter.Width < inter.Height) {
+ collLeft = blockBox.Value.Center.X < collisionBox.Bounds.Center.X;
+ collRight = blockBox.Value.Center.X > collisionBox.Bounds.Center.X;
+
+ targetPosition.Target += new Vector2(blockBox.Value.Center.X < collisionBox.Bounds.Center.X ? inter.Width : -inter.Width, 0f);
+ } else {
+ collUp = blockBox.Value.Center.Y < collisionBox.Bounds.Center.Y;
+ collDown = blockBox.Value.Center.Y > collisionBox.Bounds.Center.Y;
+
+ targetPosition.Target += new Vector2(0f, blockBox.Value.Center.Y < collisionBox.Bounds.Center.Y ? inter.Height : -inter.Height);
+ }
+
+ collisionBox.Update(targetPosition.Target);
+ }
+ }
+
+ physicsEntity.CollidingDown = collDown;
+ physicsEntity.CollidingUp = collUp;
+ physicsEntity.CollidingLeft = collLeft;
+ physicsEntity.CollidingRight = collRight;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/game/systems/ui/GameGUIDrawSystem.cs b/source/game/systems/ui/GameGUIDrawSystem.cs
new file mode 100644
index 0000000..0140786
--- /dev/null
+++ b/source/game/systems/ui/GameGUIDrawSystem.cs
@@ -0,0 +1,12 @@
+using Celesteia.GUIs.Game;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Entities.Systems;
+
+namespace Celesteia.Game.Systems.UI {
+ public class GameGUIDrawSystem : DrawSystem {
+ private GameGUI _gui;
+
+ public GameGUIDrawSystem(GameGUI gui) => _gui = gui;
+ public override void Draw(GameTime gameTime) => _gui.Draw(gameTime);
+ }
+} \ No newline at end of file