Skip to content

Commit

Permalink
refactor: camera system & impls
Browse files Browse the repository at this point in the history
  • Loading branch information
cherrynik committed Nov 9, 2023
1 parent 5911f5a commit e70358f
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ private static void RegisterDataComponents(IServiceRegistry serviceRegistry)

private static void RegisterTagComponents(IServiceRegistry serviceRegistry)
{
RegisterCameraComponent(serviceRegistry);
RegisterPlayerMovementComponent(serviceRegistry);
}

Expand All @@ -49,6 +50,11 @@ private static void RegisterAnimatedRenderComponents(IServiceRegistry serviceReg
RegisterCharacterAnimatorComponent(serviceRegistry);
}

private static void RegisterCameraComponent(IServiceRegistry serviceRegistry)
{
serviceRegistry.RegisterSingleton(_ => new CameraComponent());
}

private static void RegisterPlayerMovementComponent(IServiceRegistry serviceRegistry)
{
serviceRegistry.RegisterSingleton(_ => new InputMovableComponent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ private static void RegisterEntity(IServiceRegistry serviceRegistry) =>
factory.GetInstance<InputMovableComponent>(),
factory.GetInstance<MovableComponent>(),
factory.GetInstance<TransformComponent>("PlayerEntity"),
factory.GetInstance<CameraComponent>(),
factory.GetInstance<RectangleCollisionComponent>(),
factory.GetInstance<MovementAnimationsComponent>(),
factory.GetInstance<CharacterAnimatorComponent>("PlayerEntity")));
Expand Down
6 changes: 3 additions & 3 deletions src/Apps/GameDesktop/CompositionRoots/GameCompositionRoot.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using GameDesktop.Resources.Internal;
using LightInject;
using Microsoft.Xna.Framework;
using MonoGame.ImGuiNet;
using Serilog;

namespace GameDesktop.CompositionRoots;
Expand All @@ -18,13 +17,14 @@ public void Compose(IServiceRegistry serviceRegistry)
Game game = new(factory.GetInstance<ILogger>(),
factory.GetInstance<IServiceContainer>())
{
IsMouseVisible = IsMouseVisible, Content = { RootDirectory = AppVariable.ContentRootDirectory, }
IsMouseVisible = IsMouseVisible,
Content = { RootDirectory = AppVariable.ContentRootDirectory, },
};

// Hack. Resolving cycle dependency issue (fundamental architecture)
// Implicitly adds itself in the game services container.
new GraphicsDeviceManager(game);

return game;
});
}
Expand Down
9 changes: 8 additions & 1 deletion src/Apps/GameDesktop/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class Game : Microsoft.Xna.Framework.Game
private SpriteBatch _spriteBatch;

private SystemsGroup _systemsGroup;
private SystemsGroup _preRenderSystemsGroup;
private SystemsGroup _renderSystemsGroup;
private SystemsGroup _debugSystemsGroup;

Expand Down Expand Up @@ -84,8 +85,12 @@ protected override void LoadContent()
_systemsGroup.AddSystem(new InputSystem(world, new KeyboardInput()));
_systemsGroup.AddSystem(new MovementSystem(world, new SimpleMovement()));

_preRenderSystemsGroup = world.CreateSystemsGroup();
_preRenderSystemsGroup.AddSystem(new RenderCharacterMovementSystem(world, _spriteBatch));

_renderSystemsGroup = world.CreateSystemsGroup();
_renderSystemsGroup.AddSystem(new RenderCharacterMovementSystem(world, _spriteBatch));
_renderSystemsGroup.AddSystem(new CameraSystem(world,
new FollowingCamera(_spriteBatch, new Viewport(0, 0, 800, 480))));

#if DEBUG
_debugSystemsGroup = world.CreateSystemsGroup();
Expand Down Expand Up @@ -129,6 +134,8 @@ protected override void Draw(GameTime gameTime)
GraphicsDevice.Clear(Color.CornflowerBlue);

_spriteBatch.Begin(samplerState: SamplerState.PointClamp);
// I guess, pre-render, pre-ui systems would go in update, to avoid frames skipping
_preRenderSystemsGroup.Update(deltaTime);
_renderSystemsGroup.Update(deltaTime);
_spriteBatch.End();

Expand Down
7 changes: 7 additions & 0 deletions src/Libs/Components/Tags/CameraComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Scellecs.Morpeh;

namespace Components.Tags;

public struct CameraComponent : IComponent
{
}
4 changes: 4 additions & 0 deletions src/Libs/Entities/PlayerEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,23 @@ public class PlayerEntity
private readonly InputMovableComponent _inputMovable;
private readonly MovableComponent _movable;
private readonly TransformComponent _transform;
private readonly CameraComponent _cameraComponent;
private readonly RectangleCollisionComponent _rectangleCollision;
private readonly MovementAnimationsComponent _movementAnimations;
private readonly CharacterAnimatorComponent _characterAnimator;

public PlayerEntity(InputMovableComponent inputMovable,
MovableComponent movable,
TransformComponent transform,
CameraComponent cameraComponent,
RectangleCollisionComponent rectangleCollision,
MovementAnimationsComponent movementAnimations,
CharacterAnimatorComponent characterAnimator)
{
_inputMovable = inputMovable;
_movable = movable;
_transform = transform;
_cameraComponent = cameraComponent;
_rectangleCollision = rectangleCollision;
_movementAnimations = movementAnimations;
_characterAnimator = characterAnimator;
Expand All @@ -73,6 +76,7 @@ public Entity Create(World @in)

private void AddTags(Entity e)
{
e.AddComponent(_cameraComponent);
e.AddComponent(_inputMovable);
e.AddComponent(_movable);
}
Expand Down
49 changes: 0 additions & 49 deletions src/Libs/Systems/Render/CameraFollowingSystem.cs

This file was deleted.

201 changes: 201 additions & 0 deletions src/Libs/Systems/Render/CameraSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using System.Numerics;
using Components.Data;
using Components.Render.Animation;
using Components.Render.Static;
using Components.Tags;
using Microsoft.Xna.Framework.Graphics;
using Scellecs.Morpeh;

namespace Systems.Render;

public interface ICamera
{
void Render(Entity e);
}

public abstract class BaseCamera
{
private readonly SpriteBatch _spriteBatch;
protected readonly Viewport _viewport;

protected BaseCamera(SpriteBatch spriteBatch, Viewport viewport)
{
_spriteBatch = spriteBatch;
_viewport = viewport;
}

protected void RenderCharacterAnimator(Entity e, Vector2 at)
{
if (!e.Has<CharacterAnimatorComponent>())
{
return;
}

ref var animator = ref e.GetComponent<CharacterAnimatorComponent>();
animator.Animation.Draw(_spriteBatch, at);
}

protected void RenderSprite(Entity e, Vector2 at)
{
if (!e.Has<SpriteComponent>())
{
return;
}

ref var spriteComponent = ref e.GetComponent<SpriteComponent>();
spriteComponent.Sprite.Draw(_spriteBatch, at);
}
}

public class StaticCamera : BaseCamera, ICamera
{
public StaticCamera(SpriteBatch spriteBatch, Viewport viewport) : base(spriteBatch, viewport)
{
}

public void Render(Entity e)
{
if (!e.Has<TransformComponent>())
{
return;
}

ref var transform = ref e.GetComponent<TransformComponent>();

base.RenderCharacterAnimator(e, at: transform.Position);
base.RenderSprite(e, at: transform.Position);
}
}

public class FollowingCamera : BaseCamera, ICamera
{
private Vector2 _position;

public FollowingCamera(SpriteBatch spriteBatch, Viewport viewport) : base(spriteBatch, viewport)
{
}

public void Render(Entity e)
{
if (!e.Has<TransformComponent>())
{
return;
}

ref var transform = ref e.GetComponent<TransformComponent>();
Vector2 position = transform.Position;

if (e.Has<CameraComponent>())
{
_position = GetCenteredPosition(off: position);
}

Vector2 relativePosition = position - _position;

base.RenderCharacterAnimator(e, at: relativePosition);
base.RenderSprite(e, at: relativePosition);
}

private Vector2 GetCenteredPosition(Vector2 off) => new(
off.X - _viewport.Width / 2,
off.Y - _viewport.Height / 2);
}

public class CameraSystem : ISystem
{
private readonly ICamera _camera;
public World World { get; set; }

public CameraSystem(World world, ICamera camera)
{
World = world;
_camera = camera;
}

public void OnAwake()
{
}

public void OnUpdate(float deltaTime)
{
// TODO: Components in the range of visibility (world grid system?)
Filter filter = World.Filter.With<TransformComponent>().Build();

IEnumerable<Entity> entities = SortEntitiesByYPosition(filter);

foreach (Entity e in entities)
{
_camera.Render(e);
}
}

private static IEnumerable<Entity> SortEntitiesByYPosition(Filter filter)
{
List<Entity> entities = new List<Entity>();

foreach (Entity e in filter)
{
entities.Add(e);
}

return entities.OrderBy(x =>
{
ref var transform = ref x.GetComponent<TransformComponent>();
return transform.Position.Y;
});
}

public void Dispose()
{
}
}

// using Entitas;
// using Entitas.Extended;
// using Microsoft.Xna.Framework;
// using Microsoft.Xna.Framework.Graphics;
//
// namespace Systems;
//
// public class CameraFollowingSystem : IDrawSystem
// {
// private readonly Contexts _contexts;
// private readonly IGroup<GameEntity> _group;
//
// public CameraFollowingSystem(Contexts contexts, IGroup<GameEntity> group)
// {
// _contexts = contexts;
// _group = group;
// }
//
// // todo: refactor, put the logic in impl
// // todo: smooth diagonal movement
// private Vector2 GetPosition(GameEntity target) =>
// new(
// (float)target.camera.Size.Width / 2 -
// (float)target.movementAnimation.PlayingAnimation.Width / 2,
// (float)target.camera.Size.Height / 2 -
// (float)target.movementAnimation.PlayingAnimation.Height / 2);
//
// public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
// {
// GameEntity[] entities = _group.GetEntities();
//
// spriteBatch.Begin(samplerState: SamplerState.PointWrap);
//
// var target = _contexts.game.cameraEntity;
// foreach (GameEntity e in entities)
// {
// Vector2 otherAt = e.transform.Position - (target?.transform.Position ?? Vector2.Zero);
// if (e.hasSprite)
// {
// e.sprite.Sprite.Draw(spriteBatch, otherAt);
// // todo: drawing complex entities' sprite/animated components
// }
//
// target?.movementAnimation.PlayingAnimation.Draw(spriteBatch, GetPosition(target));
// }
//
// spriteBatch.End();
// }
// }
Loading

0 comments on commit e70358f

Please sign in to comment.