Created
August 14, 2025 20:33
-
-
Save PumpkinPaul/2e418da8556dfdbef93fb5fc98bed606 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using MoonTools.ECS; | |
using Pathogen.Game.ECS.Components; | |
using System.Numerics; | |
using ECSSystem = MoonTools.ECS.System; | |
namespace Pathogen.Game.ECS.Systems; | |
/// <summary> | |
/// Sets the TransformMatrixComponent component for entities in the world. | |
/// </summary> | |
public sealed class TransformSystem : ECSSystem | |
{ | |
readonly Filter _filter; | |
public TransformSystem( | |
World world | |
) : base(world) | |
{ | |
_filter = FilterBuilder | |
.Include<TransformComponent>() | |
.Include<TransformMatrixComponent>() | |
.Build(); | |
} | |
public override void Update(TimeSpan elapsedTime) | |
{ | |
// Consider the following scene hierarchy... | |
// A | |
// |__ B | |
// |__ C | |
// |__ D | |
// E | |
// |__ F | |
// G | |
// |__ H | |
// All entities, A to H will be present in the filter and we process them in that order (A, B, C, D, E, F, G, H) | |
// Normal foreach iteration starts with entities added to the world last (H) going towards entities added to the world first (A). | |
// As we need to ensure parent transforms are updated before child transforms, we use an old Skool for loop. | |
// A is a root entity so there will be NO InRelation, the TransformMatrixComponent will be the result of A's TransformComponent. | |
// Next we process B, it DOES have an InRelation to a parent (A) so the TransformMatrixComponent will be the result of | |
// B's TramsformComponent multipled by A's TransformMatrixComponent (in that order). | |
// Next we process C, it DOES have an InRelation to a parent (B) so the TransformMatrixComponent will be the result of | |
// C's TransformComponent multipled by B's TransformMatrixComponent (in that order). | |
// ...and so on... | |
var count = _filter.Count; | |
for (var i = 0; i < count; i++) | |
{ | |
var entity = _filter.NthEntity(i); | |
ref readonly var transform = ref Get<TransformComponent>(entity); | |
var localMatrix = Matrix4x4.CreateScale(transform.Scale) * Matrix4x4.CreateFromQuaternion(transform.Rotation) * Matrix4x4.CreateTranslation(transform.Position); | |
if (HasInRelation<TransformParentChildRelation>(entity) == false) | |
{ | |
Set(entity, new TransformMatrixComponent | |
{ | |
Value = localMatrix | |
}); | |
continue; | |
} | |
// Children can only have one transform parent so get the singleton / first | |
var parent = InRelationSingleton<TransformParentChildRelation>(entity); | |
ref readonly var parentTransformMatrix = ref Get<TransformMatrixComponent>(parent); | |
Set(entity, new TransformMatrixComponent | |
{ | |
Value = localMatrix * parentTransformMatrix.Value | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment