Skip to content

Commit

Permalink
feat: pivot system working
Browse files Browse the repository at this point in the history
  • Loading branch information
cherrynik committed Jul 2, 2024
1 parent 685f910 commit f2fa7db
Show file tree
Hide file tree
Showing 18 changed files with 155 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ private static void RegisterDataComponents(IServiceRegistry serviceRegistry)
var texture = factory.GetInstance<string, Texture2D>("Content/SpriteSheets/Main.png");
var sprite = new Sprite("Pebble", new TextureRegion("Pebble", texture, new(208, 48, 16, 16)));

return new SpriteComponent(sprite);
return new SpriteComponent(sprite, factory.GetInstance<TransformComponent>());
}, "Pebble");

serviceRegistry.RegisterSingleton(factory =>
{
var texture = factory.GetInstance<string, Texture2D>("Content/SpriteSheets/Main.png");
var sprite = new Sprite("Tree", new TextureRegion("Tree", texture, new(144, 0, 48, 96)));

return new SpriteComponent(sprite);
return new SpriteComponent(sprite, factory.GetInstance<TransformComponent>());
}, "Tree");
RegisterTransformComponent(serviceRegistry);
RegisterRectangleColliderComponent(serviceRegistry);
Expand Down Expand Up @@ -106,7 +106,7 @@ private static void RegisterCameraComponent(IServiceRegistry serviceRegistry)
private static void RegisterPlayerMovementComponent(IServiceRegistry serviceRegistry)
{
serviceRegistry.RegisterSingleton(_ => new InputMovableComponent());
serviceRegistry.RegisterSingleton(_ => new MovableComponent());
serviceRegistry.RegisterSingleton(_ => new MovableComponent(5f));
}

private static void RegisterSpriteComponent(IServiceRegistry serviceRegistry)
Expand All @@ -119,7 +119,7 @@ private static void RegisterSpriteComponent(IServiceRegistry serviceRegistry)
Dictionary<Sector, AnimatedSprite> idle = getAnimations(PlayerSpriteSheetPath, "Idle");
AnimatedSprite defaultSprite = idle[Sector.Down];

return new SpriteComponent(defaultSprite);
return new SpriteComponent(defaultSprite, factory.GetInstance<TransformComponent>());
}, "Player");

// serviceRegistry.RegisterSingleton(factory =>
Expand Down Expand Up @@ -150,7 +150,10 @@ private static void RegisterTransformComponent(IServiceRegistry serviceRegistry)
serviceRegistry.RegisterTransient(_ => new TransformComponent());

serviceRegistry.RegisterSingleton(_ =>
new TransformComponent { Position = new(316, 116) }, "PlayerEntity");
new TransformComponent { Position = new(0, 4) }, "PlayerAnimations");

serviceRegistry.RegisterSingleton(_ =>
new TransformComponent { Position = new(316, 116), Pivot = Sector.Up }, "PlayerEntity");

serviceRegistry.RegisterSingleton(_ =>
new TransformComponent { Position = new(300, 100) }, "DummyEntity");
Expand Down Expand Up @@ -190,7 +193,8 @@ private static void RegisterCharacterAnimatorComponent(IServiceRegistry serviceR
var movementAnimations = factory.GetInstance<MovementAnimationsComponent>("PlayerEntity");
const Sector facing = Sector.Right;

return new CharacterAnimatorComponent(facing, movementAnimations.IdleAnimations[facing]);
return new CharacterAnimatorComponent(facing, movementAnimations.IdleAnimations[facing],
factory.GetInstance<TransformComponent>("PlayerAnimations"));
}, "PlayerEntity");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private static void RegisterEntryPoint(IServiceRegistry serviceRegistry)
#if DEBUG
const int w = 2, h = 2;
Texture2D pivotPixel = new(factory.GetInstance<SpriteBatch>().GraphicsDevice, w, h);
pivotPixel.SetData(Enumerable.Repeat(Color.Red, w * h).ToArray());
pivotPixel.SetData(Enumerable.Repeat(Color.Khaki, w * h).ToArray());

Texture2D colliderPixel = new(factory.GetInstance<SpriteBatch>().GraphicsDevice, w, h);
colliderPixel.SetData(Enumerable.Repeat(Color.LawnGreen, w * h).ToArray());
Expand Down
1 change: 1 addition & 0 deletions src/Libs/Components/Data/RectangleColliderComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ namespace Components.Data;
public struct RectangleColliderComponent : IComponent
{
public Rectangle Size;
public TransformComponent LocalTransform;
public bool IsTrigger;
}
14 changes: 13 additions & 1 deletion src/Libs/Components/Data/TransformComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@ public struct TransformComponent : IComponent
{
public Vector2 Position;
public Vector2 Velocity;
public Sector Pivot;
public Sector Pivot; // Shouldn't be set in DI, as it's registered at LDtk

public Vector2 GetOffPivot(float w, float h) => GetOffPivot(w, h, Pivot);

private static Vector2 GetOffPivot(float w, float h, Sector sector)
{
var pivot = MathUtils.SectorToVector(sector);

return new Vector2(
(pivot.X + 1) * w / 2,
(-pivot.Y + 1) * h / 2
);
}
}

// Input Scan System -> Write Velocity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
using System.Numerics;
using Components.Data;
using MonoGame.Aseprite.Sprites;
using Scellecs.Morpeh;
using Services.Math;

namespace Components.Render.Animation;

public struct CharacterAnimatorComponent(Sector facing, AnimatedSprite animation) : IComponent
public interface IPivotted
{
public Vector2 GetOffPivot(TransformComponent entityTransform);
}

public struct CharacterAnimatorComponent(Sector facing, AnimatedSprite animation, TransformComponent transform)
: IComponent, IPivotted
{
public Sector Facing = facing;
public AnimatedSprite Animation = animation;
public TransformComponent LocalTransform { get; } = transform;

public Vector2 GetOffPivot(TransformComponent entityTransform) =>
entityTransform.GetOffPivot(Animation.Width, Animation.Height);
}
11 changes: 9 additions & 2 deletions src/Libs/Components/Render/Static/SpriteComponent.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
using MonoGame.Aseprite.Sprites;
using System.Numerics;
using Components.Data;
using Components.Render.Animation;
using MonoGame.Aseprite.Sprites;
using Scellecs.Morpeh;

namespace Components.Render.Static;

public readonly struct SpriteComponent(Sprite sprite) : IComponent
public readonly struct SpriteComponent(Sprite sprite, TransformComponent transform) : IComponent, IPivotted
{
public Sprite Sprite { get; } = sprite;
public TransformComponent LocalTransform { get; } = transform;

public Vector2 GetOffPivot(TransformComponent entityTransform) =>
entityTransform.GetOffPivot(Sprite.Width, Sprite.Height);
}
5 changes: 4 additions & 1 deletion src/Libs/Components/Tags/MovableComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@

namespace Components.Tags;

public struct MovableComponent : IComponent;
public struct MovableComponent(float speed) : IComponent
{
public float Speed = speed;
};
1 change: 1 addition & 0 deletions src/Libs/Entities/Factories/Items/Trees/TreeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using LightInject;
using Scellecs.Morpeh;
using Scellecs.Morpeh.Extended.Extensions;
using Services.Math;

namespace Entities.Factories.Items.Trees;

Expand Down
5 changes: 5 additions & 0 deletions src/Libs/Services/Math/MathUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public static class MathUtils
{
public static Vector2 SectorToVector(Sector sector)
{
if (sector is Sector.Center)
{
return Vector2.Zero;
}

const int sectors = 8;

var angle = 360.0 / sectors * (int)sector;
Expand Down
5 changes: 1 addition & 4 deletions src/Libs/Services/Movement/Movement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ public class SimpleMovement : IMovement
{
public Vector2 Move(Vector2 from, Vector2 by)
{
if (by.Equals(Vector2.Zero))
{
return from;
}
if (by.Equals(Vector2.Zero)) return from;

return from + Vector2.Normalize(by);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Xna.Framework.Graphics;
using Scellecs.Morpeh;
using Scellecs.Morpeh.Extended;
using Services.Math;

namespace Systems.Debugging.Render;

Expand Down Expand Up @@ -44,7 +45,10 @@ public void OnUpdate(float deltaTime)
ref var transform = ref e.GetComponent<TransformComponent>();
ref var rectCollider = ref e.GetComponent<RectangleColliderComponent>();

DrawRectangleBorders(camera.WorldToScreen(transform.Position), rectCollider.Size);
DrawRectangleBorders(
camera.WorldToScreen(transform.Position) + rectCollider.LocalTransform.Position -
transform.GetOffPivot(rectCollider.Size.Width, rectCollider.Size.Height),
rectCollider.Size);
}
}

Expand Down
30 changes: 28 additions & 2 deletions src/Libs/Systems.Debugging/Render/PivotRenderSystem.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Components.Data;
using Components.Render.Animation;
using Components.Render.Static;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Scellecs.Morpeh;
using Scellecs.Morpeh.Extended;
using Color = Microsoft.Xna.Framework.Color;

namespace Systems.Debugging.Render;

Expand All @@ -28,7 +30,31 @@ public void OnUpdate(float deltaTime)
{
ref var transform = ref e.GetComponent<TransformComponent>();

spriteBatch.Draw(texture: pixel, position: camera.WorldToScreen(transform.Position), color: Color.Gold);
if (e.Has<SpriteComponent>())
{
ref var sprite = ref e.GetComponent<SpriteComponent>();
var pivotOffset = transform.GetOffPivot(sprite.Sprite.Width, sprite.Sprite.Height);
spriteBatch.Draw(texture: pixel,
position: camera.WorldToScreen(transform.Position) + sprite.LocalTransform.Position -
pivotOffset,
color: Color.White,
sourceRectangle: new Rectangle(0, 0, 16, 16));
}

if (e.Has<CharacterAnimatorComponent>())
{
ref var characterAnimator = ref e.GetComponent<CharacterAnimatorComponent>();
spriteBatch.Draw(texture: pixel,
position: camera.WorldToScreen(transform.Position) + characterAnimator.LocalTransform.Position -
transform.GetOffPivot(characterAnimator.Animation.Width,
characterAnimator.Animation.Height),
color: Color.White,
sourceRectangle: new Rectangle(0, 0, 16, 16));
}

spriteBatch.Draw(texture: pixel,
position: camera.WorldToScreen(transform.Position),
color: Color.Gold);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Libs/Systems.Debugging/World/EntitiesList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ private static void DrawComponentEditor(Type component, Entity e)
ref TransformComponent transformComponent = ref e.GetComponent<TransformComponent>();

ImGui.SliderFloat2("Position", ref transformComponent.Position, 0, 300);
ImGui.Text($"Pivot: {transformComponent.Pivot.ToString()}");
}
else if (component == typeof(InventoryComponent))
{
Expand Down
5 changes: 4 additions & 1 deletion src/Libs/Systems/MovementSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ public void OnUpdate(float deltaTime)
foreach (Entity e in filter)
{
ref TransformComponent transform = ref e.GetComponent<TransformComponent>();
ref MovableComponent movableComponent = ref e.GetComponent<MovableComponent>();

transform.Position = movement.Move(from: transform.Position, by: transform.Velocity);
// TODO: make frame independent, make able to change the speed
transform.Position =
movement.Move(from: transform.Position, by: transform.Velocity * deltaTime * movableComponent.Speed);
}
}

Expand Down
27 changes: 25 additions & 2 deletions src/Libs/Systems/Render/RenderCharacterMovementAnimationSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Xna.Framework.Graphics;
using Scellecs.Morpeh;
using Scellecs.Morpeh.Extended;
using Services.Math;

namespace Systems.Render;

Expand Down Expand Up @@ -42,15 +43,19 @@ public void OnUpdate(float deltaTime)
if (e.Has<CharacterAnimatorComponent>())
{
ref var animator = ref e.GetComponent<CharacterAnimatorComponent>();
var pivotOffset = animator.GetOffPivot(transform);
var localTransform = animator.LocalTransform;

animator.Animation.Draw(spriteBatch, at);
animator.Animation.Draw(spriteBatch, at + localTransform.Position - pivotOffset);
}

if (e.Has<SpriteComponent>())
{
ref var sprite = ref e.GetComponent<SpriteComponent>();
var pivotOffset = sprite.GetOffPivot(transform);
var localTransform = sprite.LocalTransform;

sprite.Sprite.Draw(spriteBatch, at);
sprite.Sprite.Draw(spriteBatch, at + localTransform.Position - pivotOffset);
}
}
}
Expand All @@ -71,6 +76,24 @@ private static IEnumerable<Entity> SortEntitiesByYPosition(Filter filter)
return entities.OrderBy(x =>
{
ref var transform = ref x.GetComponent<TransformComponent>();

// if (x.Has<SpriteComponent>())
// {
// ref var sprite = ref x.GetComponent<SpriteComponent>();
// var localTransform = sprite.LocalTransform;
// return transform.Position.Y + localTransform.Position.Y -
// transform.GetOffPivot(sprite.Sprite.Width, sprite.Sprite.Height).Y;
// }
//
// if (x.Has<CharacterAnimatorComponent>())
// {
// ref var animator = ref x.GetComponent<CharacterAnimatorComponent>();
// var localTransform = animator.LocalTransform;
//
// return transform.Position.Y + localTransform.Position.Y -
// transform.GetOffPivot(animator.Animation.Width, animator.Animation.Height).Y;
// }

return transform.Position.Y;
});
}
Expand Down
18 changes: 9 additions & 9 deletions src/Libs/Systems/Render/TilesRenderingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ private void RenderLevel(LDtkLevel level, CameraComponent camera)
switch (layer._Type)
{
case LayerType.Tiles:
foreach (TileInstance tile in layer.GridTiles.Where(_ => layer._TilesetDefUid.HasValue))
{
Vector2 tilePos = new(tile.Px.X + layer._PxTotalOffsetX, tile.Px.Y + layer._PxTotalOffsetY);
var position = camera.WorldToScreen(tilePos);
Rectangle rect = new(tile.Src.X, tile.Src.Y, layer._GridSize, layer._GridSize);
SpriteEffects mirror = (SpriteEffects)tile.F;
spriteBatch.Draw(texture, position, rect, new Color(1f, 1f, 1f, layer._Opacity), 0,
Vector2.Zero, 1f, mirror, 0);
}
// foreach (TileInstance tile in layer.GridTiles.Where(_ => layer._TilesetDefUid.HasValue))
// {
// Vector2 tilePos = new(tile.Px.X + layer._PxTotalOffsetX, tile.Px.Y + layer._PxTotalOffsetY);
// var position = camera.WorldToScreen(tilePos);
// Rectangle rect = new(tile.Src.X, tile.Src.Y, layer._GridSize, layer._GridSize);
// SpriteEffects mirror = (SpriteEffects)tile.F;
// spriteBatch.Draw(texture, position, rect, new Color(1f, 1f, 1f, layer._Opacity), 0,
// new Vector2(0, 0), 1f, mirror, 0);
// }

break;

Expand Down
22 changes: 19 additions & 3 deletions src/Libs/Systems/WorldInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,31 @@ public void OnAwake()
if (e is null) continue;

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

transform.Pivot = MathUtils.LdtkPivotToSector(new Vector2(entity._Pivot.X, entity._Pivot.Y));
var pivotOffset = MathUtils.SectorToVector(transform.Pivot);
var mappedLDtkPivot = MapAndFlip(new Vector2(entity._Pivot.X, entity._Pivot.Y));
transform.Pivot = MathUtils.VectorToSector(mappedLDtkPivot);
// var pivotOffset = MathUtils.SectorToVector(transform.Pivot);

transform.Position = new Vector2((float)entity._WorldX, (float)entity._WorldY);

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.

Check warning on line 58 in src/Libs/Systems/WorldInitializer.cs

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Nullable value type may be null.
}
}
}

private static Vector2 MapAndFlip(Vector2 v)
{
// Define the mapping and flipping logic
float[] mapping = [-1, 0, 1];

// Map x component to the corresponding index in mapping array
int indexX = (int)(v.X * (mapping.Length - 1));
float mappedX = mapping[indexX];

// Map y component to the corresponding index in mapping array and flip y
int indexY = (int)(v.Y * (mapping.Length - 1));
float mappedY = -mapping[indexY];

return new Vector2(mappedX, mappedY);
}

public void Dispose()
{
}
Expand Down
8 changes: 6 additions & 2 deletions src/UnitTests/UnitTests.Services/SectorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ public void Setup()
}

[Test]
public void VectorZeroIsSectorRight()
public void Center()
{
Sector sector = MathUtils.VectorToSector(Vector2.Zero);
Vector2 center = new(0, 0);
Sector sector = MathUtils.VectorToSector(center);
Assert.That(sector, Is.EqualTo(Sector.Right));

Vector2 inverted = MathUtils.SectorToVector(Sector.Center);
Assert.That(inverted, Is.EqualTo(new Vector2(float.Sign(center.X), float.Sign(center.Y))));
}

[Test]
Expand Down

0 comments on commit f2fa7db

Please sign in to comment.