From 9af44d48b38e1807132989e358b553a201ebce61 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 17 Mar 2025 21:32:37 +0300 Subject: [PATCH 01/32] refactor: code styles enforced with .editorconfig --- .editorconfig | 225 ++++++++++++++++++ Engine.Core/Abstract/BaseEntity.cs | 1 - Engine.Core/Abstract/IBehaviourController.cs | 1 - Engine.Core/Abstract/ICoroutineYield.cs | 2 - Engine.Core/Abstract/ITransform.cs | 1 - Engine.Core/BehaviourBase.cs | 2 - Engine.Core/BehaviourController.cs | 10 +- Engine.Core/Exceptions/AssignException.cs | 3 +- .../Exceptions/NotAssignedException.cs | 2 +- Engine.Core/GameManager.cs | 3 +- Engine.Core/Transform.cs | 3 +- Engine.Physics2D/Abstract/IShapeCollider2D.cs | 1 - Engine.Physics2D/Collider2DBehaviourBase.cs | 1 - Engine.Physics2D/Collider2DCircleBehaviour.cs | 2 - Engine.Physics2D/Collider2DShapeBehaviour.cs | 1 - Engine.Physics2D/CollisionDetector2D.cs | 4 +- Engine.Physics2D/Physics2D.cs | 4 +- Engine.Physics2D/PhysicsEngine2D.cs | 4 +- Engine.Physics2D/PhysicsEngine2DCollector.cs | 5 +- Engine.Physics2D/Primitives/Line.cs | 12 +- Engine.Physics2D/Primitives/Projection.cs | 2 +- Engine.Physics2D/RigidBody2D.cs | 2 - 22 files changed, 243 insertions(+), 48 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b314c0c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,225 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +# (Please don't specify an indent_size here; that has too many unintended consequences.) +spelling_exclusion_path = SpellingExclusions.dic + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Powershell files +[*.ps1] +indent_size = 2 + +# Shell script files +[*.sh] +end_of_line = lf +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:none +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Whitespace options +dotnet_style_allow_multiple_blank_lines_experimental = false:error + +# IDE0055: Fix formatting +# Workaround for https://github.com/dotnet/roslyn/issues/70570 +dotnet_diagnostic.IDE0055.severity = suggestion + +# https://github.com/dotnet/roslyn-analyzers/issues/7436 - False positives from valid GetDeclaredSymbol calls +dotnet_diagnostic.RS1039.severity = none + +# CSharp code style settings: + +# IDE0029: Use coalesce expression +dotnet_diagnostic.IDE0029.severity = none + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +[*.cs] +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Whitespace options +csharp_style_allow_embedded_statements_on_same_line_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning +csharp_style_var_elsewhere = false:warning + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Blocks are allowed +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = warning + +[src/{Compilers,ExpressionEvaluator,Scripting}/**Test**/*.{cs,vb}] + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = none + +[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] + +# IDE0011: Add braces +csharp_prefer_braces = false:warning +# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = warning + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# CA1012: Abstract types should not have public constructors +dotnet_diagnostic.CA1012.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning + +# Prefer "var" everywhere +dotnet_diagnostic.IDE0007.severity = warning +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning +csharp_style_var_elsewhere = false:warning + +# csharp_style_allow_embedded_statements_on_same_line_experimental +dotnet_diagnostic.IDE2001.severity = warning + +# csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental +dotnet_diagnostic.IDE2004.severity = warning + +# csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental +dotnet_diagnostic.IDE2005.severity = warning + +# csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental +dotnet_diagnostic.IDE2006.severity = warning + +[src/{VisualStudio}/**/*.{cs,vb}] +# CA1822: Make member static +# There is a risk of accidentally breaking an internal API that partners rely on though IVT. +dotnet_code_quality.CA1822.api_surface = private + +[**/{ExternalAccess}/**/*.{cs,vb}] + +# RS0016: Only enable if API files are present +dotnet_public_api_analyzer.require_api_files = true + +dotnet_diagnostic.RS0051.severity = error +dotnet_diagnostic.RS0052.severity = error +dotnet_diagnostic.RS0053.severity = error +dotnet_diagnostic.RS0054.severity = error +dotnet_diagnostic.RS0055.severity = error +dotnet_diagnostic.RS0056.severity = error +dotnet_diagnostic.RS0057.severity = error +dotnet_diagnostic.RS0058.severity = error +dotnet_diagnostic.RS0059.severity = error +dotnet_diagnostic.RS0060.severity = error +dotnet_diagnostic.RS0061.severity = error diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/Abstract/BaseEntity.cs index 2209087..50fdb77 100644 --- a/Engine.Core/Abstract/BaseEntity.cs +++ b/Engine.Core/Abstract/BaseEntity.cs @@ -14,7 +14,6 @@ public abstract class BaseEntity : IEntity public event IAssignableStateEnable.OnStateEnableAssignedEventHandler? OnStateEnableAssigned = null; public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - private IStateEnable _stateEnable = null!; private bool _initialized = false; diff --git a/Engine.Core/Abstract/IBehaviourController.cs b/Engine.Core/Abstract/IBehaviourController.cs index 5bfb27a..f93d5ea 100644 --- a/Engine.Core/Abstract/IBehaviourController.cs +++ b/Engine.Core/Abstract/IBehaviourController.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; namespace Syntriax.Engine.Core.Abstract; diff --git a/Engine.Core/Abstract/ICoroutineYield.cs b/Engine.Core/Abstract/ICoroutineYield.cs index a0d9be2..1b03404 100644 --- a/Engine.Core/Abstract/ICoroutineYield.cs +++ b/Engine.Core/Abstract/ICoroutineYield.cs @@ -1,5 +1,3 @@ -using System.Collections; - namespace Syntriax.Engine.Core.Abstract; public interface ICoroutineYield diff --git a/Engine.Core/Abstract/ITransform.cs b/Engine.Core/Abstract/ITransform.cs index 7254020..cd5e66f 100644 --- a/Engine.Core/Abstract/ITransform.cs +++ b/Engine.Core/Abstract/ITransform.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Syntriax.Engine.Core.Abstract; diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs index 6f1872f..d0ba25e 100644 --- a/Engine.Core/BehaviourBase.cs +++ b/Engine.Core/BehaviourBase.cs @@ -10,12 +10,10 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour public event IBehaviour.OnPriorityChangedEventHandler? OnPriorityChanged = null; - private IBehaviourController _behaviourController = null!; private int _priority = 0; - public IBehaviourController BehaviourController => _behaviourController; public override bool IsActive => base.IsActive && BehaviourController.GameObject.StateEnable.Enabled; diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs index 3d51fec..154b5a5 100644 --- a/Engine.Core/BehaviourController.cs +++ b/Engine.Core/BehaviourController.cs @@ -1,7 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Syntriax.Engine.Core.Abstract; @@ -32,7 +31,6 @@ public class BehaviourController : IBehaviourController public IGameObject GameObject => _gameObject; - public bool IsInitialized { get => _initialized; @@ -67,7 +65,7 @@ public class BehaviourController : IBehaviourController public T? GetBehaviour() { - foreach (var behaviourItem in behaviours) + foreach (IBehaviour behaviourItem in behaviours) if (behaviourItem is T result) return result; @@ -77,7 +75,7 @@ public class BehaviourController : IBehaviourController public IList GetBehaviours() { List? behaviours = null; - foreach (var behaviourItem in this.behaviours) + foreach (IBehaviour behaviourItem in this.behaviours) { if (behaviourItem is not T behaviour) continue; @@ -92,7 +90,7 @@ public class BehaviourController : IBehaviourController public void GetBehaviours(IList results) { results.Clear(); - foreach (var behaviourItem in behaviours) + foreach (IBehaviour behaviourItem in behaviours) { if (behaviourItem is not T behaviour) continue; @@ -136,7 +134,6 @@ public class BehaviourController : IBehaviourController return true; } - public bool Initialize() { if (IsInitialized) @@ -210,7 +207,6 @@ public class BehaviourController : IBehaviourController behaviours.Add(behaviour); } - private void OnPriorityChange(IBehaviour sender, int previousPriority) { behaviours.Remove(sender); diff --git a/Engine.Core/Exceptions/AssignException.cs b/Engine.Core/Exceptions/AssignException.cs index c1e5d19..9adc27e 100644 --- a/Engine.Core/Exceptions/AssignException.cs +++ b/Engine.Core/Exceptions/AssignException.cs @@ -1,5 +1,4 @@ using System; -using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Core.Exceptions; @@ -11,7 +10,7 @@ public class AssignException : Exception // public static AssignException FromStateEnable(IStateEnable? stateEnable) // => new AssignException($"{nameof(IGameObject.AssignStateEnable)} failed on type {stateEnable?.GetType().ToString() ?? "\"null\""}"); public static AssignException From(T to, T2? value) - => new AssignException($"Assign operation has failed on T: {typeof(T).FullName}, value: {value?.GetType().ToString() ?? "\"null\""}"); + => new($"Assign operation has failed on T: {typeof(T).FullName}, value: {value?.GetType().ToString() ?? "\"null\""}"); // public static AssignException FromBehaviourController(IBehaviourController? behaviourController) // => new AssignException($"{nameof(IGameObject.AssignBehaviourController)} failed on type {behaviourController?.GetType().ToString() ?? "\"null\""}"); } diff --git a/Engine.Core/Exceptions/NotAssignedException.cs b/Engine.Core/Exceptions/NotAssignedException.cs index 8ff06df..8480fcf 100644 --- a/Engine.Core/Exceptions/NotAssignedException.cs +++ b/Engine.Core/Exceptions/NotAssignedException.cs @@ -9,7 +9,7 @@ public class NotAssignedException : Exception public NotAssignedException(string? message) : base(message) { } public static NotAssignedException From(T1 to, T2? value) where T1 : IAssignable - => new NotAssignedException($"{typeof(T2).Name} has not been assigned to {typeof(T1).Name}"); + => new($"{typeof(T2).Name} has not been assigned to {typeof(T1).Name}"); public static void Check(T1 to, T2? value) where T1 : IAssignable { diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index 0438c81..053bf64 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; @@ -102,7 +101,7 @@ public class GameManager : BaseEntity, IGameManager base.InitializeInternal(); NotAssignedException.Check(this, StateEnable); - foreach (var gameObject in GameObjects) + foreach (IGameObject gameObject in GameObjects) gameObject.Initialize(); } diff --git a/Engine.Core/Transform.cs b/Engine.Core/Transform.cs index 3603d28..3451e70 100644 --- a/Engine.Core/Transform.cs +++ b/Engine.Core/Transform.cs @@ -20,7 +20,6 @@ public class Transform : ITransform public event ITransform.OnChildrenAddedEventHandler? OnChildrenAdded = null; public event ITransform.OnChildrenRemovedEventHandler? OnChildrenRemoved = null; - private Vector2D _position = Vector2D.Zero; private Vector2D _scale = Vector2D.One; private float _rotation = 0f; @@ -179,7 +178,7 @@ public class Transform : ITransform { // TODO No idea how logical this is to propagate this to the children the way I'm doing right now. // I was originally gonna just call `child.OnParentChanged?.Invoke(child, child.Parent);` but seems an unnecessary call too? - foreach (var child in Children) // TODO CHECK ERRORS + foreach (ITransform child in Children) // TODO CHECK ERRORS child.SetParent(this); } diff --git a/Engine.Physics2D/Abstract/IShapeCollider2D.cs b/Engine.Physics2D/Abstract/IShapeCollider2D.cs index 96d4d1f..4280d27 100644 --- a/Engine.Physics2D/Abstract/IShapeCollider2D.cs +++ b/Engine.Physics2D/Abstract/IShapeCollider2D.cs @@ -2,7 +2,6 @@ using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D.Abstract; - /// /// Represents a with a custom . /// diff --git a/Engine.Physics2D/Collider2DBehaviourBase.cs b/Engine.Physics2D/Collider2DBehaviourBase.cs index 82abd91..5688655 100644 --- a/Engine.Physics2D/Collider2DBehaviourBase.cs +++ b/Engine.Physics2D/Collider2DBehaviourBase.cs @@ -10,7 +10,6 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D public event ICollider2D.OnCollisionResolvedEventHandler? OnCollisionResolved = null; public event ICollider2D.OnTriggeredEventHandler? OnTriggered = null; - protected bool NeedsRecalculation { get; private set; } = true; protected IRigidBody2D? _rigidBody2D = null; diff --git a/Engine.Physics2D/Collider2DCircleBehaviour.cs b/Engine.Physics2D/Collider2DCircleBehaviour.cs index 7314c02..37bf006 100644 --- a/Engine.Physics2D/Collider2DCircleBehaviour.cs +++ b/Engine.Physics2D/Collider2DCircleBehaviour.cs @@ -8,10 +8,8 @@ public class Collider2DCircleBehaviour : Collider2DBehaviourBase, ICircleCollide public Circle CircleWorld { get; protected set; } = Circle.UnitCircle; public Circle CircleLocal { get; set; } = Circle.UnitCircle; - public override void CalculateCollider() => CircleWorld = Transform.TransformCircle(CircleLocal); - public Collider2DCircleBehaviour() { } public Collider2DCircleBehaviour(Circle circle) => CircleLocal = circle; } diff --git a/Engine.Physics2D/Collider2DShapeBehaviour.cs b/Engine.Physics2D/Collider2DShapeBehaviour.cs index a658b14..7a2681d 100644 --- a/Engine.Physics2D/Collider2DShapeBehaviour.cs +++ b/Engine.Physics2D/Collider2DShapeBehaviour.cs @@ -12,7 +12,6 @@ public class Collider2DShapeBehaviour : Collider2DBehaviourBase, IShapeCollider2 public override void CalculateCollider() => Transform.TransformShape(ShapeLocal, ref _shapeWorld); - public Collider2DShapeBehaviour() { } public Collider2DShapeBehaviour(Shape shape) => ShapeLocal = shape; } diff --git a/Engine.Physics2D/CollisionDetector2D.cs b/Engine.Physics2D/CollisionDetector2D.cs index b3e1643..b944dde 100644 --- a/Engine.Physics2D/CollisionDetector2D.cs +++ b/Engine.Physics2D/CollisionDetector2D.cs @@ -42,7 +42,7 @@ public class CollisionDetector2D : ICollisionDetector2D private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation collisionInformation) { - var vertices = left.ShapeWorld.Vertices; + System.Collections.Generic.IReadOnlyList vertices = left.ShapeWorld.Vertices; int count = vertices.Count; for (int indexProjection = 0; indexProjection < count; indexProjection++) @@ -66,7 +66,7 @@ public class CollisionDetector2D : ICollisionDetector2D { collisionInformation = default; - var vertices = shapeCollider.ShapeWorld.Vertices; + System.Collections.Generic.IReadOnlyList vertices = shapeCollider.ShapeWorld.Vertices; int count = vertices.Count; for (int indexProjection = 0; indexProjection < count; indexProjection++) diff --git a/Engine.Physics2D/Physics2D.cs b/Engine.Physics2D/Physics2D.cs index f717d7e..64e0f80 100644 --- a/Engine.Physics2D/Physics2D.cs +++ b/Engine.Physics2D/Physics2D.cs @@ -5,11 +5,11 @@ namespace Syntriax.Engine.Physics2D; public static partial class Physics2D { - public static bool Overlaps(this Shape shape, Vector2D point) => Overlaps(shape, point, out var _); + public static bool Overlaps(this Shape shape, Vector2D point) => Overlaps(shape, point, out float _); public static bool Overlaps(this Shape shape, Vector2D point, out float depth) { depth = float.MaxValue; - var vertices = shape.Vertices; + System.Collections.Generic.IReadOnlyList vertices = shape.Vertices; int count = vertices.Count; for (int indexProjection = 0; indexProjection < count; indexProjection++) diff --git a/Engine.Physics2D/PhysicsEngine2D.cs b/Engine.Physics2D/PhysicsEngine2D.cs index 38823a8..11aa4f9 100644 --- a/Engine.Physics2D/PhysicsEngine2D.cs +++ b/Engine.Physics2D/PhysicsEngine2D.cs @@ -27,7 +27,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidBodies.Add(rigidBody); - foreach (var collider2D in rigidBody.BehaviourController.GetBehaviours()) + foreach (ICollider2D collider2D in rigidBody.BehaviourController.GetBehaviours()) colliders.Add(collider2D); rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; @@ -50,7 +50,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D StepRigidBody(rigidBodies[i], intervalDeltaTime); // Can Parallel - foreach (var collider in colliders) + foreach (ICollider2D collider in colliders) collider.Recalculate(); // Can Parallel diff --git a/Engine.Physics2D/PhysicsEngine2DCollector.cs b/Engine.Physics2D/PhysicsEngine2DCollector.cs index 64154a2..5851fd7 100644 --- a/Engine.Physics2D/PhysicsEngine2DCollector.cs +++ b/Engine.Physics2D/PhysicsEngine2DCollector.cs @@ -18,7 +18,6 @@ public class PhysicsEngine2DCollector : HierarchyObjectBase, IPhysicsEngine2D protected BehaviourCollector colliderCollector = new(); protected BehaviourCollector physicsUpdateCollector = new(); - public int IterationPerStep { get => _iterationPerStep; set => _iterationPerStep = value < 1 ? 1 : value; } public void Step(float deltaTime) @@ -28,11 +27,11 @@ public class PhysicsEngine2DCollector : HierarchyObjectBase, IPhysicsEngine2D for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++) { // Can Parallel - foreach (var rigidBody in rigidBodyCollector) + foreach (IRigidBody2D rigidBody in rigidBodyCollector) StepRigidBody(rigidBody, intervalDeltaTime); // Can Parallel - foreach (var collider in colliderCollector) + foreach (ICollider2D collider in colliderCollector) collider.Recalculate(); // Can Parallel diff --git a/Engine.Physics2D/Primitives/Line.cs b/Engine.Physics2D/Primitives/Line.cs index 61558d2..84447f4 100644 --- a/Engine.Physics2D/Primitives/Line.cs +++ b/Engine.Physics2D/Primitives/Line.cs @@ -173,17 +173,13 @@ public readonly struct Line(Vector2D from, Vector2D to) /// public static Vector2D ClosestPointTo(Line line, Vector2D point) { - // Convert edge points to vectors - var edgeVector = new Vector2D(line.To.X - line.From.X, line.To.Y - line.From.Y); - var pointVector = new Vector2D(point.X - line.From.X, point.Y - line.From.Y); + Vector2D edgeVector = new(line.To.X - line.From.X, line.To.Y - line.From.Y); + Vector2D pointVector = new(point.X - line.From.X, point.Y - line.From.Y); - // Calculate the projection of pointVector onto edgeVector float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); - // Clamp t to the range [0, 1] to ensure the closest point is on the edge t = MathF.Max(0, MathF.Min(1, t)); - // Calculate the closest point on the edge float closestX = line.From.X + t * edgeVector.X; float closestY = line.From.Y + t * edgeVector.Y; @@ -207,13 +203,11 @@ public static class LineExtensions /// public static Vector2D Lerp(this Line line, float t) => Line.Lerp(line, t); - /// /// The equation of the defined by this segment. /// public static LineEquation ToLineEquation(this Line line) => Line.GetLineEquation(line); - /// /// Determines whether the specified lies on the . /// @@ -224,13 +218,11 @@ public static class LineExtensions /// public static float GetT(this Line line, Vector2D point) => Line.GetT(line, point); - /// /// Checks if the segment intersects with another segment. /// public static bool Intersects(this Line left, Line right) => Line.Intersects(left, right); - /// /// Determines whether two segments intersect. /// diff --git a/Engine.Physics2D/Primitives/Projection.cs b/Engine.Physics2D/Primitives/Projection.cs index 67b6b74..1db3211 100644 --- a/Engine.Physics2D/Primitives/Projection.cs +++ b/Engine.Physics2D/Primitives/Projection.cs @@ -27,7 +27,7 @@ public readonly struct Projection(float min, float max) /// The first projection to check. /// The second projection to check. /// if the projections overlap; otherwise, . - public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out var _); + public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out float _); /// /// Checks if two projections overlap and calculates the depth of the overlap. diff --git a/Engine.Physics2D/RigidBody2D.cs b/Engine.Physics2D/RigidBody2D.cs index f53180e..4628a5d 100644 --- a/Engine.Physics2D/RigidBody2D.cs +++ b/Engine.Physics2D/RigidBody2D.cs @@ -11,7 +11,6 @@ public class RigidBody2D : Behaviour, IRigidBody2D private const float LOWEST_ALLOWED_MASS = 0.00001f; private float _mass = 1f; - public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault(); public Vector2D Velocity { get; set; } = Vector2D.Zero; @@ -22,6 +21,5 @@ public class RigidBody2D : Behaviour, IRigidBody2D ITransform IAssignableTransform.Transform => Transform; - public bool Assign(ITransform transform) => GameObject.Assign(transform); } -- 2.47.1 From 62b43025b9636ae76e91e7bca200a2a13f9311bd Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 17 Mar 2025 21:38:26 +0300 Subject: [PATCH 02/32] chore: improved exception messages --- Engine.Core/Exceptions/AssignException.cs | 9 +-------- Engine.Core/Exceptions/NotAssignedException.cs | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Engine.Core/Exceptions/AssignException.cs b/Engine.Core/Exceptions/AssignException.cs index 9adc27e..ec4f234 100644 --- a/Engine.Core/Exceptions/AssignException.cs +++ b/Engine.Core/Exceptions/AssignException.cs @@ -7,13 +7,6 @@ public class AssignException : Exception public AssignException() : base("Assign operation has failed.") { } public AssignException(string? message) : base(message) { } - // public static AssignException FromStateEnable(IStateEnable? stateEnable) - // => new AssignException($"{nameof(IGameObject.AssignStateEnable)} failed on type {stateEnable?.GetType().ToString() ?? "\"null\""}"); public static AssignException From(T to, T2? value) - => new($"Assign operation has failed on T: {typeof(T).FullName}, value: {value?.GetType().ToString() ?? "\"null\""}"); - // public static AssignException FromBehaviourController(IBehaviourController? behaviourController) - // => new AssignException($"{nameof(IGameObject.AssignBehaviourController)} failed on type {behaviourController?.GetType().ToString() ?? "\"null\""}"); + => new($"Assign operation has failed on T: {to?.GetType().FullName ?? "\"null\""}, value: {value?.GetType().ToString() ?? "\"null\""}"); } -// throw new Exception($"{nameof(IGameObject.AssignTransform)} failed on type {transform?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); -// throw new Exception($"{nameof(IGameObject.AssignBehaviourController)} failed on type {behaviourController?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); -// throw new Exception($"{nameof(IGameObject.AssignStateEnable)} failed on type {stateEnable?.GetType().ToString() ?? "null"} for type {typeof(T).FullName}"); diff --git a/Engine.Core/Exceptions/NotAssignedException.cs b/Engine.Core/Exceptions/NotAssignedException.cs index 8480fcf..51ac615 100644 --- a/Engine.Core/Exceptions/NotAssignedException.cs +++ b/Engine.Core/Exceptions/NotAssignedException.cs @@ -9,7 +9,7 @@ public class NotAssignedException : Exception public NotAssignedException(string? message) : base(message) { } public static NotAssignedException From(T1 to, T2? value) where T1 : IAssignable - => new($"{typeof(T2).Name} has not been assigned to {typeof(T1).Name}"); + => new($"{value?.GetType().FullName ?? "\"null\""} has not been assigned to {to?.GetType().FullName ?? "\"null\""}"); public static void Check(T1 to, T2? value) where T1 : IAssignable { -- 2.47.1 From 9ecf0b900f7fd6e3d8bc25170997a49f4b0d1545 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 17 Mar 2025 21:54:43 +0300 Subject: [PATCH 03/32] refactor: renamed primitives --- Engine.Physics2D/Abstract/IShapeCollider2D.cs | 10 +- Engine.Physics2D/Collider2DShapeBehaviour.cs | 8 +- Engine.Physics2D/CollisionDetector2D.cs | 16 +-- Engine.Physics2D/Physics2D.cs | 8 +- Engine.Physics2D/Primitives/Circle.cs | 4 +- .../Primitives/{Line.cs => Line2D.cs} | 107 +++++++++--------- .../{LineEquation.cs => Line2DEquation.cs} | 14 +-- .../{Projection.cs => Projection1D.cs} | 16 +-- .../Primitives/{Shape.cs => Shape2D.cs} | 60 +++++----- 9 files changed, 120 insertions(+), 123 deletions(-) rename Engine.Physics2D/Primitives/{Line.cs => Line2D.cs} (60%) rename Engine.Physics2D/Primitives/{LineEquation.cs => Line2DEquation.cs} (75%) rename Engine.Physics2D/Primitives/{Projection.cs => Projection1D.cs} (80%) rename Engine.Physics2D/Primitives/{Shape.cs => Shape2D.cs} (78%) diff --git a/Engine.Physics2D/Abstract/IShapeCollider2D.cs b/Engine.Physics2D/Abstract/IShapeCollider2D.cs index 4280d27..87aca76 100644 --- a/Engine.Physics2D/Abstract/IShapeCollider2D.cs +++ b/Engine.Physics2D/Abstract/IShapeCollider2D.cs @@ -3,17 +3,17 @@ using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D.Abstract; /// -/// Represents a with a custom . +/// Represents a with a custom . /// public interface IShapeCollider2D : ICollider2D { /// - /// Gets or sets the local of the . + /// Gets or sets the local of the . /// - Shape ShapeLocal { get; set; } + Shape2D ShapeLocal { get; set; } /// - /// Gets the world space representation of the . + /// Gets the world space representation of the . /// - Shape ShapeWorld { get; } + Shape2D ShapeWorld { get; } } diff --git a/Engine.Physics2D/Collider2DShapeBehaviour.cs b/Engine.Physics2D/Collider2DShapeBehaviour.cs index 7a2681d..95de053 100644 --- a/Engine.Physics2D/Collider2DShapeBehaviour.cs +++ b/Engine.Physics2D/Collider2DShapeBehaviour.cs @@ -5,13 +5,13 @@ namespace Syntriax.Engine.Physics2D; public class Collider2DShapeBehaviour : Collider2DBehaviourBase, IShapeCollider2D { - public Shape ShapeWorld { get => _shapeWorld; protected set => _shapeWorld = value; } - public Shape ShapeLocal { get; set; } = Shape.Box; + public Shape2D ShapeWorld { get => _shapeWorld; protected set => _shapeWorld = value; } + public Shape2D ShapeLocal { get; set; } = Shape2D.Box; - private Shape _shapeWorld = Shape.Box.CreateCopy(); + private Shape2D _shapeWorld = Shape2D.Box.CreateCopy(); public override void CalculateCollider() => Transform.TransformShape(ShapeLocal, ref _shapeWorld); public Collider2DShapeBehaviour() { } - public Collider2DShapeBehaviour(Shape shape) => ShapeLocal = shape; + public Collider2DShapeBehaviour(Shape2D shape) => ShapeLocal = shape; } diff --git a/Engine.Physics2D/CollisionDetector2D.cs b/Engine.Physics2D/CollisionDetector2D.cs index b944dde..e6fd1e7 100644 --- a/Engine.Physics2D/CollisionDetector2D.cs +++ b/Engine.Physics2D/CollisionDetector2D.cs @@ -49,8 +49,8 @@ public class CollisionDetector2D : ICollisionDetector2D { Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized; - Projection leftProjection = left.ShapeWorld.ToProjection(projectionVector); - Projection rightProjection = right.ShapeWorld.ToProjection(projectionVector); + Projection1D leftProjection = left.ShapeWorld.ToProjection(projectionVector); + Projection1D rightProjection = right.ShapeWorld.ToProjection(projectionVector); if (!leftProjection.Overlaps(rightProjection, out float depth)) return false; @@ -73,8 +73,8 @@ public class CollisionDetector2D : ICollisionDetector2D { Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized; - Projection shapeProjection = shapeCollider.ShapeWorld.ToProjection(projectionVector); - Projection circleProjection = circleCollider.CircleWorld.ToProjection(projectionVector); + Projection1D shapeProjection = shapeCollider.ShapeWorld.ToProjection(projectionVector); + Projection1D circleProjection = circleCollider.CircleWorld.ToProjection(projectionVector); if (!shapeProjection.Overlaps(circleProjection, out float depth)) return false; @@ -86,8 +86,8 @@ public class CollisionDetector2D : ICollisionDetector2D { Vector2D shapeToCircleProjectionVector = shapeCollider.Transform.Position.FromTo(circleCollider.CircleWorld.Center).Normalized; - Projection shapeProjection = shapeCollider.ShapeWorld.ToProjection(shapeToCircleProjectionVector); - Projection circleProjection = circleCollider.CircleWorld.ToProjection(shapeToCircleProjectionVector); + Projection1D shapeProjection = shapeCollider.ShapeWorld.ToProjection(shapeToCircleProjectionVector); + Projection1D circleProjection = circleCollider.CircleWorld.ToProjection(shapeToCircleProjectionVector); if (!shapeProjection.Overlaps(circleProjection, out float depth)) return false; @@ -105,8 +105,8 @@ public class CollisionDetector2D : ICollisionDetector2D Vector2D leftToRightCenterProjectionVector = left.CircleWorld.Center.FromTo(right.CircleWorld.Center).Normalized; - Projection leftProjection = left.CircleWorld.ToProjection(leftToRightCenterProjectionVector); - Projection rightProjection = right.CircleWorld.ToProjection(leftToRightCenterProjectionVector); + Projection1D leftProjection = left.CircleWorld.ToProjection(leftToRightCenterProjectionVector); + Projection1D rightProjection = right.CircleWorld.ToProjection(leftToRightCenterProjectionVector); bool collision = leftProjection.Overlaps(rightProjection, out float depth); diff --git a/Engine.Physics2D/Physics2D.cs b/Engine.Physics2D/Physics2D.cs index 64e0f80..60b9d8b 100644 --- a/Engine.Physics2D/Physics2D.cs +++ b/Engine.Physics2D/Physics2D.cs @@ -5,8 +5,8 @@ namespace Syntriax.Engine.Physics2D; public static partial class Physics2D { - public static bool Overlaps(this Shape shape, Vector2D point) => Overlaps(shape, point, out float _); - public static bool Overlaps(this Shape shape, Vector2D point, out float depth) + public static bool Overlaps(this Shape2D shape, Vector2D point) => Overlaps(shape, point, out float _); + public static bool Overlaps(this Shape2D shape, Vector2D point, out float depth) { depth = float.MaxValue; System.Collections.Generic.IReadOnlyList vertices = shape.Vertices; @@ -16,7 +16,7 @@ public static partial class Physics2D { Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized; - Projection shapeProjection = shape.ToProjection(projectionVector); + Projection1D shapeProjection = shape.ToProjection(projectionVector); float projectedPoint = point.Dot(projectionVector); if (shapeProjection.Max < projectedPoint || shapeProjection.Min > projectedPoint) @@ -90,5 +90,5 @@ public static partial class Physics2D return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f); } - public static bool LaysOn(this Vector2D point, Line line) => Line.Intersects(line, point); + public static bool LaysOn(this Vector2D point, Line2D line) => Line2D.Intersects(line, point); } diff --git a/Engine.Physics2D/Primitives/Circle.cs b/Engine.Physics2D/Primitives/Circle.cs index 5e0ae2a..5787921 100644 --- a/Engine.Physics2D/Primitives/Circle.cs +++ b/Engine.Physics2D/Primitives/Circle.cs @@ -59,7 +59,7 @@ public readonly struct Circle(Vector2D center, float radius) /// /// Projects the onto the specified . /// - public static Projection Project(Circle circle, Vector2D projectionVector) + public static Projection1D Project(Circle circle, Vector2D projectionVector) { float projectedCenter = circle.Center.Dot(projectionVector); return new(projectedCenter - circle.Radius, projectedCenter + circle.Radius); @@ -101,7 +101,7 @@ public static class CircleExtensions /// /// Projects the onto the specified . /// - public static Projection ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector); + public static Projection1D ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector); /// /// Transforms the by the specified . diff --git a/Engine.Physics2D/Primitives/Line.cs b/Engine.Physics2D/Primitives/Line2D.cs similarity index 60% rename from Engine.Physics2D/Primitives/Line.cs rename to Engine.Physics2D/Primitives/Line2D.cs index 84447f4..920fda5 100644 --- a/Engine.Physics2D/Primitives/Line.cs +++ b/Engine.Physics2D/Primitives/Line2D.cs @@ -11,64 +11,64 @@ namespace Syntriax.Engine.Physics2D.Primitives; /// /// Initializes a new instance of the Line struct with the specified endpoints. /// -/// The starting point of the segment. -/// The ending point of the segment. +/// The starting point of the segment. +/// The ending point of the segment. [System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")] -public readonly struct Line(Vector2D from, Vector2D to) +public readonly struct Line2D(Vector2D from, Vector2D to) { /// - /// The starting point of the segment. + /// The starting point of the segment. /// public readonly Vector2D From = from; /// - /// The ending point of the segment. + /// The ending point of the segment. /// public readonly Vector2D To = to; /// - /// The reversed segment. + /// The reversed segment. /// - public readonly Line Reversed => new(To, From); + public readonly Line2D Reversed => new(To, From); /// - /// The normalized direction of the segment. + /// The normalized direction of the segment. /// public readonly Vector2D Direction => From.FromTo(To).Normalize(); /// - /// The length of the segment. + /// The length of the segment. /// public readonly float Length => From.FromTo(To).Length(); /// - /// The squared length of the segment. + /// The squared length of the segment. /// public readonly float LengthSquared => From.FromTo(To).LengthSquared(); /// - /// The equation of the defined by this segment. + /// The equation of the defined by this segment. /// - public static LineEquation GetLineEquation(Line line) + public static Line2DEquation GetLineEquation(Line2D line) { Vector2D slopeVector = line.From.FromTo(line.To); float slope = slopeVector.Y / slopeVector.X; float yOffset = line.From.Y - (slope * line.From.X); - return new LineEquation(slope, yOffset); + return new Line2DEquation(slope, yOffset); } /// - /// Determines whether the specified lies on the . + /// Determines whether the specified lies on the . /// - public static bool Intersects(Line line, Vector2D point) - => LineEquation.Resolve(GetLineEquation(line), point.X).ApproximatelyEquals(point.Y); + public static bool Intersects(Line2D line, Vector2D point) + => Line2DEquation.Resolve(GetLineEquation(line), point.X).ApproximatelyEquals(point.Y); /// - /// Calculates the parameter 't' representing the point's position on the segment. + /// Calculates the parameter 't' representing the point's position on the segment. /// - public static float GetT(Line line, Vector2D point) + public static float GetT(Line2D line, Vector2D point) { float fromX = MathF.Abs(line.From.X); float toX = MathF.Abs(line.To.X); @@ -91,9 +91,9 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Checks if the segment intersects with another segment. + /// Checks if the segment intersects with another segment. /// - public static bool Intersects(Line left, Line right) + public static bool Intersects(Line2D left, Line2D right) { int o1 = Vector2D.Orientation(left.From, left.To, right.From); int o2 = Vector2D.Orientation(left.From, left.To, right.To); @@ -112,9 +112,9 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Checks if the point lies within the segment. + /// Checks if the point lies within the segment. /// - public static bool OnSegment(Line line, Vector2D point) + public static bool OnSegment(Line2D line, Vector2D point) { if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) && point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y)) @@ -124,9 +124,9 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Determines whether two segments intersect. + /// Determines whether two segments intersect. /// - public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point) + public static bool Intersects(Line2D left, Line2D right, [NotNullWhen(returnValue: true)] out Vector2D? point) { point = null; @@ -139,15 +139,15 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Finds the point of intersection between two segments. + /// Finds the point of intersection between two segments. /// - public static Vector2D IntersectionPoint(Line left, Line right) + public static Vector2D IntersectionPoint(Line2D left, Line2D right) => Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right)); /// - /// Calculates the parameter 't' representing the intersection point's position on the segment. + /// Calculates the parameter 't' representing the intersection point's position on the segment. /// - public static float IntersectionParameterT(Line left, Line right) + public static float IntersectionParameterT(Line2D left, Line2D right) { float numerator = (left.From.X - right.From.X) * (right.From.Y - right.To.Y) - (left.From.Y - right.From.Y) * (right.From.X - right.To.X); float denominator = (left.From.X - left.To.X) * (right.From.Y - right.To.Y) - (left.From.Y - left.To.Y) * (right.From.X - right.To.X); @@ -160,21 +160,18 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Linearly interpolates between the two endpoints of the segment using parameter 't'. + /// Linearly interpolates between the two endpoints of the segment using parameter 't'. /// - public static Vector2D Lerp(Line line, float t) - => new( - line.From.X + (line.To.X - line.From.X) * t, - line.From.Y + (line.To.Y - line.From.Y) * t - ); + public static Vector2D Lerp(Line2D line, float t) + => Vector2D.Lerp(line.From, line.To, t); /// - /// Calculates the closest point on the segment to the specified point. + /// Calculates the closest point on the segment to the specified point. /// - public static Vector2D ClosestPointTo(Line line, Vector2D point) + public static Vector2D ClosestPointTo(Line2D line, Vector2D point) { - Vector2D edgeVector = new(line.To.X - line.From.X, line.To.Y - line.From.Y); - Vector2D pointVector = new(point.X - line.From.X, point.Y - line.From.Y); + Vector2D edgeVector = line.From.FromTo(line.To); + Vector2D pointVector = point - line.From; float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); @@ -187,49 +184,49 @@ public readonly struct Line(Vector2D from, Vector2D to) } /// - /// Checks if two segments are approximately equal. + /// Checks if two segments are approximately equal. /// - public static bool ApproximatelyEquals(Line left, Line right) + public static bool ApproximatelyEquals(Line2D left, Line2D right) => left.From.ApproximatelyEquals(right.From) && left.To.ApproximatelyEquals(right.To); } /// /// Provides extension methods for the Line struct. /// -public static class LineExtensions +public static class Line2DExtensions { /// - /// Linearly interpolates between the two endpoints of the segment using parameter 't'. + /// Linearly interpolates between the two endpoints of the segment using parameter 't'. /// - public static Vector2D Lerp(this Line line, float t) => Line.Lerp(line, t); + public static Vector2D Lerp(this Line2D line, float t) => Line2D.Lerp(line, t); /// - /// The equation of the defined by this segment. + /// The equation of the defined by this segment. /// - public static LineEquation ToLineEquation(this Line line) => Line.GetLineEquation(line); + public static Line2DEquation ToLineEquation(this Line2D line) => Line2D.GetLineEquation(line); /// - /// Determines whether the specified lies on the . + /// Determines whether the specified lies on the . /// - public static bool Intersects(this Line line, Vector2D point) => Line.Intersects(line, point); + public static bool Intersects(this Line2D line, Vector2D point) => Line2D.Intersects(line, point); /// - /// Calculates the parameter 't' representing the point's position on the segment. + /// Calculates the parameter 't' representing the point's position on the segment. /// - public static float GetT(this Line line, Vector2D point) => Line.GetT(line, point); + public static float GetT(this Line2D line, Vector2D point) => Line2D.GetT(line, point); /// - /// Checks if the segment intersects with another segment. + /// Checks if the segment intersects with another segment. /// - public static bool Intersects(this Line left, Line right) => Line.Intersects(left, right); + public static bool Intersects(this Line2D left, Line2D right) => Line2D.Intersects(left, right); /// - /// Determines whether two segments intersect. + /// Determines whether two segments intersect. /// - public static bool Intersects(this Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point) => Line.Intersects(left, right, out point); + public static bool Intersects(this Line2D left, Line2D right, [NotNullWhen(returnValue: true)] out Vector2D? point) => Line2D.Intersects(left, right, out point); /// - /// Checks if two s are approximately equal. + /// Checks if two s are approximately equal. /// - public static bool ApproximatelyEquals(this Line left, Line right) => Line.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Line2D left, Line2D right) => Line2D.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/LineEquation.cs b/Engine.Physics2D/Primitives/Line2DEquation.cs similarity index 75% rename from Engine.Physics2D/Primitives/LineEquation.cs rename to Engine.Physics2D/Primitives/Line2DEquation.cs index 5640f47..b64f7a2 100644 --- a/Engine.Physics2D/Primitives/LineEquation.cs +++ b/Engine.Physics2D/Primitives/Line2DEquation.cs @@ -8,10 +8,10 @@ namespace Syntriax.Engine.Physics2D.Primitives; /// The slope of the line. /// The y-intercept of the line. /// -/// Initializes a new instance of the struct with the specified slope and y-intercept. +/// Initializes a new instance of the struct with the specified slope and y-intercept. /// [System.Diagnostics.DebuggerDisplay("y = {Slope}x + {OffsetY}")] -public readonly struct LineEquation(float slope, float offsetY) +public readonly struct Line2DEquation(float slope, float offsetY) { /// /// The slope of the line equation. @@ -29,7 +29,7 @@ public readonly struct LineEquation(float slope, float offsetY) /// The line equation to resolve. /// The x-coordinate for which to resolve the y-coordinate. /// The y-coordinate resolved using the line equation. - public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b + public static float Resolve(Line2DEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b /// /// Checks if two line equations are approximately equal. @@ -37,14 +37,14 @@ public readonly struct LineEquation(float slope, float offsetY) /// The first line equation to compare. /// The second line equation to compare. /// True if the line equations are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(LineEquation left, LineEquation right) + public static bool ApproximatelyEquals(Line2DEquation left, Line2DEquation right) => left.Slope.ApproximatelyEquals(right.Slope) && left.OffsetY.ApproximatelyEquals(right.OffsetY); } /// /// Provides extension methods for the LineEquation struct. /// -public static class LineEquationExtensions +public static class Line2DEquationExtensions { /// /// Resolves the y-coordinate for a given x-coordinate using the line equation. @@ -52,7 +52,7 @@ public static class LineEquationExtensions /// The line equation to resolve. /// The x-coordinate for which to resolve the y-coordinate. /// The y-coordinate resolved using the line equation. - public static float Resolve(this LineEquation lineEquation, float x) => LineEquation.Resolve(lineEquation, x); + public static float Resolve(this Line2DEquation lineEquation, float x) => Line2DEquation.Resolve(lineEquation, x); /// /// Checks if two line equations are approximately equal. @@ -60,5 +60,5 @@ public static class LineEquationExtensions /// The first line equation to compare. /// The second line equation to compare. /// True if the line equations are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(this LineEquation left, LineEquation right) => LineEquation.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Line2DEquation left, Line2DEquation right) => Line2DEquation.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/Projection.cs b/Engine.Physics2D/Primitives/Projection1D.cs similarity index 80% rename from Engine.Physics2D/Primitives/Projection.cs rename to Engine.Physics2D/Primitives/Projection1D.cs index 1db3211..3ee27bd 100644 --- a/Engine.Physics2D/Primitives/Projection.cs +++ b/Engine.Physics2D/Primitives/Projection1D.cs @@ -6,10 +6,10 @@ namespace Syntriax.Engine.Physics2D.Primitives; /// The minimum value of the projection. /// The maximum value of the projection. /// -/// Initializes a new instance of the struct with the specified minimum and maximum values. +/// Initializes a new instance of the struct with the specified minimum and maximum values. /// [System.Diagnostics.DebuggerDisplay("Min: {Min}, Max: {Max}")] -public readonly struct Projection(float min, float max) +public readonly struct Projection1D(float min, float max) { /// /// Gets the minimum value of the projection. @@ -27,7 +27,7 @@ public readonly struct Projection(float min, float max) /// The first projection to check. /// The second projection to check. /// if the projections overlap; otherwise, . - public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out float _); + public static bool Overlaps(Projection1D left, Projection1D right) => Overlaps(left, right, out float _); /// /// Checks if two projections overlap and calculates the depth of the overlap. @@ -36,7 +36,7 @@ public readonly struct Projection(float min, float max) /// The second projection to check. /// The depth of the overlap, if any. /// if the projections overlap; otherwise, . - public static bool Overlaps(Projection left, Projection right, out float depth) + public static bool Overlaps(Projection1D left, Projection1D right, out float depth) { // TODO Try to improve this bool rightMinInLeft = right.Min > left.Min && right.Min < left.Max; @@ -73,9 +73,9 @@ public readonly struct Projection(float min, float max) } /// -/// Provides extension methods for the struct. +/// Provides extension methods for the struct. /// -public static class ProjectionExtensions +public static class Projection1DExtensions { /// /// Checks if two projections overlap. @@ -83,7 +83,7 @@ public static class ProjectionExtensions /// The first projection to check. /// The second projection to check. /// if the projections overlap; otherwise, . - public static bool Overlaps(this Projection left, Projection right) => Projection.Overlaps(left, right); + public static bool Overlaps(this Projection1D left, Projection1D right) => Projection1D.Overlaps(left, right); /// /// Checks if two projections overlap and calculates the depth of the overlap. @@ -92,5 +92,5 @@ public static class ProjectionExtensions /// The second projection to check. /// The depth of the overlap, if any. /// if the projections overlap; otherwise, . - public static bool Overlaps(this Projection left, Projection right, out float depth) => Projection.Overlaps(left, right, out depth); + public static bool Overlaps(this Projection1D left, Projection1D right, out float depth) => Projection1D.Overlaps(left, right, out depth); } diff --git a/Engine.Physics2D/Primitives/Shape.cs b/Engine.Physics2D/Primitives/Shape2D.cs similarity index 78% rename from Engine.Physics2D/Primitives/Shape.cs rename to Engine.Physics2D/Primitives/Shape2D.cs index 0640196..335323e 100644 --- a/Engine.Physics2D/Primitives/Shape.cs +++ b/Engine.Physics2D/Primitives/Shape2D.cs @@ -11,15 +11,15 @@ namespace Syntriax.Engine.Physics2D.Primitives; /// /// The vertices of the shape. /// -/// Initializes a new instance of the struct with the specified vertices. +/// Initializes a new instance of the struct with the specified vertices. /// [System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")] -public readonly struct Shape(List vertices) : IEnumerable +public readonly struct Shape2D(List vertices) : IEnumerable { - public static readonly Shape Triangle = CreateNgon(3, Vector2D.Up); - public static readonly Shape Box = CreateNgon(4, Vector2D.One); - public static readonly Shape Pentagon = CreateNgon(5, Vector2D.Up); - public static readonly Shape Hexagon = CreateNgon(6, Vector2D.Right); + public static readonly Shape2D Triangle = CreateNgon(3, Vector2D.Up); + public static readonly Shape2D Box = CreateNgon(4, Vector2D.One); + public static readonly Shape2D Pentagon = CreateNgon(5, Vector2D.Up); + public static readonly Shape2D Hexagon = CreateNgon(6, Vector2D.Right); private readonly List _verticesList = vertices; @@ -40,14 +40,14 @@ public readonly struct Shape(List vertices) : IEnumerable /// /// The shape to copy. /// A copy of the input shape. - public static Shape CreateCopy(Shape shape) => new(new List(shape.Vertices)); + public static Shape2D CreateCopy(Shape2D shape) => new(new List(shape.Vertices)); /// /// Creates a regular polygon (ngon) with the specified number of vertices. /// /// The number of vertices in the polygon. /// A regular polygon with the specified number of vertices. - public static Shape CreateNgon(int vertexCount) => CreateNgon(vertexCount, Vector2D.Up); + public static Shape2D CreateNgon(int vertexCount) => CreateNgon(vertexCount, Vector2D.Up); /// /// Creates a regular polygon (ngon) with the specified number of vertices and a rotation position. @@ -55,7 +55,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The number of vertices in the polygon. /// The position to use for rotation. /// A regular polygon with the specified number of vertices and rotation position. - public static Shape CreateNgon(int vertexCount, Vector2D positionToRotate) + public static Shape2D CreateNgon(int vertexCount, Vector2D positionToRotate) { if (vertexCount < 3) throw new System.ArgumentException($"{nameof(vertexCount)} must have a value of more than 2."); @@ -75,7 +75,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// /// The shape to enclose. /// The super triangle that encloses the given shape. - public static Triangle GetSuperTriangle(Shape shape) + public static Triangle GetSuperTriangle(Shape2D shape) { float minX = float.MaxValue, minY = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue; @@ -106,7 +106,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// /// The shape to get lines from. /// The list to populate with lines. - public static void GetLines(Shape shape, IList lines) + public static void GetLines(Shape2D shape, IList lines) { lines.Clear(); for (int i = 0; i < shape.Vertices.Count - 1; i++) @@ -119,9 +119,9 @@ public readonly struct Shape(List vertices) : IEnumerable /// /// The shape to get lines from. /// A list of lines that form the edges of the shape. - public static List GetLines(Shape shape) + public static List GetLines(Shape2D shape) { - List lines = new(shape.Vertices.Count - 1); + List lines = new(shape.Vertices.Count - 1); GetLines(shape, lines); return lines; } @@ -132,7 +132,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The shape to project. /// The vector to project onto. /// The list to populate with projected values. - public static void Project(Shape shape, Vector2D projectionVector, IList list) + public static void Project(Shape2D shape, Vector2D projectionVector, IList list) { list.Clear(); @@ -147,7 +147,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The shape to project. /// The vector to project onto. /// The projection of the shape onto the vector. - public static Projection Project(Shape shape, Vector2D projectionVector) + public static Projection1D Project(Shape2D shape, Vector2D projectionVector) { float min = float.MaxValue; float max = float.MinValue; @@ -168,7 +168,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The shape to transform. /// The transform to apply. /// The transformed shape. - public static Shape TransformShape(Shape shape, ITransform transform) + public static Shape2D TransformShape(Shape2D shape, ITransform transform) { List vertices = new(shape.Vertices.Count); @@ -176,7 +176,7 @@ public readonly struct Shape(List vertices) : IEnumerable for (int i = 0; i < count; i++) vertices.Add(transform.TransformVector2D(shape[i])); - return new Shape(vertices); + return new Shape2D(vertices); } /// @@ -185,7 +185,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The shape to transform. /// The transform to apply. /// The transformed shape. - public static void TransformShape(Shape from, ITransform transform, ref Shape to) + public static void TransformShape(Shape2D from, ITransform transform, ref Shape2D to) { to._verticesList.Clear(); @@ -200,7 +200,7 @@ public readonly struct Shape(List vertices) : IEnumerable /// The first shape to compare. /// The second shape to compare. /// true if the shapes are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(Shape left, Shape right) + public static bool ApproximatelyEquals(Shape2D left, Shape2D right) { if (left.Vertices.Count != right.Vertices.Count) return false; @@ -220,37 +220,37 @@ public readonly struct Shape(List vertices) : IEnumerable } /// -/// Provides extension methods for the struct. +/// Provides extension methods for the struct. /// -public static class ShapeExtensions +public static class Shape2DExtensions { /// /// Creates a copy of the shape. /// /// The shape to copy. /// A copy of the input shape. - public static Shape CreateCopy(this Shape shape) => Shape.CreateCopy(shape); + public static Shape2D CreateCopy(this Shape2D shape) => Shape2D.CreateCopy(shape); /// /// Gets the super triangle that encloses the shape. /// /// The shape to enclose. /// The super triangle that encloses the shape. - public static Triangle ToSuperTriangle(this Shape shape) => Shape.GetSuperTriangle(shape); + public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape); /// /// Gets the lines that form the edges of the shape. /// /// The shape to get lines from. /// The list to populate with lines. - public static void ToLines(this Shape shape, IList lines) => Shape.GetLines(shape, lines); + public static void ToLines(this Shape2D shape, IList lines) => Shape2D.GetLines(shape, lines); /// /// Gets a list of lines that form the edges of the shape. /// /// The shape to get lines from. /// A list of lines that form the edges of the shape. - public static List ToLines(this Shape shape) => Shape.GetLines(shape); + public static List ToLines(this Shape2D shape) => Shape2D.GetLines(shape); /// /// Projects the shape onto a vector. @@ -258,7 +258,7 @@ public static class ShapeExtensions /// The shape to project. /// The vector to project onto. /// The list to populate with projected values. - public static void ToProjection(this Shape shape, Vector2D projectionVector, IList list) => Shape.Project(shape, projectionVector, list); + public static void ToProjection(this Shape2D shape, Vector2D projectionVector, IList list) => Shape2D.Project(shape, projectionVector, list); /// /// Projects the shape onto a vector. @@ -266,7 +266,7 @@ public static class ShapeExtensions /// The shape to project. /// The vector to project onto. /// The projection of the shape onto the vector. - public static Projection ToProjection(this Shape shape, Vector2D projectionVector) => Shape.Project(shape, projectionVector); + public static Projection1D ToProjection(this Shape2D shape, Vector2D projectionVector) => Shape2D.Project(shape, projectionVector); /// /// Transforms the shape using the specified transform. @@ -274,7 +274,7 @@ public static class ShapeExtensions /// The transform to apply. /// The shape to transform. /// The transformed shape. - public static Shape TransformShape(this ITransform transform, Shape shape) => Shape.TransformShape(shape, transform); + public static Shape2D TransformShape(this ITransform transform, Shape2D shape) => Shape2D.TransformShape(shape, transform); /// /// Transforms the shape using the specified transform. @@ -282,7 +282,7 @@ public static class ShapeExtensions /// The transform to apply. /// The shape to transform. /// The transformed shape. - public static void TransformShape(this ITransform transform, Shape from, ref Shape to) => Shape.TransformShape(from, transform, ref to); + public static void TransformShape(this ITransform transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to); /// /// Determines whether two shapes are approximately equal. @@ -290,5 +290,5 @@ public static class ShapeExtensions /// The first shape to compare. /// The second shape to compare. /// true if the shapes are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(this Shape left, Shape right) => Shape.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Shape2D left, Shape2D right) => Shape2D.ApproximatelyEquals(left, right); } -- 2.47.1 From 183966d2394a3cfa4b8ff1d6c6f26eb354431dca Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 17 Mar 2025 21:57:09 +0300 Subject: [PATCH 04/32] refactor: moved 2D primitives from Physics2D to Core --- Engine.Core/Extensions/Vector2DExtensions.cs | 195 ----------------- Engine.Core/Extensions/Vector3DExtensions.cs | 189 ----------------- .../Primitives/AABB.cs | 4 +- .../Primitives/Circle.cs | 6 +- .../Primitives/Line2D.cs | 10 +- .../Primitives/Line2DEquation.cs | 4 +- .../Primitives/Projection1D.cs | 2 +- .../Primitives/Shape2D.cs | 4 +- .../Primitives/Triangle.cs | 4 +- Engine.Core/{ => Primitives}/Vector2D.cs | 199 ++++++++++++++++++ Engine.Core/{ => Primitives}/Vector3D.cs | 194 +++++++++++++++++ .../Abstract/ICircleCollider2D.cs | 2 +- Engine.Physics2D/Abstract/IShapeCollider2D.cs | 2 +- Engine.Physics2D/Collider2DCircleBehaviour.cs | 2 +- Engine.Physics2D/Collider2DShapeBehaviour.cs | 2 +- Engine.Physics2D/CollisionDetector2D.cs | 1 - Engine.Physics2D/Physics2D.cs | 1 - 17 files changed, 408 insertions(+), 413 deletions(-) delete mode 100644 Engine.Core/Extensions/Vector2DExtensions.cs delete mode 100644 Engine.Core/Extensions/Vector3DExtensions.cs rename {Engine.Physics2D => Engine.Core}/Primitives/AABB.cs (98%) rename {Engine.Physics2D => Engine.Core}/Primitives/Circle.cs (96%) rename {Engine.Physics2D => Engine.Core}/Primitives/Line2D.cs (98%) rename {Engine.Physics2D => Engine.Core}/Primitives/Line2DEquation.cs (97%) rename {Engine.Physics2D => Engine.Core}/Primitives/Projection1D.cs (98%) rename {Engine.Physics2D => Engine.Core}/Primitives/Shape2D.cs (99%) rename {Engine.Physics2D => Engine.Core}/Primitives/Triangle.cs (95%) rename Engine.Core/{ => Primitives}/Vector2D.cs (58%) rename Engine.Core/{ => Primitives}/Vector3D.cs (58%) diff --git a/Engine.Core/Extensions/Vector2DExtensions.cs b/Engine.Core/Extensions/Vector2DExtensions.cs deleted file mode 100644 index c51003f..0000000 --- a/Engine.Core/Extensions/Vector2DExtensions.cs +++ /dev/null @@ -1,195 +0,0 @@ -namespace Syntriax.Engine.Core; - -/// -/// Provides extension methods for type. -/// -public static class Vector2DExtensions -{ - /// - /// Returns the representation of the . - /// - /// The input . - /// The representation of the provided . - public static Vector3D As3D(this Vector2D vector) => new(vector.X, vector.Y, 0f); - - /// - /// Calculates the length of the . - /// - /// The input . - /// The length of the . - public static float Length(this Vector2D vector) => Vector2D.Length(vector); - - /// - /// Calculates the squared length of the . - /// - /// The input . - /// The squared length of the . - public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); - - /// - /// Calculates the distance between two s. - /// - /// The starting . - /// The ending . - /// The distance between the two s. - public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); - - /// - /// Returns the with its components inverted. - /// - /// The input . - /// The inverted . - public static Vector2D Invert(this Vector2D vector) => Vector2D.Invert(vector); - - /// - /// Adds two s component-wise. - /// - /// The first . - /// The vector to be added. - /// The result of the addition. - public static Vector2D Add(this Vector2D vector, Vector2D vectorToAdd) => Vector2D.Add(vector, vectorToAdd); - - /// - /// Subtracts one from another component-wise. - /// - /// The first . - /// The to be subtracted. - /// The result of the subtraction. - public static Vector2D Subtract(this Vector2D vector, Vector2D vectorToSubtract) => Vector2D.Subtract(vector, vectorToSubtract); - - /// - /// Multiplies a by a scalar value. - /// - /// The to multiply. - /// The scalar value to multiply with. - /// The result of the multiplication. - public static Vector2D Multiply(this Vector2D vector, float value) => Vector2D.Multiply(vector, value); - - /// - /// Divides a by a scalar value. - /// - /// The to divide. - /// The scalar value to divide with. - /// The result of the division. - public static Vector2D Divide(this Vector2D vector, float value) => Vector2D.Divide(vector, value); - - /// - /// Returns a with the absolute values of each component. - /// - /// The input . - /// The with absolute values. - public static Vector2D Abs(this Vector2D vector) => Vector2D.Abs(vector); - - /// - /// Reflects a off a surface with the specified normal. - /// - /// The to reflect. - /// The normal of the reflecting surface. - /// The reflected . - public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal); - - /// - /// Normalizes the (creates a with the same direction but with a length of 1). - /// - /// The input . - /// The normalized . - public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); - - /// - /// Creates a pointing from one point to another. - /// - /// The starting point. - /// The ending point. - /// The pointing from to . - public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); - - /// - /// Scales a by another component-wise. - /// - /// The to scale. - /// The containing the scaling factors for each component. - /// The scaled . - public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.Scale(vector, scale); - - /// - /// Calculates the perpendicular to the given . - /// - /// The input . - /// A perpendicular to the input . - public static Vector2D Perpendicular(this Vector2D vector) => Vector2D.Perpendicular(vector); - - /// - /// Rotates a by the specified angle (in radians). - /// - /// The to rotate. - /// The angle to rotate by, in radians. - /// The rotated . - public static Vector2D Rotate(this Vector2D vector, float angleInRadian) => Vector2D.Rotate(vector, angleInRadian); - - /// - /// Returns the component-wise minimum of two s. - /// - /// The first . - /// The second . - /// The containing the minimum components from both input s. - public static Vector2D Min(this Vector2D left, Vector2D right) => Vector2D.Min(left, right); - - /// - /// Returns the component-wise maximum of two s. - /// - /// The first . - /// The second . - /// The containing the maximum components from both input s. - public static Vector2D Max(this Vector2D left, Vector2D right) => Vector2D.Max(left, right); - - /// - /// Clamps each component of a between the corresponding component of two other s. - /// - /// The to clamp. - /// The representing the minimum values for each component. - /// The representing the maximum values for each component. - /// The clamped . - public static Vector2D Clamp(this Vector2D vector, Vector2D min, Vector2D max) => Vector2D.Clamp(vector, min, max); - - /// - /// Linearly interpolates between two s. - /// - /// The start . - /// The end . - /// The interpolation parameter (between 0 and 1). - /// The interpolated . - public static Vector2D Lerp(this Vector2D from, Vector2D to, float t) => Vector2D.Lerp(from, to, t); - - /// - /// Calculates the cross product of two s. - /// - /// The first . - /// The second . - /// The cross product of the two s. - public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); - - /// - /// Calculates the angle in radians between two s. - /// - /// The first . - /// The second . - /// The angle between the two s in radians. - public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); - - /// - /// Calculates the dot product of two s. - /// - /// The first . - /// The second . - /// The dot product of the two s. - public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); - - /// - /// Checks whether two s are approximately equal within a certain epsilon range. - /// - /// The first . - /// The second . - /// The maximum difference allowed between components. - /// True if the s are approximately equal, false otherwise. - public static bool ApproximatelyEquals(this Vector2D left, Vector2D right, float epsilon = float.Epsilon) => Vector2D.ApproximatelyEquals(left, right, epsilon); -} diff --git a/Engine.Core/Extensions/Vector3DExtensions.cs b/Engine.Core/Extensions/Vector3DExtensions.cs deleted file mode 100644 index d3612d4..0000000 --- a/Engine.Core/Extensions/Vector3DExtensions.cs +++ /dev/null @@ -1,189 +0,0 @@ -namespace Syntriax.Engine.Core; - -/// -/// Provides extension methods for type. -/// -public static class Vector3DExtensions -{ - /// - /// Returns the representation of the . - /// - /// The input . - /// The representation of the provided . - public static Vector2D As2D(this Vector3D vector) => new(vector.X, vector.Y); - - /// - /// Calculates the length of the . - /// - /// The input . - /// The length of the . - public static float Length(this Vector3D vector) => Vector3D.Length(vector); - - /// - /// Calculates the squared length of the . - /// - /// The input . - /// The squared length of the . - public static float LengthSquared(this Vector3D vector) => Vector3D.LengthSquared(vector); - - /// - /// Calculates the distance between two s. - /// - /// The starting . - /// The ending . - /// The distance between the two s. - public static float Distance(this Vector3D from, Vector3D to) => Vector3D.Distance(from, to); - - /// - /// Returns the with its components inverted. - /// - /// The input . - /// The inverted . - public static Vector3D Invert(this Vector3D vector) => Vector3D.Invert(vector); - - /// - /// Adds two s component-wise. - /// - /// The first . - /// The vector to be added. - /// The result of the addition. - public static Vector3D Add(this Vector3D vector, Vector3D vectorToAdd) => Vector3D.Add(vector, vectorToAdd); - - /// - /// Subtracts one from another component-wise. - /// - /// The first . - /// The to be subtracted. - /// The result of the subtraction. - public static Vector3D Subtract(this Vector3D vector, Vector3D vectorToSubtract) => Vector3D.Subtract(vector, vectorToSubtract); - - /// - /// Multiplies a by a scalar value. - /// - /// The to multiply. - /// The scalar value to multiply with. - /// The result of the multiplication. - public static Vector3D Multiply(this Vector3D vector, float value) => Vector3D.Multiply(vector, value); - - /// - /// Divides a by a scalar value. - /// - /// The to divide. - /// The scalar value to divide with. - /// The result of the division. - public static Vector3D Divide(this Vector3D vector, float value) => Vector3D.Divide(vector, value); - - /// - /// Returns a with the absolute values of each component. - /// - /// The input . - /// The with absolute values. - public static Vector3D Abs(this Vector3D vector) => Vector3D.Abs(vector); - - /// - /// Reflects a off a surface with the specified normal. - /// - /// The to reflect. - /// The normal of the reflecting surface. - /// The reflected . - public static Vector3D Reflect(this Vector3D vector, Vector3D normal) => Vector3D.Reflect(vector, normal); - - /// - /// Normalizes the (creates a with the same direction but with a length of 1). - /// - /// The input . - /// The normalized . - public static Vector3D Normalize(this Vector3D vector) => Vector3D.Normalize(vector); - - /// - /// Creates a pointing from one point to another. - /// - /// The starting point. - /// The ending point. - /// The pointing from to . - public static Vector3D FromTo(this Vector3D from, Vector3D to) => Vector3D.FromTo(from, to); - - /// - /// Scales a by another component-wise. - /// - /// The to scale. - /// The containing the scaling factors for each component. - /// The scaled . - public static Vector3D Scale(this Vector3D vector, Vector3D scale) => Vector3D.Scale(vector, scale); - - /// - /// Rotates a by the specified angle (in radians). - /// - /// The to rotate. - /// The to rotate around. - /// The angle to rotate by, in radians. - /// The rotated . - public static Vector3D Rotate(this Vector3D vector, Vector3D normal, float angleInRadian) => Vector3D.Rotate(vector, normal, angleInRadian); - - /// - /// Returns the component-wise minimum of two s. - /// - /// The first . - /// The second . - /// The containing the minimum components from both input s. - public static Vector3D Min(this Vector3D left, Vector3D right) => Vector3D.Min(left, right); - - /// - /// Returns the component-wise maximum of two s. - /// - /// The first . - /// The second . - /// The containing the maximum components from both input s. - public static Vector3D Max(this Vector3D left, Vector3D right) => Vector3D.Max(left, right); - - /// - /// Clamps each component of a between the corresponding component of two other s. - /// - /// The to clamp. - /// The representing the minimum values for each component. - /// The representing the maximum values for each component. - /// The clamped . - public static Vector3D Clamp(this Vector3D vector, Vector3D min, Vector3D max) => Vector3D.Clamp(vector, min, max); - - /// - /// Linearly interpolates between two s. - /// - /// The start . - /// The end . - /// The interpolation parameter (between 0 and 1). - /// The interpolated . - public static Vector3D Lerp(this Vector3D from, Vector3D to, float t) => Vector3D.Lerp(from, to, t); - - /// - /// Calculates the cross product of two s. - /// - /// The first . - /// The second . - /// The cross product of the two s. - public static Vector3D Cross(this Vector3D left, Vector3D right) => Vector3D.Cross(left, right); - - /// - /// Calculates the angle in radians between two s. - /// - /// The first . - /// The second . - /// The angle between the two s in radians. - public static float AngleBetween(this Vector3D left, Vector3D right) => Vector3D.Angle(left, right); - - /// - /// Calculates the dot product of two s. - /// - /// The first . - /// The second . - /// The dot product of the two s. - public static float Dot(this Vector3D left, Vector3D right) => Vector3D.Dot(left, right); - - /// - /// Checks whether two s are approximately equal within a certain epsilon range. - /// - /// The first . - /// The second . - /// The maximum difference allowed between components. - /// True if the s are approximately equal, false otherwise. - public static bool ApproximatelyEquals(this Vector3D left, Vector3D right, float epsilon = float.Epsilon) => Vector3D.ApproximatelyEquals(left, right, epsilon); -} diff --git a/Engine.Physics2D/Primitives/AABB.cs b/Engine.Core/Primitives/AABB.cs similarity index 98% rename from Engine.Physics2D/Primitives/AABB.cs rename to Engine.Core/Primitives/AABB.cs index 6d1191b..cbf60a5 100644 --- a/Engine.Physics2D/Primitives/AABB.cs +++ b/Engine.Core/Primitives/AABB.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents an Axis-Aligned Bounding Box (AABB) in 2D space. diff --git a/Engine.Physics2D/Primitives/Circle.cs b/Engine.Core/Primitives/Circle.cs similarity index 96% rename from Engine.Physics2D/Primitives/Circle.cs rename to Engine.Core/Primitives/Circle.cs index 5787921..1833a65 100644 --- a/Engine.Physics2D/Primitives/Circle.cs +++ b/Engine.Core/Primitives/Circle.cs @@ -1,9 +1,7 @@ using System.Diagnostics; - -using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents a 2D circle. @@ -11,7 +9,7 @@ namespace Syntriax.Engine.Physics2D.Primitives; /// The center of the circle. /// The radius of the circle. /// -/// Initializes a new instance of the Circle struct with the specified center and radius. +/// Initializes a new instance of the struct with the specified center and radius. /// [DebuggerDisplay("Center: {Center.ToString(),nq}, Radius: {Radius}")] public readonly struct Circle(Vector2D center, float radius) diff --git a/Engine.Physics2D/Primitives/Line2D.cs b/Engine.Core/Primitives/Line2D.cs similarity index 98% rename from Engine.Physics2D/Primitives/Line2D.cs rename to Engine.Core/Primitives/Line2D.cs index 920fda5..0a11de2 100644 --- a/Engine.Physics2D/Primitives/Line2D.cs +++ b/Engine.Core/Primitives/Line2D.cs @@ -1,18 +1,16 @@ using System; using System.Diagnostics.CodeAnalysis; -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents a 2D line segment defined by two endpoints. /// -/// -/// Initializes a new instance of the Line struct with the specified endpoints. -/// /// The starting point of the segment. /// The ending point of the segment. +/// +/// Initializes a new instance of the struct with the specified endpoints. +/// [System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")] public readonly struct Line2D(Vector2D from, Vector2D to) { diff --git a/Engine.Physics2D/Primitives/Line2DEquation.cs b/Engine.Core/Primitives/Line2DEquation.cs similarity index 97% rename from Engine.Physics2D/Primitives/Line2DEquation.cs rename to Engine.Core/Primitives/Line2DEquation.cs index b64f7a2..20d33ab 100644 --- a/Engine.Physics2D/Primitives/Line2DEquation.cs +++ b/Engine.Core/Primitives/Line2DEquation.cs @@ -1,6 +1,4 @@ -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents a line equation in the form y = mx + b. diff --git a/Engine.Physics2D/Primitives/Projection1D.cs b/Engine.Core/Primitives/Projection1D.cs similarity index 98% rename from Engine.Physics2D/Primitives/Projection1D.cs rename to Engine.Core/Primitives/Projection1D.cs index 3ee27bd..9c72fdd 100644 --- a/Engine.Physics2D/Primitives/Projection1D.cs +++ b/Engine.Core/Primitives/Projection1D.cs @@ -1,4 +1,4 @@ -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents a range of values along a single axis. diff --git a/Engine.Physics2D/Primitives/Shape2D.cs b/Engine.Core/Primitives/Shape2D.cs similarity index 99% rename from Engine.Physics2D/Primitives/Shape2D.cs rename to Engine.Core/Primitives/Shape2D.cs index 335323e..95d94df 100644 --- a/Engine.Physics2D/Primitives/Shape2D.cs +++ b/Engine.Core/Primitives/Shape2D.cs @@ -1,10 +1,8 @@ using System.Collections; using System.Collections.Generic; - -using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; /// /// Represents a shape defined by a collection of vertices. diff --git a/Engine.Physics2D/Primitives/Triangle.cs b/Engine.Core/Primitives/Triangle.cs similarity index 95% rename from Engine.Physics2D/Primitives/Triangle.cs rename to Engine.Core/Primitives/Triangle.cs index 9695460..8e3ce88 100644 --- a/Engine.Physics2D/Primitives/Triangle.cs +++ b/Engine.Core/Primitives/Triangle.cs @@ -1,8 +1,6 @@ using System; -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; +namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")] public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) diff --git a/Engine.Core/Vector2D.cs b/Engine.Core/Primitives/Vector2D.cs similarity index 58% rename from Engine.Core/Vector2D.cs rename to Engine.Core/Primitives/Vector2D.cs index cfa0b18..001973d 100644 --- a/Engine.Core/Vector2D.cs +++ b/Engine.Core/Primitives/Vector2D.cs @@ -5,6 +5,11 @@ namespace Syntriax.Engine.Core; /// /// Represents a two-dimensional vector. /// +/// X position of the . +/// Y position of the . +/// +/// Initializes a new instance of the struct with the specified positions. +/// [System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")] public readonly struct Vector2D(float x, float y) { @@ -300,3 +305,197 @@ public readonly struct Vector2D(float x, float y) /// A hash code for the . public override int GetHashCode() => HashCode.Combine(X, Y); } + +/// +/// Provides extension methods for type. +/// +public static class Vector2DExtensions +{ + /// + /// Returns the representation of the . + /// + /// The input . + /// The representation of the provided . + public static Vector3D As3D(this Vector2D vector) => new(vector.X, vector.Y, 0f); + + /// + /// Calculates the length of the . + /// + /// The input . + /// The length of the . + public static float Length(this Vector2D vector) => Vector2D.Length(vector); + + /// + /// Calculates the squared length of the . + /// + /// The input . + /// The squared length of the . + public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); + + /// + /// Calculates the distance between two s. + /// + /// The starting . + /// The ending . + /// The distance between the two s. + public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); + + /// + /// Returns the with its components inverted. + /// + /// The input . + /// The inverted . + public static Vector2D Invert(this Vector2D vector) => Vector2D.Invert(vector); + + /// + /// Adds two s component-wise. + /// + /// The first . + /// The vector to be added. + /// The result of the addition. + public static Vector2D Add(this Vector2D vector, Vector2D vectorToAdd) => Vector2D.Add(vector, vectorToAdd); + + /// + /// Subtracts one from another component-wise. + /// + /// The first . + /// The to be subtracted. + /// The result of the subtraction. + public static Vector2D Subtract(this Vector2D vector, Vector2D vectorToSubtract) => Vector2D.Subtract(vector, vectorToSubtract); + + /// + /// Multiplies a by a scalar value. + /// + /// The to multiply. + /// The scalar value to multiply with. + /// The result of the multiplication. + public static Vector2D Multiply(this Vector2D vector, float value) => Vector2D.Multiply(vector, value); + + /// + /// Divides a by a scalar value. + /// + /// The to divide. + /// The scalar value to divide with. + /// The result of the division. + public static Vector2D Divide(this Vector2D vector, float value) => Vector2D.Divide(vector, value); + + /// + /// Returns a with the absolute values of each component. + /// + /// The input . + /// The with absolute values. + public static Vector2D Abs(this Vector2D vector) => Vector2D.Abs(vector); + + /// + /// Reflects a off a surface with the specified normal. + /// + /// The to reflect. + /// The normal of the reflecting surface. + /// The reflected . + public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal); + + /// + /// Normalizes the (creates a with the same direction but with a length of 1). + /// + /// The input . + /// The normalized . + public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); + + /// + /// Creates a pointing from one point to another. + /// + /// The starting point. + /// The ending point. + /// The pointing from to . + public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); + + /// + /// Scales a by another component-wise. + /// + /// The to scale. + /// The containing the scaling factors for each component. + /// The scaled . + public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.Scale(vector, scale); + + /// + /// Calculates the perpendicular to the given . + /// + /// The input . + /// A perpendicular to the input . + public static Vector2D Perpendicular(this Vector2D vector) => Vector2D.Perpendicular(vector); + + /// + /// Rotates a by the specified angle (in radians). + /// + /// The to rotate. + /// The angle to rotate by, in radians. + /// The rotated . + public static Vector2D Rotate(this Vector2D vector, float angleInRadian) => Vector2D.Rotate(vector, angleInRadian); + + /// + /// Returns the component-wise minimum of two s. + /// + /// The first . + /// The second . + /// The containing the minimum components from both input s. + public static Vector2D Min(this Vector2D left, Vector2D right) => Vector2D.Min(left, right); + + /// + /// Returns the component-wise maximum of two s. + /// + /// The first . + /// The second . + /// The containing the maximum components from both input s. + public static Vector2D Max(this Vector2D left, Vector2D right) => Vector2D.Max(left, right); + + /// + /// Clamps each component of a between the corresponding component of two other s. + /// + /// The to clamp. + /// The representing the minimum values for each component. + /// The representing the maximum values for each component. + /// The clamped . + public static Vector2D Clamp(this Vector2D vector, Vector2D min, Vector2D max) => Vector2D.Clamp(vector, min, max); + + /// + /// Linearly interpolates between two s. + /// + /// The start . + /// The end . + /// The interpolation parameter (between 0 and 1). + /// The interpolated . + public static Vector2D Lerp(this Vector2D from, Vector2D to, float t) => Vector2D.Lerp(from, to, t); + + /// + /// Calculates the cross product of two s. + /// + /// The first . + /// The second . + /// The cross product of the two s. + public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); + + /// + /// Calculates the angle in radians between two s. + /// + /// The first . + /// The second . + /// The angle between the two s in radians. + public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); + + /// + /// Calculates the dot product of two s. + /// + /// The first . + /// The second . + /// The dot product of the two s. + public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); + + /// + /// Checks whether two s are approximately equal within a certain epsilon range. + /// + /// The first . + /// The second . + /// The maximum difference allowed between components. + /// True if the s are approximately equal, false otherwise. + public static bool ApproximatelyEquals(this Vector2D left, Vector2D right, float epsilon = float.Epsilon) => Vector2D.ApproximatelyEquals(left, right, epsilon); +} diff --git a/Engine.Core/Vector3D.cs b/Engine.Core/Primitives/Vector3D.cs similarity index 58% rename from Engine.Core/Vector3D.cs rename to Engine.Core/Primitives/Vector3D.cs index 3c259b5..6b57ef5 100644 --- a/Engine.Core/Vector3D.cs +++ b/Engine.Core/Primitives/Vector3D.cs @@ -5,6 +5,12 @@ namespace Syntriax.Engine.Core; /// /// Represents a three-dimensional vector. /// +/// X position of the . +/// Y position of the . +/// Z position of the . +/// +/// Initializes a new instance of the struct with the specified positions. +/// [System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")] public readonly struct Vector3D(float x, float y, float z) { @@ -284,3 +290,191 @@ public readonly struct Vector3D(float x, float y, float z) /// A hash code for the . public override int GetHashCode() => HashCode.Combine(X, Y, Z); } + +/// +/// Provides extension methods for type. +/// +public static class Vector3DExtensions +{ + /// + /// Returns the representation of the . + /// + /// The input . + /// The representation of the provided . + public static Vector2D As2D(this Vector3D vector) => new(vector.X, vector.Y); + + /// + /// Calculates the length of the . + /// + /// The input . + /// The length of the . + public static float Length(this Vector3D vector) => Vector3D.Length(vector); + + /// + /// Calculates the squared length of the . + /// + /// The input . + /// The squared length of the . + public static float LengthSquared(this Vector3D vector) => Vector3D.LengthSquared(vector); + + /// + /// Calculates the distance between two s. + /// + /// The starting . + /// The ending . + /// The distance between the two s. + public static float Distance(this Vector3D from, Vector3D to) => Vector3D.Distance(from, to); + + /// + /// Returns the with its components inverted. + /// + /// The input . + /// The inverted . + public static Vector3D Invert(this Vector3D vector) => Vector3D.Invert(vector); + + /// + /// Adds two s component-wise. + /// + /// The first . + /// The vector to be added. + /// The result of the addition. + public static Vector3D Add(this Vector3D vector, Vector3D vectorToAdd) => Vector3D.Add(vector, vectorToAdd); + + /// + /// Subtracts one from another component-wise. + /// + /// The first . + /// The to be subtracted. + /// The result of the subtraction. + public static Vector3D Subtract(this Vector3D vector, Vector3D vectorToSubtract) => Vector3D.Subtract(vector, vectorToSubtract); + + /// + /// Multiplies a by a scalar value. + /// + /// The to multiply. + /// The scalar value to multiply with. + /// The result of the multiplication. + public static Vector3D Multiply(this Vector3D vector, float value) => Vector3D.Multiply(vector, value); + + /// + /// Divides a by a scalar value. + /// + /// The to divide. + /// The scalar value to divide with. + /// The result of the division. + public static Vector3D Divide(this Vector3D vector, float value) => Vector3D.Divide(vector, value); + + /// + /// Returns a with the absolute values of each component. + /// + /// The input . + /// The with absolute values. + public static Vector3D Abs(this Vector3D vector) => Vector3D.Abs(vector); + + /// + /// Reflects a off a surface with the specified normal. + /// + /// The to reflect. + /// The normal of the reflecting surface. + /// The reflected . + public static Vector3D Reflect(this Vector3D vector, Vector3D normal) => Vector3D.Reflect(vector, normal); + + /// + /// Normalizes the (creates a with the same direction but with a length of 1). + /// + /// The input . + /// The normalized . + public static Vector3D Normalize(this Vector3D vector) => Vector3D.Normalize(vector); + + /// + /// Creates a pointing from one point to another. + /// + /// The starting point. + /// The ending point. + /// The pointing from to . + public static Vector3D FromTo(this Vector3D from, Vector3D to) => Vector3D.FromTo(from, to); + + /// + /// Scales a by another component-wise. + /// + /// The to scale. + /// The containing the scaling factors for each component. + /// The scaled . + public static Vector3D Scale(this Vector3D vector, Vector3D scale) => Vector3D.Scale(vector, scale); + + /// + /// Rotates a by the specified angle (in radians). + /// + /// The to rotate. + /// The to rotate around. + /// The angle to rotate by, in radians. + /// The rotated . + public static Vector3D Rotate(this Vector3D vector, Vector3D normal, float angleInRadian) => Vector3D.Rotate(vector, normal, angleInRadian); + + /// + /// Returns the component-wise minimum of two s. + /// + /// The first . + /// The second . + /// The containing the minimum components from both input s. + public static Vector3D Min(this Vector3D left, Vector3D right) => Vector3D.Min(left, right); + + /// + /// Returns the component-wise maximum of two s. + /// + /// The first . + /// The second . + /// The containing the maximum components from both input s. + public static Vector3D Max(this Vector3D left, Vector3D right) => Vector3D.Max(left, right); + + /// + /// Clamps each component of a between the corresponding component of two other s. + /// + /// The to clamp. + /// The representing the minimum values for each component. + /// The representing the maximum values for each component. + /// The clamped . + public static Vector3D Clamp(this Vector3D vector, Vector3D min, Vector3D max) => Vector3D.Clamp(vector, min, max); + + /// + /// Linearly interpolates between two s. + /// + /// The start . + /// The end . + /// The interpolation parameter (between 0 and 1). + /// The interpolated . + public static Vector3D Lerp(this Vector3D from, Vector3D to, float t) => Vector3D.Lerp(from, to, t); + + /// + /// Calculates the cross product of two s. + /// + /// The first . + /// The second . + /// The cross product of the two s. + public static Vector3D Cross(this Vector3D left, Vector3D right) => Vector3D.Cross(left, right); + + /// + /// Calculates the angle in radians between two s. + /// + /// The first . + /// The second . + /// The angle between the two s in radians. + public static float AngleBetween(this Vector3D left, Vector3D right) => Vector3D.Angle(left, right); + + /// + /// Calculates the dot product of two s. + /// + /// The first . + /// The second . + /// The dot product of the two s. + public static float Dot(this Vector3D left, Vector3D right) => Vector3D.Dot(left, right); + + /// + /// Checks whether two s are approximately equal within a certain epsilon range. + /// + /// The first . + /// The second . + /// The maximum difference allowed between components. + /// True if the s are approximately equal, false otherwise. + public static bool ApproximatelyEquals(this Vector3D left, Vector3D right, float epsilon = float.Epsilon) => Vector3D.ApproximatelyEquals(left, right, epsilon); +} diff --git a/Engine.Physics2D/Abstract/ICircleCollider2D.cs b/Engine.Physics2D/Abstract/ICircleCollider2D.cs index a41820f..2dc2efc 100644 --- a/Engine.Physics2D/Abstract/ICircleCollider2D.cs +++ b/Engine.Physics2D/Abstract/ICircleCollider2D.cs @@ -1,4 +1,4 @@ -using Syntriax.Engine.Physics2D.Primitives; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Abstract; diff --git a/Engine.Physics2D/Abstract/IShapeCollider2D.cs b/Engine.Physics2D/Abstract/IShapeCollider2D.cs index 87aca76..e9d0ba4 100644 --- a/Engine.Physics2D/Abstract/IShapeCollider2D.cs +++ b/Engine.Physics2D/Abstract/IShapeCollider2D.cs @@ -1,4 +1,4 @@ -using Syntriax.Engine.Physics2D.Primitives; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Abstract; diff --git a/Engine.Physics2D/Collider2DCircleBehaviour.cs b/Engine.Physics2D/Collider2DCircleBehaviour.cs index 37bf006..ebf7766 100644 --- a/Engine.Physics2D/Collider2DCircleBehaviour.cs +++ b/Engine.Physics2D/Collider2DCircleBehaviour.cs @@ -1,5 +1,5 @@ +using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Abstract; -using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; diff --git a/Engine.Physics2D/Collider2DShapeBehaviour.cs b/Engine.Physics2D/Collider2DShapeBehaviour.cs index 95de053..a5d393c 100644 --- a/Engine.Physics2D/Collider2DShapeBehaviour.cs +++ b/Engine.Physics2D/Collider2DShapeBehaviour.cs @@ -1,5 +1,5 @@ +using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Abstract; -using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; diff --git a/Engine.Physics2D/CollisionDetector2D.cs b/Engine.Physics2D/CollisionDetector2D.cs index e6fd1e7..69bb501 100644 --- a/Engine.Physics2D/CollisionDetector2D.cs +++ b/Engine.Physics2D/CollisionDetector2D.cs @@ -1,6 +1,5 @@ using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Abstract; -using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; diff --git a/Engine.Physics2D/Physics2D.cs b/Engine.Physics2D/Physics2D.cs index 60b9d8b..6293b95 100644 --- a/Engine.Physics2D/Physics2D.cs +++ b/Engine.Physics2D/Physics2D.cs @@ -1,5 +1,4 @@ using Syntriax.Engine.Core; -using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; -- 2.47.1 From 25043bbcde5ef40da1ea1c111baf37d2b2c558f6 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 18 Mar 2025 22:10:59 +0300 Subject: [PATCH 05/32] docs: fixed typo on Vector3D --- Engine.Core/Primitives/Vector3D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine.Core/Primitives/Vector3D.cs b/Engine.Core/Primitives/Vector3D.cs index 6b57ef5..7078c11 100644 --- a/Engine.Core/Primitives/Vector3D.cs +++ b/Engine.Core/Primitives/Vector3D.cs @@ -25,7 +25,7 @@ public readonly struct Vector3D(float x, float y, float z) public readonly float Y = y; /// - /// The Y coordinate of the . + /// The Z coordinate of the . /// public readonly float Z = z; -- 2.47.1 From 5c542039ed718e88b083c6e1af21aa5a98b2fb1a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 21 Mar 2025 21:53:38 +0300 Subject: [PATCH 06/32] chore: added more implicit conversions on Vector2D and Vector3D --- Engine.Core/Primitives/Vector2D.cs | 2 ++ Engine.Core/Primitives/Vector3D.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Engine.Core/Primitives/Vector2D.cs b/Engine.Core/Primitives/Vector2D.cs index 001973d..074f472 100644 --- a/Engine.Core/Primitives/Vector2D.cs +++ b/Engine.Core/Primitives/Vector2D.cs @@ -77,6 +77,8 @@ public readonly struct Vector2D(float x, float y) public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y; public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y; + public static implicit operator System.Numerics.Vector2(Vector2D vector) => new(vector.X, vector.Y); + public static implicit operator Vector2D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y); public static implicit operator Vector2D(Vector3D vector) => new(vector.X, vector.Y); public static implicit operator Vector2D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y); diff --git a/Engine.Core/Primitives/Vector3D.cs b/Engine.Core/Primitives/Vector3D.cs index 7078c11..aeef7ac 100644 --- a/Engine.Core/Primitives/Vector3D.cs +++ b/Engine.Core/Primitives/Vector3D.cs @@ -92,6 +92,8 @@ public readonly struct Vector3D(float x, float y, float z) public static bool operator ==(Vector3D left, Vector3D right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z; public static bool operator !=(Vector3D left, Vector3D right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z; + public static implicit operator System.Numerics.Vector3(Vector3D vector) => new(vector.X, vector.Y, vector.Z); + public static implicit operator Vector3D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z); public static implicit operator Vector3D(Vector2D vector) => new(vector.X, vector.Y, 0f); public static implicit operator Vector3D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f); -- 2.47.1 From b2a286b5e5564350a5558ed9c7fe51d7eedb75df Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 21 Mar 2025 22:04:00 +0300 Subject: [PATCH 07/32] feat: added quaternion struct --- Engine.Core/Primitives/Quaternion.cs | 372 +++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 Engine.Core/Primitives/Quaternion.cs diff --git a/Engine.Core/Primitives/Quaternion.cs b/Engine.Core/Primitives/Quaternion.cs new file mode 100644 index 0000000..383a6bf --- /dev/null +++ b/Engine.Core/Primitives/Quaternion.cs @@ -0,0 +1,372 @@ +using System; + +namespace Syntriax.Engine.Core; + +/// +/// Represents a 3D space rotation. +/// +/// X(i) position of the . +/// Y(j) position of the . +/// Z(k) position of the . +/// W(a) position of the . +/// +/// Initializes a new instance of the struct with the specified positions. +/// +[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")] +public readonly struct Quaternion(float x, float y, float z, float w) +{ + /// + /// The X(i) imaginary of the . + /// + public readonly float X = x; + + /// + /// The Y(j) imaginary of the . + /// + public readonly float Y = y; + + /// + /// The Z(k) imaginary of the . + /// + public readonly float Z = z; + + /// + /// The W(a) scalar of the . + /// + public readonly float W = w; + + /// + /// The magnitude (length) of the . + /// + public float Magnitude => Length(this); + + /// + /// The squared magnitude (length) of the . + /// + public float MagnitudeSquared => LengthSquared(this); + + /// + /// The normalized form of the (a with the same direction and a magnitude of 1). + /// + public Quaternion Normalized => Normalize(this); + + /// + /// Represents the with no rotation. + /// + public readonly static Quaternion Zero = new(0f, 0f, 0f, 0f); + + /// + /// Represents the identity . + /// + public readonly static Quaternion Identity = new(0f, 0f, 0f, 1f); + + public static Quaternion operator -(Quaternion quaternion) => new(-quaternion.X, -quaternion.Y, -quaternion.Z, quaternion.W); + public static Quaternion operator +(Quaternion left, Quaternion right) => new(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W); + public static Quaternion operator -(Quaternion left, Quaternion right) => new(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W); + public static Quaternion operator *(Quaternion quaternion, float value) => new(quaternion.X * value, quaternion.Y * value, quaternion.Z * value, quaternion.W * value); + public static Quaternion operator *(float value, Quaternion quaternion) => new(quaternion.X * value, quaternion.Y * value, quaternion.Z * value, quaternion.W * value); + public static Quaternion operator *(Quaternion left, Quaternion right) + => new( + left.W * right.X + left.X * right.W + left.Y * right.Z - left.Z * right.Y, + left.W * right.Y + left.Y * right.W + left.Z * right.X - left.X * right.Z, + left.W * right.Z + left.Z * right.W + left.X * right.Y - left.Y * right.X, + left.W * right.W - left.X * right.X - left.Y * right.Y - left.Z * right.Z + ); + public static Quaternion operator /(Quaternion quaternion, float value) => new(quaternion.X / value, quaternion.Y / value, quaternion.Z / value, quaternion.W / value); + public static bool operator ==(Quaternion left, Quaternion right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W; + public static bool operator !=(Quaternion left, Quaternion right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W; + + public static implicit operator Quaternion(System.Numerics.Quaternion quaternion) => new(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); + public static implicit operator System.Numerics.Quaternion(Quaternion quaternion) => new(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); + + /// + /// Calculates the length of the . + /// + /// The . + /// The length of the . + public static float Length(Quaternion quaternion) => Math.Sqrt(LengthSquared(quaternion)); + + /// + /// Calculates the squared length of the . + /// + /// The . + /// The squared length of the . + public static float LengthSquared(Quaternion quaternion) => quaternion.X * quaternion.X + quaternion.Y * quaternion.Y + quaternion.Z * quaternion.Z + quaternion.Z * quaternion.Z + quaternion.W * quaternion.W; + + /// + /// Adds two s. + /// + /// The first . + /// The second . + /// The sum of the two s. + public static Quaternion Add(Quaternion left, Quaternion right) => left + right; + + /// + /// Subtracts one from another. + /// + /// The to subtract from. + /// The to subtract. + /// The result of subtracting the second from the first. + public static Quaternion Subtract(Quaternion left, Quaternion right) => left - right; + + /// + /// Multiplies a by a scalar value. + /// + /// The . + /// The scalar value. + /// The result of multiplying the by the scalar value. + public static Quaternion Multiply(Quaternion quaternion, float value) => quaternion * value; + + /// + /// Divides a by a scalar value. + /// + /// The . + /// The scalar value. + /// The result of dividing the by the scalar value. + public static Quaternion Divide(Quaternion quaternion, float value) => quaternion / value; + + /// + /// Normalizes the (creates a unit with the same direction). + /// + /// The to normalize. + /// The normalized . + public static Quaternion Normalize(Quaternion quaternion) => quaternion / Length(quaternion); + + /// + /// Inverts the direction of the . + /// + /// The . + /// The inverted . + public static Quaternion Invert(Quaternion quaternion) => Conjugate(quaternion) / LengthSquared(quaternion); + + /// + /// Conjugate of the . + /// + /// The . + /// The inverted . + public static Quaternion Conjugate(Quaternion quaternion) => -quaternion; + + /// + /// Rotates a by applying the provided . + /// + /// The to be rotated. + /// The to used for applying rotation. + /// The rotated . + public static Vector3D RotateVector(Vector3D vector, Quaternion quaternion) + { + Quaternion rotation = quaternion * new Quaternion(vector.X, vector.Y, vector.Z, 0) * Invert(quaternion); + return new(rotation.X, rotation.Y, rotation.Z); + } + + /// + /// Performs spherical linear interpolation between two s. + /// + /// The starting (t = 0). + /// The target (t = 1). + /// The interpolation parameter. + /// The interpolated . + public static Quaternion SLerp(Quaternion from, Quaternion to, float t) + { + float dot = Dot(from, to); + + if (dot < 0.0f) + { + from = new Quaternion(-from.X, -from.Y, -from.Z, -from.W); + dot = -dot; + } + + if (dot > 0.9995f) + return Lerp(from, to, t); + + float angle = MathF.Acos(dot); + float sinAngle = MathF.Sin(angle); + + float fromWeight = MathF.Sin((1f - t) * angle) / sinAngle; + float toWeight = MathF.Sin(t * angle) / sinAngle; + + return from * fromWeight + to * toWeight; + } + + /// + /// Performs linear interpolation between two s. + /// + /// The starting (t = 0). + /// The target (t = 1). + /// The interpolation parameter. + /// The interpolated . + public static Quaternion Lerp(Quaternion from, Quaternion to, float t) => Normalize(new(from.X.Lerp(to.X, t), from.W.Lerp(to.W, t), from.Z.Lerp(to.Z, t), from.W.Lerp(to.W, t))); + + /// + /// Calculates the dot product of two s. + /// + /// The first . + /// The second . + /// The dot product of the two s. + public static float Dot(Quaternion left, Quaternion right) => left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + + /// + /// Calculates the from given axis and angle. + /// + /// The axis of the rotation in . + /// The angle in radians. + /// The rotation calculated by the given parameters. + public static Quaternion FromAxisAngle(Vector3D axis, float angle) + { + float halfAngle = angle * .5f; + float sinHalf = MathF.Sin(halfAngle); + return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, MathF.Cos(halfAngle)); + } + + /// + /// Checks if two s are approximately equal within a specified epsilon range. + /// + /// The first . + /// The second . + /// The epsilon range. + /// if the s are approximately equal; otherwise, . + public static bool ApproximatelyEquals(Quaternion left, Quaternion right, float epsilon = float.Epsilon) + => left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon) && left.Z.ApproximatelyEquals(right.Z, epsilon) && left.W.ApproximatelyEquals(right.W, epsilon); + + /// + /// Converts the to its string representation. + /// + /// A string representation of the . + public override string ToString() => $"{nameof(Quaternion)}({W}, {X}, {Y}, {Z})"; + + /// + /// Determines whether the specified object is equal to the current . + /// + /// The object to compare with the current . + /// if the specified object is equal to the current ; otherwise, . + public override bool Equals(object? obj) => obj is Quaternion objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y) && Z.Equals(objVec.Z) && W.Equals(objVec.W); + + /// + /// Generates a hash code for the . + /// + /// A hash code for the . + public override int GetHashCode() => HashCode.Combine(X, Y, Z); +} + +/// +/// Provides extension methods for type. +/// +public static class QuaternionExtensions +{ + /// + /// Calculates the length of the . + /// + /// The . + /// The length of the . + public static float Length(this Quaternion quaternion) => Quaternion.Length(quaternion); + + /// + /// Calculates the squared length of the . + /// + /// The . + /// The squared length of the . + public static float LengthSquared(this Quaternion quaternion) => Quaternion.LengthSquared(quaternion); + + /// + /// Adds two s. + /// + /// The first . + /// The second . + /// The sum of the two s. + public static Quaternion Add(this Quaternion left, Quaternion right) => Quaternion.Add(left, right); + + /// + /// Subtracts one from another. + /// + /// The to subtract from. + /// The to subtract. + /// The result of subtracting the second from the first. + public static Quaternion Subtract(this Quaternion left, Quaternion right) => Quaternion.Subtract(left, right); + + /// + /// Multiplies a by a scalar value. + /// + /// The . + /// The scalar value. + /// The result of multiplying the by the scalar value. + public static Quaternion Multiply(this Quaternion quaternion, float value) => Quaternion.Multiply(quaternion, value); + + /// + /// Divides a by a scalar value. + /// + /// The . + /// The scalar value. + /// The result of dividing the by the scalar value. + public static Quaternion Divide(this Quaternion quaternion, float value) => Quaternion.Divide(quaternion, value); + + /// + /// Normalizes the (creates a unit with the same direction). + /// + /// The to normalize. + /// The normalized . + public static Quaternion Normalize(this Quaternion quaternion) => Quaternion.Normalize(quaternion); + + /// + /// Inverts the direction of the . + /// + /// The . + /// The inverted . + public static Quaternion Invert(this Quaternion quaternion) => Quaternion.Invert(quaternion); + + /// + /// Conjugate of the . + /// + /// The . + /// The inverted . + public static Quaternion Conjugate(this Quaternion quaternion) => Quaternion.Conjugate(quaternion); + + /// + /// Rotates a by applying the provided . + /// + /// The to be rotated. + /// The to used for applying rotation. + /// The rotated . + public static Vector3D RotateVector(this Vector3D vector, Quaternion quaternion) => Quaternion.RotateVector(vector, quaternion); + + /// + /// Performs spherical linear interpolation between two s. + /// + /// The starting (t = 0). + /// The target (t = 1). + /// The interpolation parameter. + /// The interpolated . + public static Quaternion SLerp(this Quaternion from, Quaternion to, float t) => Quaternion.SLerp(from, to, t); + + /// + /// Performs linear interpolation between two s. + /// + /// The starting (t = 0). + /// The target (t = 1). + /// The interpolation parameter. + /// The interpolated . + public static Quaternion Lerp(this Quaternion from, Quaternion to, float t) => Quaternion.Lerp(from, to, t); + + /// + /// Calculates the dot product of two s. + /// + /// The first . + /// The second . + /// The dot product of the two s. + public static float Dot(this Quaternion left, Quaternion right) => Quaternion.Dot(left, right); + + /// + /// Calculates the from given axis and angle. + /// + /// The axis of the rotation in . + /// The angle in radians. + /// The rotation calculated by the given parameters. + public static Quaternion CreateRotationFromAxis(this Vector3D axis, float angle) => Quaternion.FromAxisAngle(axis, angle); + + /// + /// Checks if two s are approximately equal within a specified epsilon range. + /// + /// The first . + /// The second . + /// The epsilon range. + /// if the s are approximately equal; otherwise, . + public static bool ApproximatelyEquals(this Quaternion left, Quaternion right, float epsilon = float.Epsilon) => Quaternion.ApproximatelyEquals(left, right, epsilon); +} -- 2.47.1 From 30caa202dc858e1d544a42fc30e4ecb2d7af358e Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 21 Mar 2025 22:33:05 +0300 Subject: [PATCH 08/32] refactor: added forgotten epsilon for Shape2D.ApproximatelyEquals --- Engine.Core/Primitives/AABB.cs | 12 +++--------- Engine.Core/Primitives/Circle.cs | 9 +++------ Engine.Core/Primitives/Line2D.cs | 9 +++------ Engine.Core/Primitives/Line2DEquation.cs | 13 ++++--------- Engine.Core/Primitives/Shape2D.cs | 12 +++--------- Engine.Core/Primitives/Triangle.cs | 6 +++--- 6 files changed, 19 insertions(+), 42 deletions(-) diff --git a/Engine.Core/Primitives/AABB.cs b/Engine.Core/Primitives/AABB.cs index cbf60a5..7e6e3c8 100644 --- a/Engine.Core/Primitives/AABB.cs +++ b/Engine.Core/Primitives/AABB.cs @@ -75,8 +75,8 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) /// The first . /// The second . /// if the s are approximately equal; otherwise, . - public static bool ApproximatelyEquals(AABB left, AABB right) - => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary); + public static bool ApproximatelyEquals(AABB left, AABB right, float epsilon = float.Epsilon) + => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary, epsilon) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary, epsilon); } /// @@ -91,11 +91,5 @@ public static class AABBExtensions /// An that bounds all the s. public static AABB ToAABB(this IEnumerable vectors) => AABB.FromVectors(vectors); - /// - /// Checks if two s are approximately equal. - /// - /// The first . - /// The second . - /// if the s are approximately equal; otherwise, . - public static bool ApproximatelyEquals(this AABB left, AABB right) => AABB.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this AABB left, AABB right, float epsilon = float.Epsilon) => AABB.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Circle.cs b/Engine.Core/Primitives/Circle.cs index 1833a65..780fd64 100644 --- a/Engine.Core/Primitives/Circle.cs +++ b/Engine.Core/Primitives/Circle.cs @@ -72,8 +72,8 @@ public readonly struct Circle(Vector2D center, float radius) /// /// Checks if two s are approximately equal. /// - public static bool ApproximatelyEquals(Circle left, Circle right) - => left.Center.ApproximatelyEquals(right.Center) && left.Radius.ApproximatelyEquals(right.Radius); + public static bool ApproximatelyEquals(Circle left, Circle right, float epsilon = float.Epsilon) + => left.Center.ApproximatelyEquals(right.Center, epsilon) && left.Radius.ApproximatelyEquals(right.Radius, epsilon); } /// @@ -106,8 +106,5 @@ public static class CircleExtensions /// public static Circle TransformCircle(this ITransform transform, Circle circle) => Circle.TransformCircle(transform, circle); - /// - /// Checks if two s are approximately equal. - /// - public static bool ApproximatelyEquals(this Circle left, Circle right) => Circle.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Circle left, Circle right, float epsilon = float.Epsilon) => Circle.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Line2D.cs b/Engine.Core/Primitives/Line2D.cs index 0a11de2..d2b776c 100644 --- a/Engine.Core/Primitives/Line2D.cs +++ b/Engine.Core/Primitives/Line2D.cs @@ -184,8 +184,8 @@ public readonly struct Line2D(Vector2D from, Vector2D to) /// /// Checks if two segments are approximately equal. /// - public static bool ApproximatelyEquals(Line2D left, Line2D right) - => left.From.ApproximatelyEquals(right.From) && left.To.ApproximatelyEquals(right.To); + public static bool ApproximatelyEquals(Line2D left, Line2D right, float epsilon = float.Epsilon) + => left.From.ApproximatelyEquals(right.From, epsilon) && left.To.ApproximatelyEquals(right.To, epsilon); } /// @@ -223,8 +223,5 @@ public static class Line2DExtensions /// public static bool Intersects(this Line2D left, Line2D right, [NotNullWhen(returnValue: true)] out Vector2D? point) => Line2D.Intersects(left, right, out point); - /// - /// Checks if two s are approximately equal. - /// - public static bool ApproximatelyEquals(this Line2D left, Line2D right) => Line2D.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Line2D left, Line2D right, float epsilon = float.Epsilon) => Line2D.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Line2DEquation.cs b/Engine.Core/Primitives/Line2DEquation.cs index 20d33ab..24479e3 100644 --- a/Engine.Core/Primitives/Line2DEquation.cs +++ b/Engine.Core/Primitives/Line2DEquation.cs @@ -34,9 +34,10 @@ public readonly struct Line2DEquation(float slope, float offsetY) /// /// The first line equation to compare. /// The second line equation to compare. + /// The epsilon range. /// True if the line equations are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(Line2DEquation left, Line2DEquation right) - => left.Slope.ApproximatelyEquals(right.Slope) && left.OffsetY.ApproximatelyEquals(right.OffsetY); + public static bool ApproximatelyEquals(Line2DEquation left, Line2DEquation right, float epsilon = float.Epsilon) + => left.Slope.ApproximatelyEquals(right.Slope, epsilon) && left.OffsetY.ApproximatelyEquals(right.OffsetY, epsilon); } /// @@ -52,11 +53,5 @@ public static class Line2DEquationExtensions /// The y-coordinate resolved using the line equation. public static float Resolve(this Line2DEquation lineEquation, float x) => Line2DEquation.Resolve(lineEquation, x); - /// - /// Checks if two line equations are approximately equal. - /// - /// The first line equation to compare. - /// The second line equation to compare. - /// True if the line equations are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(this Line2DEquation left, Line2DEquation right) => Line2DEquation.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Line2DEquation left, Line2DEquation right, float epsilon = float.Epsilon) => Line2DEquation.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Shape2D.cs b/Engine.Core/Primitives/Shape2D.cs index 95d94df..a2c5433 100644 --- a/Engine.Core/Primitives/Shape2D.cs +++ b/Engine.Core/Primitives/Shape2D.cs @@ -198,13 +198,13 @@ public readonly struct Shape2D(List vertices) : IEnumerable /// The first shape to compare. /// The second shape to compare. /// true if the shapes are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(Shape2D left, Shape2D right) + public static bool ApproximatelyEquals(Shape2D left, Shape2D right, float epsilon = float.Epsilon) { if (left.Vertices.Count != right.Vertices.Count) return false; for (int i = 0; i < left.Vertices.Count; i++) - if (!left.Vertices[i].ApproximatelyEquals(right.Vertices[i])) + if (!left.Vertices[i].ApproximatelyEquals(right.Vertices[i], epsilon)) return false; return true; @@ -282,11 +282,5 @@ public static class Shape2DExtensions /// The transformed shape. public static void TransformShape(this ITransform transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to); - /// - /// Determines whether two shapes are approximately equal. - /// - /// The first shape to compare. - /// The second shape to compare. - /// true if the shapes are approximately equal; otherwise, false. - public static bool ApproximatelyEquals(this Shape2D left, Shape2D right) => Shape2D.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Triangle.cs b/Engine.Core/Primitives/Triangle.cs index 8e3ce88..1dfbf2f 100644 --- a/Engine.Core/Primitives/Triangle.cs +++ b/Engine.Core/Primitives/Triangle.cs @@ -37,11 +37,11 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) return new(center, Vector2D.Distance(center, triangle.A)); } - public static bool ApproximatelyEquals(Triangle left, Triangle right) - => left.A.ApproximatelyEquals(right.A) && left.B.ApproximatelyEquals(right.B) && left.C.ApproximatelyEquals(right.C); + public static bool ApproximatelyEquals(Triangle left, Triangle right, float epsilon = float.Epsilon) + => left.A.ApproximatelyEquals(right.A, epsilon) && left.B.ApproximatelyEquals(right.B, epsilon) && left.C.ApproximatelyEquals(right.C, epsilon); } public static class TriangleExtensions { - public static bool ApproximatelyEquals(this Triangle left, Triangle right) => Triangle.ApproximatelyEquals(left, right); + public static bool ApproximatelyEquals(this Triangle left, Triangle right, float epsilon = float.Epsilon) => Triangle.ApproximatelyEquals(left, right, epsilon); } -- 2.47.1 From 95ddba02308e3e62d10d952ee1be480b39a327e3 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 21 Mar 2025 23:01:47 +0300 Subject: [PATCH 09/32] docs: updated extension methods to inherit the original method's documentation --- Engine.Core/Primitives/AABB.cs | 8 +- Engine.Core/Primitives/Circle.cs | 25 ++-- Engine.Core/Primitives/Line2D.cs | 31 ++--- Engine.Core/Primitives/Line2DEquation.cs | 8 +- Engine.Core/Primitives/Projection1D.cs | 15 +-- Engine.Core/Primitives/Quaternion.cs | 105 +++------------ Engine.Core/Primitives/Shape2D.cs | 54 ++------ Engine.Core/Primitives/Triangle.cs | 8 ++ Engine.Core/Primitives/Vector2D.cs | 165 ++++------------------- Engine.Core/Primitives/Vector3D.cs | 160 +++------------------- 10 files changed, 108 insertions(+), 471 deletions(-) diff --git a/Engine.Core/Primitives/AABB.cs b/Engine.Core/Primitives/AABB.cs index 7e6e3c8..fad4569 100644 --- a/Engine.Core/Primitives/AABB.cs +++ b/Engine.Core/Primitives/AABB.cs @@ -74,6 +74,7 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) /// /// The first . /// The second . + /// The epsilon range. /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(AABB left, AABB right, float epsilon = float.Epsilon) => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary, epsilon) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary, epsilon); @@ -84,12 +85,9 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) /// public static class AABBExtensions { - /// - /// Converts a collection of s to an . - /// - /// The collection of s. - /// An that bounds all the s. + /// public static AABB ToAABB(this IEnumerable vectors) => AABB.FromVectors(vectors); + /// public static bool ApproximatelyEquals(this AABB left, AABB right, float epsilon = float.Epsilon) => AABB.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Circle.cs b/Engine.Core/Primitives/Circle.cs index 780fd64..acb4ace 100644 --- a/Engine.Core/Primitives/Circle.cs +++ b/Engine.Core/Primitives/Circle.cs @@ -72,6 +72,10 @@ public readonly struct Circle(Vector2D center, float radius) /// /// Checks if two s are approximately equal. /// + /// The first . + /// The second . + /// The epsilon range. + /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(Circle left, Circle right, float epsilon = float.Epsilon) => left.Center.ApproximatelyEquals(right.Center, epsilon) && left.Radius.ApproximatelyEquals(right.Radius, epsilon); } @@ -81,30 +85,21 @@ public readonly struct Circle(Vector2D center, float radius) /// public static class CircleExtensions { - /// - /// Sets the center of the . - /// + /// public static Circle SetCenter(this Circle circle, Vector2D center) => Circle.SetCenter(circle, center); - /// - /// Sets the radius of the . - /// + /// public static Circle SetRadius(this Circle circle, float radius) => Circle.SetRadius(circle, radius); - /// - /// Moves the by the specified . - /// + /// public static Circle Displace(this Circle circle, Vector2D displaceVector) => Circle.Displace(circle, displaceVector); - /// - /// Projects the onto the specified . - /// + /// public static Projection1D ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector); - /// - /// Transforms the by the specified . - /// + /// public static Circle TransformCircle(this ITransform transform, Circle circle) => Circle.TransformCircle(transform, circle); + /// public static bool ApproximatelyEquals(this Circle left, Circle right, float epsilon = float.Epsilon) => Circle.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Line2D.cs b/Engine.Core/Primitives/Line2D.cs index d2b776c..83b6f8c 100644 --- a/Engine.Core/Primitives/Line2D.cs +++ b/Engine.Core/Primitives/Line2D.cs @@ -184,44 +184,37 @@ public readonly struct Line2D(Vector2D from, Vector2D to) /// /// Checks if two segments are approximately equal. /// + /// The first . + /// The second . + /// The epsilon range. + /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(Line2D left, Line2D right, float epsilon = float.Epsilon) => left.From.ApproximatelyEquals(right.From, epsilon) && left.To.ApproximatelyEquals(right.To, epsilon); } /// -/// Provides extension methods for the Line struct. +/// Provides extension methods for the struct. /// public static class Line2DExtensions { - /// - /// Linearly interpolates between the two endpoints of the segment using parameter 't'. - /// + /// public static Vector2D Lerp(this Line2D line, float t) => Line2D.Lerp(line, t); - /// - /// The equation of the defined by this segment. - /// + /// public static Line2DEquation ToLineEquation(this Line2D line) => Line2D.GetLineEquation(line); - /// - /// Determines whether the specified lies on the . - /// + /// public static bool Intersects(this Line2D line, Vector2D point) => Line2D.Intersects(line, point); - /// - /// Calculates the parameter 't' representing the point's position on the segment. - /// + /// public static float GetT(this Line2D line, Vector2D point) => Line2D.GetT(line, point); - /// - /// Checks if the segment intersects with another segment. - /// + /// public static bool Intersects(this Line2D left, Line2D right) => Line2D.Intersects(left, right); - /// - /// Determines whether two segments intersect. - /// + /// public static bool Intersects(this Line2D left, Line2D right, [NotNullWhen(returnValue: true)] out Vector2D? point) => Line2D.Intersects(left, right, out point); + /// public static bool ApproximatelyEquals(this Line2D left, Line2D right, float epsilon = float.Epsilon) => Line2D.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Line2DEquation.cs b/Engine.Core/Primitives/Line2DEquation.cs index 24479e3..d76c20d 100644 --- a/Engine.Core/Primitives/Line2DEquation.cs +++ b/Engine.Core/Primitives/Line2DEquation.cs @@ -45,13 +45,9 @@ public readonly struct Line2DEquation(float slope, float offsetY) /// public static class Line2DEquationExtensions { - /// - /// Resolves the y-coordinate for a given x-coordinate using the line equation. - /// - /// The line equation to resolve. - /// The x-coordinate for which to resolve the y-coordinate. - /// The y-coordinate resolved using the line equation. + /// public static float Resolve(this Line2DEquation lineEquation, float x) => Line2DEquation.Resolve(lineEquation, x); + /// public static bool ApproximatelyEquals(this Line2DEquation left, Line2DEquation right, float epsilon = float.Epsilon) => Line2DEquation.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Projection1D.cs b/Engine.Core/Primitives/Projection1D.cs index 9c72fdd..8a78413 100644 --- a/Engine.Core/Primitives/Projection1D.cs +++ b/Engine.Core/Primitives/Projection1D.cs @@ -77,20 +77,9 @@ public readonly struct Projection1D(float min, float max) /// public static class Projection1DExtensions { - /// - /// Checks if two projections overlap. - /// - /// The first projection to check. - /// The second projection to check. - /// if the projections overlap; otherwise, . + /// public static bool Overlaps(this Projection1D left, Projection1D right) => Projection1D.Overlaps(left, right); - /// - /// Checks if two projections overlap and calculates the depth of the overlap. - /// - /// The first projection to check. - /// The second projection to check. - /// The depth of the overlap, if any. - /// if the projections overlap; otherwise, . + /// public static bool Overlaps(this Projection1D left, Projection1D right, out float depth) => Projection1D.Overlaps(left, right, out depth); } diff --git a/Engine.Core/Primitives/Quaternion.cs b/Engine.Core/Primitives/Quaternion.cs index 383a6bf..4593ee3 100644 --- a/Engine.Core/Primitives/Quaternion.cs +++ b/Engine.Core/Primitives/Quaternion.cs @@ -252,121 +252,48 @@ public readonly struct Quaternion(float x, float y, float z, float w) /// public static class QuaternionExtensions { - /// - /// Calculates the length of the . - /// - /// The . - /// The length of the . + /// public static float Length(this Quaternion quaternion) => Quaternion.Length(quaternion); - /// - /// Calculates the squared length of the . - /// - /// The . - /// The squared length of the . + /// public static float LengthSquared(this Quaternion quaternion) => Quaternion.LengthSquared(quaternion); - /// - /// Adds two s. - /// - /// The first . - /// The second . - /// The sum of the two s. + /// public static Quaternion Add(this Quaternion left, Quaternion right) => Quaternion.Add(left, right); - /// - /// Subtracts one from another. - /// - /// The to subtract from. - /// The to subtract. - /// The result of subtracting the second from the first. + /// public static Quaternion Subtract(this Quaternion left, Quaternion right) => Quaternion.Subtract(left, right); - /// - /// Multiplies a by a scalar value. - /// - /// The . - /// The scalar value. - /// The result of multiplying the by the scalar value. + /// public static Quaternion Multiply(this Quaternion quaternion, float value) => Quaternion.Multiply(quaternion, value); - /// - /// Divides a by a scalar value. - /// - /// The . - /// The scalar value. - /// The result of dividing the by the scalar value. + /// public static Quaternion Divide(this Quaternion quaternion, float value) => Quaternion.Divide(quaternion, value); - /// - /// Normalizes the (creates a unit with the same direction). - /// - /// The to normalize. - /// The normalized . + /// public static Quaternion Normalize(this Quaternion quaternion) => Quaternion.Normalize(quaternion); - /// - /// Inverts the direction of the . - /// - /// The . - /// The inverted . + /// public static Quaternion Invert(this Quaternion quaternion) => Quaternion.Invert(quaternion); - /// - /// Conjugate of the . - /// - /// The . - /// The inverted . + /// public static Quaternion Conjugate(this Quaternion quaternion) => Quaternion.Conjugate(quaternion); - /// - /// Rotates a by applying the provided . - /// - /// The to be rotated. - /// The to used for applying rotation. - /// The rotated . + /// public static Vector3D RotateVector(this Vector3D vector, Quaternion quaternion) => Quaternion.RotateVector(vector, quaternion); - /// - /// Performs spherical linear interpolation between two s. - /// - /// The starting (t = 0). - /// The target (t = 1). - /// The interpolation parameter. - /// The interpolated . + /// public static Quaternion SLerp(this Quaternion from, Quaternion to, float t) => Quaternion.SLerp(from, to, t); - /// - /// Performs linear interpolation between two s. - /// - /// The starting (t = 0). - /// The target (t = 1). - /// The interpolation parameter. - /// The interpolated . + /// public static Quaternion Lerp(this Quaternion from, Quaternion to, float t) => Quaternion.Lerp(from, to, t); - /// - /// Calculates the dot product of two s. - /// - /// The first . - /// The second . - /// The dot product of the two s. + /// public static float Dot(this Quaternion left, Quaternion right) => Quaternion.Dot(left, right); - /// - /// Calculates the from given axis and angle. - /// - /// The axis of the rotation in . - /// The angle in radians. - /// The rotation calculated by the given parameters. - public static Quaternion CreateRotationFromAxis(this Vector3D axis, float angle) => Quaternion.FromAxisAngle(axis, angle); + /// + public static Quaternion CreateRotation(this Vector3D axis, float angle) => Quaternion.FromAxisAngle(axis, angle); - /// - /// Checks if two s are approximately equal within a specified epsilon range. - /// - /// The first . - /// The second . - /// The epsilon range. - /// if the s are approximately equal; otherwise, . + /// public static bool ApproximatelyEquals(this Quaternion left, Quaternion right, float epsilon = float.Epsilon) => Quaternion.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Shape2D.cs b/Engine.Core/Primitives/Shape2D.cs index a2c5433..8e8b5fe 100644 --- a/Engine.Core/Primitives/Shape2D.cs +++ b/Engine.Core/Primitives/Shape2D.cs @@ -197,6 +197,7 @@ public readonly struct Shape2D(List vertices) : IEnumerable /// /// The first shape to compare. /// The second shape to compare. + /// The epsilon range. /// true if the shapes are approximately equal; otherwise, false. public static bool ApproximatelyEquals(Shape2D left, Shape2D right, float epsilon = float.Epsilon) { @@ -222,65 +223,30 @@ public readonly struct Shape2D(List vertices) : IEnumerable /// public static class Shape2DExtensions { - /// - /// Creates a copy of the shape. - /// - /// The shape to copy. - /// A copy of the input shape. + /// public static Shape2D CreateCopy(this Shape2D shape) => Shape2D.CreateCopy(shape); - /// - /// Gets the super triangle that encloses the shape. - /// - /// The shape to enclose. - /// The super triangle that encloses the shape. + /// public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape); - /// - /// Gets the lines that form the edges of the shape. - /// - /// The shape to get lines from. - /// The list to populate with lines. + /// public static void ToLines(this Shape2D shape, IList lines) => Shape2D.GetLines(shape, lines); - /// - /// Gets a list of lines that form the edges of the shape. - /// - /// The shape to get lines from. - /// A list of lines that form the edges of the shape. + /// public static List ToLines(this Shape2D shape) => Shape2D.GetLines(shape); - /// - /// Projects the shape onto a vector. - /// - /// The shape to project. - /// The vector to project onto. - /// The list to populate with projected values. + /// public static void ToProjection(this Shape2D shape, Vector2D projectionVector, IList list) => Shape2D.Project(shape, projectionVector, list); - /// - /// Projects the shape onto a vector. - /// - /// The shape to project. - /// The vector to project onto. - /// The projection of the shape onto the vector. + /// public static Projection1D ToProjection(this Shape2D shape, Vector2D projectionVector) => Shape2D.Project(shape, projectionVector); - /// - /// Transforms the shape using the specified transform. - /// - /// The transform to apply. - /// The shape to transform. - /// The transformed shape. + /// public static Shape2D TransformShape(this ITransform transform, Shape2D shape) => Shape2D.TransformShape(shape, transform); - /// - /// Transforms the shape using the specified transform. - /// - /// The transform to apply. - /// The shape to transform. - /// The transformed shape. + /// public static void TransformShape(this ITransform transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to); + /// public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Triangle.cs b/Engine.Core/Primitives/Triangle.cs index 1dfbf2f..e36ac03 100644 --- a/Engine.Core/Primitives/Triangle.cs +++ b/Engine.Core/Primitives/Triangle.cs @@ -37,11 +37,19 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) return new(center, Vector2D.Distance(center, triangle.A)); } + /// + /// Determines whether two s are approximately equal. + /// + /// The first to compare. + /// The second to compare. + /// The epsilon range. + /// true if the s are approximately equal; otherwise, false. public static bool ApproximatelyEquals(Triangle left, Triangle right, float epsilon = float.Epsilon) => left.A.ApproximatelyEquals(right.A, epsilon) && left.B.ApproximatelyEquals(right.B, epsilon) && left.C.ApproximatelyEquals(right.C, epsilon); } public static class TriangleExtensions { + /// public static bool ApproximatelyEquals(this Triangle left, Triangle right, float epsilon = float.Epsilon) => Triangle.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Vector2D.cs b/Engine.Core/Primitives/Vector2D.cs index 074f472..e005e24 100644 --- a/Engine.Core/Primitives/Vector2D.cs +++ b/Engine.Core/Primitives/Vector2D.cs @@ -313,191 +313,72 @@ public readonly struct Vector2D(float x, float y) /// public static class Vector2DExtensions { - /// - /// Returns the representation of the . - /// - /// The input . - /// The representation of the provided . - public static Vector3D As3D(this Vector2D vector) => new(vector.X, vector.Y, 0f); - - /// - /// Calculates the length of the . - /// - /// The input . - /// The length of the . + /// public static float Length(this Vector2D vector) => Vector2D.Length(vector); - /// - /// Calculates the squared length of the . - /// - /// The input . - /// The squared length of the . + /// s. - /// - /// The starting . - /// The ending . - /// The distance between the two s. + /// public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); - /// - /// Returns the with its components inverted. - /// - /// The input . - /// The inverted . + /// s component-wise. - /// - /// The first . - /// The vector to be added. - /// The result of the addition. + /// public static Vector2D Add(this Vector2D vector, Vector2D vectorToAdd) => Vector2D.Add(vector, vectorToAdd); - /// - /// Subtracts one from another component-wise. - /// - /// The first . - /// The to be subtracted. - /// The result of the subtraction. + /// public static Vector2D Subtract(this Vector2D vector, Vector2D vectorToSubtract) => Vector2D.Subtract(vector, vectorToSubtract); - /// - /// Multiplies a by a scalar value. - /// - /// The to multiply. - /// The scalar value to multiply with. - /// The result of the multiplication. + /// public static Vector2D Multiply(this Vector2D vector, float value) => Vector2D.Multiply(vector, value); - /// - /// Divides a by a scalar value. - /// - /// The to divide. - /// The scalar value to divide with. - /// The result of the division. + /// public static Vector2D Divide(this Vector2D vector, float value) => Vector2D.Divide(vector, value); - /// - /// Returns a with the absolute values of each component. - /// - /// The input . - /// The with absolute values. + /// public static Vector2D Abs(this Vector2D vector) => Vector2D.Abs(vector); - /// - /// Reflects a off a surface with the specified normal. - /// - /// The to reflect. - /// The normal of the reflecting surface. - /// The reflected . + /// public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal); - /// - /// Normalizes the (creates a with the same direction but with a length of 1). - /// - /// The input . - /// The normalized . + /// public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); - /// - /// Creates a pointing from one point to another. - /// - /// The starting point. - /// The ending point. - /// The pointing from to . + /// public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); - /// - /// Scales a by another component-wise. - /// - /// The to scale. - /// The containing the scaling factors for each component. - /// The scaled . + /// public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.Scale(vector, scale); - /// - /// Calculates the perpendicular to the given . - /// - /// The input . - /// A perpendicular to the input . + /// public static Vector2D Perpendicular(this Vector2D vector) => Vector2D.Perpendicular(vector); - /// - /// Rotates a by the specified angle (in radians). - /// - /// The to rotate. - /// The angle to rotate by, in radians. - /// The rotated . + /// public static Vector2D Rotate(this Vector2D vector, float angleInRadian) => Vector2D.Rotate(vector, angleInRadian); - /// - /// Returns the component-wise minimum of two s. - /// - /// The first . - /// The second . - /// The containing the minimum components from both input s. + /// public static Vector2D Min(this Vector2D left, Vector2D right) => Vector2D.Min(left, right); - /// - /// Returns the component-wise maximum of two s. - /// - /// The first . - /// The second . - /// The containing the maximum components from both input s. + /// public static Vector2D Max(this Vector2D left, Vector2D right) => Vector2D.Max(left, right); - /// - /// Clamps each component of a between the corresponding component of two other s. - /// - /// The to clamp. - /// The representing the minimum values for each component. - /// The representing the maximum values for each component. - /// The clamped . + /// public static Vector2D Clamp(this Vector2D vector, Vector2D min, Vector2D max) => Vector2D.Clamp(vector, min, max); - /// - /// Linearly interpolates between two s. - /// - /// The start . - /// The end . - /// The interpolation parameter (between 0 and 1). - /// The interpolated . + /// public static Vector2D Lerp(this Vector2D from, Vector2D to, float t) => Vector2D.Lerp(from, to, t); - /// - /// Calculates the cross product of two s. - /// - /// The first . - /// The second . - /// The cross product of the two s. + /// public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); - /// - /// Calculates the angle in radians between two s. - /// - /// The first . - /// The second . - /// The angle between the two s in radians. + /// public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); - /// - /// Calculates the dot product of two s. - /// - /// The first . - /// The second . - /// The dot product of the two s. + /// public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); - /// - /// Checks whether two s are approximately equal within a certain epsilon range. - /// - /// The first . - /// The second . - /// The maximum difference allowed between components. - /// True if the s are approximately equal, false otherwise. + /// public static bool ApproximatelyEquals(this Vector2D left, Vector2D right, float epsilon = float.Epsilon) => Vector2D.ApproximatelyEquals(left, right, epsilon); } diff --git a/Engine.Core/Primitives/Vector3D.cs b/Engine.Core/Primitives/Vector3D.cs index aeef7ac..1c869e1 100644 --- a/Engine.Core/Primitives/Vector3D.cs +++ b/Engine.Core/Primitives/Vector3D.cs @@ -298,185 +298,69 @@ public readonly struct Vector3D(float x, float y, float z) /// public static class Vector3DExtensions { - /// - /// Returns the representation of the . - /// - /// The input . - /// The representation of the provided . - public static Vector2D As2D(this Vector3D vector) => new(vector.X, vector.Y); - - /// - /// Calculates the length of the . - /// - /// The input . - /// The length of the . + /// public static float Length(this Vector3D vector) => Vector3D.Length(vector); - /// - /// Calculates the squared length of the . - /// - /// The input . - /// The squared length of the . + /// public static float LengthSquared(this Vector3D vector) => Vector3D.LengthSquared(vector); - /// - /// Calculates the distance between two s. - /// - /// The starting . - /// The ending . - /// The distance between the two s. + /// public static float Distance(this Vector3D from, Vector3D to) => Vector3D.Distance(from, to); - /// - /// Returns the with its components inverted. - /// - /// The input . - /// The inverted . + /// public static Vector3D Invert(this Vector3D vector) => Vector3D.Invert(vector); - /// - /// Adds two s component-wise. - /// - /// The first . - /// The vector to be added. - /// The result of the addition. + /// public static Vector3D Add(this Vector3D vector, Vector3D vectorToAdd) => Vector3D.Add(vector, vectorToAdd); - /// - /// Subtracts one from another component-wise. - /// - /// The first . - /// The to be subtracted. - /// The result of the subtraction. + /// public static Vector3D Subtract(this Vector3D vector, Vector3D vectorToSubtract) => Vector3D.Subtract(vector, vectorToSubtract); - /// - /// Multiplies a by a scalar value. - /// - /// The to multiply. - /// The scalar value to multiply with. - /// The result of the multiplication. + /// public static Vector3D Multiply(this Vector3D vector, float value) => Vector3D.Multiply(vector, value); - /// - /// Divides a by a scalar value. - /// - /// The to divide. - /// The scalar value to divide with. - /// The result of the division. + /// public static Vector3D Divide(this Vector3D vector, float value) => Vector3D.Divide(vector, value); - /// - /// Returns a with the absolute values of each component. - /// - /// The input . - /// The with absolute values. + /// public static Vector3D Abs(this Vector3D vector) => Vector3D.Abs(vector); - /// - /// Reflects a off a surface with the specified normal. - /// - /// The to reflect. - /// The normal of the reflecting surface. - /// The reflected . + /// public static Vector3D Reflect(this Vector3D vector, Vector3D normal) => Vector3D.Reflect(vector, normal); - /// - /// Normalizes the (creates a with the same direction but with a length of 1). - /// - /// The input . - /// The normalized . + /// public static Vector3D Normalize(this Vector3D vector) => Vector3D.Normalize(vector); - /// - /// Creates a pointing from one point to another. - /// - /// The starting point. - /// The ending point. - /// The pointing from to . + /// public static Vector3D FromTo(this Vector3D from, Vector3D to) => Vector3D.FromTo(from, to); - /// - /// Scales a by another component-wise. - /// - /// The to scale. - /// The containing the scaling factors for each component. - /// The scaled . + /// public static Vector3D Scale(this Vector3D vector, Vector3D scale) => Vector3D.Scale(vector, scale); - /// - /// Rotates a by the specified angle (in radians). - /// - /// The to rotate. - /// The to rotate around. - /// The angle to rotate by, in radians. - /// The rotated . + /// public static Vector3D Rotate(this Vector3D vector, Vector3D normal, float angleInRadian) => Vector3D.Rotate(vector, normal, angleInRadian); - /// - /// Returns the component-wise minimum of two s. - /// - /// The first . - /// The second . - /// The containing the minimum components from both input s. + /// public static Vector3D Min(this Vector3D left, Vector3D right) => Vector3D.Min(left, right); - /// - /// Returns the component-wise maximum of two s. - /// - /// The first . - /// The second . - /// The containing the maximum components from both input s. + /// public static Vector3D Max(this Vector3D left, Vector3D right) => Vector3D.Max(left, right); - /// - /// Clamps each component of a between the corresponding component of two other s. - /// - /// The to clamp. - /// The representing the minimum values for each component. - /// The representing the maximum values for each component. - /// The clamped . + /// public static Vector3D Clamp(this Vector3D vector, Vector3D min, Vector3D max) => Vector3D.Clamp(vector, min, max); - /// - /// Linearly interpolates between two s. - /// - /// The start . - /// The end . - /// The interpolation parameter (between 0 and 1). - /// The interpolated . + /// public static Vector3D Lerp(this Vector3D from, Vector3D to, float t) => Vector3D.Lerp(from, to, t); - /// - /// Calculates the cross product of two s. - /// - /// The first . - /// The second . - /// The cross product of the two s. + /// public static Vector3D Cross(this Vector3D left, Vector3D right) => Vector3D.Cross(left, right); - /// - /// Calculates the angle in radians between two s. - /// - /// The first . - /// The second . - /// The angle between the two s in radians. + /// public static float AngleBetween(this Vector3D left, Vector3D right) => Vector3D.Angle(left, right); - /// - /// Calculates the dot product of two s. - /// - /// The first . - /// The second . - /// The dot product of the two s. + /// public static float Dot(this Vector3D left, Vector3D right) => Vector3D.Dot(left, right); - /// - /// Checks whether two s are approximately equal within a certain epsilon range. - /// - /// The first . - /// The second . - /// The maximum difference allowed between components. - /// True if the s are approximately equal, false otherwise. + /// public static bool ApproximatelyEquals(this Vector3D left, Vector3D right, float epsilon = float.Epsilon) => Vector3D.ApproximatelyEquals(left, right, epsilon); } -- 2.47.1 From 5fc8c012b31c3b7a57afbef20ef4a573cdf27c15 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 26 Mar 2025 13:57:46 +0300 Subject: [PATCH 10/32] feat: quaternion to matrix4x4 methods --- Engine.Core/Primitives/Quaternion.cs | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Engine.Core/Primitives/Quaternion.cs b/Engine.Core/Primitives/Quaternion.cs index 4593ee3..7a04539 100644 --- a/Engine.Core/Primitives/Quaternion.cs +++ b/Engine.Core/Primitives/Quaternion.cs @@ -217,6 +217,63 @@ public readonly struct Quaternion(float x, float y, float z, float w) return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, MathF.Cos(halfAngle)); } + /// + /// Calculates the from given yaw, pitch and roll values. + /// + /// The rotation calculated by the given parameters. + public static Quaternion FromAngles(float x, float y, float z) + { + float cosX = Math.Cos(x * .5f); + float sinX = Math.Sin(x * .5f); + float cosY = Math.Cos(y * .5f); + float sinY = Math.Sin(y * .5f); + float cozZ = Math.Cos(z * .5f); + float sinZ = Math.Sin(z * .5f); + + return new Quaternion( + x: sinX * cosY * cozZ - cosX * sinY * sinZ, + y: cosX * sinY * cozZ + sinX * cosY * sinZ, + z: cosX * cosY * sinZ - sinX * sinY * cozZ, + w: cosX * cosY * cozZ + sinX * sinY * sinZ + ); + } + + /// + /// Calculates the from given . + /// + /// The axis of the rotation in . + /// The angle in radians. + /// The rotation calculated by the given . + public static System.Numerics.Matrix4x4 ToRotationMatrix4x4(Quaternion quaternion) + { + float m00 = 1 - 2 * (quaternion.Y * quaternion.Y + quaternion.Z * quaternion.Z); + float m01 = 2 * (quaternion.X * quaternion.Y - quaternion.W * quaternion.Z); + float m02 = 2 * (quaternion.X * quaternion.Z + quaternion.W * quaternion.Y); + float m03 = 0; + + float m10 = 2 * (quaternion.X * quaternion.Y + quaternion.W * quaternion.Z); + float m11 = 1 - 2 * (quaternion.X * quaternion.X + quaternion.Z * quaternion.Z); + float m12 = 2 * (quaternion.Y * quaternion.Z - quaternion.W * quaternion.X); + float m13 = 0; + + float m20 = 2 * (quaternion.X * quaternion.Z - quaternion.W * quaternion.Y); + float m21 = 2 * (quaternion.Y * quaternion.Z + quaternion.W * quaternion.X); + float m22 = 1 - 2 * (quaternion.X * quaternion.X + quaternion.Y * quaternion.Y); + float m23 = 0; + + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + + return new( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 + ); + } + /// /// Checks if two s are approximately equal within a specified epsilon range. /// @@ -291,6 +348,9 @@ public static class QuaternionExtensions /// public static float Dot(this Quaternion left, Quaternion right) => Quaternion.Dot(left, right); + /// + public static System.Numerics.Matrix4x4 ToRotationMatrix4x4(this Quaternion quaternion) => Quaternion.ToRotationMatrix4x4(quaternion); + /// public static Quaternion CreateRotation(this Vector3D axis, float angle) => Quaternion.FromAxisAngle(axis, angle); -- 2.47.1 From d825bb55d33ca8161904dcc8700734d88b2999a8 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 26 Mar 2025 14:19:47 +0300 Subject: [PATCH 11/32] refactor!: Transform events now send previous values of their changed fields --- Engine.Core/Abstract/ITransform.cs | 42 ++++++++++++++++++-- Engine.Core/Transform.cs | 44 ++++++++++++++------- Engine.Physics2D/Collider2DBehaviourBase.cs | 16 ++++---- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/Engine.Core/Abstract/ITransform.cs b/Engine.Core/Abstract/ITransform.cs index cd5e66f..a170f39 100644 --- a/Engine.Core/Abstract/ITransform.cs +++ b/Engine.Core/Abstract/ITransform.cs @@ -95,10 +95,46 @@ public interface ITransform : IAssignableGameObject, IEnumerable /// The child to remove. void RemoveChild(ITransform transform); - delegate void OnPositionChangedEventHandler(ITransform sender); - delegate void OnScaleChangedEventHandler(ITransform sender); - delegate void OnRotationChangedEventHandler(ITransform sender); + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnPositionChangedEventHandler(ITransform sender, Vector2D previousPosition); + + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnScaleChangedEventHandler(ITransform sender, Vector2D previousScale); + + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnRotationChangedEventHandler(ITransform sender, float previousRotation); + + /// + /// Delegate for the event triggered when the 's parent changes. + /// + /// The that the parent has changed. + /// The previous the sender was a child of. + /// The new and current the sender is a child of. delegate void OnParentChangedEventHandler(ITransform sender, ITransform? previousParent, ITransform? newParent); + + /// + /// Delegate for the event triggered when a new added as a child. + /// + /// The parent this event is being called from. + /// The that got removed as a children of the sender . delegate void OnChildrenAddedEventHandler(ITransform sender, ITransform childrenAdded); + + /// + /// Delegate for the event triggered when a new removed from being a child. + /// + /// The parent this event is being called from. + /// The that got removed as a children of the sender . delegate void OnChildrenRemovedEventHandler(ITransform sender, ITransform childrenRemoved); } diff --git a/Engine.Core/Transform.cs b/Engine.Core/Transform.cs index 3451e70..cddbfc5 100644 --- a/Engine.Core/Transform.cs +++ b/Engine.Core/Transform.cs @@ -43,9 +43,11 @@ public class Transform : ITransform if (value == _position) return; + Vector2D previousPosition = _position; _position = value; + UpdateLocalPosition(); - OnPositionChanged?.Invoke(this); + OnPositionChanged?.Invoke(this, _position); } } @@ -57,9 +59,11 @@ public class Transform : ITransform if (value == _scale) return; + Vector2D previousScale = _scale; _scale = value; + UpdateLocalScale(); - OnScaleChanged?.Invoke(this); + OnScaleChanged?.Invoke(this, previousScale); } } @@ -71,9 +75,12 @@ public class Transform : ITransform if (value == _rotation) return; + + float previousRotation = _rotation; _rotation = value; + UpdateLocalPosition(); - OnRotationChanged?.Invoke(this); + OnRotationChanged?.Invoke(this, previousRotation); } } @@ -85,9 +92,11 @@ public class Transform : ITransform if (value == _localPosition) return; + Vector2D previousPosition = _position; _localPosition = value; + UpdatePosition(); - OnPositionChanged?.Invoke(this); + OnPositionChanged?.Invoke(this, previousPosition); } } @@ -99,9 +108,11 @@ public class Transform : ITransform if (value == _localScale) return; + Vector2D previousScale = _scale; _localScale = value; + UpdateScale(); - OnScaleChanged?.Invoke(this); + OnScaleChanged?.Invoke(this, previousScale); } } @@ -113,9 +124,11 @@ public class Transform : ITransform if (value == _localRotation) return; + float previousRotation = _rotation; _localRotation = value; + UpdateRotation(); - OnRotationChanged?.Invoke(this); + OnRotationChanged?.Invoke(this, previousRotation); } } @@ -182,33 +195,36 @@ public class Transform : ITransform child.SetParent(this); } - private void RecalculatePosition(ITransform _) + private void RecalculatePosition(ITransform _, Vector2D previousPosition) { if (Parent is null) return; UpdatePosition(); - OnPositionChanged?.Invoke(this); + + OnPositionChanged?.Invoke(this, previousPosition); } - private void RecalculateScale(ITransform _) + private void RecalculateScale(ITransform _, Vector2D previousScale) { if (Parent is null) return; UpdateScale(); - OnScaleChanged?.Invoke(this); + + OnScaleChanged?.Invoke(this, previousScale); } - private void RecalculateRotation(ITransform _) + private void RecalculateRotation(ITransform _, float previousRotation) { if (Parent is null) return; - UpdatePosition(); + // UpdatePosition(); UpdateRotation(); - OnPositionChanged?.Invoke(this); - OnRotationChanged?.Invoke(this); + + // OnPositionChanged?.Invoke(this, previousPosition); + OnRotationChanged?.Invoke(this, previousRotation); } private void UpdateLocalPosition() diff --git a/Engine.Physics2D/Collider2DBehaviourBase.cs b/Engine.Physics2D/Collider2DBehaviourBase.cs index 5688655..2a06b4a 100644 --- a/Engine.Physics2D/Collider2DBehaviourBase.cs +++ b/Engine.Physics2D/Collider2DBehaviourBase.cs @@ -39,9 +39,9 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D BehaviourController.OnBehaviourAdded += OnBehaviourAddedToController; BehaviourController.OnBehaviourRemoved += OnBehaviourRemovedFromController; - Transform.OnPositionChanged += SetNeedsRecalculation; - Transform.OnRotationChanged += SetNeedsRecalculation; - Transform.OnScaleChanged += SetNeedsRecalculation; + Transform.OnPositionChanged += SetNeedsRecalculationFromPosition; + Transform.OnRotationChanged += SetNeedsRecalculationFromRotation; + Transform.OnScaleChanged += SetNeedsRecalculationFromScale; Transform.OnParentChanged += UpdateRigidBody2D; } @@ -62,16 +62,18 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D _rigidBody2D = null; } - private void SetNeedsRecalculation(ITransform transform) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromScale(ITransform sender, Vector2D previousScale) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromPosition(ITransform sender, Vector2D previousPosition) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromRotation(ITransform sender, float previousRotation) => NeedsRecalculation = true; protected override void OnFinalize() { BehaviourController.OnBehaviourAdded -= OnBehaviourAddedToController; BehaviourController.OnBehaviourRemoved -= OnBehaviourRemovedFromController; - Transform.OnScaleChanged -= SetNeedsRecalculation; + Transform.OnScaleChanged -= SetNeedsRecalculationFromScale; - Transform.OnPositionChanged -= SetNeedsRecalculation; - Transform.OnRotationChanged -= SetNeedsRecalculation; + Transform.OnPositionChanged -= SetNeedsRecalculationFromPosition; + Transform.OnRotationChanged -= SetNeedsRecalculationFromRotation; } public void Detect(CollisionDetectionInformation collisionDetectionInformation) => OnCollisionDetected?.Invoke(this, collisionDetectionInformation); -- 2.47.1 From 4ec1a32db20e868985cefb9c6a36d5680fe5b529 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 28 Mar 2025 17:47:05 +0300 Subject: [PATCH 12/32] refactor!: IGameObject removed --- .../Assignable/IAssignableGameObject.cs | 26 -- .../Assignable/IAssignableTransform.cs | 26 -- ...ntroller.cs => IHasBehaviourController.cs} | 4 +- .../{IAssignableEntity.cs => IHasEntity.cs} | 4 +- ...nableGameManager.cs => IHasGameManager.cs} | 6 +- .../Assignable/IHasHierarchyObject.cs | 26 ++ ...nableStateEnable.cs => IHasStateEnable.cs} | 4 +- .../Abstract/Assignable/IHierarchyObject.cs | 64 ---- Engine.Core/Abstract/BaseEntity.cs | 13 +- Engine.Core/Abstract/IBehaviour.cs | 2 +- Engine.Core/Abstract/IBehaviour2D.cs | 6 + Engine.Core/Abstract/IBehaviourCollector.cs | 2 +- Engine.Core/Abstract/IBehaviourController.cs | 4 +- Engine.Core/Abstract/ICamera2D.cs | 2 +- Engine.Core/Abstract/IEntity.cs | 2 +- Engine.Core/Abstract/IGameManager.cs | 29 +- Engine.Core/Abstract/IGameObject.cs | 19 -- Engine.Core/Abstract/IHierarchyObject.cs | 131 ++++++++ .../{IInitialize.cs => IInitializable.cs} | 8 +- Engine.Core/Abstract/IStateEnable.cs | 2 +- Engine.Core/Abstract/ITransform.cs | 140 --------- Engine.Core/Abstract/ITransform2D.cs | 73 +++++ Engine.Core/Behaviour.cs | 39 ++- Engine.Core/Behaviour2D.cs | 28 ++ Engine.Core/BehaviourBase.cs | 4 +- Engine.Core/BehaviourCollector.cs | 38 +-- Engine.Core/BehaviourController.cs | 34 +- Engine.Core/CoroutineManager.cs | 2 +- Engine.Core/Engine.Core.puml | 46 +++ .../Exceptions/NotAssignedException.cs | 4 +- .../Abstract/TransformExtensions.cs | 2 +- .../BehaviourControllerExtensions.cs | 6 +- Engine.Core/Extensions/BehaviourExtensions.cs | 16 +- .../Extensions/GameManagerExtensions.cs | 4 +- .../Extensions/GameObjectExtensions.cs | 12 - .../Extensions/HierarchyObjectExtensions.cs | 6 + Engine.Core/Extensions/TransformExtensions.cs | 2 +- .../Factory/BehaviourControllerFactory.cs | 10 +- Engine.Core/Factory/BehaviourFactory.cs | 10 +- Engine.Core/Factory/GameObjectFactory.cs | 42 --- Engine.Core/Factory/HierarchyObjectFactory.cs | 35 +++ Engine.Core/Factory/TransformFactory.cs | 4 +- Engine.Core/GameManager.cs | 145 +++------ Engine.Core/GameObject.cs | 151 --------- Engine.Core/HierarchyObject.cs | 136 ++++++++ Engine.Core/HierarchyObjectBase.cs | 142 --------- Engine.Core/Primitives/Circle.cs | 8 +- Engine.Core/Primitives/Shape2D.cs | 12 +- Engine.Core/StateEnable.cs | 2 +- Engine.Core/Transform.cs | 297 ------------------ Engine.Core/Transform2D.cs | 255 +++++++++++++++ Engine.Input/Abstract/IButtonInputs.cs | 2 +- Engine.Physics2D/Abstract/ICollider2D.cs | 5 +- Engine.Physics2D/Abstract/IRigidBody2D.cs | 2 +- Engine.Physics2D/Collider2DBehaviourBase.cs | 17 +- Engine.Physics2D/PhysicsCoroutineManager.cs | 2 +- Engine.Physics2D/PhysicsEngine2DCollector.cs | 2 +- Engine.Physics2D/RigidBody2D.cs | 9 +- 58 files changed, 937 insertions(+), 1187 deletions(-) delete mode 100644 Engine.Core/Abstract/Assignable/IAssignableGameObject.cs delete mode 100644 Engine.Core/Abstract/Assignable/IAssignableTransform.cs rename Engine.Core/Abstract/Assignable/{IAssignableBehaviourController.cs => IHasBehaviourController.cs} (85%) rename Engine.Core/Abstract/Assignable/{IAssignableEntity.cs => IHasEntity.cs} (86%) rename Engine.Core/Abstract/Assignable/{IAssignableGameManager.cs => IHasGameManager.cs} (81%) create mode 100644 Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs rename Engine.Core/Abstract/Assignable/{IAssignableStateEnable.cs => IHasStateEnable.cs} (86%) delete mode 100644 Engine.Core/Abstract/Assignable/IHierarchyObject.cs create mode 100644 Engine.Core/Abstract/IBehaviour2D.cs delete mode 100644 Engine.Core/Abstract/IGameObject.cs create mode 100644 Engine.Core/Abstract/IHierarchyObject.cs rename Engine.Core/Abstract/{IInitialize.cs => IInitializable.cs} (81%) delete mode 100644 Engine.Core/Abstract/ITransform.cs create mode 100644 Engine.Core/Abstract/ITransform2D.cs create mode 100644 Engine.Core/Behaviour2D.cs create mode 100644 Engine.Core/Engine.Core.puml delete mode 100644 Engine.Core/Extensions/GameObjectExtensions.cs delete mode 100644 Engine.Core/Factory/GameObjectFactory.cs create mode 100644 Engine.Core/Factory/HierarchyObjectFactory.cs delete mode 100644 Engine.Core/GameObject.cs create mode 100644 Engine.Core/HierarchyObject.cs delete mode 100644 Engine.Core/HierarchyObjectBase.cs delete mode 100644 Engine.Core/Transform.cs create mode 100644 Engine.Core/Transform2D.cs diff --git a/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs b/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs deleted file mode 100644 index fbcfcca..0000000 --- a/Engine.Core/Abstract/Assignable/IAssignableGameObject.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Syntriax.Engine.Core.Abstract; - -/// -/// Indicates the object is an with an assignable field. -/// -public interface IAssignableGameObject : IAssignable -{ - /// - /// Event triggered when the value has has been assigned a new value. - /// - event OnGameObjectAssignedEventHandler? OnGameObjectAssigned; - - /// - IGameObject GameObject { get; } - - /// - /// Assign a value to the field of this object. - /// - /// New to assign. - /// - /// , if the value given assigned successfully assigned, if not. - /// - bool Assign(IGameObject gameObject); - - delegate void OnGameObjectAssignedEventHandler(IAssignableGameObject sender); -} diff --git a/Engine.Core/Abstract/Assignable/IAssignableTransform.cs b/Engine.Core/Abstract/Assignable/IAssignableTransform.cs deleted file mode 100644 index 797c1b7..0000000 --- a/Engine.Core/Abstract/Assignable/IAssignableTransform.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Syntriax.Engine.Core.Abstract; - -/// -/// Indicates the object is an with an assignable field. -/// -public interface IAssignableTransform : IAssignable -{ - /// - /// Event triggered when the value has has been assigned a new value. - /// - event OnTransformAssignedEventHandler? OnTransformAssigned; - - /// - ITransform Transform { get; } - - /// - /// Assign a value to the field of this object. - /// - /// New to assign. - /// - /// , if the value given assigned successfully assigned, if not. - /// - bool Assign(ITransform transform); - - delegate void OnTransformAssignedEventHandler(IAssignableTransform sender); -} diff --git a/Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs b/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs similarity index 85% rename from Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs rename to Engine.Core/Abstract/Assignable/IHasBehaviourController.cs index 0365bd6..b5218c3 100644 --- a/Engine.Core/Abstract/Assignable/IAssignableBehaviourController.cs +++ b/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Indicates the object is an with an assignable field. /// -public interface IAssignableBehaviourController : IAssignable +public interface IHasBehaviourController : IAssignable { /// /// Event triggered when the value has has been assigned a new value. @@ -22,5 +22,5 @@ public interface IAssignableBehaviourController : IAssignable /// bool Assign(IBehaviourController behaviourController); - delegate void OnBehaviourControllerAssignedEventHandler(IAssignableBehaviourController sender); + delegate void OnBehaviourControllerAssignedEventHandler(IHasBehaviourController sender); } diff --git a/Engine.Core/Abstract/Assignable/IAssignableEntity.cs b/Engine.Core/Abstract/Assignable/IHasEntity.cs similarity index 86% rename from Engine.Core/Abstract/Assignable/IAssignableEntity.cs rename to Engine.Core/Abstract/Assignable/IHasEntity.cs index ad96566..6ffcaeb 100644 --- a/Engine.Core/Abstract/Assignable/IAssignableEntity.cs +++ b/Engine.Core/Abstract/Assignable/IHasEntity.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Indicates the object is an with an assignable field. /// -public interface IAssignableEntity : IAssignable +public interface IHasEntity : IAssignable { /// /// Event triggered when the value has has been assigned a new value. @@ -22,5 +22,5 @@ public interface IAssignableEntity : IAssignable /// bool Assign(IEntity entity); - delegate void OnEntityAssignedEventHandler(IAssignableEntity sender); + delegate void OnEntityAssignedEventHandler(IHasEntity sender); } diff --git a/Engine.Core/Abstract/Assignable/IAssignableGameManager.cs b/Engine.Core/Abstract/Assignable/IHasGameManager.cs similarity index 81% rename from Engine.Core/Abstract/Assignable/IAssignableGameManager.cs rename to Engine.Core/Abstract/Assignable/IHasGameManager.cs index 27f9559..cb3f4d4 100644 --- a/Engine.Core/Abstract/Assignable/IAssignableGameManager.cs +++ b/Engine.Core/Abstract/Assignable/IHasGameManager.cs @@ -1,9 +1,9 @@ namespace Syntriax.Engine.Core.Abstract; /// -/// Indicates the object is an with an assignable field. +/// Indicates the object is an with an assignable field. /// -public interface IAssignableGameManager : IAssignable +public interface IHasGameManager : IAssignable { /// /// Event triggered when the value has has been assigned a new value. @@ -22,5 +22,5 @@ public interface IAssignableGameManager : IAssignable /// bool Assign(IGameManager gameManager); - delegate void OnGameManagerAssignedEventHandler(IAssignableGameManager sender); + delegate void OnGameManagerAssignedEventHandler(IHasGameManager sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs b/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs new file mode 100644 index 0000000..f8d3df9 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs @@ -0,0 +1,26 @@ +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IHasHierarchyObject : IAssignable +{ + /// + /// Event triggered when the value has has been assigned a new value. + /// + event OnHierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned; + + /// + IHierarchyObject HierarchyObject { get; } + + /// + /// Assign a value to the field of this object. + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(IHierarchyObject hierarchyObject); + + delegate void OnHierarchyObjectAssignedEventHandler(IHasHierarchyObject sender); +} diff --git a/Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs b/Engine.Core/Abstract/Assignable/IHasStateEnable.cs similarity index 86% rename from Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs rename to Engine.Core/Abstract/Assignable/IHasStateEnable.cs index 8a366f6..54a5b52 100644 --- a/Engine.Core/Abstract/Assignable/IAssignableStateEnable.cs +++ b/Engine.Core/Abstract/Assignable/IHasStateEnable.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Indicates the object is an with an assignable field. /// -public interface IAssignableStateEnable : IAssignable +public interface IHasStateEnable : IAssignable { /// /// Event triggered when the value has has been assigned a new value. @@ -22,5 +22,5 @@ public interface IAssignableStateEnable : IAssignable /// bool Assign(IStateEnable stateEnable); - delegate void OnStateEnableAssignedEventHandler(IAssignableStateEnable sender); + delegate void OnStateEnableAssignedEventHandler(IHasStateEnable sender); } diff --git a/Engine.Core/Abstract/Assignable/IHierarchyObject.cs b/Engine.Core/Abstract/Assignable/IHierarchyObject.cs deleted file mode 100644 index ccc153b..0000000 --- a/Engine.Core/Abstract/Assignable/IHierarchyObject.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace Syntriax.Engine.Core.Abstract; - -/// -/// Represents an that can enter and exit a hierarchy within the system. -/// This interface allows for tracking the object's presence in the hierarchy and provides events -/// for notifying when the see enters or exits the hierarchy. -/// -public interface IHierarchyObject : IEntity, INameable -{ - /// - /// Event triggered when the enters the hierarchy. - /// - event OnEnteredHierarchyEventHandler? OnEnteredHierarchy; - - /// - /// Event triggered when the exits the hierarchy. - /// - event OnExitedHierarchyEventHandler? OnExitedHierarchy; - - /// - /// Gets the associated with this , if any. - /// - IGameManager GameManager { get; } - - /// - /// Indicates whether the is currently in the hierarchy. - /// - bool IsInHierarchy { get; } - - /// - /// Internal method to handle entering the hierarchy. - /// This should be called by the system to properly manage hierarchy states. - /// - /// The game manager that is managing this hierarchy. - /// - /// if the successfully entered the hierarchy; - /// if it failed to do so. - /// - internal bool EnterHierarchy(IGameManager gameManager); - - /// - /// Internal method to handle exiting the hierarchy. - /// This should be called by the system to properly manage hierarchy states. - /// - /// - /// if the successfully exited the hierarchy; - /// if it failed to do so. - /// - internal bool ExitHierarchy(); - - /// - /// EventHandler delegate for the event triggered when the enters the hierarchy of a . - /// - /// The that entered the hierarchy. - /// The that the has entered it's hierarchy. - delegate void OnEnteredHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); - - /// - /// EventHandler delegate for the event triggered when the exits the hierarchy of a . - /// - /// The that exited the hierarchy. - /// The that the has exited it's hierarchy. - delegate void OnExitedHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); -} diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/Abstract/BaseEntity.cs index 50fdb77..ae456e1 100644 --- a/Engine.Core/Abstract/BaseEntity.cs +++ b/Engine.Core/Abstract/BaseEntity.cs @@ -1,17 +1,15 @@ using System; -using Syntriax.Engine.Core.Exceptions; - namespace Syntriax.Engine.Core.Abstract; public abstract class BaseEntity : IEntity { public event IEntity.OnIdChangedEventHandler? OnIdChanged = null; - public event IInitialize.OnInitializedEventHandler? OnInitialized = null; - public event IInitialize.OnFinalizedEventHandler? OnFinalized = null; + public event IInitializable.OnInitializedEventHandler? OnInitialized = null; + public event IInitializable.OnFinalizedEventHandler? OnFinalized = null; - public event IAssignableStateEnable.OnStateEnableAssignedEventHandler? OnStateEnableAssigned = null; + public event IHasStateEnable.OnStateEnableAssignedEventHandler? OnStateEnableAssigned = null; public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; private IStateEnable _stateEnable = null!; @@ -28,6 +26,9 @@ public abstract class BaseEntity : IEntity get => _id; set { + if (IsInitialized) + throw new($"Can't change {nameof(Id)} of {_id} because it's initialized"); + if (value == _id) return; @@ -85,7 +86,7 @@ public abstract class BaseEntity : IEntity if (IsInitialized) return false; - NotAssignedException.Check(this, _stateEnable); + _stateEnable ??= new Factory.StateEnableFactory().Instantiate(this); InitializeInternal(); diff --git a/Engine.Core/Abstract/IBehaviour.cs b/Engine.Core/Abstract/IBehaviour.cs index 9f6df38..cdd25a1 100644 --- a/Engine.Core/Abstract/IBehaviour.cs +++ b/Engine.Core/Abstract/IBehaviour.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a behaviour that any object in the game might use to interact with itself or other objects. /// -public interface IBehaviour : IEntity, IAssignableBehaviourController, IAssignableStateEnable +public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable { /// /// Event triggered when the priority of the changes. diff --git a/Engine.Core/Abstract/IBehaviour2D.cs b/Engine.Core/Abstract/IBehaviour2D.cs new file mode 100644 index 0000000..558d664 --- /dev/null +++ b/Engine.Core/Abstract/IBehaviour2D.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Core.Abstract; + +public interface IBehaviour2D : IBehaviour +{ + ITransform2D Transform { get; } +} diff --git a/Engine.Core/Abstract/IBehaviourCollector.cs b/Engine.Core/Abstract/IBehaviourCollector.cs index 967abe1..84bf28b 100644 --- a/Engine.Core/Abstract/IBehaviourCollector.cs +++ b/Engine.Core/Abstract/IBehaviourCollector.cs @@ -7,7 +7,7 @@ namespace Syntriax.Engine.Core.Abstract; /// Provides mechanisms for tracking additions and removals, and notifies subscribers when such events occur on the assigned . /// /// The type of objects tracked by the collector. -public interface IBehaviourCollector : IAssignableGameManager, IEnumerable where T : class +public interface IBehaviourCollector : IHasGameManager, IEnumerable where T : class { /// /// Event triggered when an object of type is added to the collector. diff --git a/Engine.Core/Abstract/IBehaviourController.cs b/Engine.Core/Abstract/IBehaviourController.cs index f93d5ea..8b92caa 100644 --- a/Engine.Core/Abstract/IBehaviourController.cs +++ b/Engine.Core/Abstract/IBehaviourController.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; namespace Syntriax.Engine.Core.Abstract; /// -/// Represents a controller for managing s and notify them accordingly about the engine's updates. Connected to an . +/// Represents a controller for managing s and notify them accordingly about the engine's updates. Connected to an . /// -public interface IBehaviourController : IInitialize, IAssignableGameObject, IEnumerable +public interface IBehaviourController : IInitializable, IHasHierarchyObject, IEnumerable { /// /// Event triggered before the update of s. diff --git a/Engine.Core/Abstract/ICamera2D.cs b/Engine.Core/Abstract/ICamera2D.cs index a70a7fa..5779092 100644 --- a/Engine.Core/Abstract/ICamera2D.cs +++ b/Engine.Core/Abstract/ICamera2D.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a 2D camera in the engine. /// -public interface ICamera2D : IBehaviour, IAssignableTransform +public interface ICamera2D : IBehaviour2D { /// /// The zoom level of the camera. diff --git a/Engine.Core/Abstract/IEntity.cs b/Engine.Core/Abstract/IEntity.cs index 34acf3b..d88e34b 100644 --- a/Engine.Core/Abstract/IEntity.cs +++ b/Engine.Core/Abstract/IEntity.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a basic entity in the engine. /// -public interface IEntity : IInitialize, IAssignableStateEnable +public interface IEntity : IInitializable, IHasStateEnable { /// /// Event triggered when the of the changes. diff --git a/Engine.Core/Abstract/IGameManager.cs b/Engine.Core/Abstract/IGameManager.cs index 5433888..9eaa0bb 100644 --- a/Engine.Core/Abstract/IGameManager.cs +++ b/Engine.Core/Abstract/IGameManager.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Syntriax.Engine.Core.Abstract; /// -/// Represents a game world responsible for managing s. +/// Represents a game world responsible for managing s. /// public interface IGameManager : IEntity { @@ -17,16 +17,6 @@ public interface IGameManager : IEntity /// event OnPreDawEventHandler? OnPreDraw; - /// - /// Event triggered when a is registered to the . - /// - event OnGameObjectRegisteredEventHandler? OnGameObjectRegistered; - - /// - /// Event triggered when a is unregistered from the . - /// - event OnGameObjectUnRegisteredEventHandler? OnGameObjectUnRegistered; - /// /// Event triggered when a is registered to the . /// @@ -37,11 +27,6 @@ public interface IGameManager : IEntity /// event OnHierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered; - /// - /// Gets a read-only list of s managed by the . - /// - IReadOnlyList GameObjects { get; } - /// /// Gets a read-only list of s managed by the . /// @@ -54,12 +39,12 @@ public interface IGameManager : IEntity void Register(IHierarchyObject hierarchyObject); /// - /// Instantiates a of type T with the given arguments and registers it to the . + /// Instantiates a of type T with the given arguments and registers it to the . /// - /// The type of to instantiate. - /// Constructor parameters for the given type of . - /// The instantiated . - T InstantiateGameObject(params object?[]? args) where T : class, IGameObject; + /// The type of to instantiate. + /// Constructor parameters for the given type of . + /// The instantiated . + T InstantiateHierarchyObject(params object?[]? args) where T : class, IHierarchyObject; /// /// Removes an from the . @@ -81,8 +66,6 @@ public interface IGameManager : IEntity delegate void OnUpdateEventHandler(IGameManager sender, EngineTime time); delegate void OnPreDawEventHandler(IGameManager sender); - delegate void OnGameObjectRegisteredEventHandler(IGameManager sender, IGameObject gameObjectRegistered); - delegate void OnGameObjectUnRegisteredEventHandler(IGameManager sender, IGameObject gameObjectUnregistered); delegate void OnHierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered); delegate void OnHierarchyObjectUnRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered); } diff --git a/Engine.Core/Abstract/IGameObject.cs b/Engine.Core/Abstract/IGameObject.cs deleted file mode 100644 index 03b187d..0000000 --- a/Engine.Core/Abstract/IGameObject.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Syntriax.Engine.Core.Abstract; - -/// -/// Represents a game object with various properties and functionalities. -/// -public interface IGameObject : IEntity, IHierarchyObject, IAssignableTransform, IAssignableBehaviourController, INameable, IInitialize -{ - /// - /// Event triggered when the method is called. - /// - event OnUpdatedEventHandler? OnUpdated; - - /// - /// Updates the game object. - /// - void Update(); - - delegate void OnUpdatedEventHandler(IGameObject sender); -} diff --git a/Engine.Core/Abstract/IHierarchyObject.cs b/Engine.Core/Abstract/IHierarchyObject.cs new file mode 100644 index 0000000..4edccda --- /dev/null +++ b/Engine.Core/Abstract/IHierarchyObject.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Represents an that can enter and exit a hierarchy within the system. +/// This interface allows for tracking the object's presence in the hierarchy and provides events +/// for notifying when the see enters or exits the hierarchy. +/// +public interface IHierarchyObject : IEntity, INameable, IHasBehaviourController, IEnumerable +{ + /// + /// Event triggered when the enters the hierarchy. + /// + event OnEnteredHierarchyEventHandler? OnEnteredHierarchy; + + /// + /// Event triggered when the exits the hierarchy. + /// + event OnExitedHierarchyEventHandler? OnExitedHierarchy; + + /// + /// Event triggered when the of the changes. The second parameter is the old . + /// + event OnParentChangedEventHandler? OnParentChanged; + + /// + /// Event triggered when a new is added to the . + /// + event OnChildrenAddedEventHandler? OnChildrenAdded; + + /// + /// Event triggered when an is removed from the . + /// + event OnChildrenRemovedEventHandler? OnChildrenRemoved; + + /// + /// Gets the this is connected to, if any. + /// + IGameManager GameManager { get; } + + /// + /// Indicates whether the is currently in the hierarchy. + /// + bool IsInHierarchy { get; } + + /// + /// The parent of the . + /// + IHierarchyObject? Parent { get; } + + /// + /// The s that have this as their . + /// + IReadOnlyList Children { get; } + + /// + /// Internal method to handle entering the hierarchy. + /// This should be called by the system to properly manage hierarchy states. + /// + /// The that is managing this hierarchy. + /// + /// if the successfully entered the hierarchy; + /// if it failed to do so. + /// + internal bool EnterHierarchy(IGameManager gameManager); + + /// + /// Internal method to handle exiting the hierarchy. + /// This should be called by the system to properly manage hierarchy states. + /// + /// + /// if the successfully exited the hierarchy; + /// if it failed to do so. + /// + internal bool ExitHierarchy(); + + /// + /// Sets the parent of this . + /// + /// The parent to set. + void SetParent(IHierarchyObject? hierarchyObject); + + /// + /// Adds a child to this . + /// + /// The child to add. + void AddChild(IHierarchyObject hierarchyObject); + + /// + /// Removes a child from this . + /// + /// The child to remove. + void RemoveChild(IHierarchyObject hierarchyObject); + + /// + /// EventHandler delegate for the event triggered when the enters the hierarchy of a . + /// + /// The that entered the hierarchy. + /// The that the has entered it's hierarchy. + delegate void OnEnteredHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); + + /// + /// EventHandler delegate for the event triggered when the exits the hierarchy of a . + /// + /// The that exited the hierarchy. + /// The that the has exited it's hierarchy. + delegate void OnExitedHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); + + /// + /// Delegate for the event triggered when the 's parent changes. + /// + /// The that the parent has changed. + /// The previous the sender was a child of. + /// The new and current the sender is a child of. + delegate void OnParentChangedEventHandler(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent); + + /// + /// Delegate for the event triggered when a new added as a child. + /// + /// The parent this event is being called from. + /// The that got removed as a children of the sender . + delegate void OnChildrenAddedEventHandler(IHierarchyObject sender, IHierarchyObject childrenAdded); + + /// + /// Delegate for the event triggered when a new removed from being a child. + /// + /// The parent this event is being called from. + /// The that got removed as a children of the sender . + delegate void OnChildrenRemovedEventHandler(IHierarchyObject sender, IHierarchyObject childrenRemoved); +} diff --git a/Engine.Core/Abstract/IInitialize.cs b/Engine.Core/Abstract/IInitializable.cs similarity index 81% rename from Engine.Core/Abstract/IInitialize.cs rename to Engine.Core/Abstract/IInitializable.cs index d4487c7..7a666d0 100644 --- a/Engine.Core/Abstract/IInitialize.cs +++ b/Engine.Core/Abstract/IInitializable.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents an entity that can be initialized and finalized. This information is useful for objects we know that are not in use and can be either recycled or dropped for garbage collection. /// -public interface IInitialize +public interface IInitializable { /// /// Event triggered when the method is called successfully. @@ -11,7 +11,7 @@ public interface IInitialize event OnInitializedEventHandler? OnInitialized; /// - /// Event triggered when the method is called successfully. + /// Event triggered when the method is called successfully. /// event OnFinalizedEventHandler? OnFinalized; @@ -32,6 +32,6 @@ public interface IInitialize /// if finalization is successful, otherwise . bool Finalize(); - delegate void OnInitializedEventHandler(IInitialize sender); - delegate void OnFinalizedEventHandler(IInitialize sender); + delegate void OnInitializedEventHandler(IInitializable sender); + delegate void OnFinalizedEventHandler(IInitializable sender); } diff --git a/Engine.Core/Abstract/IStateEnable.cs b/Engine.Core/Abstract/IStateEnable.cs index 8591eb4..3ef6726 100644 --- a/Engine.Core/Abstract/IStateEnable.cs +++ b/Engine.Core/Abstract/IStateEnable.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents an entity with an enable state that can be toggled. /// -public interface IStateEnable : IAssignableEntity +public interface IStateEnable : IHasEntity { /// /// Event triggered when the state of the changes. diff --git a/Engine.Core/Abstract/ITransform.cs b/Engine.Core/Abstract/ITransform.cs deleted file mode 100644 index a170f39..0000000 --- a/Engine.Core/Abstract/ITransform.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.Collections.Generic; - -namespace Syntriax.Engine.Core.Abstract; - -/// -/// Represents the transformation properties of an object such as position, scale, and rotation. -/// -public interface ITransform : IAssignableGameObject, IEnumerable -{ - /// - /// Event triggered when the of the changes. - /// - event OnPositionChangedEventHandler? OnPositionChanged; - - /// - /// Event triggered when the of the changes. - /// - event OnScaleChangedEventHandler? OnScaleChanged; - - /// - /// Event triggered when the of the changes. - /// - event OnRotationChangedEventHandler? OnRotationChanged; - - /// - /// Event triggered when the of the changes. The second parameter is the old . - /// - event OnParentChangedEventHandler? OnParentChanged; - - /// - /// Event triggered when a new is added to the . - /// - event OnChildrenAddedEventHandler? OnChildrenAdded; - - /// - /// Event triggered when an is removed from the . - /// - event OnChildrenRemovedEventHandler? OnChildrenRemoved; - - /// - /// The world position of the in 2D space. - /// - Vector2D Position { get; set; } - - /// - /// The world scale of the . - /// - Vector2D Scale { get; set; } - - /// - /// The world rotation of the in degrees. - /// - float Rotation { get; set; } - - /// - /// The local position of the in 2D space. - /// - Vector2D LocalPosition { get; set; } - - /// - /// The local scale of the . - /// - Vector2D LocalScale { get; set; } - - /// - /// The local rotation of the in degrees. - /// - float LocalRotation { get; set; } - - /// - /// The parent of the . - /// - ITransform? Parent { get; } - - /// - /// The s that have this as their . - /// - IReadOnlyList Children { get; } - - /// - /// Sets the parent of this . - /// - /// The parent to set. - void SetParent(ITransform? transform); - - /// - /// Adds a child to this . - /// - /// The child to add. - void AddChild(ITransform transform); - - /// - /// Removes a child from this . - /// - /// The child to remove. - void RemoveChild(ITransform transform); - - /// - /// Delegate for the event triggered when the 's rotation changes. - /// - /// The that the parent has changed. - /// The previous of the . - delegate void OnPositionChangedEventHandler(ITransform sender, Vector2D previousPosition); - - /// - /// Delegate for the event triggered when the 's rotation changes. - /// - /// The that the parent has changed. - /// The previous of the . - delegate void OnScaleChangedEventHandler(ITransform sender, Vector2D previousScale); - - /// - /// Delegate for the event triggered when the 's rotation changes. - /// - /// The that the parent has changed. - /// The previous of the . - delegate void OnRotationChangedEventHandler(ITransform sender, float previousRotation); - - /// - /// Delegate for the event triggered when the 's parent changes. - /// - /// The that the parent has changed. - /// The previous the sender was a child of. - /// The new and current the sender is a child of. - delegate void OnParentChangedEventHandler(ITransform sender, ITransform? previousParent, ITransform? newParent); - - /// - /// Delegate for the event triggered when a new added as a child. - /// - /// The parent this event is being called from. - /// The that got removed as a children of the sender . - delegate void OnChildrenAddedEventHandler(ITransform sender, ITransform childrenAdded); - - /// - /// Delegate for the event triggered when a new removed from being a child. - /// - /// The parent this event is being called from. - /// The that got removed as a children of the sender . - delegate void OnChildrenRemovedEventHandler(ITransform sender, ITransform childrenRemoved); -} diff --git a/Engine.Core/Abstract/ITransform2D.cs b/Engine.Core/Abstract/ITransform2D.cs new file mode 100644 index 0000000..3209784 --- /dev/null +++ b/Engine.Core/Abstract/ITransform2D.cs @@ -0,0 +1,73 @@ +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Represents the transformation properties of an object such as position, scale, and rotation in 2D space. +/// +public interface ITransform2D : IBehaviour +{ + /// + /// Event triggered when the of the changes. + /// + event OnPositionChangedEventHandler? OnPositionChanged; + + /// + /// Event triggered when the of the changes. + /// + event OnScaleChangedEventHandler? OnScaleChanged; + + /// + /// Event triggered when the of the changes. + /// + event OnRotationChangedEventHandler? OnRotationChanged; + + /// + /// The world position of the in 2D space. + /// + Vector2D Position { get; set; } + + /// + /// The world scale of the . + /// + Vector2D Scale { get; set; } + + /// + /// The world rotation of the in degrees. + /// + float Rotation { get; set; } + + /// + /// The local position of the in 2D space. + /// + Vector2D LocalPosition { get; set; } + + /// + /// The local scale of the . + /// + Vector2D LocalScale { get; set; } + + /// + /// The local rotation of the in degrees. + /// + float LocalRotation { get; set; } + + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnPositionChangedEventHandler(ITransform2D sender, Vector2D previousPosition); + + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnScaleChangedEventHandler(ITransform2D sender, Vector2D previousScale); + + /// + /// Delegate for the event triggered when the 's rotation changes. + /// + /// The that the parent has changed. + /// The previous of the . + delegate void OnRotationChangedEventHandler(ITransform2D sender, float previousRotation); +} diff --git a/Engine.Core/Behaviour.cs b/Engine.Core/Behaviour.cs index 13d1117..ab1c651 100644 --- a/Engine.Core/Behaviour.cs +++ b/Engine.Core/Behaviour.cs @@ -6,9 +6,8 @@ public abstract class Behaviour : BehaviourBase { private bool isInitializedThisFrame = false; - protected IGameManager GameManager => BehaviourController.GameObject.GameManager; - protected IGameObject GameObject => BehaviourController.GameObject; - protected ITransform Transform => BehaviourController.GameObject.Transform; + protected IGameManager GameManager => BehaviourController.HierarchyObject.GameManager; + protected IHierarchyObject HierarchyObject => BehaviourController.HierarchyObject; public Behaviour() { @@ -18,43 +17,43 @@ public abstract class Behaviour : BehaviourBase } protected virtual void OnUnassign() { } - private void OnUnassign(IAssignable assignable) => OnUnassign(); + protected virtual void OnUnassign(IAssignable assignable) => OnUnassign(); protected virtual void OnInitialize() { } - private void OnInitialize(IInitialize _) + protected virtual void OnInitialize(IInitializable _) { isInitializedThisFrame = true; BehaviourController.OnPreUpdate += PreUpdate; BehaviourController.OnPreDraw += PreDraw; BehaviourController.OnUpdate += Update; - BehaviourController.GameObject.OnEnteredHierarchy += EnteredHierarchy; - BehaviourController.GameObject.OnExitedHierarchy += ExitedHierarchy; + BehaviourController.HierarchyObject.OnEnteredHierarchy += EnteredHierarchy; + BehaviourController.HierarchyObject.OnExitedHierarchy += ExitedHierarchy; OnInitialize(); - if (GameObject.IsInHierarchy) - EnteredHierarchy(GameObject, GameManager); + if (HierarchyObject.IsInHierarchy) + EnteredHierarchy(HierarchyObject, GameManager); } protected virtual void OnFinalize() { } - private void OnFinalize(IInitialize _) + protected virtual void OnFinalize(IInitializable _) { BehaviourController.OnPreUpdate -= PreUpdate; BehaviourController.OnPreDraw -= PreDraw; BehaviourController.OnUpdate -= Update; - BehaviourController.GameObject.OnEnteredHierarchy -= EnteredHierarchy; - BehaviourController.GameObject.OnExitedHierarchy -= ExitedHierarchy; + BehaviourController.HierarchyObject.OnEnteredHierarchy -= EnteredHierarchy; + BehaviourController.HierarchyObject.OnExitedHierarchy -= ExitedHierarchy; OnFinalize(); - if (GameObject.IsInHierarchy) - ExitedHierarchy(GameObject, GameManager); + if (HierarchyObject.IsInHierarchy) + ExitedHierarchy(HierarchyObject, GameManager); } protected virtual void OnPreUpdatePreActiveCheck() { } protected virtual void OnPreUpdate() { } - private void PreUpdate(IBehaviourController _) + protected virtual void PreUpdate(IBehaviourController _) { OnPreUpdatePreActiveCheck(); @@ -68,7 +67,7 @@ public abstract class Behaviour : BehaviourBase } protected virtual void OnFirstActiveFrame() { } - private void FirstActiveFrame() + protected virtual void FirstActiveFrame() { OnFirstActiveFrame(); isInitializedThisFrame = false; @@ -76,7 +75,7 @@ public abstract class Behaviour : BehaviourBase protected virtual void OnUpdatePreActiveCheck() { } protected virtual void OnUpdate() { } - private void Update(IBehaviourController _) + protected virtual void Update(IBehaviourController _) { OnUpdatePreActiveCheck(); @@ -88,7 +87,7 @@ public abstract class Behaviour : BehaviourBase protected virtual void OnPreDrawPreActiveCheck() { } protected virtual void OnPreDraw() { } - private void PreDraw(IBehaviourController _) + protected virtual void PreDraw(IBehaviourController _) { OnPreDrawPreActiveCheck(); @@ -99,8 +98,8 @@ public abstract class Behaviour : BehaviourBase } protected virtual void OnEnteredHierarchy(IGameManager gameManager) { } - private void EnteredHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnEnteredHierarchy(gameManager); + protected virtual void EnteredHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnEnteredHierarchy(gameManager); protected virtual void OnExitedHierarchy(IGameManager gameManager) { } - private void ExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnExitedHierarchy(gameManager); + protected virtual void ExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnExitedHierarchy(gameManager); } diff --git a/Engine.Core/Behaviour2D.cs b/Engine.Core/Behaviour2D.cs new file mode 100644 index 0000000..4225e24 --- /dev/null +++ b/Engine.Core/Behaviour2D.cs @@ -0,0 +1,28 @@ +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public abstract class Behaviour2D : Behaviour, IBehaviour2D +{ + public ITransform2D Transform { get; private set; } = null!; + + protected sealed override void OnInitialize(IInitializable _) + { + Transform = BehaviourController.GetBehaviourInChildren() ?? throw new($"{HierarchyObject.Name} does not contain any {nameof(ITransform2D)}"); + base.OnInitialize(_); + } + + protected sealed override void OnFinalize(IInitializable _) + { + Transform = null!; + base.OnFinalize(_); + } + + protected sealed override void OnUnassign(IAssignable assignable) => base.OnUnassign(assignable); + protected sealed override void PreUpdate(IBehaviourController behaviourController) => base.PreUpdate(behaviourController); + protected sealed override void FirstActiveFrame() => base.FirstActiveFrame(); + protected sealed override void Update(IBehaviourController behaviourController) => base.Update(behaviourController); + protected sealed override void PreDraw(IBehaviourController behaviourController) => base.PreDraw(behaviourController); + protected sealed override void EnteredHierarchy(IHierarchyObject sender, IGameManager gameManager) => base.EnteredHierarchy(sender, gameManager); + protected sealed override void ExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) => base.ExitedHierarchy(sender, gameManager); +} diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs index d0ba25e..dfa7a16 100644 --- a/Engine.Core/BehaviourBase.cs +++ b/Engine.Core/BehaviourBase.cs @@ -6,7 +6,7 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")] public abstract class BehaviourBase : BaseEntity, IBehaviour { - public event IAssignableBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; + public event IHasBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; public event IBehaviour.OnPriorityChangedEventHandler? OnPriorityChanged = null; @@ -16,7 +16,7 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour public IBehaviourController BehaviourController => _behaviourController; - public override bool IsActive => base.IsActive && BehaviourController.GameObject.StateEnable.Enabled; + public override bool IsActive => base.IsActive && BehaviourController.HierarchyObject.StateEnable.Enabled; public int Priority { diff --git a/Engine.Core/BehaviourCollector.cs b/Engine.Core/BehaviourCollector.cs index 769825c..034a957 100644 --- a/Engine.Core/BehaviourCollector.cs +++ b/Engine.Core/BehaviourCollector.cs @@ -9,7 +9,7 @@ namespace Syntriax.Engine.Core; public class BehaviourCollector : IBehaviourCollector where T : class { public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - public event IAssignableGameManager.OnGameManagerAssignedEventHandler? OnGameManagerAssigned = null; + public event IHasGameManager.OnGameManagerAssignedEventHandler? OnGameManagerAssigned = null; public event IBehaviourCollector.OnCollectedEventHandler? OnCollected = null; public event IBehaviourCollector.OnRemovedEventHandler? OnRemoved = null; @@ -24,22 +24,22 @@ public class BehaviourCollector : IBehaviourCollector where T : class public BehaviourCollector() { } public BehaviourCollector(IGameManager gameManager) => Assign(gameManager); - private void OnGameObjectRegistered(IGameManager manager, IGameObject gameObject) + private void OnHierarchyObjectRegistered(IGameManager manager, IHierarchyObject hierarchyObject) { - gameObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; - gameObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; + hierarchyObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; + hierarchyObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; - foreach (IBehaviour item in gameObject.BehaviourController) - OnBehaviourAdded(gameObject.BehaviourController, item); + foreach (IBehaviour item in hierarchyObject.BehaviourController) + OnBehaviourAdded(hierarchyObject.BehaviourController, item); } - private void OnGameObjectUnregistered(IGameManager manager, IGameObject gameObject) + private void OnHierarchyObjectUnregistered(IGameManager manager, IHierarchyObject hierarchyObject) { - gameObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded; - gameObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved; + hierarchyObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded; + hierarchyObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved; - foreach (IBehaviour item in gameObject.BehaviourController) - OnBehaviourRemoved(gameObject.BehaviourController, item); + foreach (IBehaviour item in hierarchyObject.BehaviourController) + OnBehaviourRemoved(hierarchyObject.BehaviourController, item); } protected virtual void OnBehaviourAdd(IBehaviour behaviour) { } @@ -71,11 +71,11 @@ public class BehaviourCollector : IBehaviourCollector where T : class if (GameManager is not null) return false; - foreach (IGameObject gameObject in gameManager.GameObjects) - OnGameObjectRegistered(gameManager, gameObject); + foreach (IHierarchyObject hierarchyObject in gameManager.HierarchyObjects) + OnHierarchyObjectRegistered(gameManager, hierarchyObject); - gameManager.OnGameObjectRegistered += OnGameObjectRegistered; - gameManager.OnGameObjectUnRegistered += OnGameObjectUnregistered; + gameManager.OnHierarchyObjectRegistered += OnHierarchyObjectRegistered; + gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered; GameManager = gameManager; OnGameManagerAssigned?.Invoke(this); @@ -88,11 +88,11 @@ public class BehaviourCollector : IBehaviourCollector where T : class if (GameManager is null) return false; - foreach (IGameObject gameObject in GameManager.GameObjects) - OnGameObjectUnregistered(GameManager, gameObject); + foreach (IHierarchyObject hierarchyObject in GameManager.HierarchyObjects) + OnHierarchyObjectUnregistered(GameManager, hierarchyObject); - GameManager.OnGameObjectRegistered -= OnGameObjectRegistered; - GameManager.OnGameObjectUnRegistered -= OnGameObjectUnregistered; + GameManager.OnHierarchyObjectRegistered -= OnHierarchyObjectRegistered; + GameManager.OnHierarchyObjectUnRegistered -= OnHierarchyObjectUnregistered; GameManager = null!; OnUnassigned?.Invoke(this); diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs index 154b5a5..1985111 100644 --- a/Engine.Core/BehaviourController.cs +++ b/Engine.Core/BehaviourController.cs @@ -17,19 +17,19 @@ public class BehaviourController : IBehaviourController public event IBehaviourController.OnBehaviourAddedEventHandler? OnBehaviourAdded = null; public event IBehaviourController.OnBehaviourRemovedEventHandler? OnBehaviourRemoved = null; - public event IAssignableGameObject.OnGameObjectAssignedEventHandler? OnGameObjectAssigned = null; + public event IHasHierarchyObject.OnHierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned = null; - public event IInitialize.OnInitializedEventHandler? OnInitialized = null; - public event IInitialize.OnFinalizedEventHandler? OnFinalized = null; + public event IInitializable.OnInitializedEventHandler? OnInitialized = null; + public event IInitializable.OnFinalizedEventHandler? OnFinalized = null; public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; private readonly IList behaviours = new List(Constants.BEHAVIOURS_SIZE_INITIAL); - private IGameObject _gameObject = null!; + private IHierarchyObject _hierarchyObject = null!; private bool _initialized = false; - public IGameObject GameObject => _gameObject; + public IHierarchyObject HierarchyObject => _hierarchyObject; public bool IsInitialized { @@ -52,7 +52,7 @@ public class BehaviourController : IBehaviourController InsertBehaviourByPriority(behaviour); behaviour.Assign(this); - behaviour.Assign(GameObject.StateEnable); + behaviour.Assign(HierarchyObject.StateEnable); behaviour.Initialize(); behaviour.OnPriorityChanged += OnPriorityChange; @@ -61,7 +61,7 @@ public class BehaviourController : IBehaviourController } public T AddBehaviour(params object?[]? args) where T : class, IBehaviour - => AddBehaviour(new Factory.BehaviourFactory().Instantiate(_gameObject, args)); + => AddBehaviour(new Factory.BehaviourFactory().Instantiate(_hierarchyObject, args)); public T? GetBehaviour() { @@ -116,7 +116,7 @@ public class BehaviourController : IBehaviourController public void RemoveBehaviour(T behaviour) where T : class, IBehaviour { if (!behaviours.Contains(behaviour)) - throw new Exception($"{behaviour.GetType().Name} does not exist in {GameObject.Name}'s {nameof(IBehaviourController)}."); + throw new Exception($"{behaviour.GetType().Name} does not exist in {HierarchyObject.Name}'s {nameof(IBehaviourController)}."); behaviour.OnPriorityChanged -= OnPriorityChange; behaviour.Finalize(); @@ -124,13 +124,13 @@ public class BehaviourController : IBehaviourController OnBehaviourRemoved?.Invoke(this, behaviour); } - public bool Assign(IGameObject gameObject) + public bool Assign(IHierarchyObject hierarchyObject) { - if (GameObject is not null && GameObject.IsInitialized) + if (HierarchyObject is not null && HierarchyObject.IsInitialized) return false; - _gameObject = gameObject; - OnGameObjectAssigned?.Invoke(this); + _hierarchyObject = hierarchyObject; + OnHierarchyObjectAssigned?.Invoke(this); return true; } @@ -139,7 +139,7 @@ public class BehaviourController : IBehaviourController if (IsInitialized) return false; - NotAssignedException.Check(this, _gameObject); + NotAssignedException.Check(this, _hierarchyObject); foreach (IBehaviour behaviour in behaviours) behaviour.Initialize(); @@ -165,14 +165,14 @@ public class BehaviourController : IBehaviourController if (IsInitialized) return false; - _gameObject = null!; + _hierarchyObject = null!; OnUnassigned?.Invoke(this); return true; } public void Update() { - if (!GameObject.StateEnable.Enabled) + if (!HierarchyObject.StateEnable.Enabled) return; OnPreUpdate?.Invoke(this); @@ -181,14 +181,14 @@ public class BehaviourController : IBehaviourController public void UpdatePreDraw() { - if (!GameObject.StateEnable.Enabled) + if (!HierarchyObject.StateEnable.Enabled) return; OnPreDraw?.Invoke(this); } public BehaviourController() { } - public BehaviourController(IGameObject gameObject) => Assign(gameObject); + public BehaviourController(IHierarchyObject hierarchyObject) => Assign(hierarchyObject); private void InsertBehaviourByPriority(T behaviour) where T : class, IBehaviour { diff --git a/Engine.Core/CoroutineManager.cs b/Engine.Core/CoroutineManager.cs index 4af22ca..b6d54c4 100644 --- a/Engine.Core/CoroutineManager.cs +++ b/Engine.Core/CoroutineManager.cs @@ -5,7 +5,7 @@ using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Core; -public class CoroutineManager : HierarchyObjectBase +public class CoroutineManager : HierarchyObject { private readonly List enumerators = []; diff --git a/Engine.Core/Engine.Core.puml b/Engine.Core/Engine.Core.puml new file mode 100644 index 0000000..f38813a --- /dev/null +++ b/Engine.Core/Engine.Core.puml @@ -0,0 +1,46 @@ +@startuml "Core Engine Relations" + +top to bottom direction +skinparam linetype ortho +skinparam nodesep 100 + +title Core Engine Relations + +interface Engine.Core.Abstract.IEntity extends Engine.Core.Abstract.IInitializable {} +interface Engine.Core.Abstract.IHierarchyObject extends Engine.Core.Abstract.IEntity, Engine.Core.Abstract.INameable {} + +interface Engine.Core.Abstract.INameable {} + +Engine.Core.Abstract.IHierarchyObject --> Engine.Core.Abstract.IBehaviourController: has +Engine.Core.Abstract.IBehaviourController "1" --> "0..*" Engine.Core.Abstract.IBehaviour: has + +interface Engine.Core.Abstract.IBehaviourController {} +interface Engine.Core.Abstract.IBehaviour {} +interface Engine.Core.Abstract.IBehaviour2D extends Engine.Core.Abstract.IBehaviour {} +interface Engine.Core.Abstract.IBehaviour3D extends Engine.Core.Abstract.IBehaviour {} + +interface Engine.Core.Abstract.IGameManager {} +Engine.Core.Abstract.IGameManager "1" -r-> "0..*" Engine.Core.Abstract.IHierarchyObject: has + +' together { +' interface Engine.Core.Abstract.IAssignable {} +' interface Engine.Core.Abstract.IHasStateEnable extends Engine.Core.Abstract.IAssignable {} +' interface Engine.Core.Abstract.IHasGameManager extends Engine.Core.Abstract.IAssignable {} +' interface Engine.Core.Abstract.IHasHierarchyObject extends Engine.Core.Abstract.IAssignable {} +' interface Engine.Core.Abstract.IHasBehaviourController extends Engine.Core.Abstract.IAssignable {} +' ' Engine.Core.Abstract.IHasStateEnable --> Engine.Core.Abstract.IStateEnable: has +' ' Engine.Core.Abstract.IHasGameManager --> Engine.Core.Abstract.IGameManager: has +' ' Engine.Core.Abstract.IHasHierarchyObject --> Engine.Core.Abstract.IHierarchyObject: has +' ' Engine.Core.Abstract.IHasBehaviourController --> Engine.Core.Abstract.IBehaviourController: has +' } + +together { + interface Engine.Core.Abstract.ITransform2D {} + interface Engine.Core.Abstract.ICamera2D {} + interface Engine.Core.Abstract.ICoroutineYield {} + interface Engine.Core.Abstract.IStateEnable {} + interface Engine.Core.Abstract.IInitializable {} + interface Engine.Core.Abstract.IBehaviourCollector {} +} + +@enduml diff --git a/Engine.Core/Exceptions/NotAssignedException.cs b/Engine.Core/Exceptions/NotAssignedException.cs index 51ac615..ef2993c 100644 --- a/Engine.Core/Exceptions/NotAssignedException.cs +++ b/Engine.Core/Exceptions/NotAssignedException.cs @@ -8,10 +8,10 @@ public class NotAssignedException : Exception public NotAssignedException() : base("The object has not been assigned.") { } public NotAssignedException(string? message) : base(message) { } - public static NotAssignedException From(T1 to, T2? value) where T1 : IAssignable + public static NotAssignedException From(T1 to, T2? value) => new($"{value?.GetType().FullName ?? "\"null\""} has not been assigned to {to?.GetType().FullName ?? "\"null\""}"); - public static void Check(T1 to, T2? value) where T1 : IAssignable + public static void Check(T1 to, T2? value) { if (value is not null) return; diff --git a/Engine.Core/Extensions/Abstract/TransformExtensions.cs b/Engine.Core/Extensions/Abstract/TransformExtensions.cs index 24244a3..af477e1 100644 --- a/Engine.Core/Extensions/Abstract/TransformExtensions.cs +++ b/Engine.Core/Extensions/Abstract/TransformExtensions.cs @@ -2,7 +2,7 @@ namespace Syntriax.Engine.Core.Abstract; public static class TransformExtensions { - public static Vector2D TransformVector2D(this ITransform transform, Vector2D vector) + public static Vector2D TransformVector2D(this ITransform2D transform, Vector2D vector) => vector.Scale(transform.Scale) .Rotate(transform.Rotation * Math.DegreeToRadian) .Add(transform.Position); diff --git a/Engine.Core/Extensions/BehaviourControllerExtensions.cs b/Engine.Core/Extensions/BehaviourControllerExtensions.cs index fc338f3..9f6706b 100644 --- a/Engine.Core/Extensions/BehaviourControllerExtensions.cs +++ b/Engine.Core/Extensions/BehaviourControllerExtensions.cs @@ -57,7 +57,7 @@ public static class BehaviourControllerExtensions if (behaviourController.GetBehaviour() is T behaviour) return behaviour; - controller = controller.GameObject.Transform.Parent?.GameObject.BehaviourController; + controller = controller.HierarchyObject.Parent?.BehaviourController; } return default; @@ -87,8 +87,8 @@ public static class BehaviourControllerExtensions if (behaviourController.GetBehaviour() is T localBehaviour) return localBehaviour; - foreach (ITransform transform in behaviourController.GameObject.Transform) - if (GetBehaviourInChildren(transform.GameObject.BehaviourController) is T behaviour) + foreach (IHierarchyObject child in behaviourController.HierarchyObject) + if (GetBehaviourInChildren(child.BehaviourController) is T behaviour) return behaviour; return default; diff --git a/Engine.Core/Extensions/BehaviourExtensions.cs b/Engine.Core/Extensions/BehaviourExtensions.cs index d78d7a6..7f28340 100644 --- a/Engine.Core/Extensions/BehaviourExtensions.cs +++ b/Engine.Core/Extensions/BehaviourExtensions.cs @@ -7,29 +7,29 @@ namespace Syntriax.Engine.Core; public static class BehaviourExtensions { - public static T? FindBehaviour(this IEnumerable gameObjects) where T : class + public static T? FindBehaviour(this IEnumerable hierarchyObjects) where T : class { - foreach (IGameObject gameObject in gameObjects) - if (gameObject.BehaviourController.GetBehaviour() is T behaviour) + foreach (IHierarchyObject hierarchyObject in hierarchyObjects) + if (hierarchyObject.BehaviourController.GetBehaviour() is T behaviour) return behaviour; return default; } - public static bool TryFindBehaviour(this IEnumerable gameObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class + public static bool TryFindBehaviour(this IEnumerable hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { - behaviour = FindBehaviour(gameObjects); + behaviour = FindBehaviour(hierarchyObjects); return behaviour is not null; } - public static void FindBehaviours(this IEnumerable gameObjects, List behaviours) where T : class + public static void FindBehaviours(this IEnumerable hierarchyObjects, List behaviours) where T : class { behaviours.Clear(); List cache = []; - foreach (IGameObject gameObject in gameObjects) + foreach (IHierarchyObject hierarchyObject in hierarchyObjects) { - gameObject.BehaviourController.GetBehaviours(cache); + hierarchyObject.BehaviourController.GetBehaviours(cache); behaviours.AddRange(cache); } } diff --git a/Engine.Core/Extensions/GameManagerExtensions.cs b/Engine.Core/Extensions/GameManagerExtensions.cs index eb1b53d..fe6949a 100644 --- a/Engine.Core/Extensions/GameManagerExtensions.cs +++ b/Engine.Core/Extensions/GameManagerExtensions.cs @@ -4,6 +4,6 @@ namespace Syntriax.Engine.Core; public static class GameManagerExtensions { - public static IGameObject InstantiateGameObject(this IGameManager gameManager, params object?[]? args) - => gameManager.InstantiateGameObject(args); + public static IHierarchyObject InstantiateHierarchyObject(this IGameManager gameManager, params object?[]? args) + => gameManager.InstantiateHierarchyObject(args); } diff --git a/Engine.Core/Extensions/GameObjectExtensions.cs b/Engine.Core/Extensions/GameObjectExtensions.cs deleted file mode 100644 index 6f33618..0000000 --- a/Engine.Core/Extensions/GameObjectExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Syntriax.Engine.Core.Abstract; - -namespace Syntriax.Engine.Core; - -public static class GameObjectExtensions -{ - public static IGameObject SetGameObject(this IGameObject gameObject, string name) - { - gameObject.Name = name; - return gameObject; - } -} diff --git a/Engine.Core/Extensions/HierarchyObjectExtensions.cs b/Engine.Core/Extensions/HierarchyObjectExtensions.cs index 6e549fe..ae4de7e 100644 --- a/Engine.Core/Extensions/HierarchyObjectExtensions.cs +++ b/Engine.Core/Extensions/HierarchyObjectExtensions.cs @@ -7,6 +7,12 @@ namespace Syntriax.Engine.Core; public static class HierarchyObjectExtensions { + public static IHierarchyObject SetHierarchyObject(this IHierarchyObject hierarchyObject, string name) + { + hierarchyObject.Name = name; + return hierarchyObject; + } + public static T? FindObject(this IEnumerable hierarchyObjects) where T : class { foreach (IHierarchyObject hierarchyObject in hierarchyObjects) diff --git a/Engine.Core/Extensions/TransformExtensions.cs b/Engine.Core/Extensions/TransformExtensions.cs index 5c1da4f..4d35da1 100644 --- a/Engine.Core/Extensions/TransformExtensions.cs +++ b/Engine.Core/Extensions/TransformExtensions.cs @@ -4,7 +4,7 @@ namespace Syntriax.Engine.Core; public static class TransformExtensions { - public static ITransform SetTransform(this ITransform transform, + public static ITransform2D SetTransform(this ITransform2D transform, Vector2D? position = null, float? rotation = null, Vector2D? scale = null, Vector2D? localPosition = null, float? localRotation = null, Vector2D? localScale = null) { diff --git a/Engine.Core/Factory/BehaviourControllerFactory.cs b/Engine.Core/Factory/BehaviourControllerFactory.cs index 00cd97c..287a8db 100644 --- a/Engine.Core/Factory/BehaviourControllerFactory.cs +++ b/Engine.Core/Factory/BehaviourControllerFactory.cs @@ -5,16 +5,16 @@ namespace Syntriax.Engine.Core.Factory; public class BehaviourControllerFactory { - public IBehaviourController Instantiate(IGameObject gameObject) - => Instantiate(gameObject); + public IBehaviourController Instantiate(IHierarchyObject hierarchyObject) + => Instantiate(hierarchyObject); - public T Instantiate(IGameObject gameObject, params object?[]? args) + public T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviourController { T behaviourController = TypeFactory.Get(args); - if (!behaviourController.Assign(gameObject)) - throw AssignException.From(behaviourController, gameObject); + if (!behaviourController.Assign(hierarchyObject)) + throw AssignException.From(behaviourController, hierarchyObject); return behaviourController; } diff --git a/Engine.Core/Factory/BehaviourFactory.cs b/Engine.Core/Factory/BehaviourFactory.cs index f75518c..bf68861 100644 --- a/Engine.Core/Factory/BehaviourFactory.cs +++ b/Engine.Core/Factory/BehaviourFactory.cs @@ -5,10 +5,10 @@ namespace Syntriax.Engine.Core.Factory; public class BehaviourFactory { - public T Instantiate(IGameObject gameObject, params object?[]? args) where T : class, IBehaviour - => Instantiate(gameObject, stateEnable: null, args); + public T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviour + => Instantiate(hierarchyObject, stateEnable: null, args); - public T Instantiate(IGameObject gameObject, IStateEnable? stateEnable, params object?[]? args) + public T Instantiate(IHierarchyObject hierarchyObject, IStateEnable? stateEnable, params object?[]? args) where T : class, IBehaviour { T behaviour = TypeFactory.Get(args); @@ -17,8 +17,8 @@ public class BehaviourFactory if (!stateEnable.Assign(behaviour)) throw AssignException.From(stateEnable, behaviour); - if (!behaviour.Assign(gameObject.BehaviourController)) - throw AssignException.From(behaviour, gameObject.BehaviourController); + if (!behaviour.Assign(hierarchyObject.BehaviourController)) + throw AssignException.From(behaviour, hierarchyObject.BehaviourController); if (!behaviour.Assign(stateEnable)) throw AssignException.From(behaviour, stateEnable); diff --git a/Engine.Core/Factory/GameObjectFactory.cs b/Engine.Core/Factory/GameObjectFactory.cs deleted file mode 100644 index 6713d39..0000000 --- a/Engine.Core/Factory/GameObjectFactory.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Core.Exceptions; - -namespace Syntriax.Engine.Core.Factory; - -public class GameObjectFactory -{ - public T Instantiate(params object?[]? args) where T : class, IGameObject - => Instantiate(transform: null, behaviourController: null, stateEnable: null, args); - - public T Instantiate( - ITransform? transform = null, - IBehaviourController? behaviourController = null, - IStateEnable? stateEnable = null, - params object?[]? args - ) - where T : class, IGameObject - { - T gameObject = TypeFactory.Get(args); - - transform ??= TypeFactory.Get(); - behaviourController ??= TypeFactory.Get(); - stateEnable ??= TypeFactory.Get(); - - if (!transform.Assign(gameObject)) - throw AssignException.From(transform, gameObject); - - if (!behaviourController.Assign(gameObject)) - throw AssignException.From(behaviourController, gameObject); - if (!stateEnable.Assign(gameObject)) - throw AssignException.From(stateEnable, gameObject); - - if (!gameObject.Assign(transform)) - throw AssignException.From(gameObject, transform); - if (!gameObject.Assign(behaviourController)) - throw AssignException.From(gameObject, behaviourController); - if (!gameObject.Assign(stateEnable)) - throw AssignException.From(gameObject, stateEnable); - - return gameObject; - } -} diff --git a/Engine.Core/Factory/HierarchyObjectFactory.cs b/Engine.Core/Factory/HierarchyObjectFactory.cs new file mode 100644 index 0000000..f3e23f1 --- /dev/null +++ b/Engine.Core/Factory/HierarchyObjectFactory.cs @@ -0,0 +1,35 @@ +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Core.Exceptions; + +namespace Syntriax.Engine.Core.Factory; + +public class HierarchyObjectFactory +{ + public T Instantiate(params object?[]? args) where T : class, IHierarchyObject + => Instantiate(behaviourController: null, stateEnable: null, args); + + public T Instantiate( + IBehaviourController? behaviourController = null, + IStateEnable? stateEnable = null, + params object?[]? args + ) + where T : class, IHierarchyObject + { + T hierarchyObject = TypeFactory.Get(args); + + behaviourController ??= TypeFactory.Get(); + stateEnable ??= TypeFactory.Get(); + + if (!behaviourController.Assign(hierarchyObject)) + throw AssignException.From(behaviourController, hierarchyObject); + if (!stateEnable.Assign(hierarchyObject)) + throw AssignException.From(stateEnable, hierarchyObject); + + if (!hierarchyObject.Assign(behaviourController)) + throw AssignException.From(hierarchyObject, behaviourController); + if (!hierarchyObject.Assign(stateEnable)) + throw AssignException.From(hierarchyObject, stateEnable); + + return hierarchyObject; + } +} diff --git a/Engine.Core/Factory/TransformFactory.cs b/Engine.Core/Factory/TransformFactory.cs index c4e7687..2b7a5dd 100644 --- a/Engine.Core/Factory/TransformFactory.cs +++ b/Engine.Core/Factory/TransformFactory.cs @@ -4,7 +4,7 @@ namespace Syntriax.Engine.Core.Factory; public class TransformFactory { - public ITransform Instantiate() => TypeFactory.Get(); - public T Instantiate(params object?[]? args) where T : class, ITransform + public ITransform2D Instantiate() => TypeFactory.Get(); + public T Instantiate(params object?[]? args) where T : class, ITransform2D => TypeFactory.Get(args); } diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index 053bf64..e44430c 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -7,33 +7,28 @@ using Syntriax.Engine.Core.Factory; namespace Syntriax.Engine.Core; -[System.Diagnostics.DebuggerDisplay("GameObject Count: {_gameObjects.Count}")] +[System.Diagnostics.DebuggerDisplay("HierarchyObject Count: {_hierarchyObjects.Count}")] public class GameManager : BaseEntity, IGameManager { public event IGameManager.OnUpdateEventHandler? OnUpdate = null; public event IGameManager.OnPreDawEventHandler? OnPreDraw = null; - public event IGameManager.OnGameObjectRegisteredEventHandler? OnGameObjectRegistered = null; - public event IGameManager.OnGameObjectUnRegisteredEventHandler? OnGameObjectUnRegistered = null; public event IGameManager.OnHierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null; public event IGameManager.OnHierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null; - private readonly List _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); - private GameObjectFactory _gameObjectFactory = null!; + private HierarchyObjectFactory _hierarchyObjectFactory = null!; - private GameObjectFactory GameObjectFactory + private HierarchyObjectFactory HierarchyObjectFactory { get { - if (_gameObjectFactory is null) - _gameObjectFactory = new GameObjectFactory(); - return _gameObjectFactory; + _hierarchyObjectFactory ??= new HierarchyObjectFactory(); + return _hierarchyObjectFactory; } } - public IReadOnlyList GameObjects => _gameObjects; public IReadOnlyList HierarchyObjects => _hierarchyObjects; public override IStateEnable StateEnable @@ -56,25 +51,28 @@ public class GameManager : BaseEntity, IGameManager if (_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is already registered to the {nameof(GameManager)}."); - if (hierarchyObject is IGameObject gameObject) - Register(gameObject); - else - { - if (!hierarchyObject.Initialize()) - throw new Exception($"{nameof(hierarchyObject)} can't be initialized"); + hierarchyObject.OnFinalized += OnHierarchyObjectFinalize; + hierarchyObject.OnExitedHierarchy += OnHierarchyObjectExitedHierarchy; - _hierarchyObjects.Add(hierarchyObject); - hierarchyObject.EnterHierarchy(this); + if (!hierarchyObject.Initialize()) + throw new Exception($"{hierarchyObject.Name} can't be initialized"); - OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject); - } + foreach (IHierarchyObject child in hierarchyObject.Children) + Register(child); + + _hierarchyObjects.Add(hierarchyObject); + + if (!hierarchyObject.EnterHierarchy(this)) + throw new Exception($"{hierarchyObject.Name} can't enter the hierarchy"); + + OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject); } - public T InstantiateGameObject(params object?[]? args) where T : class, IGameObject + public T InstantiateHierarchyObject(params object?[]? args) where T : class, IHierarchyObject { - T gameObject = GameObjectFactory.Instantiate(args); - Register(gameObject); - return gameObject; + T hierarchyObject = HierarchyObjectFactory.Instantiate(args); + Register(hierarchyObject); + return hierarchyObject; } public void Remove(IHierarchyObject hierarchyObject) @@ -82,18 +80,21 @@ public class GameManager : BaseEntity, IGameManager if (!_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}."); - if (hierarchyObject is IGameObject gameObject) - Unregister(gameObject); - else - { - _hierarchyObjects.Remove(hierarchyObject); - hierarchyObject.ExitHierarchy(); + hierarchyObject.OnFinalized -= OnHierarchyObjectFinalize; + hierarchyObject.OnExitedHierarchy -= OnHierarchyObjectExitedHierarchy; - if (!hierarchyObject.Finalize()) - throw new Exception($"{nameof(hierarchyObject)} can't be finalized"); + foreach (IHierarchyObject child in hierarchyObject.Children) + Remove(child); - OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject); - } + _hierarchyObjects.Remove(hierarchyObject); + + if (!hierarchyObject.ExitHierarchy()) + throw new Exception($"{hierarchyObject.Name} can't exit the hierarchy"); + + if (!hierarchyObject.Finalize()) + throw new Exception($"{hierarchyObject.Name} can't be finalized"); + + OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject); } protected override void InitializeInternal() @@ -101,93 +102,45 @@ public class GameManager : BaseEntity, IGameManager base.InitializeInternal(); NotAssignedException.Check(this, StateEnable); - foreach (IGameObject gameObject in GameObjects) - gameObject.Initialize(); + foreach (IHierarchyObject hierarchyObject in HierarchyObjects) + hierarchyObject.Initialize(); } protected override void FinalizeInternal() { base.FinalizeInternal(); - for (int i = GameObjects.Count; i >= 0; i--) - GameObjects[i].Finalize(); + for (int i = HierarchyObjects.Count; i >= 0; i--) + HierarchyObjects[i].Finalize(); } public void Update(EngineTime time) { Time.SetTime(time); - for (int i = 0; i < GameObjects.Count; i++) - GameObjects[i].BehaviourController.Update(); + for (int i = 0; i < HierarchyObjects.Count; i++) + HierarchyObjects[i].BehaviourController.Update(); OnUpdate?.Invoke(this, time); } public void PreDraw() { - for (int i = 0; i < GameObjects.Count; i++) - GameObjects[i].BehaviourController.UpdatePreDraw(); + for (int i = 0; i < HierarchyObjects.Count; i++) + HierarchyObjects[i].BehaviourController.UpdatePreDraw(); OnPreDraw?.Invoke(this); } ///////////////////////////////////////////////////////////////// - private void Register(IGameObject gameObject) + private void OnHierarchyObjectFinalize(IInitializable initializable) { - if (_gameObjects.Contains(gameObject)) - throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is already registered to the {nameof(GameManager)}."); - - gameObject.OnFinalized += OnGameObjectFinalize; - gameObject.OnExitedHierarchy += OnGameObjectExitedHierarchy; - - if (!gameObject.Initialize()) - throw new Exception($"{nameof(gameObject)} can't be initialized"); - - foreach (ITransform child in gameObject.Transform.Children) - Register(child.GameObject); - - _gameObjects.Add(gameObject); - _hierarchyObjects.Add(gameObject); - - if (!gameObject.EnterHierarchy(this)) - throw new Exception($"{nameof(gameObject)} can't enter the hierarchy"); - - OnHierarchyObjectRegistered?.Invoke(this, gameObject); - OnGameObjectRegistered?.Invoke(this, gameObject); + if (initializable is IHierarchyObject hierarchyObject) + Remove(hierarchyObject); } - private void Unregister(IGameObject gameObject) + private void OnHierarchyObjectExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) { - if (!_gameObjects.Contains(gameObject)) - throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is not registered to the {nameof(GameManager)}."); - - gameObject.OnFinalized -= OnGameObjectFinalize; - gameObject.OnExitedHierarchy -= OnGameObjectExitedHierarchy; - - foreach (ITransform child in gameObject.Transform.Children) - Unregister(child.GameObject); - - _gameObjects.Remove(gameObject); - _hierarchyObjects.Remove(gameObject); - - if (!gameObject.ExitHierarchy()) - throw new Exception($"{nameof(gameObject)} can't exit the hierarchy"); - - if (!gameObject.Finalize()) - throw new Exception($"{nameof(gameObject)} can't be finalized"); - - OnHierarchyObjectUnRegistered?.Invoke(this, gameObject); - OnGameObjectUnRegistered?.Invoke(this, gameObject); - } - - private void OnGameObjectFinalize(IInitialize initialize) - { - if (initialize is IGameObject gameObject) - Unregister(gameObject); - } - - private void OnGameObjectExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) - { - if (sender is IGameObject gameObject) - Unregister(gameObject); + if (sender is IHierarchyObject hierarchyObject) + Remove(hierarchyObject); } } diff --git a/Engine.Core/GameObject.cs b/Engine.Core/GameObject.cs deleted file mode 100644 index fcb4a91..0000000 --- a/Engine.Core/GameObject.cs +++ /dev/null @@ -1,151 +0,0 @@ -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Core.Exceptions; - -namespace Syntriax.Engine.Core; - -[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")] -public class GameObject : BaseEntity, IGameObject -{ - public event IHierarchyObject.OnEnteredHierarchyEventHandler? OnEnteredHierarchy = null; - public event IHierarchyObject.OnExitedHierarchyEventHandler? OnExitedHierarchy = null; - - public event IAssignableTransform.OnTransformAssignedEventHandler? OnTransformAssigned = null; - public event IAssignableBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; - - public event INameable.OnNameChangedEventHandler? OnNameChanged = null; - - public event IGameObject.OnUpdatedEventHandler? OnUpdated = null; - - private ITransform _transform = null!; - private IBehaviourController _behaviourController = null!; - private IGameManager _gameManager = null!; - - private string _name = nameof(GameObject); - - public ITransform Transform => _transform; - public IBehaviourController BehaviourController => _behaviourController; - public IGameManager GameManager => _gameManager; - public bool IsInHierarchy => GameManager is not null; - - public string Name - { - get => _name; - set - { - if (value == _name) return; - - string previousName = _name; - _name = value; - OnNameChanged?.Invoke(this, previousName); - } - } - - protected override void InitializeInternal() - { - base.InitializeInternal(); - - NotAssignedException.Check(this, _transform); - NotAssignedException.Check(this, _behaviourController); - - if (!_behaviourController.Initialize()) - throw new System.Exception($"Failed to Initialize {BehaviourController.GetType().Name} on {Transform.GameObject.Name}"); - } - - public void Update() - { - if (!StateEnable.Enabled) - return; - - OnUpdated?.Invoke(this); - } - - protected override void FinalizeInternal() - { - base.FinalizeInternal(); - - if (!_behaviourController.Finalize()) - throw new System.Exception($"Failed to Finalize {BehaviourController.GetType().Name} on {Transform.GameObject.Name}"); - } - - public bool Assign(ITransform transform) - { - if (IsInitialized) - return false; - - _transform = transform; - OnTransformAssigned?.Invoke(this); - transform.OnParentChanged += OnParentChangedInternal; - OnParentChangedInternal(transform, null, transform.Parent); - return true; - } - - public bool Assign(IBehaviourController behaviourController) - { - if (IsInitialized) - return false; - - _behaviourController = behaviourController; - OnBehaviourControllerAssigned?.Invoke(this); - return true; - } - - protected override void UnassignInternal() - { - base.UnassignInternal(); - - _transform.OnParentChanged -= OnParentChangedInternal; - OnParentChangedInternal(_transform, _transform.Parent, null); - _transform = null!; - _behaviourController = null!; - _gameManager = null!; - } - - public GameObject() { OnBehaviourControllerAssigned += ConnectBehaviourController; } - - private void ConnectBehaviourController(IAssignableBehaviourController controller) - { - controller.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; - controller.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; - } - private void OnBehaviourRemoved(IBehaviourController _, IBehaviour behaviour) { if (IsInitialized) behaviour.Finalize(); } - private void OnBehaviourAdded(IBehaviourController _, IBehaviour behaviour) { if (!IsInitialized) behaviour.Initialize(); } - - private void OnParentChangedInternal(ITransform sender, ITransform? previousParent, ITransform? newParent) - { - if (previousParent is not null) - { - previousParent.OnParentChanged -= OnParentChangedInternal; - previousParent.GameObject.OnEnteredHierarchy -= EnterHierarchyInternal; - previousParent.GameObject.OnExitedHierarchy -= ExitHierarchyInternal; - } - if (newParent is not null) - { - newParent.OnParentChanged += OnParentChangedInternal; - newParent.GameObject.OnEnteredHierarchy += EnterHierarchyInternal; - newParent.GameObject.OnExitedHierarchy += ExitHierarchyInternal; - } - } - - private void EnterHierarchyInternal(IHierarchyObject sender, IGameManager gameManager) => ((IHierarchyObject)this).EnterHierarchy(gameManager); - private void ExitHierarchyInternal(IHierarchyObject sender, IGameManager gameManager) => ((IHierarchyObject)this).ExitHierarchy(); - - bool IHierarchyObject.EnterHierarchy(IGameManager gameManager) - { - if (IsInHierarchy) - return false; - - _gameManager = gameManager; - OnEnteredHierarchy?.Invoke(this, gameManager); - return true; - } - - bool IHierarchyObject.ExitHierarchy() - { - if (!IsInHierarchy || _gameManager is not IGameManager gameManager) - return false; - - _gameManager = null!; - OnExitedHierarchy?.Invoke(this, gameManager); - return true; - } -} diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs new file mode 100644 index 0000000..c27e9bb --- /dev/null +++ b/Engine.Core/HierarchyObject.cs @@ -0,0 +1,136 @@ +using System.Collections; +using System.Collections.Generic; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")] +public class HierarchyObject : BaseEntity, IHierarchyObject +{ + public event IHierarchyObject.OnEnteredHierarchyEventHandler? OnEnteredHierarchy = null; + public event IHierarchyObject.OnExitedHierarchyEventHandler? OnExitedHierarchy = null; + public event IHierarchyObject.OnParentChangedEventHandler? OnParentChanged = null; + public event IHierarchyObject.OnChildrenAddedEventHandler? OnChildrenAdded = null; + public event IHierarchyObject.OnChildrenRemovedEventHandler? OnChildrenRemoved = null; + public event IHasBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; + public event INameable.OnNameChangedEventHandler? OnNameChanged = null; + + private string _name = nameof(HierarchyObject); + private IGameManager _gameManager = null!; + private IBehaviourController _behaviourController = null!; + private readonly List _children = []; + + public IHierarchyObject? Parent { get; private set; } = null; + public IReadOnlyList Children => _children; + public IGameManager GameManager => _gameManager; + public bool IsInHierarchy => _gameManager is not null; + + public string Name + { + get => _name; + set + { + if (value == _name) return; + + string previousName = _name; + _name = value; + OnNameChanged?.Invoke(this, previousName); + } + } + + public IBehaviourController BehaviourController => _behaviourController; + + protected virtual void OnEnteringHierarchy(IGameManager gameManager) { } + bool IHierarchyObject.EnterHierarchy(IGameManager gameManager) + { + if (IsInHierarchy) + return false; + + _gameManager = gameManager; + OnEnteringHierarchy(gameManager); + OnEnteredHierarchy?.Invoke(this, gameManager); + return true; + } + + protected virtual void OnExitingHierarchy(IGameManager gameManager) { } + bool IHierarchyObject.ExitHierarchy() + { + if (!IsInHierarchy || _gameManager is not IGameManager gameManager) + return false; + + _gameManager = null!; + OnExitingHierarchy(gameManager); + OnExitedHierarchy?.Invoke(this, gameManager); + return true; + } + + public void SetParent(IHierarchyObject? parent) + { + if (parent == this || Parent == parent) + return; + + IHierarchyObject? previousParent = Parent; + if (previousParent is not null) + { + previousParent.RemoveChild(this); + previousParent.OnParentChanged -= NotifyChildrenOnParentChange; + } + + Parent = parent; + + if (parent is not null) + { + parent.AddChild(this); + parent.OnParentChanged += NotifyChildrenOnParentChange; + } + + OnParentChanged?.Invoke(this, previousParent, parent); + } + + public void AddChild(IHierarchyObject parent) + { + if (_children.Contains(parent)) + return; + + _children.Add(parent); + parent.SetParent(this); + OnChildrenAdded?.Invoke(this, parent); + } + + public void RemoveChild(IHierarchyObject parent) + { + if (!_children.Remove(parent)) + return; + + parent.SetParent(null); + OnChildrenRemoved?.Invoke(this, parent); + } + + private void NotifyChildrenOnParentChange(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent) + { + // TODO No idea how logical this is to propagate this to the children the way I'm doing right now. + // I was originally gonna just call `child.OnParentChanged?.Invoke(child, child.parentTransform);` but seems an unnecessary call too? + foreach (IHierarchyObject child in Children) // TODO CHECK ERRORS + child.SetParent(this); + } + + public bool Assign(IBehaviourController behaviourController) + { + if (IsInitialized) + return false; + + _behaviourController = behaviourController; + OnBehaviourControllerAssigned?.Invoke(this); + return true; + } + + protected override void InitializeInternal() + { + base.InitializeInternal(); + _behaviourController ??= new Factory.BehaviourControllerFactory().Instantiate(this); + } + + public IEnumerator GetEnumerator() => _children.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator(); +} diff --git a/Engine.Core/HierarchyObjectBase.cs b/Engine.Core/HierarchyObjectBase.cs deleted file mode 100644 index 0807a81..0000000 --- a/Engine.Core/HierarchyObjectBase.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Syntriax.Engine.Core.Abstract; - -namespace Syntriax.Engine.Core; - -public abstract class HierarchyObjectBase : IHierarchyObject -{ - public event IHierarchyObject.OnEnteredHierarchyEventHandler? OnEnteredHierarchy = null; - public event IHierarchyObject.OnExitedHierarchyEventHandler? OnExitedHierarchy = null; - public event IEntity.OnIdChangedEventHandler? OnIdChanged = null; - public event IInitialize.OnInitializedEventHandler? OnInitialized = null; - public event IInitialize.OnFinalizedEventHandler? OnFinalized = null; - public event IAssignableStateEnable.OnStateEnableAssignedEventHandler? OnStateEnableAssigned = null; - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - public event INameable.OnNameChangedEventHandler? OnNameChanged = null; - - private string _id = string.Empty; - private string _name = nameof(HierarchyObjectBase); - private bool _initialized = false; - private IStateEnable _stateEnable = null!; - private IGameManager _gameManager = null!; - - public IGameManager GameManager => _gameManager; - - public bool IsInHierarchy => _gameManager is not null; - - public bool IsInitialized - { - get => _initialized; - private set - { - if (value == _initialized) - return; - - _initialized = value; - if (value) - OnInitialized?.Invoke(this); - else - OnFinalized?.Invoke(this); - } - } - - public virtual IStateEnable StateEnable => _stateEnable; - - public string Name - { - get => _name; - set - { - if (value == _name) return; - - string previousName = _name; - _name = value; - OnNameChanged?.Invoke(this, previousName); - } - } - - public string Id - { - get => _id; - set - { - if (value == _id) - return; - - string previousId = _id; - - _id = value; - OnIdChanged?.Invoke(this, previousId); - } - } - - public bool Assign(IStateEnable stateEnable) - { - if (IsInitialized) - return false; - - _stateEnable = stateEnable; - _stateEnable.Assign(this); - OnStateEnableAssigned?.Invoke(this); - return true; - } - - protected virtual void UnassignInternal() { } - public bool Unassign() - { - if (IsInitialized) - return false; - - UnassignInternal(); - - OnUnassigned?.Invoke(this); - return true; - } - - protected virtual void InitializeInternal() { } - public bool Initialize() - { - if (IsInitialized) - return false; - - InitializeInternal(); - - IsInitialized = true; - return true; - } - - protected virtual void FinalizeInternal() { } - public bool Finalize() - { - if (!IsInitialized) - return false; - - FinalizeInternal(); - - IsInitialized = false; - return true; - } - - protected virtual void OnEnteringHierarchy(IGameManager gameManager) { } - bool IHierarchyObject.EnterHierarchy(IGameManager gameManager) - { - if (IsInHierarchy) - return false; - - _gameManager = gameManager; - OnEnteringHierarchy(gameManager); - OnEnteredHierarchy?.Invoke(this, gameManager); - return true; - } - - protected virtual void OnExitingHierarchy(IGameManager gameManager) { } - bool IHierarchyObject.ExitHierarchy() - { - if (!IsInHierarchy || _gameManager is not IGameManager gameManager) - return false; - - _gameManager = null!; - OnExitingHierarchy(gameManager); - OnExitedHierarchy?.Invoke(this, gameManager); - return true; - } -} diff --git a/Engine.Core/Primitives/Circle.cs b/Engine.Core/Primitives/Circle.cs index acb4ace..ae99589 100644 --- a/Engine.Core/Primitives/Circle.cs +++ b/Engine.Core/Primitives/Circle.cs @@ -64,9 +64,9 @@ public readonly struct Circle(Vector2D center, float radius) } /// - /// Transforms the by the specified . + /// Transforms the by the specified . /// - public static Circle TransformCircle(ITransform transform, Circle circle) + public static Circle TransformCircle(ITransform2D transform, Circle circle) => new(transform.TransformVector2D(circle.Center), circle.Radius * (transform.Scale.Magnitude / Vector2D.One.Magnitude)); /// @@ -97,8 +97,8 @@ public static class CircleExtensions /// public static Projection1D ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector); - /// - public static Circle TransformCircle(this ITransform transform, Circle circle) => Circle.TransformCircle(transform, circle); + /// + public static Circle TransformCircle(this ITransform2D transform, Circle circle) => Circle.TransformCircle(transform, circle); /// public static bool ApproximatelyEquals(this Circle left, Circle right, float epsilon = float.Epsilon) => Circle.ApproximatelyEquals(left, right, epsilon); diff --git a/Engine.Core/Primitives/Shape2D.cs b/Engine.Core/Primitives/Shape2D.cs index 8e8b5fe..59c894c 100644 --- a/Engine.Core/Primitives/Shape2D.cs +++ b/Engine.Core/Primitives/Shape2D.cs @@ -166,7 +166,7 @@ public readonly struct Shape2D(List vertices) : IEnumerable /// The shape to transform. /// The transform to apply. /// The transformed shape. - public static Shape2D TransformShape(Shape2D shape, ITransform transform) + public static Shape2D TransformShape(Shape2D shape, ITransform2D transform) { List vertices = new(shape.Vertices.Count); @@ -183,7 +183,7 @@ public readonly struct Shape2D(List vertices) : IEnumerable /// The shape to transform. /// The transform to apply. /// The transformed shape. - public static void TransformShape(Shape2D from, ITransform transform, ref Shape2D to) + public static void TransformShape(Shape2D from, ITransform2D transform, ref Shape2D to) { to._verticesList.Clear(); @@ -241,11 +241,11 @@ public static class Shape2DExtensions /// public static Projection1D ToProjection(this Shape2D shape, Vector2D projectionVector) => Shape2D.Project(shape, projectionVector); - /// - public static Shape2D TransformShape(this ITransform transform, Shape2D shape) => Shape2D.TransformShape(shape, transform); + /// + public static Shape2D TransformShape(this ITransform2D transform, Shape2D shape) => Shape2D.TransformShape(shape, transform); - /// - public static void TransformShape(this ITransform transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to); + /// + public static void TransformShape(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to); /// public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon); diff --git a/Engine.Core/StateEnable.cs b/Engine.Core/StateEnable.cs index 3451fbb..3885b7c 100644 --- a/Engine.Core/StateEnable.cs +++ b/Engine.Core/StateEnable.cs @@ -5,7 +5,7 @@ namespace Syntriax.Engine.Core; public class StateEnable : IStateEnable { public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - public event IAssignableEntity.OnEntityAssignedEventHandler? OnEntityAssigned = null; + public event IHasEntity.OnEntityAssignedEventHandler? OnEntityAssigned = null; public event IStateEnable.OnNameChangedEventHandler? OnEnabledChanged = null; private bool _enabled = true; diff --git a/Engine.Core/Transform.cs b/Engine.Core/Transform.cs deleted file mode 100644 index cddbfc5..0000000 --- a/Engine.Core/Transform.cs +++ /dev/null @@ -1,297 +0,0 @@ -using System.Collections; -using System.Collections.Generic; - -using Syntriax.Engine.Core.Abstract; - -namespace Syntriax.Engine.Core; - -[System.Diagnostics.DebuggerDisplay("Name: {GameObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")] -public class Transform : ITransform -{ - public event IAssignableGameObject.OnGameObjectAssignedEventHandler? OnGameObjectAssigned = null; - - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - - public event ITransform.OnPositionChangedEventHandler? OnPositionChanged = null; - public event ITransform.OnScaleChangedEventHandler? OnScaleChanged = null; - public event ITransform.OnRotationChangedEventHandler? OnRotationChanged = null; - - public event ITransform.OnParentChangedEventHandler? OnParentChanged = null; - public event ITransform.OnChildrenAddedEventHandler? OnChildrenAdded = null; - public event ITransform.OnChildrenRemovedEventHandler? OnChildrenRemoved = null; - - private Vector2D _position = Vector2D.Zero; - private Vector2D _scale = Vector2D.One; - private float _rotation = 0f; - - private Vector2D _localPosition = Vector2D.Zero; - private Vector2D _localScale = Vector2D.One; - private float _localRotation = 0f; - - private readonly List _children = []; - - public IGameObject GameObject { get; private set; } = null!; - public ITransform? Parent { get; private set; } = null; - - public IReadOnlyList Children => _children; - - public Vector2D Position - { - get => _position; - set - { - if (value == _position) - return; - - Vector2D previousPosition = _position; - _position = value; - - UpdateLocalPosition(); - OnPositionChanged?.Invoke(this, _position); - } - } - - public Vector2D Scale - { - get => _localScale.Scale(Parent?.Scale ?? Vector2D.One); - set - { - if (value == _scale) - return; - - Vector2D previousScale = _scale; - _scale = value; - - UpdateLocalScale(); - OnScaleChanged?.Invoke(this, previousScale); - } - } - - public float Rotation - { - get => _localRotation + (Parent?.Rotation ?? 0f); - set - { - if (value == _rotation) - return; - - - float previousRotation = _rotation; - _rotation = value; - - UpdateLocalPosition(); - OnRotationChanged?.Invoke(this, previousRotation); - } - } - - public Vector2D LocalPosition - { - get => _localPosition; - set - { - if (value == _localPosition) - return; - - Vector2D previousPosition = _position; - _localPosition = value; - - UpdatePosition(); - OnPositionChanged?.Invoke(this, previousPosition); - } - } - - public Vector2D LocalScale - { - get => _localScale; - set - { - if (value == _localScale) - return; - - Vector2D previousScale = _scale; - _localScale = value; - - UpdateScale(); - OnScaleChanged?.Invoke(this, previousScale); - } - } - - public float LocalRotation - { - get => _localRotation; - set - { - if (value == _localRotation) - return; - - float previousRotation = _rotation; - _localRotation = value; - - UpdateRotation(); - OnRotationChanged?.Invoke(this, previousRotation); - } - } - - public void SetParent(ITransform? transform) - { - if (transform == this || Parent == transform) - return; - - ITransform? previousParent = Parent; - if (previousParent is not null) - { - previousParent.RemoveChild(this); - previousParent.OnPositionChanged -= RecalculatePosition; - previousParent.OnScaleChanged -= RecalculateScale; - previousParent.OnRotationChanged -= RecalculateRotation; - previousParent.OnParentChanged -= NotifyChildrenOnParentChange; - } - - Parent = transform; - - if (transform is not null) - { - transform.AddChild(this); - transform.OnPositionChanged += RecalculatePosition; - transform.OnScaleChanged += RecalculateScale; - transform.OnRotationChanged += RecalculateRotation; - transform.OnParentChanged += NotifyChildrenOnParentChange; - } - - UpdateLocalPosition(); - UpdateLocalScale(); - UpdateLocalRotation(); - - OnParentChanged?.Invoke(this, previousParent, transform); - } - - public void AddChild(ITransform transform) - { - if (_children.Contains(transform)) - return; - - _children.Add(transform); - transform.SetParent(this); - OnChildrenAdded?.Invoke(this, transform); - } - - public void RemoveChild(ITransform transform) - { - if (!_children.Remove(transform)) - return; - - transform.SetParent(null); - OnChildrenRemoved?.Invoke(this, transform); - } - - public IEnumerator GetEnumerator() => _children.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator(); - - private void NotifyChildrenOnParentChange(ITransform transform, ITransform? previousParent, ITransform? newParent) - { - // TODO No idea how logical this is to propagate this to the children the way I'm doing right now. - // I was originally gonna just call `child.OnParentChanged?.Invoke(child, child.Parent);` but seems an unnecessary call too? - foreach (ITransform child in Children) // TODO CHECK ERRORS - child.SetParent(this); - } - - private void RecalculatePosition(ITransform _, Vector2D previousPosition) - { - if (Parent is null) - return; - - UpdatePosition(); - - OnPositionChanged?.Invoke(this, previousPosition); - } - - private void RecalculateScale(ITransform _, Vector2D previousScale) - { - if (Parent is null) - return; - - UpdateScale(); - - OnScaleChanged?.Invoke(this, previousScale); - } - - private void RecalculateRotation(ITransform _, float previousRotation) - { - if (Parent is null) - return; - - // UpdatePosition(); - UpdateRotation(); - - // OnPositionChanged?.Invoke(this, previousPosition); - OnRotationChanged?.Invoke(this, previousRotation); - } - - private void UpdateLocalPosition() - { - if (Parent is null) - _localPosition = Position; - else - _localPosition = Parent.Position.FromTo(Position).Scale(Parent.Scale); - } - - private void UpdateLocalScale() - { - if (Parent is null) - _localScale = Scale; - else - _localScale = Scale.Scale(new(1f / Parent.Scale.X, 1f / Parent.Scale.Y)); - } - - private void UpdateLocalRotation() - { - if (Parent is null) - _localRotation = Rotation; - else - _localRotation = Rotation - Parent.Rotation; - } - - private void UpdatePosition() - { - if (Parent is null) - _position = LocalPosition.Rotate(0f * Math.DegreeToRadian); - else - _position = Parent.Position + LocalPosition.Scale(new(Parent.Scale.X, Parent.Scale.Y)).Rotate(Parent.Rotation * Math.DegreeToRadian); - } - - private void UpdateScale() - { - if (Parent is null) - _scale = LocalScale; - else - _scale = Vector2D.Scale(Parent.Scale, LocalScale); - } - - private void UpdateRotation() - { - if (Parent is null) - _rotation = LocalRotation; - else - _rotation = Parent.Rotation + LocalRotation; - } - - public bool Assign(IGameObject gameObject) - { - if (GameObject is not null && GameObject.IsInitialized) - return false; - - GameObject = gameObject; - OnGameObjectAssigned?.Invoke(this); - return true; - } - - public bool Unassign() - { - if (GameObject is not null && GameObject.IsInitialized) - return false; - - GameObject = null!; - OnUnassigned?.Invoke(this); - return true; - } -} diff --git a/Engine.Core/Transform2D.cs b/Engine.Core/Transform2D.cs new file mode 100644 index 0000000..1ae6c63 --- /dev/null +++ b/Engine.Core/Transform2D.cs @@ -0,0 +1,255 @@ +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +[System.Diagnostics.DebuggerDisplay("Name: {HierarchyObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")] +public class Transform2D : Behaviour, ITransform2D +{ + public event ITransform2D.OnPositionChangedEventHandler? OnPositionChanged = null; + public event ITransform2D.OnScaleChangedEventHandler? OnScaleChanged = null; + public event ITransform2D.OnRotationChangedEventHandler? OnRotationChanged = null; + + private Vector2D _position = Vector2D.Zero; + private Vector2D _scale = Vector2D.One; + private float _rotation = 0f; + + private Vector2D _localPosition = Vector2D.Zero; + private Vector2D _localScale = Vector2D.One; + private float _localRotation = 0f; + + private ITransform2D? parentTransform = null; + + public Vector2D Position + { + get => _position; + set + { + if (value == _position) + return; + + Vector2D previousPosition = _position; + _position = value; + + UpdateLocalPosition(); + OnPositionChanged?.Invoke(this, _position); + } + } + + public Vector2D Scale + { + get => _scale; + set + { + if (value == _scale) + return; + + Vector2D previousScale = _scale; + _scale = value; + + UpdateLocalScale(); + OnScaleChanged?.Invoke(this, previousScale); + } + } + + public float Rotation + { + get => _rotation; + set + { + if (value == _rotation) + return; + + float previousRotation = _rotation; + _rotation = value; + + UpdateLocalRotation(); + OnRotationChanged?.Invoke(this, previousRotation); + } + } + + public Vector2D LocalPosition + { + get => _localPosition; + set + { + if (value == _localPosition) + return; + + Vector2D previousPosition = _position; + _localPosition = value; + + UpdatePosition(); + OnPositionChanged?.Invoke(this, previousPosition); + } + } + + public Vector2D LocalScale + { + get => _localScale; + set + { + if (value == _localScale) + return; + + Vector2D previousScale = _scale; + _localScale = value; + + UpdateScale(); + OnScaleChanged?.Invoke(this, previousScale); + } + } + + public float LocalRotation + { + get => _localRotation; + set + { + if (value == _localRotation) + return; + + float previousRotation = _rotation; + _localRotation = value; + + UpdateRotation(); + OnRotationChanged?.Invoke(this, previousRotation); + } + } + + private void RecalculatePosition(ITransform2D _, Vector2D previousPosition) + { + if (parentTransform is null) + return; + + float previousRotation = Rotation; + + UpdatePosition(); + UpdateRotation(); + + OnPositionChanged?.Invoke(this, previousPosition); + OnRotationChanged?.Invoke(this, previousRotation); + } + + private void RecalculateScale(ITransform2D _, Vector2D previousScale) + { + if (parentTransform is null) + return; + + UpdateScale(); + + OnScaleChanged?.Invoke(this, previousScale); + } + + private void RecalculateRotation(ITransform2D _, float previousRotation) + { + if (parentTransform is null) + return; + + Vector2D previousPosition = Position; + + UpdatePosition(); + UpdateRotation(); + + OnPositionChanged?.Invoke(this, previousPosition); + OnRotationChanged?.Invoke(this, previousRotation); + } + + private void UpdateLocalPosition() + { + if (parentTransform is null) + _localPosition = Position; + else + _localPosition = parentTransform.Position.FromTo(Position).Scale(parentTransform.Scale); + } + + private void UpdateLocalScale() + { + if (parentTransform is null) + _localScale = Scale; + else + _localScale = Scale.Scale(new(1f / parentTransform.Scale.X, 1f / parentTransform.Scale.Y)); + } + + private void UpdateLocalRotation() + { + if (parentTransform is null) + _localRotation = Rotation; + else + _localRotation = Rotation - parentTransform.Rotation; + } + + private void UpdatePosition() + { + if (parentTransform is null) + _position = LocalPosition.Rotate(0f * Math.DegreeToRadian); + else + _position = parentTransform.Position + LocalPosition.Scale(new(parentTransform.Scale.X, parentTransform.Scale.Y)).Rotate(parentTransform.Rotation * Math.DegreeToRadian); + } + + private void UpdateScale() + { + if (parentTransform is null) + _scale = LocalScale; + else + _scale = (parentTransform?.Scale ?? Vector2D.One).Scale(_localScale); + } + + private void UpdateRotation() + { + if (parentTransform is null) + _rotation = LocalRotation; + else + _rotation = parentTransform.Rotation + LocalRotation; + } + + protected override void InitializeInternal() + { + UpdateParent(BehaviourController.HierarchyObject.Parent); + BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged; + } + + protected override void FinalizeInternal() + { + BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged; + } + + private void UpdateParent(IHierarchyObject? parent) + { + ITransform2D? previousParent = parentTransform; + if (previousParent is not null) + { + previousParent.BehaviourController.HierarchyObject.RemoveChild(HierarchyObject); + previousParent.OnPositionChanged -= RecalculatePosition; + previousParent.OnScaleChanged -= RecalculateScale; + previousParent.OnRotationChanged -= RecalculateRotation; + previousParent.BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged; + } + + parentTransform = parent?.BehaviourController.GetBehaviour(); + + if (parentTransform is not null) + { + parentTransform.BehaviourController.HierarchyObject.AddChild(HierarchyObject); + parentTransform.OnPositionChanged += RecalculatePosition; + parentTransform.OnScaleChanged += RecalculateScale; + parentTransform.OnRotationChanged += RecalculateRotation; + parentTransform.BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged; + + UpdatePosition(); + UpdateScale(); + UpdateRotation(); + } + + UpdateLocalPosition(); + UpdateLocalScale(); + UpdateLocalRotation(); + + OnPositionChanged?.Invoke(this, Position); + OnScaleChanged?.Invoke(this, Scale); + OnRotationChanged?.Invoke(this, Rotation); + } + + private void OnParentChanged(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent) + { + UpdateParent(newParent); + } +} diff --git a/Engine.Input/Abstract/IButtonInputs.cs b/Engine.Input/Abstract/IButtonInputs.cs index 0882d17..e117c9a 100644 --- a/Engine.Input/Abstract/IButtonInputs.cs +++ b/Engine.Input/Abstract/IButtonInputs.cs @@ -2,7 +2,7 @@ using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Input; -public interface IButtonInputs : IAssignableStateEnable +public interface IButtonInputs : IHasStateEnable { event ButtonCallbackEventHandler? OnAnyButtonPressed; event ButtonCallbackEventHandler? OnAnyButtonReleased; diff --git a/Engine.Physics2D/Abstract/ICollider2D.cs b/Engine.Physics2D/Abstract/ICollider2D.cs index be6baf6..0d43232 100644 --- a/Engine.Physics2D/Abstract/ICollider2D.cs +++ b/Engine.Physics2D/Abstract/ICollider2D.cs @@ -5,7 +5,7 @@ namespace Syntriax.Engine.Physics2D.Abstract; /// /// Represents a 2D collider. /// -public interface ICollider2D : IBehaviour, IAssignableTransform +public interface ICollider2D : IBehaviour { /// /// Event triggered when a collision is detected. @@ -22,6 +22,9 @@ public interface ICollider2D : IBehaviour, IAssignableTransform /// event OnTriggeredEventHandler? OnTriggered; + /// + ITransform2D Transform { get; } + /// /// The associated with the . /// diff --git a/Engine.Physics2D/Abstract/IRigidBody2D.cs b/Engine.Physics2D/Abstract/IRigidBody2D.cs index 9b8b68c..89b1685 100644 --- a/Engine.Physics2D/Abstract/IRigidBody2D.cs +++ b/Engine.Physics2D/Abstract/IRigidBody2D.cs @@ -6,7 +6,7 @@ namespace Syntriax.Engine.Physics2D.Abstract; /// /// Represents a 2D rigid body in the engine. /// -public interface IRigidBody2D : IBehaviour, IAssignableTransform +public interface IRigidBody2D : IBehaviour2D { /// /// The physics material of the . diff --git a/Engine.Physics2D/Collider2DBehaviourBase.cs b/Engine.Physics2D/Collider2DBehaviourBase.cs index 2a06b4a..bb7a329 100644 --- a/Engine.Physics2D/Collider2DBehaviourBase.cs +++ b/Engine.Physics2D/Collider2DBehaviourBase.cs @@ -4,7 +4,7 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D +public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D { public event ICollider2D.OnCollisionDetectedEventHandler? OnCollisionDetected = null; public event ICollider2D.OnCollisionResolvedEventHandler? OnCollisionResolved = null; @@ -16,11 +16,6 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D public IRigidBody2D? RigidBody2D => _rigidBody2D; public bool IsTrigger { get; set; } = false; - ITransform IAssignableTransform.Transform => Transform; - public event IAssignableTransform.OnTransformAssignedEventHandler? OnTransformAssigned { add => GameObject.OnTransformAssigned += value; remove => GameObject.OnTransformAssigned -= value; } - - bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform); - public void Recalculate() { if (!NeedsRecalculation) @@ -42,10 +37,10 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D Transform.OnPositionChanged += SetNeedsRecalculationFromPosition; Transform.OnRotationChanged += SetNeedsRecalculationFromRotation; Transform.OnScaleChanged += SetNeedsRecalculationFromScale; - Transform.OnParentChanged += UpdateRigidBody2D; + HierarchyObject.OnParentChanged += UpdateRigidBody2D; } - private void UpdateRigidBody2D(ITransform sender, ITransform? previousParent, ITransform? newParent) + private void UpdateRigidBody2D(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent) { BehaviourController.TryGetBehaviourInParent(out _rigidBody2D); } @@ -62,9 +57,9 @@ public abstract class Collider2DBehaviourBase : Behaviour, ICollider2D _rigidBody2D = null; } - private void SetNeedsRecalculationFromScale(ITransform sender, Vector2D previousScale) => NeedsRecalculation = true; - private void SetNeedsRecalculationFromPosition(ITransform sender, Vector2D previousPosition) => NeedsRecalculation = true; - private void SetNeedsRecalculationFromRotation(ITransform sender, float previousRotation) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromScale(ITransform2D sender, Vector2D previousScale) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromPosition(ITransform2D sender, Vector2D previousPosition) => NeedsRecalculation = true; + private void SetNeedsRecalculationFromRotation(ITransform2D sender, float previousRotation) => NeedsRecalculation = true; protected override void OnFinalize() { diff --git a/Engine.Physics2D/PhysicsCoroutineManager.cs b/Engine.Physics2D/PhysicsCoroutineManager.cs index 939f94f..e2ed13d 100644 --- a/Engine.Physics2D/PhysicsCoroutineManager.cs +++ b/Engine.Physics2D/PhysicsCoroutineManager.cs @@ -7,7 +7,7 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public class PhysicsCoroutineManager : HierarchyObjectBase +public class PhysicsCoroutineManager : HierarchyObject { private readonly List enumerators = []; private IPhysicsEngine2D? physicsEngine = null; diff --git a/Engine.Physics2D/PhysicsEngine2DCollector.cs b/Engine.Physics2D/PhysicsEngine2DCollector.cs index 5851fd7..59d9963 100644 --- a/Engine.Physics2D/PhysicsEngine2DCollector.cs +++ b/Engine.Physics2D/PhysicsEngine2DCollector.cs @@ -4,7 +4,7 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public class PhysicsEngine2DCollector : HierarchyObjectBase, IPhysicsEngine2D +public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D { public event IPhysicsEngine2D.OnPhysicsIterationEventHandler? OnPhysicsIteration = null; public event IPhysicsEngine2D.OnPhysicsStepEventHandler? OnPhysicsStep = null; diff --git a/Engine.Physics2D/RigidBody2D.cs b/Engine.Physics2D/RigidBody2D.cs index 4628a5d..9e5aa04 100644 --- a/Engine.Physics2D/RigidBody2D.cs +++ b/Engine.Physics2D/RigidBody2D.cs @@ -1,13 +1,10 @@ using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public class RigidBody2D : Behaviour, IRigidBody2D +public class RigidBody2D : Behaviour2D, IRigidBody2D { - event IAssignableTransform.OnTransformAssignedEventHandler? IAssignableTransform.OnTransformAssigned { add => GameObject.OnTransformAssigned += value; remove => GameObject.OnTransformAssigned -= value; } - private const float LOWEST_ALLOWED_MASS = 0.00001f; private float _mass = 1f; @@ -18,8 +15,4 @@ public class RigidBody2D : Behaviour, IRigidBody2D public bool IsStatic { get; set; } = false; public float Mass { get => _mass; set => _mass = Core.Math.Max(value, LOWEST_ALLOWED_MASS); } - - ITransform IAssignableTransform.Transform => Transform; - - public bool Assign(ITransform transform) => GameObject.Assign(transform); } -- 2.47.1 From b9ee1ec2325b2a86cfa555fdf34229d5efee084b Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 29 Mar 2025 10:30:31 +0300 Subject: [PATCH 13/32] fix: unassigned fields on factories --- Engine.Core/Factory/BehaviourControllerFactory.cs | 3 +++ Engine.Core/Factory/StateEnableFactory.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Engine.Core/Factory/BehaviourControllerFactory.cs b/Engine.Core/Factory/BehaviourControllerFactory.cs index 287a8db..d242503 100644 --- a/Engine.Core/Factory/BehaviourControllerFactory.cs +++ b/Engine.Core/Factory/BehaviourControllerFactory.cs @@ -13,6 +13,9 @@ public class BehaviourControllerFactory { T behaviourController = TypeFactory.Get(args); + if (!hierarchyObject.Assign(behaviourController)) + throw AssignException.From(hierarchyObject, behaviourController); + if (!behaviourController.Assign(hierarchyObject)) throw AssignException.From(behaviourController, hierarchyObject); diff --git a/Engine.Core/Factory/StateEnableFactory.cs b/Engine.Core/Factory/StateEnableFactory.cs index 1c00847..05167ae 100644 --- a/Engine.Core/Factory/StateEnableFactory.cs +++ b/Engine.Core/Factory/StateEnableFactory.cs @@ -11,6 +11,9 @@ public class StateEnableFactory { T stateEnable = TypeFactory.Get(args); + if (!entity.Assign(stateEnable)) + throw AssignException.From(entity, stateEnable); + if (!stateEnable.Assign(entity)) throw AssignException.From(stateEnable, entity); -- 2.47.1 From 5c3e0f6581e493692d2d70b2335c3e76d9fc836a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 29 Mar 2025 21:40:30 +0300 Subject: [PATCH 14/32] feat: added basic state machine system & Engine.Systems class library --- Engine.Systems/Engine.Systems.csproj | 13 +++++ Engine.Systems/StateMachine/IState.cs | 22 ++++++++ Engine.Systems/StateMachine/State.cs | 52 +++++++++++++++++++ .../StateMachine/StateBehaviourBase.cs | 37 +++++++++++++ Engine.Systems/StateMachine/StateMachine.cs | 49 +++++++++++++++++ .../StateMachine/StateTransition.cs | 11 ++++ 6 files changed, 184 insertions(+) create mode 100644 Engine.Systems/Engine.Systems.csproj create mode 100644 Engine.Systems/StateMachine/IState.cs create mode 100644 Engine.Systems/StateMachine/State.cs create mode 100644 Engine.Systems/StateMachine/StateBehaviourBase.cs create mode 100644 Engine.Systems/StateMachine/StateMachine.cs create mode 100644 Engine.Systems/StateMachine/StateTransition.cs diff --git a/Engine.Systems/Engine.Systems.csproj b/Engine.Systems/Engine.Systems.csproj new file mode 100644 index 0000000..2ba7eb9 --- /dev/null +++ b/Engine.Systems/Engine.Systems.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Engine.Systems/StateMachine/IState.cs b/Engine.Systems/StateMachine/IState.cs new file mode 100644 index 0000000..ff20be4 --- /dev/null +++ b/Engine.Systems/StateMachine/IState.cs @@ -0,0 +1,22 @@ +namespace Syntriax.Engine.StateMachine; + +public interface IState +{ + event StateUpdateEventHandler? OnStateUpdate; + event StateTransitionedFromEventHandler? OnStateTransitionedFrom; + event StateTransitionedToEventHandler? OnStateTransitionedTo; + event StateTransitionReadyEventHandler? OnStateTransitionReady; + + string Name { get; } + + IState? GetNextState(); + + void Update(); + void TransitionTo(IState from); + void TransitionFrom(IState to); + + delegate void StateUpdateEventHandler(IState sender); + delegate void StateTransitionedFromEventHandler(IState sender, IState toState); + delegate void StateTransitionedToEventHandler(IState sender, IState fromState); + delegate void StateTransitionReadyEventHandler(IState sender, IState toState); +} diff --git a/Engine.Systems/StateMachine/State.cs b/Engine.Systems/StateMachine/State.cs new file mode 100644 index 0000000..5ebe352 --- /dev/null +++ b/Engine.Systems/StateMachine/State.cs @@ -0,0 +1,52 @@ +namespace Syntriax.Engine.StateMachine; + +public class State : IState +{ + public event IState.StateUpdateEventHandler? OnStateUpdate = null; + public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null; + public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null; + public event IState.StateTransitionReadyEventHandler? OnStateTransitionReady = null; + + private readonly List transitions = []; + private readonly Dictionary possibleTransitions = []; + + public string Name { get; set; } = "Default State Name"; + public IReadOnlyList Transitions => transitions; + public IReadOnlyDictionary PossibleTransitions => possibleTransitions; + + public void RemoveTransition(string name) + { + if (!possibleTransitions.TryGetValue(name, out StateTransition stateTransition)) + return; + + transitions.Remove(stateTransition); + possibleTransitions.Remove(name); + } + + public void AddTransition(string name, StateTransition stateTransition) + { + if (transitions.Contains(stateTransition)) + return; + + transitions.Add(stateTransition); + possibleTransitions.Add(name, stateTransition); + } + + public void Update() + { + if (GetNextState() is IState transitionState) + OnStateTransitionReady?.Invoke(this, transitionState); + OnStateUpdate?.Invoke(this); + } + + public void TransitionTo(IState from) => OnStateTransitionedTo?.Invoke(this, from); + public void TransitionFrom(IState to) => OnStateTransitionedFrom?.Invoke(this, to); + + public IState? GetNextState() + { + foreach (StateTransition stateTransition in transitions) + if (stateTransition.CanTransition) + return stateTransition.State; + return null; + } +} diff --git a/Engine.Systems/StateMachine/StateBehaviourBase.cs b/Engine.Systems/StateMachine/StateBehaviourBase.cs new file mode 100644 index 0000000..d51f888 --- /dev/null +++ b/Engine.Systems/StateMachine/StateBehaviourBase.cs @@ -0,0 +1,37 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.StateMachine; + +public abstract class StateBehaviourBase : Behaviour, IState +{ + public event IState.StateUpdateEventHandler? OnStateUpdate = null; + public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null; + public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null; + + public abstract event IState.StateTransitionReadyEventHandler? OnStateTransitionReady; + + public abstract string Name { get; } + + protected virtual void OnUpdateState() { } + public void Update() + { + OnUpdateState(); + OnStateUpdate?.Invoke(this); + } + + protected virtual void OnTransitionedToState(IState from) { } + public void TransitionTo(IState from) + { + OnTransitionedToState(from); + OnStateTransitionedTo?.Invoke(this, from); + } + + protected virtual void OnTransitionedFromState(IState to) { } + public void TransitionFrom(IState to) + { + OnTransitionedFromState(to); + OnStateTransitionedFrom?.Invoke(this, to); + } + + public abstract IState? GetNextState(); +} diff --git a/Engine.Systems/StateMachine/StateMachine.cs b/Engine.Systems/StateMachine/StateMachine.cs new file mode 100644 index 0000000..791427f --- /dev/null +++ b/Engine.Systems/StateMachine/StateMachine.cs @@ -0,0 +1,49 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.StateMachine; + +public class StateMachine : Behaviour +{ + public event OnStateChangedEventHandler? OnStateChanged = null; + + private IState _state = new State(); + public IState State + { + get => _state; + set + { + if (_state == value) + return; + + IState previousState = _state; + previousState.OnStateTransitionReady -= OnStateTransitionReady; + + _state = value; + previousState.TransitionFrom(value); + value.TransitionTo(_state); + OnStateChanged?.Invoke(this, previousState, value); + + value.OnStateTransitionReady += OnStateTransitionReady; + } + } + + private void OnStateTransitionReady(IState sender, IState toState) + { + State = toState; + while (State.GetNextState() is IState nextState) + State = nextState; + } + + protected override void OnUpdate() + { + if (State is null) + return; + + while (State.GetNextState() is IState nextState) + State = nextState; + + State.Update(); + } + + public delegate void OnStateChangedEventHandler(StateMachine sender, IState previousState, IState newState); +} diff --git a/Engine.Systems/StateMachine/StateTransition.cs b/Engine.Systems/StateMachine/StateTransition.cs new file mode 100644 index 0000000..d0cff8e --- /dev/null +++ b/Engine.Systems/StateMachine/StateTransition.cs @@ -0,0 +1,11 @@ +namespace Syntriax.Engine.StateMachine; + +public readonly record struct StateTransition(IState State, IReadOnlyList> Conditions) +{ + public static implicit operator (IState state, IReadOnlyList> conditions)(StateTransition value) + => (value.State, value.Conditions); + public static implicit operator StateTransition((IState state, IReadOnlyList> conditions) value) + => new(value.state, value.conditions); + + public bool CanTransition => !Conditions.Any(c => !c.Invoke()); +} -- 2.47.1 From f9785462b0de31cf6811d49078a11420d0533bfe Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 29 Mar 2025 21:51:51 +0300 Subject: [PATCH 15/32] refactor: delegate names updated to have no "On" prefix --- .../Abstract/Assignable/IAssignable.cs | 4 ++-- .../Assignable/IHasBehaviourController.cs | 4 ++-- Engine.Core/Abstract/Assignable/IHasEntity.cs | 4 ++-- .../Abstract/Assignable/IHasGameManager.cs | 4 ++-- .../Assignable/IHasHierarchyObject.cs | 4 ++-- .../Abstract/Assignable/IHasStateEnable.cs | 4 ++-- Engine.Core/Abstract/BaseEntity.cs | 10 +++++----- Engine.Core/Abstract/IBehaviour.cs | 4 ++-- Engine.Core/Abstract/IBehaviourCollector.cs | 8 ++++---- Engine.Core/Abstract/IBehaviourController.cs | 20 +++++++++---------- Engine.Core/Abstract/IEntity.cs | 4 ++-- Engine.Core/Abstract/IGameManager.cs | 16 +++++++-------- Engine.Core/Abstract/IHierarchyObject.cs | 20 +++++++++---------- Engine.Core/Abstract/IInitializable.cs | 8 ++++---- Engine.Core/Abstract/INameable.cs | 4 ++-- Engine.Core/Abstract/IStateEnable.cs | 4 ++-- Engine.Core/Abstract/ITransform2D.cs | 12 +++++------ Engine.Core/BehaviourBase.cs | 4 ++-- Engine.Core/BehaviourCollector.cs | 8 ++++---- Engine.Core/BehaviourController.cs | 18 ++++++++--------- Engine.Core/GameManager.cs | 8 ++++---- Engine.Core/HierarchyObject.cs | 14 ++++++------- Engine.Core/StateEnable.cs | 6 +++--- Engine.Core/Transform2D.cs | 6 +++--- Engine.Physics2D/Abstract/ICollider2D.cs | 12 +++++------ Engine.Physics2D/Abstract/IPhysicsEngine2D.cs | 8 ++++---- Engine.Physics2D/Collider2DBehaviourBase.cs | 6 +++--- Engine.Physics2D/PhysicsEngine2D.cs | 4 ++-- Engine.Physics2D/PhysicsEngine2DCollector.cs | 4 ++-- Engine.Systems/StateMachine/StateMachine.cs | 4 ++-- 30 files changed, 118 insertions(+), 118 deletions(-) diff --git a/Engine.Core/Abstract/Assignable/IAssignable.cs b/Engine.Core/Abstract/Assignable/IAssignable.cs index bd4af57..04137dc 100644 --- a/Engine.Core/Abstract/Assignable/IAssignable.cs +++ b/Engine.Core/Abstract/Assignable/IAssignable.cs @@ -8,7 +8,7 @@ public interface IAssignable /// /// Event triggered when the 's fields are unassigned and completely ready to recycle. /// - event OnUnassignedEventHandler? OnUnassigned; + event UnassignEventHandler? OnUnassigned; /// /// Unassign 's all fields and make it ready to recycle. @@ -18,5 +18,5 @@ public interface IAssignable /// bool Unassign(); - delegate void OnUnassignedEventHandler(IAssignable sender); + delegate void UnassignEventHandler(IAssignable sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs b/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs index b5218c3..496147d 100644 --- a/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs +++ b/Engine.Core/Abstract/Assignable/IHasBehaviourController.cs @@ -8,7 +8,7 @@ public interface IHasBehaviourController : IAssignable /// /// Event triggered when the value has has been assigned a new value. /// - event OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned; + event BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned; /// IBehaviourController BehaviourController { get; } @@ -22,5 +22,5 @@ public interface IHasBehaviourController : IAssignable /// bool Assign(IBehaviourController behaviourController); - delegate void OnBehaviourControllerAssignedEventHandler(IHasBehaviourController sender); + delegate void BehaviourControllerAssignedEventHandler(IHasBehaviourController sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasEntity.cs b/Engine.Core/Abstract/Assignable/IHasEntity.cs index 6ffcaeb..90e8ec6 100644 --- a/Engine.Core/Abstract/Assignable/IHasEntity.cs +++ b/Engine.Core/Abstract/Assignable/IHasEntity.cs @@ -8,7 +8,7 @@ public interface IHasEntity : IAssignable /// /// Event triggered when the value has has been assigned a new value. /// - event OnEntityAssignedEventHandler? OnEntityAssigned; + event EntityAssignedEventHandler? OnEntityAssigned; /// IEntity Entity { get; } @@ -22,5 +22,5 @@ public interface IHasEntity : IAssignable /// bool Assign(IEntity entity); - delegate void OnEntityAssignedEventHandler(IHasEntity sender); + delegate void EntityAssignedEventHandler(IHasEntity sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasGameManager.cs b/Engine.Core/Abstract/Assignable/IHasGameManager.cs index cb3f4d4..9946837 100644 --- a/Engine.Core/Abstract/Assignable/IHasGameManager.cs +++ b/Engine.Core/Abstract/Assignable/IHasGameManager.cs @@ -8,7 +8,7 @@ public interface IHasGameManager : IAssignable /// /// Event triggered when the value has has been assigned a new value. /// - event OnGameManagerAssignedEventHandler? OnGameManagerAssigned; + event GameManagerAssignedEventHandler? OnGameManagerAssigned; /// IGameManager GameManager { get; } @@ -22,5 +22,5 @@ public interface IHasGameManager : IAssignable /// bool Assign(IGameManager gameManager); - delegate void OnGameManagerAssignedEventHandler(IHasGameManager sender); + delegate void GameManagerAssignedEventHandler(IHasGameManager sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs b/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs index f8d3df9..6b7c6c9 100644 --- a/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs +++ b/Engine.Core/Abstract/Assignable/IHasHierarchyObject.cs @@ -8,7 +8,7 @@ public interface IHasHierarchyObject : IAssignable /// /// Event triggered when the value has has been assigned a new value. /// - event OnHierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned; + event HierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned; /// IHierarchyObject HierarchyObject { get; } @@ -22,5 +22,5 @@ public interface IHasHierarchyObject : IAssignable /// bool Assign(IHierarchyObject hierarchyObject); - delegate void OnHierarchyObjectAssignedEventHandler(IHasHierarchyObject sender); + delegate void HierarchyObjectAssignedEventHandler(IHasHierarchyObject sender); } diff --git a/Engine.Core/Abstract/Assignable/IHasStateEnable.cs b/Engine.Core/Abstract/Assignable/IHasStateEnable.cs index 54a5b52..73561e7 100644 --- a/Engine.Core/Abstract/Assignable/IHasStateEnable.cs +++ b/Engine.Core/Abstract/Assignable/IHasStateEnable.cs @@ -8,7 +8,7 @@ public interface IHasStateEnable : IAssignable /// /// Event triggered when the value has has been assigned a new value. /// - event OnStateEnableAssignedEventHandler? OnStateEnableAssigned; + event StateEnableAssignedEventHandler? OnStateEnableAssigned; /// IStateEnable StateEnable { get; } @@ -22,5 +22,5 @@ public interface IHasStateEnable : IAssignable /// bool Assign(IStateEnable stateEnable); - delegate void OnStateEnableAssignedEventHandler(IHasStateEnable sender); + delegate void StateEnableAssignedEventHandler(IHasStateEnable sender); } diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/Abstract/BaseEntity.cs index ae456e1..52e67a9 100644 --- a/Engine.Core/Abstract/BaseEntity.cs +++ b/Engine.Core/Abstract/BaseEntity.cs @@ -4,13 +4,13 @@ namespace Syntriax.Engine.Core.Abstract; public abstract class BaseEntity : IEntity { - public event IEntity.OnIdChangedEventHandler? OnIdChanged = null; + public event IEntity.IdChangedEventHandler? OnIdChanged = null; - public event IInitializable.OnInitializedEventHandler? OnInitialized = null; - public event IInitializable.OnFinalizedEventHandler? OnFinalized = null; + public event IInitializable.InitializedEventHandler? OnInitialized = null; + public event IInitializable.FinalizedEventHandler? OnFinalized = null; - public event IHasStateEnable.OnStateEnableAssignedEventHandler? OnStateEnableAssigned = null; - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; + public event IHasStateEnable.StateEnableAssignedEventHandler? OnStateEnableAssigned = null; + public event IAssignable.UnassignEventHandler? OnUnassigned = null; private IStateEnable _stateEnable = null!; diff --git a/Engine.Core/Abstract/IBehaviour.cs b/Engine.Core/Abstract/IBehaviour.cs index cdd25a1..9fc2d30 100644 --- a/Engine.Core/Abstract/IBehaviour.cs +++ b/Engine.Core/Abstract/IBehaviour.cs @@ -8,7 +8,7 @@ public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable /// /// Event triggered when the priority of the changes. /// - event OnPriorityChangedEventHandler? OnPriorityChanged; + event PriorityChangedEventHandler? OnPriorityChanged; /// /// The priority of the . @@ -20,5 +20,5 @@ public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable /// bool IsActive { get; } - delegate void OnPriorityChangedEventHandler(IBehaviour sender, int previousPriority); + delegate void PriorityChangedEventHandler(IBehaviour sender, int previousPriority); } diff --git a/Engine.Core/Abstract/IBehaviourCollector.cs b/Engine.Core/Abstract/IBehaviourCollector.cs index 84bf28b..e0d38e9 100644 --- a/Engine.Core/Abstract/IBehaviourCollector.cs +++ b/Engine.Core/Abstract/IBehaviourCollector.cs @@ -12,24 +12,24 @@ public interface IBehaviourCollector : IHasGameManager, IEnumerable where /// /// Event triggered when an object of type is added to the collector. /// - event OnCollectedEventHandler? OnCollected; + event CollectedEventHandler? OnCollected; /// /// Event triggered when an object of type is removed from the collector. /// - event OnRemovedEventHandler? OnRemoved; + event RemovedEventHandler? OnRemoved; /// /// Delegate for handling the event. /// /// The instance of the that triggered the event. /// The object of type that was added to the collector. - public delegate void OnCollectedEventHandler(BehaviourCollector sender, T behaviourCollected); + public delegate void CollectedEventHandler(BehaviourCollector sender, T behaviourCollected); /// /// Delegate for handling the event. /// /// The instance of the that triggered the event. /// The object of type that was removed from the collector. - public delegate void OnRemovedEventHandler(BehaviourCollector sender, T behaviourRemoved); + public delegate void RemovedEventHandler(BehaviourCollector sender, T behaviourRemoved); } diff --git a/Engine.Core/Abstract/IBehaviourController.cs b/Engine.Core/Abstract/IBehaviourController.cs index 8b92caa..64fa28e 100644 --- a/Engine.Core/Abstract/IBehaviourController.cs +++ b/Engine.Core/Abstract/IBehaviourController.cs @@ -10,27 +10,27 @@ public interface IBehaviourController : IInitializable, IHasHierarchyObject, IEn /// /// Event triggered before the update of s. /// - event OnPreUpdateEventHandler? OnPreUpdate; + event PreUpdateEventHandler? OnPreUpdate; /// /// Event triggered during the update of s. /// - event OnUpdateEventHandler? OnUpdate; + event UpdateEventHandler? OnUpdate; /// /// Event triggered before the drawing phase. /// - event OnPreDrawEventHandler? OnPreDraw; + event PreDrawEventHandler? OnPreDraw; /// /// Event triggered when a is added to the . /// - event OnBehaviourAddedEventHandler? OnBehaviourAdded; + event BehaviourAddedEventHandler? OnBehaviourAdded; /// /// Event triggered when a is removed from the . /// - event OnBehaviourRemovedEventHandler? OnBehaviourRemoved; + event BehaviourRemovedEventHandler? OnBehaviourRemoved; /// /// Adds a to the . @@ -93,10 +93,10 @@ public interface IBehaviourController : IInitializable, IHasHierarchyObject, IEn /// void UpdatePreDraw(); - delegate void OnPreUpdateEventHandler(IBehaviourController sender); - delegate void OnUpdateEventHandler(IBehaviourController sender); - delegate void OnPreDrawEventHandler(IBehaviourController sender); - delegate void OnBehaviourAddedEventHandler(IBehaviourController sender, IBehaviour behaviourAdded); - delegate void OnBehaviourRemovedEventHandler(IBehaviourController sender, IBehaviour behaviourRemoved); + delegate void PreUpdateEventHandler(IBehaviourController sender); + delegate void UpdateEventHandler(IBehaviourController sender); + delegate void PreDrawEventHandler(IBehaviourController sender); + delegate void BehaviourAddedEventHandler(IBehaviourController sender, IBehaviour behaviourAdded); + delegate void BehaviourRemovedEventHandler(IBehaviourController sender, IBehaviour behaviourRemoved); } diff --git a/Engine.Core/Abstract/IEntity.cs b/Engine.Core/Abstract/IEntity.cs index d88e34b..984603b 100644 --- a/Engine.Core/Abstract/IEntity.cs +++ b/Engine.Core/Abstract/IEntity.cs @@ -9,12 +9,12 @@ public interface IEntity : IInitializable, IHasStateEnable /// Event triggered when the of the changes. /// The string action parameter is the previous of the . /// - event OnIdChangedEventHandler? OnIdChanged; + event IdChangedEventHandler? OnIdChanged; /// /// The ID of the . /// string Id { get; set; } - delegate void OnIdChangedEventHandler(IEntity sender, string previousId); + delegate void IdChangedEventHandler(IEntity sender, string previousId); } diff --git a/Engine.Core/Abstract/IGameManager.cs b/Engine.Core/Abstract/IGameManager.cs index 9eaa0bb..85df155 100644 --- a/Engine.Core/Abstract/IGameManager.cs +++ b/Engine.Core/Abstract/IGameManager.cs @@ -10,22 +10,22 @@ public interface IGameManager : IEntity /// /// Event triggered when is called on the . /// - event OnUpdateEventHandler? OnUpdate; + event UpdateEventHandler? OnUpdate; /// /// Event triggered when is called on the . /// - event OnPreDawEventHandler? OnPreDraw; + event PreDawEventHandler? OnPreDraw; /// /// Event triggered when a is registered to the . /// - event OnHierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered; + event HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered; /// /// Event triggered when a is unregistered from the . /// - event OnHierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered; + event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered; /// /// Gets a read-only list of s managed by the . @@ -63,9 +63,9 @@ public interface IGameManager : IEntity /// void PreDraw(); - delegate void OnUpdateEventHandler(IGameManager sender, EngineTime time); - delegate void OnPreDawEventHandler(IGameManager sender); + delegate void UpdateEventHandler(IGameManager sender, EngineTime time); + delegate void PreDawEventHandler(IGameManager sender); - delegate void OnHierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered); - delegate void OnHierarchyObjectUnRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered); + delegate void HierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered); + delegate void HierarchyObjectUnRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered); } diff --git a/Engine.Core/Abstract/IHierarchyObject.cs b/Engine.Core/Abstract/IHierarchyObject.cs index 4edccda..aa5d7c3 100644 --- a/Engine.Core/Abstract/IHierarchyObject.cs +++ b/Engine.Core/Abstract/IHierarchyObject.cs @@ -12,27 +12,27 @@ public interface IHierarchyObject : IEntity, INameable, IHasBehaviourController, /// /// Event triggered when the enters the hierarchy. /// - event OnEnteredHierarchyEventHandler? OnEnteredHierarchy; + event EnteredHierarchyEventHandler? OnEnteredHierarchy; /// /// Event triggered when the exits the hierarchy. /// - event OnExitedHierarchyEventHandler? OnExitedHierarchy; + event ExitedHierarchyEventHandler? OnExitedHierarchy; /// /// Event triggered when the of the changes. The second parameter is the old . /// - event OnParentChangedEventHandler? OnParentChanged; + event ParentChangedEventHandler? OnParentChanged; /// /// Event triggered when a new is added to the . /// - event OnChildrenAddedEventHandler? OnChildrenAdded; + event ChildrenAddedEventHandler? OnChildrenAdded; /// /// Event triggered when an is removed from the . /// - event OnChildrenRemovedEventHandler? OnChildrenRemoved; + event ChildrenRemovedEventHandler? OnChildrenRemoved; /// /// Gets the this is connected to, if any. @@ -98,14 +98,14 @@ public interface IHierarchyObject : IEntity, INameable, IHasBehaviourController, /// /// The that entered the hierarchy. /// The that the has entered it's hierarchy. - delegate void OnEnteredHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); + delegate void EnteredHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); /// /// EventHandler delegate for the event triggered when the exits the hierarchy of a . /// /// The that exited the hierarchy. /// The that the has exited it's hierarchy. - delegate void OnExitedHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); + delegate void ExitedHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager); /// /// Delegate for the event triggered when the 's parent changes. @@ -113,19 +113,19 @@ public interface IHierarchyObject : IEntity, INameable, IHasBehaviourController, /// The that the parent has changed. /// The previous the sender was a child of. /// The new and current the sender is a child of. - delegate void OnParentChangedEventHandler(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent); + delegate void ParentChangedEventHandler(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent); /// /// Delegate for the event triggered when a new added as a child. /// /// The parent this event is being called from. /// The that got removed as a children of the sender . - delegate void OnChildrenAddedEventHandler(IHierarchyObject sender, IHierarchyObject childrenAdded); + delegate void ChildrenAddedEventHandler(IHierarchyObject sender, IHierarchyObject childrenAdded); /// /// Delegate for the event triggered when a new removed from being a child. /// /// The parent this event is being called from. /// The that got removed as a children of the sender . - delegate void OnChildrenRemovedEventHandler(IHierarchyObject sender, IHierarchyObject childrenRemoved); + delegate void ChildrenRemovedEventHandler(IHierarchyObject sender, IHierarchyObject childrenRemoved); } diff --git a/Engine.Core/Abstract/IInitializable.cs b/Engine.Core/Abstract/IInitializable.cs index 7a666d0..54ff8a1 100644 --- a/Engine.Core/Abstract/IInitializable.cs +++ b/Engine.Core/Abstract/IInitializable.cs @@ -8,12 +8,12 @@ public interface IInitializable /// /// Event triggered when the method is called successfully. /// - event OnInitializedEventHandler? OnInitialized; + event InitializedEventHandler? OnInitialized; /// /// Event triggered when the method is called successfully. /// - event OnFinalizedEventHandler? OnFinalized; + event FinalizedEventHandler? OnFinalized; /// /// The value indicating whether the entity has been initialized. @@ -32,6 +32,6 @@ public interface IInitializable /// if finalization is successful, otherwise . bool Finalize(); - delegate void OnInitializedEventHandler(IInitializable sender); - delegate void OnFinalizedEventHandler(IInitializable sender); + delegate void InitializedEventHandler(IInitializable sender); + delegate void FinalizedEventHandler(IInitializable sender); } diff --git a/Engine.Core/Abstract/INameable.cs b/Engine.Core/Abstract/INameable.cs index 202cc49..4a60100 100644 --- a/Engine.Core/Abstract/INameable.cs +++ b/Engine.Core/Abstract/INameable.cs @@ -8,12 +8,12 @@ public interface INameable /// /// Event triggered when the name of the entity changes. /// - event OnNameChangedEventHandler? OnNameChanged; + event NameChangedEventHandler? OnNameChanged; /// /// The name of the entity. /// string Name { get; set; } - delegate void OnNameChangedEventHandler(INameable sender, string previousName); + delegate void NameChangedEventHandler(INameable sender, string previousName); } diff --git a/Engine.Core/Abstract/IStateEnable.cs b/Engine.Core/Abstract/IStateEnable.cs index 3ef6726..8debf8c 100644 --- a/Engine.Core/Abstract/IStateEnable.cs +++ b/Engine.Core/Abstract/IStateEnable.cs @@ -8,12 +8,12 @@ public interface IStateEnable : IHasEntity /// /// Event triggered when the state of the changes. /// - event OnNameChangedEventHandler? OnEnabledChanged; + event NameChangedEventHandler? OnEnabledChanged; /// /// The value indicating whether the is enabled. /// bool Enabled { get; set; } - delegate void OnNameChangedEventHandler(IStateEnable sender, bool previousState); + delegate void NameChangedEventHandler(IStateEnable sender, bool previousState); } diff --git a/Engine.Core/Abstract/ITransform2D.cs b/Engine.Core/Abstract/ITransform2D.cs index 3209784..f085501 100644 --- a/Engine.Core/Abstract/ITransform2D.cs +++ b/Engine.Core/Abstract/ITransform2D.cs @@ -8,17 +8,17 @@ public interface ITransform2D : IBehaviour /// /// Event triggered when the of the changes. /// - event OnPositionChangedEventHandler? OnPositionChanged; + event PositionChangedEventHandler? OnPositionChanged; /// /// Event triggered when the of the changes. /// - event OnScaleChangedEventHandler? OnScaleChanged; + event ScaleChangedEventHandler? OnScaleChanged; /// /// Event triggered when the of the changes. /// - event OnRotationChangedEventHandler? OnRotationChanged; + event RotationChangedEventHandler? OnRotationChanged; /// /// The world position of the in 2D space. @@ -55,19 +55,19 @@ public interface ITransform2D : IBehaviour /// /// The that the parent has changed. /// The previous of the . - delegate void OnPositionChangedEventHandler(ITransform2D sender, Vector2D previousPosition); + delegate void PositionChangedEventHandler(ITransform2D sender, Vector2D previousPosition); /// /// Delegate for the event triggered when the 's rotation changes. /// /// The that the parent has changed. /// The previous of the . - delegate void OnScaleChangedEventHandler(ITransform2D sender, Vector2D previousScale); + delegate void ScaleChangedEventHandler(ITransform2D sender, Vector2D previousScale); /// /// Delegate for the event triggered when the 's rotation changes. /// /// The that the parent has changed. /// The previous of the . - delegate void OnRotationChangedEventHandler(ITransform2D sender, float previousRotation); + delegate void RotationChangedEventHandler(ITransform2D sender, float previousRotation); } diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs index dfa7a16..8a7bbca 100644 --- a/Engine.Core/BehaviourBase.cs +++ b/Engine.Core/BehaviourBase.cs @@ -6,9 +6,9 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")] public abstract class BehaviourBase : BaseEntity, IBehaviour { - public event IHasBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; + public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; - public event IBehaviour.OnPriorityChangedEventHandler? OnPriorityChanged = null; + public event IBehaviour.PriorityChangedEventHandler? OnPriorityChanged = null; private IBehaviourController _behaviourController = null!; diff --git a/Engine.Core/BehaviourCollector.cs b/Engine.Core/BehaviourCollector.cs index 034a957..19e0a07 100644 --- a/Engine.Core/BehaviourCollector.cs +++ b/Engine.Core/BehaviourCollector.cs @@ -8,11 +8,11 @@ namespace Syntriax.Engine.Core; public class BehaviourCollector : IBehaviourCollector where T : class { - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - public event IHasGameManager.OnGameManagerAssignedEventHandler? OnGameManagerAssigned = null; + public event IAssignable.UnassignEventHandler? OnUnassigned = null; + public event IHasGameManager.GameManagerAssignedEventHandler? OnGameManagerAssigned = null; - public event IBehaviourCollector.OnCollectedEventHandler? OnCollected = null; - public event IBehaviourCollector.OnRemovedEventHandler? OnRemoved = null; + public event IBehaviourCollector.CollectedEventHandler? OnCollected = null; + public event IBehaviourCollector.RemovedEventHandler? OnRemoved = null; protected readonly List _behaviours = new(32); diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs index 1985111..f25c099 100644 --- a/Engine.Core/BehaviourController.cs +++ b/Engine.Core/BehaviourController.cs @@ -11,18 +11,18 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")] public class BehaviourController : IBehaviourController { - public event IBehaviourController.OnPreUpdateEventHandler? OnPreUpdate = null; - public event IBehaviourController.OnUpdateEventHandler? OnUpdate = null; - public event IBehaviourController.OnPreDrawEventHandler? OnPreDraw = null; + public event IBehaviourController.PreUpdateEventHandler? OnPreUpdate = null; + public event IBehaviourController.UpdateEventHandler? OnUpdate = null; + public event IBehaviourController.PreDrawEventHandler? OnPreDraw = null; - public event IBehaviourController.OnBehaviourAddedEventHandler? OnBehaviourAdded = null; - public event IBehaviourController.OnBehaviourRemovedEventHandler? OnBehaviourRemoved = null; - public event IHasHierarchyObject.OnHierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned = null; + public event IBehaviourController.BehaviourAddedEventHandler? OnBehaviourAdded = null; + public event IBehaviourController.BehaviourRemovedEventHandler? OnBehaviourRemoved = null; + public event IHasHierarchyObject.HierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned = null; - public event IInitializable.OnInitializedEventHandler? OnInitialized = null; - public event IInitializable.OnFinalizedEventHandler? OnFinalized = null; + public event IInitializable.InitializedEventHandler? OnInitialized = null; + public event IInitializable.FinalizedEventHandler? OnFinalized = null; - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; + public event IAssignable.UnassignEventHandler? OnUnassigned = null; private readonly IList behaviours = new List(Constants.BEHAVIOURS_SIZE_INITIAL); diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index e44430c..a4f00f4 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -10,11 +10,11 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("HierarchyObject Count: {_hierarchyObjects.Count}")] public class GameManager : BaseEntity, IGameManager { - public event IGameManager.OnUpdateEventHandler? OnUpdate = null; - public event IGameManager.OnPreDawEventHandler? OnPreDraw = null; + public event IGameManager.UpdateEventHandler? OnUpdate = null; + public event IGameManager.PreDawEventHandler? OnPreDraw = null; - public event IGameManager.OnHierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null; - public event IGameManager.OnHierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null; + public event IGameManager.HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null; + public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null; private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs index c27e9bb..8691f11 100644 --- a/Engine.Core/HierarchyObject.cs +++ b/Engine.Core/HierarchyObject.cs @@ -8,13 +8,13 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")] public class HierarchyObject : BaseEntity, IHierarchyObject { - public event IHierarchyObject.OnEnteredHierarchyEventHandler? OnEnteredHierarchy = null; - public event IHierarchyObject.OnExitedHierarchyEventHandler? OnExitedHierarchy = null; - public event IHierarchyObject.OnParentChangedEventHandler? OnParentChanged = null; - public event IHierarchyObject.OnChildrenAddedEventHandler? OnChildrenAdded = null; - public event IHierarchyObject.OnChildrenRemovedEventHandler? OnChildrenRemoved = null; - public event IHasBehaviourController.OnBehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; - public event INameable.OnNameChangedEventHandler? OnNameChanged = null; + public event IHierarchyObject.EnteredHierarchyEventHandler? OnEnteredHierarchy = null; + public event IHierarchyObject.ExitedHierarchyEventHandler? OnExitedHierarchy = null; + public event IHierarchyObject.ParentChangedEventHandler? OnParentChanged = null; + public event IHierarchyObject.ChildrenAddedEventHandler? OnChildrenAdded = null; + public event IHierarchyObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null; + public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; + public event INameable.NameChangedEventHandler? OnNameChanged = null; private string _name = nameof(HierarchyObject); private IGameManager _gameManager = null!; diff --git a/Engine.Core/StateEnable.cs b/Engine.Core/StateEnable.cs index 3885b7c..f00391b 100644 --- a/Engine.Core/StateEnable.cs +++ b/Engine.Core/StateEnable.cs @@ -4,9 +4,9 @@ namespace Syntriax.Engine.Core; public class StateEnable : IStateEnable { - public event IAssignable.OnUnassignedEventHandler? OnUnassigned = null; - public event IHasEntity.OnEntityAssignedEventHandler? OnEntityAssigned = null; - public event IStateEnable.OnNameChangedEventHandler? OnEnabledChanged = null; + public event IAssignable.UnassignEventHandler? OnUnassigned = null; + public event IHasEntity.EntityAssignedEventHandler? OnEntityAssigned = null; + public event IStateEnable.NameChangedEventHandler? OnEnabledChanged = null; private bool _enabled = true; private IEntity _entity = null!; diff --git a/Engine.Core/Transform2D.cs b/Engine.Core/Transform2D.cs index 1ae6c63..05a13d4 100644 --- a/Engine.Core/Transform2D.cs +++ b/Engine.Core/Transform2D.cs @@ -5,9 +5,9 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Name: {HierarchyObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")] public class Transform2D : Behaviour, ITransform2D { - public event ITransform2D.OnPositionChangedEventHandler? OnPositionChanged = null; - public event ITransform2D.OnScaleChangedEventHandler? OnScaleChanged = null; - public event ITransform2D.OnRotationChangedEventHandler? OnRotationChanged = null; + public event ITransform2D.PositionChangedEventHandler? OnPositionChanged = null; + public event ITransform2D.ScaleChangedEventHandler? OnScaleChanged = null; + public event ITransform2D.RotationChangedEventHandler? OnRotationChanged = null; private Vector2D _position = Vector2D.Zero; private Vector2D _scale = Vector2D.One; diff --git a/Engine.Physics2D/Abstract/ICollider2D.cs b/Engine.Physics2D/Abstract/ICollider2D.cs index 0d43232..379c083 100644 --- a/Engine.Physics2D/Abstract/ICollider2D.cs +++ b/Engine.Physics2D/Abstract/ICollider2D.cs @@ -10,17 +10,17 @@ public interface ICollider2D : IBehaviour /// /// Event triggered when a collision is detected. /// - event OnCollisionDetectedEventHandler? OnCollisionDetected; + event CollisionDetectedEventHandler? OnCollisionDetected; /// /// Event triggered when a collision is resolved. /// - event OnCollisionResolvedEventHandler? OnCollisionResolved; + event CollisionResolvedEventHandler? OnCollisionResolved; /// /// Event triggered when another triggers this . /// - event OnTriggeredEventHandler? OnTriggered; + event TriggeredEventHandler? OnTriggered; /// ITransform2D Transform { get; } @@ -44,7 +44,7 @@ public interface ICollider2D : IBehaviour void Resolve(CollisionDetectionInformation collisionDetectionInformation); void Trigger(ICollider2D initiator); - delegate void OnCollisionDetectedEventHandler(ICollider2D sender, CollisionDetectionInformation collisionDetectionInformation); - delegate void OnCollisionResolvedEventHandler(ICollider2D sender, CollisionDetectionInformation collisionDetectionInformation); - delegate void OnTriggeredEventHandler(ICollider2D sender, ICollider2D initiatorCollider); + delegate void CollisionDetectedEventHandler(ICollider2D sender, CollisionDetectionInformation collisionDetectionInformation); + delegate void CollisionResolvedEventHandler(ICollider2D sender, CollisionDetectionInformation collisionDetectionInformation); + delegate void TriggeredEventHandler(ICollider2D sender, ICollider2D initiatorCollider); } diff --git a/Engine.Physics2D/Abstract/IPhysicsEngine2D.cs b/Engine.Physics2D/Abstract/IPhysicsEngine2D.cs index 512593c..e9947a8 100644 --- a/Engine.Physics2D/Abstract/IPhysicsEngine2D.cs +++ b/Engine.Physics2D/Abstract/IPhysicsEngine2D.cs @@ -8,12 +8,12 @@ public interface IPhysicsEngine2D /// /// Event triggered when the has done a single physics iteration. /// - event OnPhysicsIterationEventHandler? OnPhysicsIteration; + event PhysicsIterationEventHandler? OnPhysicsIteration; /// /// Event triggered when the has done a full physics step/>. /// - event OnPhysicsStepEventHandler? OnPhysicsStep; + event PhysicsStepEventHandler? OnPhysicsStep; /// /// The number of iterations the performs per step. @@ -26,6 +26,6 @@ public interface IPhysicsEngine2D /// The time step. void Step(float deltaTime); - delegate void OnPhysicsIterationEventHandler(IPhysicsEngine2D sender, float iterationDeltaTime); - delegate void OnPhysicsStepEventHandler(IPhysicsEngine2D sender, float stepDeltaTime); + delegate void PhysicsIterationEventHandler(IPhysicsEngine2D sender, float iterationDeltaTime); + delegate void PhysicsStepEventHandler(IPhysicsEngine2D sender, float stepDeltaTime); } diff --git a/Engine.Physics2D/Collider2DBehaviourBase.cs b/Engine.Physics2D/Collider2DBehaviourBase.cs index bb7a329..1b64136 100644 --- a/Engine.Physics2D/Collider2DBehaviourBase.cs +++ b/Engine.Physics2D/Collider2DBehaviourBase.cs @@ -6,9 +6,9 @@ namespace Syntriax.Engine.Physics2D; public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D { - public event ICollider2D.OnCollisionDetectedEventHandler? OnCollisionDetected = null; - public event ICollider2D.OnCollisionResolvedEventHandler? OnCollisionResolved = null; - public event ICollider2D.OnTriggeredEventHandler? OnTriggered = null; + public event ICollider2D.CollisionDetectedEventHandler? OnCollisionDetected = null; + public event ICollider2D.CollisionResolvedEventHandler? OnCollisionResolved = null; + public event ICollider2D.TriggeredEventHandler? OnTriggered = null; protected bool NeedsRecalculation { get; private set; } = true; protected IRigidBody2D? _rigidBody2D = null; diff --git a/Engine.Physics2D/PhysicsEngine2D.cs b/Engine.Physics2D/PhysicsEngine2D.cs index 11aa4f9..90c1b35 100644 --- a/Engine.Physics2D/PhysicsEngine2D.cs +++ b/Engine.Physics2D/PhysicsEngine2D.cs @@ -7,8 +7,8 @@ namespace Syntriax.Engine.Physics2D; public class PhysicsEngine2D : IPhysicsEngine2D { - public event IPhysicsEngine2D.OnPhysicsIterationEventHandler? OnPhysicsIteration = null; - public event IPhysicsEngine2D.OnPhysicsStepEventHandler? OnPhysicsStep = null; + public event IPhysicsEngine2D.PhysicsIterationEventHandler? OnPhysicsIteration = null; + public event IPhysicsEngine2D.PhysicsStepEventHandler? OnPhysicsStep = null; private readonly List rigidBodies = new(32); private readonly List colliders = new(64); diff --git a/Engine.Physics2D/PhysicsEngine2DCollector.cs b/Engine.Physics2D/PhysicsEngine2DCollector.cs index 59d9963..7f60be1 100644 --- a/Engine.Physics2D/PhysicsEngine2DCollector.cs +++ b/Engine.Physics2D/PhysicsEngine2DCollector.cs @@ -6,8 +6,8 @@ namespace Syntriax.Engine.Physics2D; public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D { - public event IPhysicsEngine2D.OnPhysicsIterationEventHandler? OnPhysicsIteration = null; - public event IPhysicsEngine2D.OnPhysicsStepEventHandler? OnPhysicsStep = null; + public event IPhysicsEngine2D.PhysicsIterationEventHandler? OnPhysicsIteration = null; + public event IPhysicsEngine2D.PhysicsStepEventHandler? OnPhysicsStep = null; private int _iterationPerStep = 1; diff --git a/Engine.Systems/StateMachine/StateMachine.cs b/Engine.Systems/StateMachine/StateMachine.cs index 791427f..4d5bda9 100644 --- a/Engine.Systems/StateMachine/StateMachine.cs +++ b/Engine.Systems/StateMachine/StateMachine.cs @@ -4,7 +4,7 @@ namespace Syntriax.Engine.StateMachine; public class StateMachine : Behaviour { - public event OnStateChangedEventHandler? OnStateChanged = null; + public event StateChangedEventHandler? OnStateChanged = null; private IState _state = new State(); public IState State @@ -45,5 +45,5 @@ public class StateMachine : Behaviour State.Update(); } - public delegate void OnStateChangedEventHandler(StateMachine sender, IState previousState, IState newState); + public delegate void StateChangedEventHandler(StateMachine sender, IState previousState, IState newState); } -- 2.47.1 From 82705ba37832de77968a3e600f8c4ba4daa8c883 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 29 Mar 2025 21:59:36 +0300 Subject: [PATCH 16/32] chore: added Engine class library to include all projects --- Engine.sln | 12 ++++++++++++ Engine/Engine.csproj | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Engine/Engine.csproj diff --git a/Engine.sln b/Engine.sln index e76e3fd..58635a5 100644 --- a/Engine.sln +++ b/Engine.sln @@ -9,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine.Inpu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine.Physics2D\Engine.Physics2D.csproj", "{3B3C3332-07E3-4A00-9898-0A5410BCB08C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine.Systems\Engine.Systems.csproj", "{8452323D-99EF-43B1-8E7B-123E02279674}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine.csproj", "{58AE79C1-9203-44AE-8022-AA180F0A71DC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,5 +34,13 @@ Global {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.Build.0 = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.Build.0 = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Engine/Engine.csproj b/Engine/Engine.csproj new file mode 100644 index 0000000..a4c8395 --- /dev/null +++ b/Engine/Engine.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + -- 2.47.1 From b73c9ed0aef204c76a90ddf68f027f6fdaca3cb7 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sun, 30 Mar 2025 20:19:03 +0300 Subject: [PATCH 17/32] refactor: got rid of the static Time class and implemented EngineTime on IGameManager --- Engine.Core/Abstract/IGameManager.cs | 15 ++++++++++----- Engine.Core/EngineTime.cs | 8 ++++---- Engine.Core/GameManager.cs | 12 ++++++------ Engine.Core/Time.cs | 15 --------------- Engine.Physics2D/PhysicsCoroutineManager.cs | 2 +- 5 files changed, 21 insertions(+), 31 deletions(-) delete mode 100644 Engine.Core/Time.cs diff --git a/Engine.Core/Abstract/IGameManager.cs b/Engine.Core/Abstract/IGameManager.cs index 85df155..8805249 100644 --- a/Engine.Core/Abstract/IGameManager.cs +++ b/Engine.Core/Abstract/IGameManager.cs @@ -8,7 +8,7 @@ namespace Syntriax.Engine.Core.Abstract; public interface IGameManager : IEntity { /// - /// Event triggered when is called on the . + /// Event triggered when is called on the . /// event UpdateEventHandler? OnUpdate; @@ -27,6 +27,11 @@ public interface IGameManager : IEntity /// event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered; + /// + /// Contains time data related to this . + /// + EngineTime Time { get; } + /// /// Gets a read-only list of s managed by the . /// @@ -53,17 +58,17 @@ public interface IGameManager : IEntity void Remove(IHierarchyObject hierarchyObject); /// - /// Updates the with the given engine time data. + /// Updates the with the given delta time. /// - /// The engine time. - void Update(EngineTime time); + /// Delta time. + void Update(EngineTime engineTime); /// /// Performs operations that should be done before the draw calls. /// void PreDraw(); - delegate void UpdateEventHandler(IGameManager sender, EngineTime time); + delegate void UpdateEventHandler(IGameManager sender, EngineTime engineTime); delegate void PreDawEventHandler(IGameManager sender); delegate void HierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered); diff --git a/Engine.Core/EngineTime.cs b/Engine.Core/EngineTime.cs index f038134..d54964c 100644 --- a/Engine.Core/EngineTime.cs +++ b/Engine.Core/EngineTime.cs @@ -2,10 +2,10 @@ using System; namespace Syntriax.Engine.Core; -public readonly struct EngineTime(TimeSpan Total, TimeSpan Elapsed) +public readonly struct EngineTime(TimeSpan TimeSinceStart, TimeSpan TimeDelta) { - public readonly TimeSpan Total = Total; - public readonly TimeSpan Elapsed = Elapsed; + public readonly TimeSpan TimeSinceStart = TimeSinceStart; + public readonly TimeSpan DeltaSpan = TimeDelta; - public readonly float DeltaTimeFrame = (float)Elapsed.TotalMilliseconds * .001f; + public readonly float DeltaTime = (float)TimeDelta.TotalSeconds; } diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index a4f00f4..8d1b597 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -19,7 +19,6 @@ public class GameManager : BaseEntity, IGameManager private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private HierarchyObjectFactory _hierarchyObjectFactory = null!; - private HierarchyObjectFactory HierarchyObjectFactory { get @@ -46,6 +45,8 @@ public class GameManager : BaseEntity, IGameManager } } + public EngineTime Time { get; private set; } = new(); + public void Register(IHierarchyObject hierarchyObject) { if (_hierarchyObjects.Contains(hierarchyObject)) @@ -113,13 +114,14 @@ public class GameManager : BaseEntity, IGameManager HierarchyObjects[i].Finalize(); } - public void Update(EngineTime time) + public void Update(EngineTime engineTime) { - Time.SetTime(time); + Time = engineTime; + for (int i = 0; i < HierarchyObjects.Count; i++) HierarchyObjects[i].BehaviourController.Update(); - OnUpdate?.Invoke(this, time); + OnUpdate?.Invoke(this, engineTime); } public void PreDraw() @@ -130,8 +132,6 @@ public class GameManager : BaseEntity, IGameManager OnPreDraw?.Invoke(this); } - ///////////////////////////////////////////////////////////////// - private void OnHierarchyObjectFinalize(IInitializable initializable) { if (initializable is IHierarchyObject hierarchyObject) diff --git a/Engine.Core/Time.cs b/Engine.Core/Time.cs deleted file mode 100644 index 34a362d..0000000 --- a/Engine.Core/Time.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Syntriax.Engine.Core; - -public static class Time -{ - private static EngineTime _engineTime = new(TimeSpan.Zero, TimeSpan.Zero); - - public static TimeSpan Total => _engineTime.Total; - public static TimeSpan Elapsed => _engineTime.Elapsed; - - public static float DeltaTimeFrame => _engineTime.DeltaTimeFrame; - - public static void SetTime(EngineTime engineTime) => _engineTime = engineTime; -} diff --git a/Engine.Physics2D/PhysicsCoroutineManager.cs b/Engine.Physics2D/PhysicsCoroutineManager.cs index e2ed13d..8daadd0 100644 --- a/Engine.Physics2D/PhysicsCoroutineManager.cs +++ b/Engine.Physics2D/PhysicsCoroutineManager.cs @@ -51,7 +51,7 @@ public class PhysicsCoroutineManager : HierarchyObject gameManager.OnUpdate -= OnUpdate; } - private void OnUpdate(IGameManager sender, EngineTime time) + private void OnUpdate(IGameManager sender, EngineTime engineTime) { if (GameManager is not IGameManager gameManager) return; -- 2.47.1 From 7a1dd7eb1a3caa6432535869121b49701746d05c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sun, 30 Mar 2025 20:29:26 +0300 Subject: [PATCH 18/32] feat: time systems added --- Engine.Systems/Time/IReadOnlyStopwatch.cs | 18 ++++ Engine.Systems/Time/IReadOnlyTicker.cs | 11 ++ Engine.Systems/Time/IReadOnlyTimer.cs | 22 ++++ Engine.Systems/Time/IStopwatch.cs | 10 ++ Engine.Systems/Time/ITicker.cs | 11 ++ Engine.Systems/Time/ITimer.cs | 10 ++ Engine.Systems/Time/StopwatchBehaviour.cs | 99 ++++++++++++++++++ Engine.Systems/Time/TickerBehaviour.cs | 38 +++++++ Engine.Systems/Time/TimerBehaviour.cs | 118 ++++++++++++++++++++++ Engine.Systems/Time/TimerState.cs | 9 ++ 10 files changed, 346 insertions(+) create mode 100644 Engine.Systems/Time/IReadOnlyStopwatch.cs create mode 100644 Engine.Systems/Time/IReadOnlyTicker.cs create mode 100644 Engine.Systems/Time/IReadOnlyTimer.cs create mode 100644 Engine.Systems/Time/IStopwatch.cs create mode 100644 Engine.Systems/Time/ITicker.cs create mode 100644 Engine.Systems/Time/ITimer.cs create mode 100644 Engine.Systems/Time/StopwatchBehaviour.cs create mode 100644 Engine.Systems/Time/TickerBehaviour.cs create mode 100644 Engine.Systems/Time/TimerBehaviour.cs create mode 100644 Engine.Systems/Time/TimerState.cs diff --git a/Engine.Systems/Time/IReadOnlyStopwatch.cs b/Engine.Systems/Time/IReadOnlyStopwatch.cs new file mode 100644 index 0000000..3caaaa9 --- /dev/null +++ b/Engine.Systems/Time/IReadOnlyStopwatch.cs @@ -0,0 +1,18 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface IReadOnlyStopwatch +{ + event StopwatchEventHandler? OnStarted; + event StopwatchDeltaEventHandler? OnDelta; + event StopwatchEventHandler? OnStopped; + + double Time { get; } + + TimerState State { get; } + + event StopwatchEventHandler? OnPaused; + event StopwatchEventHandler? OnResumed; + + delegate void StopwatchEventHandler(IReadOnlyStopwatch sender); + delegate void StopwatchDeltaEventHandler(IReadOnlyStopwatch sender, double delta); +} diff --git a/Engine.Systems/Time/IReadOnlyTicker.cs b/Engine.Systems/Time/IReadOnlyTicker.cs new file mode 100644 index 0000000..9ffec3b --- /dev/null +++ b/Engine.Systems/Time/IReadOnlyTicker.cs @@ -0,0 +1,11 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface IReadOnlyTicker : IReadOnlyStopwatch +{ + event TickerTickEventHandler? OnTick; + + int TickCounter { get; } + double TickPeriod { get; set; } + + delegate void TickerTickEventHandler(IReadOnlyTicker sender); +} diff --git a/Engine.Systems/Time/IReadOnlyTimer.cs b/Engine.Systems/Time/IReadOnlyTimer.cs new file mode 100644 index 0000000..660ccb7 --- /dev/null +++ b/Engine.Systems/Time/IReadOnlyTimer.cs @@ -0,0 +1,22 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface IReadOnlyTimer +{ + event TimerEventHandler? OnStarted; + event TimerDeltaEventHandler? OnDelta; + event TimerEventHandler? OnStopped; + + event TimerEventHandler? OnPaused; + event TimerEventHandler? OnResumed; + + double StartTime { get; } + double Remaining { get; } + + float Percentage { get; } + + TimerState State { get; } + + delegate void TimerEventHandler(IReadOnlyTimer sender); + delegate void TimerDeltaEventHandler(IReadOnlyTimer sender, double delta); + +} diff --git a/Engine.Systems/Time/IStopwatch.cs b/Engine.Systems/Time/IStopwatch.cs new file mode 100644 index 0000000..57c8227 --- /dev/null +++ b/Engine.Systems/Time/IStopwatch.cs @@ -0,0 +1,10 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface IStopwatch : IReadOnlyStopwatch +{ + void StopwatchStart(); + void StopwatchStop(); + + void StopwatchPause(); + void StopwatchResume(); +} diff --git a/Engine.Systems/Time/ITicker.cs b/Engine.Systems/Time/ITicker.cs new file mode 100644 index 0000000..081a021 --- /dev/null +++ b/Engine.Systems/Time/ITicker.cs @@ -0,0 +1,11 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface ITicker : IStopwatch +{ + event TickerTickEventHandler? OnTick; + + int TickCounter { get; } + double TickPeriod { get; set; } + + delegate void TickerTickEventHandler(ITicker sender); +} diff --git a/Engine.Systems/Time/ITimer.cs b/Engine.Systems/Time/ITimer.cs new file mode 100644 index 0000000..bc7b5ff --- /dev/null +++ b/Engine.Systems/Time/ITimer.cs @@ -0,0 +1,10 @@ +namespace Syntriax.Engine.Systems.Time; + +public interface ITimer : IReadOnlyTimer +{ + void TimerStart(double time); + void TimerStop(); + + void TimerPause(); + void TimerResume(); +} diff --git a/Engine.Systems/Time/StopwatchBehaviour.cs b/Engine.Systems/Time/StopwatchBehaviour.cs new file mode 100644 index 0000000..1d59e80 --- /dev/null +++ b/Engine.Systems/Time/StopwatchBehaviour.cs @@ -0,0 +1,99 @@ +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Systems.Time; + +public class StopwatchBehaviour : Behaviour, IStopwatch +{ + public event IReadOnlyStopwatch.StopwatchEventHandler? OnStarted = null; + public event IReadOnlyStopwatch.StopwatchDeltaEventHandler? OnDelta = null; + public event IReadOnlyStopwatch.StopwatchEventHandler? OnStopped = null; + public event IReadOnlyStopwatch.StopwatchEventHandler? OnPaused = null; + public event IReadOnlyStopwatch.StopwatchEventHandler? OnResumed = null; + + public double Time { get; protected set; } = 0f; + public TimerState State { get; protected set; } = TimerState.Idle; + + private bool shouldBeTicking = false; + private bool hasStartedTickingBefore = false; + + public virtual void StopwatchStart() + { + Time = 0f; + + shouldBeTicking = true; + hasStartedTickingBefore = false; + + if (IsActive) + StartStopwatch(); + } + + public virtual void StopwatchStop() + { + if (!shouldBeTicking) + return; + + shouldBeTicking = false; + + State = TimerState.Stopped; + OnStopped?.Invoke(this); + } + + protected override void OnUpdate() + { + if (State is not TimerState.Ticking) + return; + + double delta = GameManager.Time.DeltaSpan.TotalSeconds; + + Time += delta; + OnDelta?.Invoke(this, delta); + } + + protected override void OnEnteredHierarchy(IGameManager gameManager) + { + if (!shouldBeTicking || State is TimerState.Ticking) + return; + + if (hasStartedTickingBefore) + StopwatchResume(); + else + StartStopwatch(); + } + + protected override void OnExitedHierarchy(IGameManager gameManager) + { + if (!shouldBeTicking || State is not TimerState.Ticking) + return; + + StopwatchPause(); + } + + public virtual void StopwatchPause() + { + State = TimerState.Paused; + OnPaused?.Invoke(this); + } + + public virtual void StopwatchResume() + { + State = TimerState.Ticking; + OnResumed?.Invoke(this); + } + + private void StartStopwatch() + { + hasStartedTickingBefore = true; + + State = TimerState.Ticking; + OnStarted?.Invoke(this); + } + + protected override void OnFinalize() + { + Time = 0f; + State = TimerState.Idle; + shouldBeTicking = false; + hasStartedTickingBefore = false; + } +} diff --git a/Engine.Systems/Time/TickerBehaviour.cs b/Engine.Systems/Time/TickerBehaviour.cs new file mode 100644 index 0000000..d1ab2f0 --- /dev/null +++ b/Engine.Systems/Time/TickerBehaviour.cs @@ -0,0 +1,38 @@ +namespace Syntriax.Engine.Systems.Time; + +public class TickerBehaviour : StopwatchBehaviour, ITicker +{ + public event ITicker.TickerTickEventHandler? OnTick = null; + + public double TickPeriod { get; set; } = 1f; + public int TickCounter { get; private set; } = 0; + + private double nextTick = 0f; + + public override void StopwatchStart() + { + TickCounter = 0; + base.StopwatchStart(); + nextTick = Time + TickPeriod; + } + + protected override void OnUpdate() + { + base.OnUpdate(); + + if (Time < nextTick) + return; + + nextTick += TickPeriod; + TickCounter++; + OnTick?.Invoke(this); + } + + protected override void OnFinalize() + { + base.OnFinalize(); + + TickCounter = 0; + nextTick = 0f; + } +} diff --git a/Engine.Systems/Time/TimerBehaviour.cs b/Engine.Systems/Time/TimerBehaviour.cs new file mode 100644 index 0000000..afd4492 --- /dev/null +++ b/Engine.Systems/Time/TimerBehaviour.cs @@ -0,0 +1,118 @@ +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Systems.Time; + +public class TimerBehaviour : Behaviour, ITimer +{ + public event IReadOnlyTimer.TimerEventHandler? OnStarted = null; + public event IReadOnlyTimer.TimerDeltaEventHandler? OnDelta = null; + public event IReadOnlyTimer.TimerEventHandler? OnStopped = null; + public event IReadOnlyTimer.TimerEventHandler? OnPaused = null; + public event IReadOnlyTimer.TimerEventHandler? OnResumed = null; + + public TimerState State { get; protected set; } = TimerState.Idle; + public double StartTime { get; protected set; } = 0f; + public float Percentage => (float)(1f - (Remaining / StartTime)); + + private double _remaining = 0f; + public double Remaining + { + get => _remaining; + protected set + { + if (value < .0f) + value = .0f; + + _remaining = value; + } + } + + private bool shouldBeTicking = false; + private bool hasStartedTickingBefore = false; + + public virtual void TimerStart(double time) + { + StartTime = time; + Remaining = time; + + shouldBeTicking = true; + hasStartedTickingBefore = false; + + if (IsActive) + StartTimer(); + } + + public virtual void TimerStop() + { + if (!shouldBeTicking) + return; + + shouldBeTicking = false; + + State = TimerState.Stopped; + OnStopped?.Invoke(this); + } + + protected override void OnUpdate() + { + if (State is not TimerState.Ticking) + return; + + double delta = GameManager.Time.DeltaSpan.TotalSeconds; + + Remaining -= delta; + OnDelta?.Invoke(this, delta); + + if (Remaining <= .0f) + TimerStop(); + } + + protected override void OnEnteredHierarchy(IGameManager gameManager) + { + if (!shouldBeTicking || State is TimerState.Ticking) + return; + + if (hasStartedTickingBefore) + TimerResume(); + else + StartTimer(); + } + + protected override void OnExitedHierarchy(IGameManager gameManager) + { + if (!shouldBeTicking || State is not TimerState.Ticking) + return; + + TimerPause(); + } + + public virtual void TimerPause() + { + State = TimerState.Paused; + OnPaused?.Invoke(this); + } + + public virtual void TimerResume() + { + State = TimerState.Ticking; + OnResumed?.Invoke(this); + } + + private void StartTimer() + { + hasStartedTickingBefore = true; + + State = TimerState.Ticking; + OnStarted?.Invoke(this); + } + + protected override void OnFinalize() + { + StartTime = 0f; + Remaining = 0f; + State = TimerState.Idle; + shouldBeTicking = false; + hasStartedTickingBefore = false; + } +} diff --git a/Engine.Systems/Time/TimerState.cs b/Engine.Systems/Time/TimerState.cs new file mode 100644 index 0000000..4702f3d --- /dev/null +++ b/Engine.Systems/Time/TimerState.cs @@ -0,0 +1,9 @@ +namespace Syntriax.Engine.Systems.Time; + +public enum TimerState +{ + Idle, + Ticking, + Paused, + Stopped +} -- 2.47.1 From e2fdf1f538a9a43bb90fbefce4768e0d62b8a77f Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 12:48:05 +0300 Subject: [PATCH 19/32] chore: added root namespace definitions for projects --- Engine.Core/Engine.Core.csproj | 2 ++ Engine.Physics2D/Engine.Physics2D.csproj | 9 +++++---- Engine.Systems/Engine.Systems.csproj | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Engine.Core/Engine.Core.csproj b/Engine.Core/Engine.Core.csproj index 5334de3..402f9f6 100644 --- a/Engine.Core/Engine.Core.csproj +++ b/Engine.Core/Engine.Core.csproj @@ -4,5 +4,7 @@ net8.0 false enable + Syntriax.Engine.Core + diff --git a/Engine.Physics2D/Engine.Physics2D.csproj b/Engine.Physics2D/Engine.Physics2D.csproj index adb4974..cb5ad55 100644 --- a/Engine.Physics2D/Engine.Physics2D.csproj +++ b/Engine.Physics2D/Engine.Physics2D.csproj @@ -1,13 +1,14 @@  - - - - net8.0 disable enable + Syntriax.Engine.Physics2D + + + + diff --git a/Engine.Systems/Engine.Systems.csproj b/Engine.Systems/Engine.Systems.csproj index 2ba7eb9..88887fb 100644 --- a/Engine.Systems/Engine.Systems.csproj +++ b/Engine.Systems/Engine.Systems.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + Syntriax.Engine.Systems -- 2.47.1 From 6170de4a7305fbba945dd14d387fae454a784fbf Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 13:00:30 +0300 Subject: [PATCH 20/32] refactor: moved Engine.Input into Engine.Systems --- Engine.Input/.gitignore | 484 ------------------ Engine.Input/Engine.Input.csproj | 12 - .../Input}/IButtonInputs.cs | 2 +- Engine.sln | 6 - 4 files changed, 1 insertion(+), 503 deletions(-) delete mode 100644 Engine.Input/.gitignore delete mode 100644 Engine.Input/Engine.Input.csproj rename {Engine.Input/Abstract => Engine.Systems/Input}/IButtonInputs.cs (93%) diff --git a/Engine.Input/.gitignore b/Engine.Input/.gitignore deleted file mode 100644 index 5e57f18..0000000 --- a/Engine.Input/.gitignore +++ /dev/null @@ -1,484 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from `dotnet new gitignore` - -# dotenv files -.env - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET -project.lock.json -project.fragment.lock.json -artifacts/ - -# Tye -.tye/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.tlog -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - -# Visual Studio 6 workspace and project file (working project files containing files to include in project) -*.dsw -*.dsp - -# Visual Studio 6 technical files -*.ncb -*.aps - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# Visual Studio History (VSHistory) files -.vshistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd - -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -# Windows Installer files from build outputs -*.cab -*.msi -*.msix -*.msm -*.msp - -# JetBrains Rider -*.sln.iml -.idea - -## -## Visual studio for Mac -## - - -# globs -Makefile.in -*.userprefs -*.usertasks -config.make -config.status -aclocal.m4 -install-sh -autom4te.cache/ -*.tar.gz -tarballs/ -test-results/ - -# Mac bundle stuff -*.dmg -*.app - -# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# Vim temporary swap files -*.swp diff --git a/Engine.Input/Engine.Input.csproj b/Engine.Input/Engine.Input.csproj deleted file mode 100644 index 2ecbd5e..0000000 --- a/Engine.Input/Engine.Input.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - diff --git a/Engine.Input/Abstract/IButtonInputs.cs b/Engine.Systems/Input/IButtonInputs.cs similarity index 93% rename from Engine.Input/Abstract/IButtonInputs.cs rename to Engine.Systems/Input/IButtonInputs.cs index e117c9a..597ebed 100644 --- a/Engine.Input/Abstract/IButtonInputs.cs +++ b/Engine.Systems/Input/IButtonInputs.cs @@ -1,6 +1,6 @@ using Syntriax.Engine.Core.Abstract; -namespace Syntriax.Engine.Input; +namespace Syntriax.Engine.Systems.Input; public interface IButtonInputs : IHasStateEnable { diff --git a/Engine.sln b/Engine.sln index 58635a5..4bc06af 100644 --- a/Engine.sln +++ b/Engine.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine.Core\Engine.Core.csproj", "{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine.Input\Engine.Input.csproj", "{12149E55-1EE8-45B4-A82E-15BA981B0C6A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine.Physics2D\Engine.Physics2D.csproj", "{3B3C3332-07E3-4A00-9898-0A5410BCB08C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine.Systems\Engine.Systems.csproj", "{8452323D-99EF-43B1-8E7B-123E02279674}" @@ -26,10 +24,6 @@ Global {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.Build.0 = Debug|Any CPU {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.ActiveCfg = Release|Any CPU {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.Build.0 = Release|Any CPU - {12149E55-1EE8-45B4-A82E-15BA981B0C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12149E55-1EE8-45B4-A82E-15BA981B0C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12149E55-1EE8-45B4-A82E-15BA981B0C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12149E55-1EE8-45B4-A82E-15BA981B0C6A}.Release|Any CPU.Build.0 = Release|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.ActiveCfg = Release|Any CPU -- 2.47.1 From d1a289885b17a635ca22a093625dbd2540f144f2 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 14:25:00 +0300 Subject: [PATCH 21/32] refactor: IGameManager.Enumerable --- Engine.Core/Abstract/IGameManager.cs | 2 +- Engine.Core/Extensions/HierarchyObjectExtensions.cs | 6 +++--- Engine.Core/GameManager.cs | 4 ++++ Engine.Physics2D/PhysicsCoroutineManager.cs | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Engine.Core/Abstract/IGameManager.cs b/Engine.Core/Abstract/IGameManager.cs index 8805249..f573639 100644 --- a/Engine.Core/Abstract/IGameManager.cs +++ b/Engine.Core/Abstract/IGameManager.cs @@ -5,7 +5,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a game world responsible for managing s. /// -public interface IGameManager : IEntity +public interface IGameManager : IEntity, IEnumerable { /// /// Event triggered when is called on the . diff --git a/Engine.Core/Extensions/HierarchyObjectExtensions.cs b/Engine.Core/Extensions/HierarchyObjectExtensions.cs index ae4de7e..d99823d 100644 --- a/Engine.Core/Extensions/HierarchyObjectExtensions.cs +++ b/Engine.Core/Extensions/HierarchyObjectExtensions.cs @@ -13,7 +13,7 @@ public static class HierarchyObjectExtensions return hierarchyObject; } - public static T? FindObject(this IEnumerable hierarchyObjects) where T : class + public static T? FindHierarchyObject(this IEnumerable hierarchyObjects) where T : class { foreach (IHierarchyObject hierarchyObject in hierarchyObjects) if (hierarchyObject is T @object) @@ -22,9 +22,9 @@ public static class HierarchyObjectExtensions return default; } - public static bool TryFindObject(this IEnumerable hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class + public static bool TryFindHierarchyObject(this IEnumerable hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { - behaviour = FindObject(hierarchyObjects); + behaviour = FindHierarchyObject(hierarchyObjects); return behaviour is not null; } diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index 8d1b597..74e89db 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; @@ -143,4 +144,7 @@ public class GameManager : BaseEntity, IGameManager if (sender is IHierarchyObject hierarchyObject) Remove(hierarchyObject); } + + public IEnumerator GetEnumerator() => _hierarchyObjects.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _hierarchyObjects.GetEnumerator(); } diff --git a/Engine.Physics2D/PhysicsCoroutineManager.cs b/Engine.Physics2D/PhysicsCoroutineManager.cs index 8daadd0..81173c3 100644 --- a/Engine.Physics2D/PhysicsCoroutineManager.cs +++ b/Engine.Physics2D/PhysicsCoroutineManager.cs @@ -25,7 +25,7 @@ public class PhysicsCoroutineManager : HierarchyObject protected override void OnEnteringHierarchy(IGameManager gameManager) { - physicsEngine = gameManager.HierarchyObjects.FindObject(); + physicsEngine = gameManager.FindHierarchyObject(); if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine) foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep; else @@ -56,7 +56,7 @@ public class PhysicsCoroutineManager : HierarchyObject if (GameManager is not IGameManager gameManager) return; - physicsEngine = gameManager.HierarchyObjects.FindObject(); + physicsEngine = gameManager.FindHierarchyObject(); if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine) { foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep; -- 2.47.1 From e8ef41af4181c5f8c01f96927a49eb77fa60f4c2 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 16:45:58 +0300 Subject: [PATCH 22/32] chore: forgotten HierarchyObject extension method name --- Engine.Core/Extensions/HierarchyObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine.Core/Extensions/HierarchyObjectExtensions.cs b/Engine.Core/Extensions/HierarchyObjectExtensions.cs index d99823d..ae9726f 100644 --- a/Engine.Core/Extensions/HierarchyObjectExtensions.cs +++ b/Engine.Core/Extensions/HierarchyObjectExtensions.cs @@ -28,7 +28,7 @@ public static class HierarchyObjectExtensions return behaviour is not null; } - public static void FindObjects(this IEnumerable hierarchyObjects, List behaviours) where T : class + public static void FindHierarchyObjects(this IEnumerable hierarchyObjects, List behaviours) where T : class { behaviours.Clear(); foreach (IHierarchyObject hierarchyObject in hierarchyObjects) -- 2.47.1 From 90c1dd9348b8540f13c5fe11f47a7279e4ccd38e Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 16:46:19 +0300 Subject: [PATCH 23/32] chore: EnumExtensions added --- Engine.Core/Extensions/EnumExtensions.cs | 9 +++++++++ Engine.Systems/Time/TimerState.cs | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 Engine.Core/Extensions/EnumExtensions.cs diff --git a/Engine.Core/Extensions/EnumExtensions.cs b/Engine.Core/Extensions/EnumExtensions.cs new file mode 100644 index 0000000..1f7e8b1 --- /dev/null +++ b/Engine.Core/Extensions/EnumExtensions.cs @@ -0,0 +1,9 @@ +using System; + +namespace Syntriax.Engine.Core; + +public static class EnumExtensions +{ + public static bool CheckFlag(this Enum left, Enum right) + => ((int)(object)left & (int)(object)right) != 0; +} diff --git a/Engine.Systems/Time/TimerState.cs b/Engine.Systems/Time/TimerState.cs index 4702f3d..4bda41a 100644 --- a/Engine.Systems/Time/TimerState.cs +++ b/Engine.Systems/Time/TimerState.cs @@ -2,8 +2,8 @@ namespace Syntriax.Engine.Systems.Time; public enum TimerState { - Idle, - Ticking, - Paused, - Stopped + Idle = 0b0001, + Ticking = 0b0010, + Paused = 0b0100, + Stopped = 0b1000 } -- 2.47.1 From cd2cd89eaef78e4ebfd166f28adbb5a5c6e5518d Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 19:37:09 +0300 Subject: [PATCH 24/32] fix: Engine referencing removed class library --- Engine/Engine.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/Engine.csproj b/Engine/Engine.csproj index a4c8395..c7b03c3 100644 --- a/Engine/Engine.csproj +++ b/Engine/Engine.csproj @@ -10,7 +10,6 @@ - -- 2.47.1 From 9f3e39e337df50fca2611e96762fe25f235cb0d0 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 31 Mar 2025 19:38:01 +0300 Subject: [PATCH 25/32] feat: basic tween system added --- Engine.Systems/Tween/Easings.cs | 72 +++++++++++++++ Engine.Systems/Tween/IEasing.cs | 7 ++ Engine.Systems/Tween/ITween.cs | 25 ++++++ Engine.Systems/Tween/Tween.cs | 82 +++++++++++++++++ Engine.Systems/Tween/TweenExtensions.cs | 90 +++++++++++++++++++ Engine.Systems/Tween/TweenManager.cs | 66 ++++++++++++++ Engine.Systems/Tween/TweenState.cs | 10 +++ .../WaitForTweenCompleteCoroutineYield.cs | 5 ++ .../Yields/WaitForTweenDoneCoroutineYield.cs | 5 ++ 9 files changed, 362 insertions(+) create mode 100644 Engine.Systems/Tween/Easings.cs create mode 100644 Engine.Systems/Tween/IEasing.cs create mode 100644 Engine.Systems/Tween/ITween.cs create mode 100644 Engine.Systems/Tween/Tween.cs create mode 100644 Engine.Systems/Tween/TweenExtensions.cs create mode 100644 Engine.Systems/Tween/TweenManager.cs create mode 100644 Engine.Systems/Tween/TweenState.cs create mode 100644 Engine.Systems/Tween/Yields/WaitForTweenCompleteCoroutineYield.cs create mode 100644 Engine.Systems/Tween/Yields/WaitForTweenDoneCoroutineYield.cs diff --git a/Engine.Systems/Tween/Easings.cs b/Engine.Systems/Tween/Easings.cs new file mode 100644 index 0000000..6e879ee --- /dev/null +++ b/Engine.Systems/Tween/Easings.cs @@ -0,0 +1,72 @@ +// Reference: https://easings.net + +namespace Syntriax.Engine.Systems.Tween; + +internal static class EaseConstants +{ + internal const float c1 = 1.70158f; + internal const float c2 = c1 * 1.525f; + internal const float c3 = c1 + 1f; + internal const float c4 = 2f * Core.Math.PI / 3; + internal const float c5 = 2f * Core.Math.PI / 4.5f; +} + +public readonly struct EaseLinear : IEasing { public readonly float Evaluate(float value) => value; } + +public readonly struct EaseInQuad : IEasing { public readonly float Evaluate(float value) => value * value; } +public readonly struct EaseOutQuad : IEasing { public readonly float Evaluate(float value) => 1f - (1f - value) * (1f - value); } +public readonly struct EaseInOutQuad : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 2f * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 2f) * .5f; } + +public readonly struct EaseInCubic : IEasing { public readonly float Evaluate(float value) => value * value * value; } +public readonly struct EaseOutCubic : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 3); } +public readonly struct EaseInOutCubic : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 4f * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 3) * .5f; } + +public readonly struct EaseInQuart : IEasing { public readonly float Evaluate(float value) => value * value * value * value; } +public readonly struct EaseOutQuart : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 4f); } +public readonly struct EaseInOutQuart : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 8 * value * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 4f) * .5f; } + +public readonly struct EaseInQuint : IEasing { public readonly float Evaluate(float value) => value * value * value * value * value; } +public readonly struct EaseOutQuint : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 5); } +public readonly struct EaseInOutQuint : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 16 * value * value * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 5) * .5f; } + +public readonly struct EaseInSine : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Cos(value * Core.Math.PI * .5f); } +public readonly struct EaseOutSine : IEasing { public readonly float Evaluate(float value) => Core.Math.Sin(value * Core.Math.PI * .5f); } +public readonly struct EaseInOutSine : IEasing { public readonly float Evaluate(float value) => -(Core.Math.Cos(Core.Math.PI * value) - 1f) * .5f; } + +public readonly struct EaseInExpo : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : Core.Math.Pow(2f, 10f * value - 10f); } +public readonly struct EaseOutExpo : IEasing { public readonly float Evaluate(float value) => value == 1f ? 1f : 1f - Core.Math.Pow(2f, -10f * value); } +public readonly struct EaseInOutExpo : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : value < 0.5f ? Core.Math.Pow(2f, 20 * value - 10f) * .5f : (2f - Core.Math.Pow(2f, -20 * value + 10f)) * .5f; } + +public readonly struct EaseInCirc : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Sqrt(1f - Core.Math.Pow(value, 2f)); } +public readonly struct EaseOutCirc : IEasing { public readonly float Evaluate(float value) => Core.Math.Sqrt(1f - Core.Math.Pow(value - 1f, 2f)); } +public readonly struct EaseInOutCirc : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? (1f - Core.Math.Sqrt(1f - Core.Math.Pow(2f * value, 2f))) * .5f : (Core.Math.Sqrt(1f - Core.Math.Pow(-2f * value + 2f, 2f)) + 1f) * .5f; } + +public readonly struct EaseInBack : IEasing { public readonly float Evaluate(float value) => EaseConstants.c3 * value * value * value - EaseConstants.c1 * value * value; } +public readonly struct EaseOutBack : IEasing { public readonly float Evaluate(float value) => 1f + EaseConstants.c3 * Core.Math.Pow(value - 1f, 3) + EaseConstants.c1 * Core.Math.Pow(value - 1f, 2f); } +public readonly struct EaseInOutBack : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? Core.Math.Pow(2f * value, 2f) * ((EaseConstants.c2 + 1f) * 2f * value - EaseConstants.c2) * .5f : (Core.Math.Pow(2f * value - 2f, 2f) * ((EaseConstants.c2 + 1f) * (value * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; } + +public readonly struct EaseInElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : -Core.Math.Pow(2f, 10f * value - 10f) * Core.Math.Sin((value * 10f - 10.75f) * EaseConstants.c4); } +public readonly struct EaseOutElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : Core.Math.Pow(2f, -10f * value) * Core.Math.Sin((value * 10f - 0.75f) * EaseConstants.c4) + 1f; } +public readonly struct EaseInOutElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : value < 0.5f ? -(Core.Math.Pow(2f, 20 * value - 10f) * Core.Math.Sin((20 * value - 11.125f) * EaseConstants.c5)) * .5f : Core.Math.Pow(2f, -20 * value + 10f) * Core.Math.Sin((20 * value - 11.125f) * EaseConstants.c5) * .5f + 1f; } + +public readonly struct EaseInBounce : IEasing { public readonly float Evaluate(float value) => 1f - new EaseOutBounce().Evaluate(1f - value); } +public readonly struct EaseOutBounce : IEasing +{ + public readonly float Evaluate(float value) + { + const float n1 = 7.5625f; + const float d1 = 2.75f; + + if (value < 1 / d1) + return n1 * value * value; + + if (value < 2 / d1) + return n1 * (value -= 1.5f / d1) * value + 0.75f; + + if (value < 2.5 / d1) + return n1 * (value -= 2.25f / d1) * value + 0.9375f; + + return n1 * (value -= 2.625f / d1) * value + 0.984375f; + } +} +public readonly struct EaseInOutBounce : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? (1f - new EaseOutBounce().Evaluate(1f - 2f * value)) * .5f : (1f + new EaseOutBounce().Evaluate(2f * value - 1f)) * .5f; } diff --git a/Engine.Systems/Tween/IEasing.cs b/Engine.Systems/Tween/IEasing.cs new file mode 100644 index 0000000..92ed50a --- /dev/null +++ b/Engine.Systems/Tween/IEasing.cs @@ -0,0 +1,7 @@ +namespace Syntriax.Engine.Systems.Tween; + +public interface IEasing +{ + float Evaluate(float value); +} + diff --git a/Engine.Systems/Tween/ITween.cs b/Engine.Systems/Tween/ITween.cs new file mode 100644 index 0000000..6f90137 --- /dev/null +++ b/Engine.Systems/Tween/ITween.cs @@ -0,0 +1,25 @@ +namespace Syntriax.Engine.Systems.Tween; + +public interface ITween +{ + event TweenEventHandler? OnStarted; + event TweenEventHandler? OnPaused; + event TweenEventHandler? OnResumed; + event TweenEventHandler? OnCancelled; + event TweenEventHandler? OnCompleted; + event TweenEventHandler? OnEnded; + + event TweenEventHandler? OnUpdated; + event TweenDeltaEventHandler? OnDeltaUpdated; + + TweenState State { get; set; } + + float Counter { get; } + float Duration { get; } + float Progress { get; } + float Value { get; } + + delegate void TweenEventHandler(ITween sender); + delegate void TweenDeltaEventHandler(ITween sender, float delta); +} + diff --git a/Engine.Systems/Tween/Tween.cs b/Engine.Systems/Tween/Tween.cs new file mode 100644 index 0000000..a9fb89d --- /dev/null +++ b/Engine.Systems/Tween/Tween.cs @@ -0,0 +1,82 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Systems.Tween; + +internal class Tween : ITween +{ + public event ITween.TweenEventHandler? OnStarted = null; + public event ITween.TweenEventHandler? OnPaused = null; + public event ITween.TweenEventHandler? OnResumed = null; + public event ITween.TweenEventHandler? OnCancelled = null; + public event ITween.TweenEventHandler? OnCompleted = null; + public event ITween.TweenEventHandler? OnEnded = null; + public event ITween.TweenEventHandler? OnUpdated = null; + public event ITween.TweenDeltaEventHandler? OnDeltaUpdated = null; + + private TweenState _state = TweenState.Idle; + public TweenState State + { + get => _state; + set + { + if (value == _state) + return; + + TweenState previousState = _state; + _state = value; + switch (value) + { + case TweenState.Completed: OnCompleted?.Invoke(this); OnEnded?.Invoke(this); break; + case TweenState.Cancelled: OnCancelled?.Invoke(this); OnEnded?.Invoke(this); break; + case TweenState.Paused: OnPaused?.Invoke(this); break; + case TweenState.Playing: + if (previousState == TweenState.Idle) + OnStarted?.Invoke(this); + else + OnResumed?.Invoke(this); + break; + } + } + } + + public float Duration { get; internal set; } = 1f; + public float Progress { get; internal set; } = 0f; + private float _counter = 0f; + + public IEasing Easing { get; set; } = new EaseLinear(); + public float Value => Easing.Evaluate(Progress); + + public float Counter + { + get => _counter; + set + { + if (value < _counter) + return; + + float previousProgress = Progress; + + _counter = value.Min(Duration).Max(0f); + Progress = Counter / Duration; + OnUpdated?.Invoke(this); + + OnDeltaUpdated?.Invoke(this, Easing.Evaluate(Progress) - Easing.Evaluate(previousProgress)); + + if (_counter >= Duration) + State = TweenState.Completed; + } + } + + internal void Reset() + { + _counter = 0f; + Progress = 0f; + State = TweenState.Idle; + } + + public Tween() { } + public Tween(float duration) + { + Duration = duration; + } +} diff --git a/Engine.Systems/Tween/TweenExtensions.cs b/Engine.Systems/Tween/TweenExtensions.cs new file mode 100644 index 0000000..77e02ac --- /dev/null +++ b/Engine.Systems/Tween/TweenExtensions.cs @@ -0,0 +1,90 @@ +namespace Syntriax.Engine.Systems.Tween; + +public static class TweenExtensions +{ + public static ITween Loop(this ITween tween, int count) + { + Tween tweenConcrete = (Tween)tween; + int counter = count; + + tweenConcrete.OnCompleted += _ => + { + if (counter-- <= 0) + return; + + tweenConcrete.Reset(); + tweenConcrete.State = TweenState.Playing; + }; + + return tween; + } + + public static ITween LoopInfinitely(this ITween tween) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnCompleted += _ => + { + tweenConcrete.Reset(); + tweenConcrete.State = TweenState.Playing; + }; + + return tween; + } + + public static ITween Ease(this ITween tween, IEasing easing) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.Easing = easing; + + return tween; + } + + public static ITween OnStart(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnStarted += _ => callback.Invoke(); + return tween; + } + public static ITween OnPause(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnPaused += _ => callback.Invoke(); + return tween; + } + public static ITween OnResume(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnResumed += _ => callback.Invoke(); + return tween; + } + public static ITween OnCancel(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnCancelled += _ => callback.Invoke(); + return tween; + } + public static ITween OnComplete(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnCompleted += _ => callback.Invoke(); + return tween; + } + public static ITween OnEnd(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnEnded += _ => callback.Invoke(); + return tween; + } + public static ITween OnUpdate(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnUpdated += _ => callback.Invoke(); + return tween; + } + public static ITween OnDeltaUpdate(this ITween tween, Action callback) + { + Tween tweenConcrete = (Tween)tween; + tweenConcrete.OnDeltaUpdated += (_, delta) => callback.Invoke(delta); + return tween; + } +} diff --git a/Engine.Systems/Tween/TweenManager.cs b/Engine.Systems/Tween/TweenManager.cs new file mode 100644 index 0000000..d045cef --- /dev/null +++ b/Engine.Systems/Tween/TweenManager.cs @@ -0,0 +1,66 @@ +using System.Collections; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Systems.Tween; + +public class TweenManager : HierarchyObject +{ + private CoroutineManager coroutineManager = null!; + + private readonly Dictionary runningCoroutines = []; + + public ITween StartTween(float duration, TweenSetCallback? setCallback = null) + { + Tween tween = new(duration); + tween.OnUpdated += tween => setCallback?.Invoke(tween.Value); + runningCoroutines.Add(tween, coroutineManager.StartCoroutine(RunTween(tween))); + return tween; + } + + private IEnumerator RunTween(Tween tween) + { + tween.State = TweenState.Playing; + yield return null; + + while (true) + { + if (tween.State.CheckFlag(TweenState.Cancelled | TweenState.Completed)) + break; + + if (tween.State.CheckFlag(TweenState.Paused)) + { + yield return null; + continue; + } + + tween.Counter += GameManager.Time.DeltaTime; + yield return null; + } + + runningCoroutines.Remove(tween); + } + + public void CancelTween(ITween tween) + { + if (!runningCoroutines.TryGetValue(tween, out IEnumerator? runningCoroutine)) + return; + + tween.State = TweenState.Cancelled; + coroutineManager.StopCoroutine(runningCoroutine); + runningCoroutines.Remove(tween); + } + + protected override void OnEnteringHierarchy(IGameManager gameManager) + { + coroutineManager = gameManager.FindHierarchyObject() ?? throw new($"No {nameof(CoroutineManager)} was found in the game manager"); + } + + protected override void OnExitingHierarchy(IGameManager gameManager) + { + coroutineManager = null!; + } + + public delegate void TweenSetCallback(float t); +} diff --git a/Engine.Systems/Tween/TweenState.cs b/Engine.Systems/Tween/TweenState.cs new file mode 100644 index 0000000..166e925 --- /dev/null +++ b/Engine.Systems/Tween/TweenState.cs @@ -0,0 +1,10 @@ +namespace Syntriax.Engine.Systems.Tween; + +public enum TweenState +{ + Idle = 0b00001, + Playing = 0b00010, + Paused = 0b00100, + Cancelled = 0b01000, + Completed = 0b10000, +} diff --git a/Engine.Systems/Tween/Yields/WaitForTweenCompleteCoroutineYield.cs b/Engine.Systems/Tween/Yields/WaitForTweenCompleteCoroutineYield.cs new file mode 100644 index 0000000..0a8c290 --- /dev/null +++ b/Engine.Systems/Tween/Yields/WaitForTweenCompleteCoroutineYield.cs @@ -0,0 +1,5 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Systems.Tween; + +public class WaitForTweenCompleteCoroutineYield(ITween tween) : CoroutineYield(() => tween.State == TweenState.Completed); diff --git a/Engine.Systems/Tween/Yields/WaitForTweenDoneCoroutineYield.cs b/Engine.Systems/Tween/Yields/WaitForTweenDoneCoroutineYield.cs new file mode 100644 index 0000000..b34330b --- /dev/null +++ b/Engine.Systems/Tween/Yields/WaitForTweenDoneCoroutineYield.cs @@ -0,0 +1,5 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Systems.Tween; + +public class WaitWhileTweenActiveCoroutineYield(ITween tween) : CoroutineYield(() => tween.State.CheckFlag(TweenState.Completed | TweenState.Cancelled)); -- 2.47.1 From 067bc51487f48a0e65ef16a550bb1bd011c3d927 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 12:18:33 +0300 Subject: [PATCH 26/32] refactor: made factories static --- Engine.Core/Abstract/BaseEntity.cs | 2 +- Engine.Core/BehaviourController.cs | 4 ++-- Engine.Core/Factory/BehaviourControllerFactory.cs | 4 ++-- Engine.Core/Factory/BehaviourFactory.cs | 4 ++-- Engine.Core/Factory/HierarchyObjectFactory.cs | 4 ++-- Engine.Core/Factory/StateEnableFactory.cs | 4 ++-- Engine.Core/Factory/TransformFactory.cs | 4 ++-- Engine.Core/GameManager.cs | 15 ++------------- Engine.Core/HierarchyObject.cs | 2 +- 9 files changed, 16 insertions(+), 27 deletions(-) diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/Abstract/BaseEntity.cs index 52e67a9..02a1ec4 100644 --- a/Engine.Core/Abstract/BaseEntity.cs +++ b/Engine.Core/Abstract/BaseEntity.cs @@ -86,7 +86,7 @@ public abstract class BaseEntity : IEntity if (IsInitialized) return false; - _stateEnable ??= new Factory.StateEnableFactory().Instantiate(this); + _stateEnable ??= Factory.StateEnableFactory.Instantiate(this); InitializeInternal(); diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs index f25c099..361ff08 100644 --- a/Engine.Core/BehaviourController.cs +++ b/Engine.Core/BehaviourController.cs @@ -52,7 +52,7 @@ public class BehaviourController : IBehaviourController InsertBehaviourByPriority(behaviour); behaviour.Assign(this); - behaviour.Assign(HierarchyObject.StateEnable); + behaviour.Assign(Factory.StateEnableFactory.Instantiate(behaviour)); behaviour.Initialize(); behaviour.OnPriorityChanged += OnPriorityChange; @@ -61,7 +61,7 @@ public class BehaviourController : IBehaviourController } public T AddBehaviour(params object?[]? args) where T : class, IBehaviour - => AddBehaviour(new Factory.BehaviourFactory().Instantiate(_hierarchyObject, args)); + => AddBehaviour(Factory.BehaviourFactory.Instantiate(_hierarchyObject, args)); public T? GetBehaviour() { diff --git a/Engine.Core/Factory/BehaviourControllerFactory.cs b/Engine.Core/Factory/BehaviourControllerFactory.cs index d242503..08804b3 100644 --- a/Engine.Core/Factory/BehaviourControllerFactory.cs +++ b/Engine.Core/Factory/BehaviourControllerFactory.cs @@ -5,10 +5,10 @@ namespace Syntriax.Engine.Core.Factory; public class BehaviourControllerFactory { - public IBehaviourController Instantiate(IHierarchyObject hierarchyObject) + public static IBehaviourController Instantiate(IHierarchyObject hierarchyObject) => Instantiate(hierarchyObject); - public T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) + public static T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviourController { T behaviourController = TypeFactory.Get(args); diff --git a/Engine.Core/Factory/BehaviourFactory.cs b/Engine.Core/Factory/BehaviourFactory.cs index bf68861..7191d1f 100644 --- a/Engine.Core/Factory/BehaviourFactory.cs +++ b/Engine.Core/Factory/BehaviourFactory.cs @@ -5,10 +5,10 @@ namespace Syntriax.Engine.Core.Factory; public class BehaviourFactory { - public T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviour + public static T Instantiate(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviour => Instantiate(hierarchyObject, stateEnable: null, args); - public T Instantiate(IHierarchyObject hierarchyObject, IStateEnable? stateEnable, params object?[]? args) + public static T Instantiate(IHierarchyObject hierarchyObject, IStateEnable? stateEnable, params object?[]? args) where T : class, IBehaviour { T behaviour = TypeFactory.Get(args); diff --git a/Engine.Core/Factory/HierarchyObjectFactory.cs b/Engine.Core/Factory/HierarchyObjectFactory.cs index f3e23f1..1cb31d3 100644 --- a/Engine.Core/Factory/HierarchyObjectFactory.cs +++ b/Engine.Core/Factory/HierarchyObjectFactory.cs @@ -5,10 +5,10 @@ namespace Syntriax.Engine.Core.Factory; public class HierarchyObjectFactory { - public T Instantiate(params object?[]? args) where T : class, IHierarchyObject + public static T Instantiate(params object?[]? args) where T : class, IHierarchyObject => Instantiate(behaviourController: null, stateEnable: null, args); - public T Instantiate( + public static T Instantiate( IBehaviourController? behaviourController = null, IStateEnable? stateEnable = null, params object?[]? args diff --git a/Engine.Core/Factory/StateEnableFactory.cs b/Engine.Core/Factory/StateEnableFactory.cs index 05167ae..aa705af 100644 --- a/Engine.Core/Factory/StateEnableFactory.cs +++ b/Engine.Core/Factory/StateEnableFactory.cs @@ -5,9 +5,9 @@ namespace Syntriax.Engine.Core.Factory; public class StateEnableFactory { - public IStateEnable Instantiate(IEntity entity) => Instantiate(entity); + public static IStateEnable Instantiate(IEntity entity) => Instantiate(entity); - public T Instantiate(IEntity entity, params object?[]? args) where T : class, IStateEnable + public static T Instantiate(IEntity entity, params object?[]? args) where T : class, IStateEnable { T stateEnable = TypeFactory.Get(args); diff --git a/Engine.Core/Factory/TransformFactory.cs b/Engine.Core/Factory/TransformFactory.cs index 2b7a5dd..e8fcad8 100644 --- a/Engine.Core/Factory/TransformFactory.cs +++ b/Engine.Core/Factory/TransformFactory.cs @@ -4,7 +4,7 @@ namespace Syntriax.Engine.Core.Factory; public class TransformFactory { - public ITransform2D Instantiate() => TypeFactory.Get(); - public T Instantiate(params object?[]? args) where T : class, ITransform2D + public static ITransform2D Instantiate() => TypeFactory.Get(); + public static T Instantiate(params object?[]? args) where T : class, ITransform2D => TypeFactory.Get(args); } diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index 74e89db..8d12255 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Exceptions; -using Syntriax.Engine.Core.Factory; namespace Syntriax.Engine.Core; @@ -19,16 +18,6 @@ public class GameManager : BaseEntity, IGameManager private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); - private HierarchyObjectFactory _hierarchyObjectFactory = null!; - private HierarchyObjectFactory HierarchyObjectFactory - { - get - { - _hierarchyObjectFactory ??= new HierarchyObjectFactory(); - return _hierarchyObjectFactory; - } - } - public IReadOnlyList HierarchyObjects => _hierarchyObjects; public override IStateEnable StateEnable @@ -37,7 +26,7 @@ public class GameManager : BaseEntity, IGameManager { if (base.StateEnable is null) { - Assign(new StateEnableFactory().Instantiate(this)); + Assign(Factory.StateEnableFactory.Instantiate(this)); if (base.StateEnable is null) throw NotAssignedException.From(this, base.StateEnable); } @@ -72,7 +61,7 @@ public class GameManager : BaseEntity, IGameManager public T InstantiateHierarchyObject(params object?[]? args) where T : class, IHierarchyObject { - T hierarchyObject = HierarchyObjectFactory.Instantiate(args); + T hierarchyObject = Factory.HierarchyObjectFactory.Instantiate(args); Register(hierarchyObject); return hierarchyObject; } diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs index 8691f11..8247e76 100644 --- a/Engine.Core/HierarchyObject.cs +++ b/Engine.Core/HierarchyObject.cs @@ -128,7 +128,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject protected override void InitializeInternal() { base.InitializeInternal(); - _behaviourController ??= new Factory.BehaviourControllerFactory().Instantiate(this); + _behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this); } public IEnumerator GetEnumerator() => _children.GetEnumerator(); -- 2.47.1 From 803b670433352a5bbb7f658bb5f0d9fb6183486d Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 12:19:12 +0300 Subject: [PATCH 27/32] fix: IBehaviourCollector delegate parameter forgot on the concrete implementation --- Engine.Core/Abstract/IBehaviourCollector.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine.Core/Abstract/IBehaviourCollector.cs b/Engine.Core/Abstract/IBehaviourCollector.cs index e0d38e9..a1d4527 100644 --- a/Engine.Core/Abstract/IBehaviourCollector.cs +++ b/Engine.Core/Abstract/IBehaviourCollector.cs @@ -22,14 +22,14 @@ public interface IBehaviourCollector : IHasGameManager, IEnumerable where /// /// Delegate for handling the event. /// - /// The instance of the that triggered the event. + /// The instance of the that triggered the event. /// The object of type that was added to the collector. - public delegate void CollectedEventHandler(BehaviourCollector sender, T behaviourCollected); + delegate void CollectedEventHandler(IBehaviourCollector sender, T behaviourCollected); /// /// Delegate for handling the event. /// - /// The instance of the that triggered the event. + /// The instance of the that triggered the event. /// The object of type that was removed from the collector. - public delegate void RemovedEventHandler(BehaviourCollector sender, T behaviourRemoved); + delegate void RemovedEventHandler(IBehaviourCollector sender, T behaviourRemoved); } -- 2.47.1 From 21600b856f8141a36d2b8977588bafe745bd5d76 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 12:19:34 +0300 Subject: [PATCH 28/32] refactor: removed unnecessary underscore on behaviour collector --- Engine.Core/BehaviourCollector.cs | 14 +++++++------- Engine.Core/BehaviourCollectorSorted.cs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Engine.Core/BehaviourCollector.cs b/Engine.Core/BehaviourCollector.cs index 19e0a07..83f6de3 100644 --- a/Engine.Core/BehaviourCollector.cs +++ b/Engine.Core/BehaviourCollector.cs @@ -14,12 +14,12 @@ public class BehaviourCollector : IBehaviourCollector where T : class public event IBehaviourCollector.CollectedEventHandler? OnCollected = null; public event IBehaviourCollector.RemovedEventHandler? OnRemoved = null; - protected readonly List _behaviours = new(32); + protected readonly List behaviours = new(32); - public IReadOnlyList Behaviours => _behaviours; + public IReadOnlyList Behaviours => behaviours; public IGameManager GameManager { get; private set; } = null!; - public T this[Index index] => _behaviours[index]; + public T this[Index index] => behaviours[index]; public BehaviourCollector() { } public BehaviourCollector(IGameManager gameManager) => Assign(gameManager); @@ -48,7 +48,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class if (behaviour is not T tBehaviour) return; - _behaviours.Add(tBehaviour); + behaviours.Add(tBehaviour); OnBehaviourAdd(behaviour); OnCollected?.Invoke(this, tBehaviour); } @@ -59,7 +59,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class if (behaviour is not T tBehaviour) return; - if (!_behaviours.Remove(tBehaviour)) + if (!behaviours.Remove(tBehaviour)) return; OnBehaviourRemove(behaviour); @@ -99,6 +99,6 @@ public class BehaviourCollector : IBehaviourCollector where T : class return true; } - public IEnumerator GetEnumerator() => _behaviours.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => _behaviours.GetEnumerator(); + public IEnumerator GetEnumerator() => behaviours.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => behaviours.GetEnumerator(); } diff --git a/Engine.Core/BehaviourCollectorSorted.cs b/Engine.Core/BehaviourCollectorSorted.cs index 3a9fc2d..2c384eb 100644 --- a/Engine.Core/BehaviourCollectorSorted.cs +++ b/Engine.Core/BehaviourCollectorSorted.cs @@ -11,7 +11,7 @@ public class BehaviourCollectorSorted : BehaviourCollector where T : class protected override void OnBehaviourAdd(IBehaviour behaviour) { if (SortBy is not null) - _behaviours.Sort(SortBy); + behaviours.Sort(SortBy); } public BehaviourCollectorSorted() { } -- 2.47.1 From d4c6288b38cc838d2c4217c079f59ec228854a52 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 12:19:58 +0300 Subject: [PATCH 29/32] feat: added behaviour collector for active behaviours only --- Engine.Core/ActiveBehaviourCollector.cs | 123 ++++++++++++++++++ Engine.Core/ActiveBehaviourCollectorSorted.cs | 19 +++ 2 files changed, 142 insertions(+) create mode 100644 Engine.Core/ActiveBehaviourCollector.cs create mode 100644 Engine.Core/ActiveBehaviourCollectorSorted.cs diff --git a/Engine.Core/ActiveBehaviourCollector.cs b/Engine.Core/ActiveBehaviourCollector.cs new file mode 100644 index 0000000..70e48d8 --- /dev/null +++ b/Engine.Core/ActiveBehaviourCollector.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class ActiveBehaviourCollector : IBehaviourCollector where T : class, IBehaviour +{ + public event IAssignable.UnassignEventHandler? OnUnassigned = null; + public event IHasGameManager.GameManagerAssignedEventHandler? OnGameManagerAssigned = null; + + public event IBehaviourCollector.CollectedEventHandler? OnCollected = null; + public event IBehaviourCollector.RemovedEventHandler? OnRemoved = null; + + private readonly List monitoringBehaviours = new(32); + protected readonly List activeBehaviours = new(32); + protected readonly Dictionary monitoringStateToBehaviour = new(32); + + public IReadOnlyList Behaviours => activeBehaviours; + public IGameManager GameManager { get; private set; } = null!; + + public T this[Index index] => activeBehaviours[index]; + + public ActiveBehaviourCollector() { } + public ActiveBehaviourCollector(IGameManager gameManager) => Assign(gameManager); + + private void OnHierarchyObjectRegistered(IGameManager manager, IHierarchyObject hierarchyObject) + { + hierarchyObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; + hierarchyObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; + + foreach (IBehaviour item in hierarchyObject.BehaviourController) + OnBehaviourAdded(hierarchyObject.BehaviourController, item); + } + + private void OnHierarchyObjectUnregistered(IGameManager manager, IHierarchyObject hierarchyObject) + { + hierarchyObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded; + hierarchyObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved; + + foreach (IBehaviour item in hierarchyObject.BehaviourController) + OnBehaviourRemoved(hierarchyObject.BehaviourController, item); + } + + protected virtual void OnBehaviourAdd(IBehaviour behaviour) { } + private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) + { + if (behaviour is not T tBehaviour) + return; + + monitoringBehaviours.Add(tBehaviour); + monitoringStateToBehaviour.Add(tBehaviour.StateEnable, tBehaviour); + tBehaviour.StateEnable.OnEnabledChanged += OnBehaviourStateChanged; + OnBehaviourStateChanged(tBehaviour.StateEnable, !tBehaviour.StateEnable.Enabled); + } + + private void OnBehaviourStateChanged(IStateEnable sender, bool previousState) + { + T behaviour = monitoringStateToBehaviour[sender]; + if (sender.Enabled) + { + activeBehaviours.Add(behaviour); + OnBehaviourAdd(behaviour); + OnCollected?.Invoke(this, behaviour); + } + else if (activeBehaviours.Contains(behaviour)) + { + activeBehaviours.Remove(behaviour); + OnBehaviourRemove(behaviour); + OnRemoved?.Invoke(this, behaviour); + } + } + + protected virtual void OnBehaviourRemove(IBehaviour behaviour) { } + private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour) + { + if (behaviour is not T tBehaviour) + return; + + if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringStateToBehaviour.Remove(tBehaviour.StateEnable)) + return; + + tBehaviour.StateEnable.OnEnabledChanged -= OnBehaviourStateChanged; + } + + public bool Assign(IGameManager gameManager) + { + if (GameManager is not null) + return false; + + foreach (IHierarchyObject hierarchyObject in gameManager.HierarchyObjects) + OnHierarchyObjectRegistered(gameManager, hierarchyObject); + + gameManager.OnHierarchyObjectRegistered += OnHierarchyObjectRegistered; + gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered; + + GameManager = gameManager; + OnGameManagerAssigned?.Invoke(this); + + return true; + } + + public bool Unassign() + { + if (GameManager is null) + return false; + + foreach (IHierarchyObject hierarchyObject in GameManager.HierarchyObjects) + OnHierarchyObjectUnregistered(GameManager, hierarchyObject); + + GameManager.OnHierarchyObjectRegistered -= OnHierarchyObjectRegistered; + GameManager.OnHierarchyObjectUnRegistered -= OnHierarchyObjectUnregistered; + + GameManager = null!; + OnUnassigned?.Invoke(this); + return true; + } + + public IEnumerator GetEnumerator() => activeBehaviours.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => activeBehaviours.GetEnumerator(); +} diff --git a/Engine.Core/ActiveBehaviourCollectorSorted.cs b/Engine.Core/ActiveBehaviourCollectorSorted.cs new file mode 100644 index 0000000..e6807c2 --- /dev/null +++ b/Engine.Core/ActiveBehaviourCollectorSorted.cs @@ -0,0 +1,19 @@ +using System; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class ActiveBehaviourCollectorSorted : ActiveBehaviourCollector where T : class, IBehaviour +{ + public Comparison? SortBy { get; set; } = null; + + protected override void OnBehaviourAdd(IBehaviour behaviour) + { + if (SortBy is not null) + activeBehaviours.Sort(SortBy); + } + + public ActiveBehaviourCollectorSorted() { } + public ActiveBehaviourCollectorSorted(IGameManager gameManager) : base(gameManager) { } +} -- 2.47.1 From 417ddca972512f8b1a2aec97a4c5b21989e8845e Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 13:22:14 +0300 Subject: [PATCH 30/32] feat: IActive interface added for hierarchy active state --- Engine.Core/Abstract/IActive.cs | 19 +++++++++++ Engine.Core/Abstract/IBehaviour.cs | 7 +--- Engine.Core/Abstract/IHierarchyObject.cs | 2 +- Engine.Core/Abstract/IStateEnable.cs | 4 +-- Engine.Core/ActiveBehaviourCollector.cs | 26 ++++++++------- Engine.Core/{Abstract => }/BaseEntity.cs | 4 +-- Engine.Core/BehaviourBase.cs | 41 +++++++++++++++++++++--- Engine.Core/BehaviourCollector.cs | 2 ++ Engine.Core/BehaviourController.cs | 2 ++ Engine.Core/Factory/BehaviourFactory.cs | 4 +-- Engine.Core/HierarchyObject.cs | 34 ++++++++++++++++++++ Engine.Core/StateEnable.cs | 4 ++- 12 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 Engine.Core/Abstract/IActive.cs rename Engine.Core/{Abstract => }/BaseEntity.cs (96%) diff --git a/Engine.Core/Abstract/IActive.cs b/Engine.Core/Abstract/IActive.cs new file mode 100644 index 0000000..34c7dd3 --- /dev/null +++ b/Engine.Core/Abstract/IActive.cs @@ -0,0 +1,19 @@ +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Represents an entity which can be active or not. +/// +public interface IActive +{ + /// + /// Event triggered when the state of the changes. + /// + event ActiveChangedEventHandler? OnActiveChanged; + + /// + /// The value indicating whether the is enabled. + /// + bool IsActive { get; } + + delegate void ActiveChangedEventHandler(IActive sender, bool previousState); +} diff --git a/Engine.Core/Abstract/IBehaviour.cs b/Engine.Core/Abstract/IBehaviour.cs index 9fc2d30..6858d0a 100644 --- a/Engine.Core/Abstract/IBehaviour.cs +++ b/Engine.Core/Abstract/IBehaviour.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a behaviour that any object in the game might use to interact with itself or other objects. /// -public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable +public interface IBehaviour : IEntity, IActive, IHasBehaviourController, IHasStateEnable { /// /// Event triggered when the priority of the changes. @@ -15,10 +15,5 @@ public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable /// int Priority { get; set; } - /// - /// The value indicating whether the is active. - /// - bool IsActive { get; } - delegate void PriorityChangedEventHandler(IBehaviour sender, int previousPriority); } diff --git a/Engine.Core/Abstract/IHierarchyObject.cs b/Engine.Core/Abstract/IHierarchyObject.cs index aa5d7c3..e3909b5 100644 --- a/Engine.Core/Abstract/IHierarchyObject.cs +++ b/Engine.Core/Abstract/IHierarchyObject.cs @@ -7,7 +7,7 @@ namespace Syntriax.Engine.Core.Abstract; /// This interface allows for tracking the object's presence in the hierarchy and provides events /// for notifying when the see enters or exits the hierarchy. /// -public interface IHierarchyObject : IEntity, INameable, IHasBehaviourController, IEnumerable +public interface IHierarchyObject : IEntity, IActive, INameable, IHasBehaviourController, IEnumerable { /// /// Event triggered when the enters the hierarchy. diff --git a/Engine.Core/Abstract/IStateEnable.cs b/Engine.Core/Abstract/IStateEnable.cs index 8debf8c..132b9bd 100644 --- a/Engine.Core/Abstract/IStateEnable.cs +++ b/Engine.Core/Abstract/IStateEnable.cs @@ -8,12 +8,12 @@ public interface IStateEnable : IHasEntity /// /// Event triggered when the state of the changes. /// - event NameChangedEventHandler? OnEnabledChanged; + event EnabledChangedEventHandler? OnEnabledChanged; /// /// The value indicating whether the is enabled. /// bool Enabled { get; set; } - delegate void NameChangedEventHandler(IStateEnable sender, bool previousState); + delegate void EnabledChangedEventHandler(IStateEnable sender, bool previousState); } diff --git a/Engine.Core/ActiveBehaviourCollector.cs b/Engine.Core/ActiveBehaviourCollector.cs index 70e48d8..f7472aa 100644 --- a/Engine.Core/ActiveBehaviourCollector.cs +++ b/Engine.Core/ActiveBehaviourCollector.cs @@ -16,7 +16,7 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas private readonly List monitoringBehaviours = new(32); protected readonly List activeBehaviours = new(32); - protected readonly Dictionary monitoringStateToBehaviour = new(32); + protected readonly Dictionary monitoringActiveToBehaviour = new(32); public IReadOnlyList Behaviours => activeBehaviours; public IGameManager GameManager { get; private set; } = null!; @@ -51,23 +51,22 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas return; monitoringBehaviours.Add(tBehaviour); - monitoringStateToBehaviour.Add(tBehaviour.StateEnable, tBehaviour); - tBehaviour.StateEnable.OnEnabledChanged += OnBehaviourStateChanged; - OnBehaviourStateChanged(tBehaviour.StateEnable, !tBehaviour.StateEnable.Enabled); + monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour); + tBehaviour.OnActiveChanged += OnBehaviourStateChanged; + OnBehaviourStateChanged(tBehaviour, !tBehaviour.IsActive); } - private void OnBehaviourStateChanged(IStateEnable sender, bool previousState) + private void OnBehaviourStateChanged(IActive sender, bool previousState) { - T behaviour = monitoringStateToBehaviour[sender]; - if (sender.Enabled) + T behaviour = monitoringActiveToBehaviour[sender]; + if (sender.IsActive) { activeBehaviours.Add(behaviour); OnBehaviourAdd(behaviour); OnCollected?.Invoke(this, behaviour); } - else if (activeBehaviours.Contains(behaviour)) + else if (activeBehaviours.Remove(behaviour)) { - activeBehaviours.Remove(behaviour); OnBehaviourRemove(behaviour); OnRemoved?.Invoke(this, behaviour); } @@ -79,10 +78,15 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas if (behaviour is not T tBehaviour) return; - if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringStateToBehaviour.Remove(tBehaviour.StateEnable)) + if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour)) return; - tBehaviour.StateEnable.OnEnabledChanged -= OnBehaviourStateChanged; + tBehaviour.OnActiveChanged -= OnBehaviourStateChanged; + if (activeBehaviours.Remove(tBehaviour)) + { + OnBehaviourRemove(tBehaviour); + OnRemoved?.Invoke(this, tBehaviour); + } } public bool Assign(IGameManager gameManager) diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/BaseEntity.cs similarity index 96% rename from Engine.Core/Abstract/BaseEntity.cs rename to Engine.Core/BaseEntity.cs index 02a1ec4..66db6b0 100644 --- a/Engine.Core/Abstract/BaseEntity.cs +++ b/Engine.Core/BaseEntity.cs @@ -19,8 +19,6 @@ public abstract class BaseEntity : IEntity public virtual IStateEnable StateEnable => _stateEnable; - public virtual bool IsActive => StateEnable.Enabled; - public string Id { get => _id; @@ -55,6 +53,7 @@ public abstract class BaseEntity : IEntity } } + protected virtual void OnAssign(IStateEnable stateEnable) { } public bool Assign(IStateEnable stateEnable) { if (IsInitialized) @@ -62,6 +61,7 @@ public abstract class BaseEntity : IEntity _stateEnable = stateEnable; _stateEnable.Assign(this); + OnAssign(stateEnable); OnStateEnableAssigned?.Invoke(this); return true; } diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs index 8a7bbca..a89f88f 100644 --- a/Engine.Core/BehaviourBase.cs +++ b/Engine.Core/BehaviourBase.cs @@ -7,17 +7,14 @@ namespace Syntriax.Engine.Core; public abstract class BehaviourBase : BaseEntity, IBehaviour { public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; - public event IBehaviour.PriorityChangedEventHandler? OnPriorityChanged = null; + public event IActive.ActiveChangedEventHandler? OnActiveChanged = null; private IBehaviourController _behaviourController = null!; - private int _priority = 0; - public IBehaviourController BehaviourController => _behaviourController; - public override bool IsActive => base.IsActive && BehaviourController.HierarchyObject.StateEnable.Enabled; - + private int _priority = 0; public int Priority { get => _priority; @@ -32,18 +29,40 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour } } + public bool IsActive { get; private set; } = false; + + protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) { if (IsInitialized) return false; _behaviourController = behaviourController; + OnAssign(behaviourController); + behaviourController.OnHierarchyObjectAssigned += OnHierarchyObjectAssigned; + if (behaviourController.HierarchyObject is not null) + OnHierarchyObjectAssigned(behaviourController); OnBehaviourControllerAssigned?.Invoke(this); return true; } + private void OnHierarchyObjectAssigned(IHasHierarchyObject sender) + { + sender.HierarchyObject.OnActiveChanged += OnHierarchyObjectActiveChanged; + UpdateActive(); + } + + protected override void OnAssign(IStateEnable stateEnable) + { + base.OnAssign(stateEnable); + + stateEnable.OnEnabledChanged += OnStateEnabledChanged; + } + protected override void UnassignInternal() { + StateEnable.OnEnabledChanged -= OnStateEnabledChanged; + BehaviourController.OnHierarchyObjectAssigned -= OnHierarchyObjectAssigned; base.UnassignInternal(); _behaviourController = null!; } @@ -54,4 +73,16 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour NotAssignedException.Check(this, _behaviourController); NotAssignedException.Check(this, StateEnable); } + + private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive(); + private void OnHierarchyObjectActiveChanged(IActive sender, bool previousState) => UpdateActive(); + + private void UpdateActive() + { + bool previousActive = IsActive; + IsActive = StateEnable.Enabled && _behaviourController.HierarchyObject.IsActive; + + if (previousActive != IsActive) + OnActiveChanged?.Invoke(this, previousActive); + } } diff --git a/Engine.Core/BehaviourCollector.cs b/Engine.Core/BehaviourCollector.cs index 83f6de3..b586523 100644 --- a/Engine.Core/BehaviourCollector.cs +++ b/Engine.Core/BehaviourCollector.cs @@ -66,6 +66,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class OnRemoved?.Invoke(this, tBehaviour); } + protected virtual void OnAssign(IGameManager gameManager) { } public bool Assign(IGameManager gameManager) { if (GameManager is not null) @@ -78,6 +79,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered; GameManager = gameManager; + OnAssign(gameManager); OnGameManagerAssigned?.Invoke(this); return true; diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs index 361ff08..341262d 100644 --- a/Engine.Core/BehaviourController.cs +++ b/Engine.Core/BehaviourController.cs @@ -124,12 +124,14 @@ public class BehaviourController : IBehaviourController OnBehaviourRemoved?.Invoke(this, behaviour); } + protected virtual void OnAssign(IHierarchyObject hierarchyObject) { } public bool Assign(IHierarchyObject hierarchyObject) { if (HierarchyObject is not null && HierarchyObject.IsInitialized) return false; _hierarchyObject = hierarchyObject; + OnAssign(hierarchyObject); OnHierarchyObjectAssigned?.Invoke(this); return true; } diff --git a/Engine.Core/Factory/BehaviourFactory.cs b/Engine.Core/Factory/BehaviourFactory.cs index 7191d1f..23bf214 100644 --- a/Engine.Core/Factory/BehaviourFactory.cs +++ b/Engine.Core/Factory/BehaviourFactory.cs @@ -17,10 +17,10 @@ public class BehaviourFactory if (!stateEnable.Assign(behaviour)) throw AssignException.From(stateEnable, behaviour); - if (!behaviour.Assign(hierarchyObject.BehaviourController)) - throw AssignException.From(behaviour, hierarchyObject.BehaviourController); if (!behaviour.Assign(stateEnable)) throw AssignException.From(behaviour, stateEnable); + if (!behaviour.Assign(hierarchyObject.BehaviourController)) + throw AssignException.From(behaviour, hierarchyObject.BehaviourController); return behaviour; } diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs index 8247e76..b25bb26 100644 --- a/Engine.Core/HierarchyObject.cs +++ b/Engine.Core/HierarchyObject.cs @@ -15,6 +15,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject public event IHierarchyObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null; public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; public event INameable.NameChangedEventHandler? OnNameChanged = null; + public event IActive.ActiveChangedEventHandler? OnActiveChanged = null; private string _name = nameof(HierarchyObject); private IGameManager _gameManager = null!; @@ -41,6 +42,8 @@ public class HierarchyObject : BaseEntity, IHierarchyObject public IBehaviourController BehaviourController => _behaviourController; + public bool IsActive { get; private set; } = false; + protected virtual void OnEnteringHierarchy(IGameManager gameManager) { } bool IHierarchyObject.EnterHierarchy(IGameManager gameManager) { @@ -48,6 +51,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject return false; _gameManager = gameManager; + UpdateActive(); OnEnteringHierarchy(gameManager); OnEnteredHierarchy?.Invoke(this, gameManager); return true; @@ -75,6 +79,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject { previousParent.RemoveChild(this); previousParent.OnParentChanged -= NotifyChildrenOnParentChange; + previousParent.OnActiveChanged -= OnParentActiveChanged; } Parent = parent; @@ -83,8 +88,10 @@ public class HierarchyObject : BaseEntity, IHierarchyObject { parent.AddChild(this); parent.OnParentChanged += NotifyChildrenOnParentChange; + parent.OnActiveChanged += OnParentActiveChanged; } + UpdateActive(); OnParentChanged?.Invoke(this, previousParent, parent); } @@ -115,16 +122,43 @@ public class HierarchyObject : BaseEntity, IHierarchyObject child.SetParent(this); } + protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) { if (IsInitialized) return false; _behaviourController = behaviourController; + OnAssign(behaviourController); OnBehaviourControllerAssigned?.Invoke(this); return true; } + protected override void OnAssign(IStateEnable stateEnable) + { + base.OnAssign(stateEnable); + + stateEnable.OnEnabledChanged += OnStateEnabledChanged; + } + + private void OnParentActiveChanged(IActive sender, bool previousState) => UpdateActive(); + private void OnStateEnabledChanged(IStateEnable senfder, bool previousState) => UpdateActive(); + + private void UpdateActive() + { + bool previousActive = IsActive; + IsActive = StateEnable.Enabled && (Parent?.IsActive ?? true); + + if (previousActive != IsActive) + OnActiveChanged?.Invoke(this, previousActive); + } + + protected override void UnassignInternal() + { + base.UnassignInternal(); + StateEnable.OnEnabledChanged -= OnStateEnabledChanged; + } + protected override void InitializeInternal() { base.InitializeInternal(); diff --git a/Engine.Core/StateEnable.cs b/Engine.Core/StateEnable.cs index f00391b..1bfa884 100644 --- a/Engine.Core/StateEnable.cs +++ b/Engine.Core/StateEnable.cs @@ -6,7 +6,7 @@ public class StateEnable : IStateEnable { public event IAssignable.UnassignEventHandler? OnUnassigned = null; public event IHasEntity.EntityAssignedEventHandler? OnEntityAssigned = null; - public event IStateEnable.NameChangedEventHandler? OnEnabledChanged = null; + public event IStateEnable.EnabledChangedEventHandler? OnEnabledChanged = null; private bool _enabled = true; private IEntity _entity = null!; @@ -27,12 +27,14 @@ public class StateEnable : IStateEnable } } + protected virtual void OnAssign(IEntity entity) { } public bool Assign(IEntity entity) { if (_entity is not null && _entity.IsInitialized) return false; _entity = entity; + OnAssign(entity); OnEntityAssigned?.Invoke(this); return true; } -- 2.47.1 From c71bf71fb3b1fb21f7fbbf4a5cd8a9944473995c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 13:29:56 +0300 Subject: [PATCH 31/32] chore: cleanup --- Engine.Core/BehaviourBase.cs | 6 +++--- Engine.Core/HierarchyObject.cs | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs index a89f88f..c385ef6 100644 --- a/Engine.Core/BehaviourBase.cs +++ b/Engine.Core/BehaviourBase.cs @@ -11,7 +11,6 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour public event IActive.ActiveChangedEventHandler? OnActiveChanged = null; private IBehaviourController _behaviourController = null!; - public IBehaviourController BehaviourController => _behaviourController; private int _priority = 0; @@ -29,7 +28,8 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour } } - public bool IsActive { get; private set; } = false; + private bool _isActive = false; + public bool IsActive => _isActive; protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) @@ -80,7 +80,7 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour private void UpdateActive() { bool previousActive = IsActive; - IsActive = StateEnable.Enabled && _behaviourController.HierarchyObject.IsActive; + _isActive = StateEnable.Enabled && _behaviourController.HierarchyObject.IsActive; if (previousActive != IsActive) OnActiveChanged?.Invoke(this, previousActive); diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs index b25bb26..2eecd4c 100644 --- a/Engine.Core/HierarchyObject.cs +++ b/Engine.Core/HierarchyObject.cs @@ -20,12 +20,15 @@ public class HierarchyObject : BaseEntity, IHierarchyObject private string _name = nameof(HierarchyObject); private IGameManager _gameManager = null!; private IBehaviourController _behaviourController = null!; + private bool _isActive = false; private readonly List _children = []; public IHierarchyObject? Parent { get; private set; } = null; public IReadOnlyList Children => _children; + public IBehaviourController BehaviourController => _behaviourController; public IGameManager GameManager => _gameManager; public bool IsInHierarchy => _gameManager is not null; + public bool IsActive => _isActive; public string Name { @@ -40,10 +43,6 @@ public class HierarchyObject : BaseEntity, IHierarchyObject } } - public IBehaviourController BehaviourController => _behaviourController; - - public bool IsActive { get; private set; } = false; - protected virtual void OnEnteringHierarchy(IGameManager gameManager) { } bool IHierarchyObject.EnterHierarchy(IGameManager gameManager) { @@ -142,12 +141,12 @@ public class HierarchyObject : BaseEntity, IHierarchyObject } private void OnParentActiveChanged(IActive sender, bool previousState) => UpdateActive(); - private void OnStateEnabledChanged(IStateEnable senfder, bool previousState) => UpdateActive(); + private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive(); private void UpdateActive() { bool previousActive = IsActive; - IsActive = StateEnable.Enabled && (Parent?.IsActive ?? true); + _isActive = StateEnable.Enabled && (Parent?.IsActive ?? true); if (previousActive != IsActive) OnActiveChanged?.Invoke(this, previousActive); -- 2.47.1 From 5756b960027e1025450e5ae7fe4ab290eed2615a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 1 Apr 2025 19:19:06 +0300 Subject: [PATCH 32/32] chore: removed unused code piece from HierarchyObject --- Engine.Core/HierarchyObject.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs index 2eecd4c..93dab51 100644 --- a/Engine.Core/HierarchyObject.cs +++ b/Engine.Core/HierarchyObject.cs @@ -77,7 +77,6 @@ public class HierarchyObject : BaseEntity, IHierarchyObject if (previousParent is not null) { previousParent.RemoveChild(this); - previousParent.OnParentChanged -= NotifyChildrenOnParentChange; previousParent.OnActiveChanged -= OnParentActiveChanged; } @@ -86,7 +85,6 @@ public class HierarchyObject : BaseEntity, IHierarchyObject if (parent is not null) { parent.AddChild(this); - parent.OnParentChanged += NotifyChildrenOnParentChange; parent.OnActiveChanged += OnParentActiveChanged; } @@ -113,14 +111,6 @@ public class HierarchyObject : BaseEntity, IHierarchyObject OnChildrenRemoved?.Invoke(this, parent); } - private void NotifyChildrenOnParentChange(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent) - { - // TODO No idea how logical this is to propagate this to the children the way I'm doing right now. - // I was originally gonna just call `child.OnParentChanged?.Invoke(child, child.parentTransform);` but seems an unnecessary call too? - foreach (IHierarchyObject child in Children) // TODO CHECK ERRORS - child.SetParent(this); - } - protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) { -- 2.47.1