Compare commits
	
		
			80 Commits
		
	
	
		
			breaking-c
			...
			feat/liten
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 05dfb92bab | |||
| 7f169fc788 | |||
| 376f18c43a | |||
| 150deaa618 | |||
| d011bf9a7a | |||
| 19124e733c | |||
| c28568d0cb | |||
| 91d301677f | |||
| 73ae55e1d4 | |||
| a35e25eb31 | |||
| 775f24c560 | |||
| 257e414c2a | |||
| 0cb8170530 | |||
| bbf71f0be6 | |||
| 41a17219b6 | |||
| 29e79cdf26 | |||
| b7a4fe9cb0 | |||
| da83802427 | |||
| 364c383e08 | |||
| 1fd8060857 | |||
| 35933dfd14 | |||
| d66b119119 | |||
| e7ee460323 | |||
| e86cf71010 | |||
| a357f0fdcb | |||
| ff3202eda9 | |||
| 8929d3282f | |||
| bc7925dbab | |||
| 80ee5d760a | |||
| de2d5fb446 | |||
| 753c0031cd | |||
| a734f52b38 | |||
| 4cb9c7dc8d | |||
| fe4618abd3 | |||
| 283556d329 | |||
| 5ef3d491c3 | |||
| 46f589d3aa | |||
| b7d49e41c3 | |||
| 677fec7acc | |||
| a9c7b8b660 | |||
| 958a75552f | |||
| 3717701171 | |||
| 4e95a3a420 | |||
| ad60412d5f | |||
| 0b2158cc7b | |||
| 3580469a07 | |||
| a7e8787579 | |||
| 45df32dabb | |||
| b3af693678 | |||
| c87827d1ef | |||
| c2d2e1fd52 | |||
| 7ad2cc5912 | |||
| ca92b12833 | |||
| fbe3087502 | |||
| ef347320fd | |||
| 1207d04d50 | |||
| 26f11b5cc0 | |||
| 481a49bb52 | |||
| ffe4fc044e | |||
| 91b05c97c4 | |||
| 2f500bef19 | |||
| 7ed6c1e050 | |||
| bd9974f410 | |||
| 42b427f49b | |||
| ef08eedc34 | |||
| 9eed074025 | |||
| 427ab5ed54 | |||
| e252d8fbb2 | |||
| 80c0f4cdd6 | |||
| 91ad13628c | |||
| 76484017e1 | |||
| faf30b8227 | |||
| bf825fd961 | |||
| 6e6475f8bf | |||
| 5b484eb38c | |||
| 04653711e9 | |||
| 40903eacc3 | |||
| a70a934b3d | |||
| 8ea76f91f6 | |||
| 11074b89d5 | 
							
								
								
									
										46
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
{
 | 
			
		||||
  // Use IntelliSense to learn about possible attributes.
 | 
			
		||||
  // Hover to view descriptions of existing attributes.
 | 
			
		||||
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 | 
			
		||||
  "version": "0.2.0",
 | 
			
		||||
  "configurations": [
 | 
			
		||||
    {
 | 
			
		||||
      "name": "Start Client",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "preLaunchTask": "build",
 | 
			
		||||
      // If you have changed target frameworks, make sure to update the program path.
 | 
			
		||||
      "program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
 | 
			
		||||
      "args": ["127.0.0.1"],
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
      // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
 | 
			
		||||
      "console": "internalConsole",
 | 
			
		||||
      "stopAtEntry": false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Core Attach",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "attach",
 | 
			
		||||
      "processId": "${command:pickProcess}"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": "Start Server",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "preLaunchTask": "build",
 | 
			
		||||
      // If you have changed target frameworks, make sure to update the program path.
 | 
			
		||||
      "program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
 | 
			
		||||
      "args": ["server"],
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
      // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
 | 
			
		||||
      "console": "internalConsole",
 | 
			
		||||
      "stopAtEntry": false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Core Attach",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "attach",
 | 
			
		||||
      "processId": "${command:pickProcess}"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								Engine
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								Engine
									
									
									
									
									
								
							 Submodule Engine updated: d08495afbb...ef21cdf213
									
								
							
							
								
								
									
										27
									
								
								Game/.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								Game/.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							@@ -1,27 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  // Use IntelliSense to learn about possible attributes.
 | 
			
		||||
  // Hover to view descriptions of existing attributes.
 | 
			
		||||
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 | 
			
		||||
  "version": "0.2.0",
 | 
			
		||||
  "configurations": [
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Core Launch (console)",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "preLaunchTask": "build",
 | 
			
		||||
      // If you have changed target frameworks, make sure to update the program path.
 | 
			
		||||
      "program": "${workspaceFolder}/bin/Debug/net8.0/${workspaceFolderBasename}.dll",
 | 
			
		||||
      "args": [],
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
      // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
 | 
			
		||||
      "console": "internalConsole",
 | 
			
		||||
      "stopAtEntry": false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Core Attach",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "attach",
 | 
			
		||||
      "processId": "${command:pickProcess}"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
using Apos.Shapes;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IDisplayableShape
 | 
			
		||||
{
 | 
			
		||||
    void Draw(ShapeBatch shapeBatch);
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@ using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IDisplayable
 | 
			
		||||
public interface IDisplayableSprite
 | 
			
		||||
{
 | 
			
		||||
    public void Draw(SpriteBatch spriteBatch);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class BallBehaviour : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
 | 
			
		||||
    public float Speed { get; set; } = 500f;
 | 
			
		||||
    public float SpeedUpMultiplier { get; set; } = .0125f;
 | 
			
		||||
 | 
			
		||||
    private readonly Random random = new();
 | 
			
		||||
    private IRigidBody2D rigidBody = null!;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody))
 | 
			
		||||
            throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}.");
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider))
 | 
			
		||||
            throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}.");
 | 
			
		||||
 | 
			
		||||
        foundCollider.OnCollisionDetected += OnCollisionDetected;
 | 
			
		||||
 | 
			
		||||
        rigidBody = foundRigidBody;
 | 
			
		||||
 | 
			
		||||
        if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager))
 | 
			
		||||
        {
 | 
			
		||||
            pongManager.OnReset += ResetBall;
 | 
			
		||||
            pongManager.OnScored += ResetBall;
 | 
			
		||||
            pongManager.OnFinished += DisableBall;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void DisableBall(PongManagerBehaviour pongManager)
 | 
			
		||||
    {
 | 
			
		||||
        BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
 | 
			
		||||
        rigidBody.Velocity = Vector2D.Zero;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void ResetBall(PongManagerBehaviour pongManager)
 | 
			
		||||
    {
 | 
			
		||||
        StateEnable.Enabled = true;
 | 
			
		||||
        BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
 | 
			
		||||
        rigidBody.Velocity = GetRandomDirection() * Speed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Vector2D GetRandomDirection()
 | 
			
		||||
    {
 | 
			
		||||
        const float AllowedRadians = 45f * Syntriax.Engine.Core.Math.DegreeToRadian;
 | 
			
		||||
        float rotation = (float)random.NextDouble() * 2f * AllowedRadians - AllowedRadians;
 | 
			
		||||
        bool isBackwards = (random.Next() % 2) == 1;
 | 
			
		||||
        return Vector2D.Right.Rotate(isBackwards ? rotation + Syntriax.Engine.Core.Math.PI : rotation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (rigidBody.Velocity.MagnitudeSquared <= 0.01f)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame;
 | 
			
		||||
        rigidBody.Velocity += speedUp * SpeedUpMultiplier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information)
 | 
			
		||||
    {
 | 
			
		||||
        if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25)
 | 
			
		||||
            rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
 | 
			
		||||
        else
 | 
			
		||||
            rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BallBehaviour() { }
 | 
			
		||||
    public BallBehaviour(Vector2D startDirection, float speed)
 | 
			
		||||
    {
 | 
			
		||||
        StartDirection = Vector2D.Normalize(startDirection);
 | 
			
		||||
        Speed = speed;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class CameraController : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    private MonoGameCamera2DBehaviour cameraBehaviour = null!;
 | 
			
		||||
    private IButtonInputs<Keys> buttonInputs = null!;
 | 
			
		||||
 | 
			
		||||
    private float defaultZoomLevel = 1f;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (BehaviourController.TryGetBehaviour(out MonoGameCamera2DBehaviour? foundCameraBehaviour))
 | 
			
		||||
            cameraBehaviour = foundCameraBehaviour;
 | 
			
		||||
 | 
			
		||||
        cameraBehaviour ??= BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>();
 | 
			
		||||
 | 
			
		||||
        if (BehaviourController.TryGetBehaviour(out IButtonInputs<Keys>? foundButtonInputs))
 | 
			
		||||
            buttonInputs = foundButtonInputs;
 | 
			
		||||
 | 
			
		||||
        buttonInputs ??= BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
        buttonInputs.RegisterOnPress(Keys.F, SwitchToFullScreen);
 | 
			
		||||
        buttonInputs.RegisterOnPress(Keys.R, ResetCamera);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.U))
 | 
			
		||||
            cameraBehaviour.Zoom += Time.Elapsed.Nanoseconds * 0.00025f;
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.J))
 | 
			
		||||
            cameraBehaviour.Zoom -= Time.Elapsed.Nanoseconds * 0.00025f;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame;
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.NumPad2)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame;
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.NumPad6)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame;
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.Q))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += Time.Elapsed.Nanoseconds * 0.0025f;
 | 
			
		||||
        if (buttonInputs.IsPressed(Keys.E))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= Time.Elapsed.Nanoseconds * 0.0025f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void SwitchToFullScreen(IButtonInputs<Keys> inputs, Keys keys)
 | 
			
		||||
    {
 | 
			
		||||
        if (cameraBehaviour.Graphics.IsFullScreen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        cameraBehaviour.Graphics.PreferMultiSampling = false;
 | 
			
		||||
        cameraBehaviour.Graphics.PreferredBackBufferWidth = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Width;
 | 
			
		||||
        cameraBehaviour.Graphics.PreferredBackBufferHeight = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Height;
 | 
			
		||||
        cameraBehaviour.Graphics.IsFullScreen = true;
 | 
			
		||||
        cameraBehaviour.Graphics.ApplyChanges();
 | 
			
		||||
 | 
			
		||||
        float previousScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Viewport.Width) + Math.Sqr(cameraBehaviour.Viewport.Height));
 | 
			
		||||
        float currentScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Width) + Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Height));
 | 
			
		||||
        defaultZoomLevel /= previousScreenSize / currentScreenSize;
 | 
			
		||||
        cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize;
 | 
			
		||||
        cameraBehaviour.Viewport = cameraBehaviour.Graphics.GraphicsDevice.Viewport;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void ResetCamera(IButtonInputs<Keys> inputs, Keys keys)
 | 
			
		||||
    {
 | 
			
		||||
        cameraBehaviour.Zoom = defaultZoomLevel;
 | 
			
		||||
        Transform.Position = Vector2D.Zero;
 | 
			
		||||
        Transform.Rotation = 0f;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Apos.Shapes;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class CircleBehaviour : Syntriax.Engine.Physics2D.Collider2DCircleBehaviour, IDisplayableShape
 | 
			
		||||
{
 | 
			
		||||
    public Color Color { get; set; } = Color.White;
 | 
			
		||||
    public float Thickness { get; set; } = .5f;
 | 
			
		||||
 | 
			
		||||
    public void Draw(ShapeBatch shapeBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!IsActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Recalculate();
 | 
			
		||||
 | 
			
		||||
        shapeBatch.BorderCircle(CircleWorld.Center.ToDisplayVector2(), CircleWorld.Radius, Color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CircleBehaviour(Circle circle) : base(circle) { }
 | 
			
		||||
    public CircleBehaviour(Circle circle, float thickness) : base(circle) { Thickness = thickness; }
 | 
			
		||||
    public CircleBehaviour(Circle circle, Color color) : base(circle) { Color = color; }
 | 
			
		||||
    public CircleBehaviour(Circle circle, Color color, float thickness) : base(circle) { Thickness = thickness; Color = color; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D
 | 
			
		||||
{
 | 
			
		||||
    public event OnMatrixTransformChangedDelegate? OnMatrixTransformChanged = null;
 | 
			
		||||
    public event OnViewportChangedDelegate? OnViewportChanged = null;
 | 
			
		||||
    public event OnZoomChangedDelegate? OnZoomChanged = null;
 | 
			
		||||
 | 
			
		||||
    private Matrix _matrixTransform = Matrix.Identity;
 | 
			
		||||
 | 
			
		||||
    private Viewport _viewport = default;
 | 
			
		||||
    private float _zoom = 1f;
 | 
			
		||||
 | 
			
		||||
    public GraphicsDeviceManager Graphics { get; } = Graphics;
 | 
			
		||||
 | 
			
		||||
    public Matrix MatrixTransform
 | 
			
		||||
    {
 | 
			
		||||
        get => _matrixTransform;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_matrixTransform == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _matrixTransform = value;
 | 
			
		||||
            OnMatrixTransformChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Position
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Position;
 | 
			
		||||
        set => Transform.Position = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Viewport Viewport
 | 
			
		||||
    {
 | 
			
		||||
        get => _viewport;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_viewport.Equals(value))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _viewport = value;
 | 
			
		||||
            OnViewportChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Zoom
 | 
			
		||||
    {
 | 
			
		||||
        get => _zoom;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            float newValue = Math.Max(0.1f, value);
 | 
			
		||||
 | 
			
		||||
            if (_zoom == newValue)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _zoom = newValue;
 | 
			
		||||
            OnZoomChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Rotation
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Rotation;
 | 
			
		||||
        set => Transform.Rotation = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public event IAssignableTransform.OnTransformAssignedDelegate? OnTransformAssigned { add => GameObject.OnTransformAssigned += value; remove => GameObject.OnTransformAssigned -= value; }
 | 
			
		||||
    ITransform IAssignableTransform.Transform => GameObject.Transform;
 | 
			
		||||
    bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
 | 
			
		||||
    // TODO This causes delay since OnPreDraw calls assuming this is called in in Update 
 | 
			
		||||
    public Vector2D ScreenToWorldPosition(Vector2D screenPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D();
 | 
			
		||||
        return worldPosition.Scale(EngineConverter.screenScale);
 | 
			
		||||
    }
 | 
			
		||||
    public Vector2D WorldToScreenPosition(Vector2D worldPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D();
 | 
			
		||||
        return screenPosition.Scale(EngineConverter.screenScale);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
        => Viewport = Graphics.GraphicsDevice.Viewport;
 | 
			
		||||
 | 
			
		||||
    protected override void OnPreDraw()
 | 
			
		||||
    {
 | 
			
		||||
        MatrixTransform =
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) *
 | 
			
		||||
            Matrix.CreateRotationZ(Rotation * Math.DegreeToRadian) *
 | 
			
		||||
            Matrix.CreateScale(Zoom) *
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void OnMatrixTransformChangedDelegate(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
    public delegate void OnViewportChangedDelegate(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
    public delegate void OnZoomChangedDelegate(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,106 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class MonoGameCameraBehaviour : BehaviourOverride, ICamera
 | 
			
		||||
{
 | 
			
		||||
    public Action<ICamera>? OnPositionChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnMatrixTransformChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnViewportChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnRotationChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnZoomChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private Matrix _matrixTransform = Matrix.Identity;
 | 
			
		||||
 | 
			
		||||
    private Viewport _viewport = default;
 | 
			
		||||
 | 
			
		||||
    private float _zoom = 1f;
 | 
			
		||||
 | 
			
		||||
    public Matrix MatrixTransform
 | 
			
		||||
    {
 | 
			
		||||
        get => _matrixTransform;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_matrixTransform == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _matrixTransform = value;
 | 
			
		||||
            OnMatrixTransformChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Position
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Position;
 | 
			
		||||
        set => Transform.Position = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Viewport Viewport
 | 
			
		||||
    {
 | 
			
		||||
        get => _viewport;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_viewport.Equals(value))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _viewport = value;
 | 
			
		||||
            OnViewportChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Zoom
 | 
			
		||||
    {
 | 
			
		||||
        get => _zoom;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            float newValue = value >= .1f ? value : .1f;
 | 
			
		||||
 | 
			
		||||
            if (_zoom == newValue)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _zoom = newValue;
 | 
			
		||||
            OnZoomChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Rotation
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Rotation;
 | 
			
		||||
        set => Transform.Rotation = value;
 | 
			
		||||
    }
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
 | 
			
		||||
 | 
			
		||||
    ITransform IAssignableTransform.Transform => throw new NotImplementedException();
 | 
			
		||||
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        MatrixTransform =
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) *
 | 
			
		||||
            Matrix.CreateRotationZ(Rotation) *
 | 
			
		||||
            Matrix.CreateScale(Zoom) *
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        Transform.OnRotationChanged += OnTransformRotationChanged;
 | 
			
		||||
        Transform.OnPositionChanged += OnTransformPositionChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        Transform.OnRotationChanged -= OnTransformRotationChanged;
 | 
			
		||||
        Transform.OnPositionChanged -= OnTransformPositionChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnTransformRotationChanged(ITransform _) => OnRotationChanged?.Invoke(this);
 | 
			
		||||
    private void OnTransformPositionChanged(ITransform _) => OnPositionChanged?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +1,53 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
public class MovementBallBehaviour(Vector2D StartDirection, float Speed) : BehaviourOverride
 | 
			
		||||
 | 
			
		||||
public class MovementBallBehaviour : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Vector2D StartDirection { get; private set; } = Vector2D.Normalize(StartDirection);
 | 
			
		||||
    public float Speed { get; set; } = Speed;
 | 
			
		||||
    public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
 | 
			
		||||
    public float Speed { get; set; } = 500f;
 | 
			
		||||
    public float SpeedUpMultiplier { get; set; } = .0125f;
 | 
			
		||||
 | 
			
		||||
    private IRigidBody2D rigidBody = null!;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidBody))
 | 
			
		||||
            throw new Exception($"Where's my {nameof(IRigidBody2D)}????");
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody))
 | 
			
		||||
            throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}.");
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider))
 | 
			
		||||
            throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}.");
 | 
			
		||||
 | 
			
		||||
        rigidBody.Velocity = StartDirection * Speed;
 | 
			
		||||
        foundRigidBody.Velocity = StartDirection * Speed;
 | 
			
		||||
        foundCollider.OnCollisionDetected += OnCollisionDetected;
 | 
			
		||||
 | 
			
		||||
        rigidBody = foundRigidBody;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protected override void OnUpdate(GameTime time)
 | 
			
		||||
    // {
 | 
			
		||||
    //     GameObject.Transform.Position += StartDirection * (time.ElapsedGameTime.Nanoseconds * .001f) * Speed;
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (rigidBody.Velocity.MagnitudeSquared <= 0.01f)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
    //     float absY = MathF.Abs(GameObject.Transform.Position.Y);
 | 
			
		||||
    //     float differenceY = absY - PlayAreaBehaviour.PlayArea.Y * 0.5f;
 | 
			
		||||
    //     if (differenceY > 0f)
 | 
			
		||||
    //     {
 | 
			
		||||
    //         if (GameObject.Transform.Position.Y > 0f)
 | 
			
		||||
    //             GameObject.Transform.Position -= Vector2.UnitY * differenceY * 2f;
 | 
			
		||||
    //         else
 | 
			
		||||
    //             GameObject.Transform.Position += Vector2.UnitY * differenceY * 2f;
 | 
			
		||||
        Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame;
 | 
			
		||||
        rigidBody.Velocity += speedUp * SpeedUpMultiplier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //         StartDirection = new(StartDirection.X, -StartDirection.Y);
 | 
			
		||||
    //     }
 | 
			
		||||
    private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information)
 | 
			
		||||
    {
 | 
			
		||||
        if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25)
 | 
			
		||||
            rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
 | 
			
		||||
        else
 | 
			
		||||
            rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //     float absX = MathF.Abs(GameObject.Transform.Position.X);
 | 
			
		||||
    //     float differenceX = absX - PlayAreaBehaviour.PlayArea.X * 0.5f;
 | 
			
		||||
    //     if (differenceX > 0f)
 | 
			
		||||
    //     {
 | 
			
		||||
    //         if (GameObject.Transform.Position.X > 0f)
 | 
			
		||||
    //             GameObject.Transform.Position -= Vector2.UnitX * differenceX * 2f;
 | 
			
		||||
    //         else
 | 
			
		||||
    //             GameObject.Transform.Position += Vector2.UnitX * differenceX * 2f;
 | 
			
		||||
 | 
			
		||||
    //         StartDirection = new(-StartDirection.X, StartDirection.Y);
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
    public MovementBallBehaviour() { }
 | 
			
		||||
    public MovementBallBehaviour(Vector2D startDirection, float speed)
 | 
			
		||||
    {
 | 
			
		||||
        StartDirection = Vector2D.Normalize(startDirection);
 | 
			
		||||
        Speed = speed;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class MovementBoxBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    private Keys Up { get; } = Up;
 | 
			
		||||
    private Keys Down { get; } = Down;
 | 
			
		||||
    public float High { get; } = High;
 | 
			
		||||
    public float Low { get; } = Low;
 | 
			
		||||
    public float Speed { get; set; } = Speed;
 | 
			
		||||
 | 
			
		||||
    private bool isUpPressed = false;
 | 
			
		||||
    private bool isDownPressed = false;
 | 
			
		||||
 | 
			
		||||
    private IButtonInputs<Keys> inputs = null!;
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (isUpPressed && isDownPressed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (isUpPressed)
 | 
			
		||||
            GameObject.Transform.Position = GameObject.Transform.Position + Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
 | 
			
		||||
        else if (isDownPressed)
 | 
			
		||||
            GameObject.Transform.Position = GameObject.Transform.Position + -Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
 | 
			
		||||
 | 
			
		||||
        GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult))
 | 
			
		||||
            throw new Exception($"{nameof(IButtonInputs<Keys>)} is missing on ${GameObject.Name}.");
 | 
			
		||||
 | 
			
		||||
        inputs = behaviourResult;
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        inputs.UnregisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.UnregisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = true;
 | 
			
		||||
    private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = false;
 | 
			
		||||
    private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = true;
 | 
			
		||||
    private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
using System;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
using Syntriax.Engine.Network;
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : NetworkBehaviour
 | 
			
		||||
{
 | 
			
		||||
    private Keys Up { get; } = Up;
 | 
			
		||||
    private Keys Down { get; } = Down;
 | 
			
		||||
    public float High { get; } = High;
 | 
			
		||||
    public float Low { get; } = Low;
 | 
			
		||||
    public float Speed { get; set; } = Speed;
 | 
			
		||||
 | 
			
		||||
    private bool isUpPressed = false;
 | 
			
		||||
    private bool isDownPressed = false;
 | 
			
		||||
 | 
			
		||||
    private IButtonInputs<Keys> inputs = null!;
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (isUpPressed && isDownPressed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (isUpPressed)
 | 
			
		||||
            Move(Vector2D.Up);
 | 
			
		||||
        else if (isDownPressed)
 | 
			
		||||
            Move(-Vector2D.Up);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void Move(Vector2D vectorToMove)
 | 
			
		||||
    {
 | 
			
		||||
        GameObject.Transform.Position = GameObject.Transform.Position + vectorToMove * (float)Time.Elapsed.TotalSeconds * Speed;
 | 
			
		||||
        GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult))
 | 
			
		||||
            inputs = behaviourResult ?? BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        inputs.UnregisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.UnregisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = true; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
 | 
			
		||||
    private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = false; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
 | 
			
		||||
    private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = true; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
 | 
			
		||||
    private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = false; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
 | 
			
		||||
 | 
			
		||||
    public override void ReceiveData<T>(T data)
 | 
			
		||||
    {
 | 
			
		||||
        if (data is not PaddleInputs paddleInputs)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Transform.Position = new(Transform.Position.X, paddleInputs.PositionY);
 | 
			
		||||
        isUpPressed = paddleInputs.IsUpPressed;
 | 
			
		||||
        isDownPressed = paddleInputs.IsDownPressed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [System.Serializable]
 | 
			
		||||
    public struct PaddleInputs : INetworkPacket
 | 
			
		||||
    {
 | 
			
		||||
        public float PositionY { get; set; }
 | 
			
		||||
        public bool IsUpPressed { get; set; }
 | 
			
		||||
        public bool IsDownPressed { get; set; }
 | 
			
		||||
 | 
			
		||||
        public void Deserialize(NetDataReader reader)
 | 
			
		||||
        {
 | 
			
		||||
            PositionY = reader.GetFloat();
 | 
			
		||||
            IsUpPressed = reader.GetBool();
 | 
			
		||||
            IsDownPressed = reader.GetBool();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Serialize(NetDataWriter writer)
 | 
			
		||||
        {
 | 
			
		||||
            writer.Put(PositionY);
 | 
			
		||||
            writer.Put(IsUpPressed);
 | 
			
		||||
            writer.Put(IsDownPressed);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class PlayAreaBehaviour : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Action<PlayAreaBehaviour>? OnPlayAreaChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private Vector2 _playArea = Vector2.Zero;
 | 
			
		||||
 | 
			
		||||
    public Vector2 PlayArea
 | 
			
		||||
    {
 | 
			
		||||
        get => _playArea;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_playArea == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _playArea = value;
 | 
			
		||||
            OnPlayAreaChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class PongManagerBehaviour : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Action<PongManagerBehaviour>? OnReset { get; set; } = null;
 | 
			
		||||
    public Action<PongManagerBehaviour>? OnFinished { get; set; } = null;
 | 
			
		||||
    public Action<PongManagerBehaviour>? OnScored { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    public int ScoreLeft { get; private set; } = 0;
 | 
			
		||||
    public int ScoreRight { get; private set; } = 0;
 | 
			
		||||
    public int ScoreSum => ScoreLeft + ScoreRight;
 | 
			
		||||
 | 
			
		||||
    public int WinScore { get; } = 5;
 | 
			
		||||
 | 
			
		||||
    public PongManagerBehaviour() => WinScore = 5;
 | 
			
		||||
    public PongManagerBehaviour(int winScore) => WinScore = winScore;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        KeyboardInputsBehaviour? buttonInputs = null!;
 | 
			
		||||
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out buttonInputs))
 | 
			
		||||
            buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
 | 
			
		||||
        buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void ScoreToLeft()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreLeft++;
 | 
			
		||||
        OnScored?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
        CheckFinish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void ScoreToRight()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreRight++;
 | 
			
		||||
        OnScored?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
        CheckFinish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Reset()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreLeft = ScoreRight = 0;
 | 
			
		||||
        OnReset?.Invoke(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void CheckFinish()
 | 
			
		||||
    {
 | 
			
		||||
        int halfwayScore = (int)(WinScore * .5f);
 | 
			
		||||
 | 
			
		||||
        if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
 | 
			
		||||
            OnFinished?.Invoke(this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Apos.Shapes;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape
 | 
			
		||||
{
 | 
			
		||||
    private IShapeCollider2D? shapeCollider = null;
 | 
			
		||||
 | 
			
		||||
    public Color Color { get; set; } = Color.White;
 | 
			
		||||
    public float Thickness { get; set; } = .5f;
 | 
			
		||||
    public bool display = true;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        BehaviourController.TryGetBehaviour(out shapeCollider);
 | 
			
		||||
 | 
			
		||||
        if (BehaviourController.TryGetBehaviour(out IButtonInputs<Microsoft.Xna.Framework.Input.Keys>? keys))
 | 
			
		||||
            keys.RegisterOnPress(Microsoft.Xna.Framework.Input.Keys.D, (_1, _2) => display = !display);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw(ShapeBatch shapeBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!display)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (shapeCollider is null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        AABB aabb = AABB.FromVectors(shapeCollider.ShapeWorld);
 | 
			
		||||
 | 
			
		||||
        shapeBatch.BorderCircle(aabb.Center.ToDisplayVector2(), 7.5f, Color.Beige);
 | 
			
		||||
 | 
			
		||||
        shapeBatch.DrawRectangle(aabb.Center.ApplyDisplayScale().Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ShapeAABBBehaviour() { }
 | 
			
		||||
    public ShapeAABBBehaviour(float Thickness) { this.Thickness = Thickness; }
 | 
			
		||||
    public ShapeAABBBehaviour(Color color) { Color = color; }
 | 
			
		||||
    public ShapeAABBBehaviour(Color color, float Thickness) { this.Thickness = Thickness; Color = color; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Apos.Shapes;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour, IDisplayableShape
 | 
			
		||||
{
 | 
			
		||||
    public Color Color { get; set; } = Color.White;
 | 
			
		||||
    public float Thickness { get; set; } = .5f;
 | 
			
		||||
 | 
			
		||||
    public void Draw(ShapeBatch shapeBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!IsActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Recalculate();
 | 
			
		||||
 | 
			
		||||
        int count = ShapeWorld.Vertices.Count;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < count - 1; i++)
 | 
			
		||||
            shapeBatch.DrawLine(ShapeWorld[i].ToDisplayVector2(), ShapeWorld[i + 1].ToDisplayVector2(), Thickness, Color, Color);
 | 
			
		||||
        shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ShapeBehaviour(Shape shape) : base(shape) { }
 | 
			
		||||
    public ShapeBehaviour(Shape shape, float thickness) : base(shape) { Thickness = thickness; }
 | 
			
		||||
    public ShapeBehaviour(Shape shape, Color color) : base(shape) { Color = color; }
 | 
			
		||||
    public ShapeBehaviour(Shape shape, Color color, float thickness) : base(shape) { Thickness = thickness; Color = color; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class TextBehaviour : BehaviourOverride, IDisplayableSprite
 | 
			
		||||
{
 | 
			
		||||
    public SpriteFont? Font { get; set; } = null;
 | 
			
		||||
    public int Size { get; set; } = 16;
 | 
			
		||||
    public string Text { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    public void Draw(SpriteBatch spriteBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!IsActive || Font is null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        spriteBatch.DrawString(Font, Text, Transform.Position.ToDisplayVector2(), Color.White, Transform.Rotation, Vector2.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public TextBehaviour() { }
 | 
			
		||||
    public TextBehaviour(SpriteFont font) => Font = font;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class TextScoreBehaviour : TextBehaviour
 | 
			
		||||
{
 | 
			
		||||
    public bool IsLeft { get; }
 | 
			
		||||
 | 
			
		||||
    private PongManagerBehaviour? pongManager = null;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!GameObject.GameManager.TryFindBehaviour(out pongManager))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        pongManager.OnScored += UpdateScores;
 | 
			
		||||
        pongManager.OnReset += UpdateScores;
 | 
			
		||||
 | 
			
		||||
        UpdateScores(pongManager);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void UpdateScores(PongManagerBehaviour pongManager)
 | 
			
		||||
    {
 | 
			
		||||
        if (IsLeft)
 | 
			
		||||
            Text = pongManager.ScoreLeft.ToString();
 | 
			
		||||
        else
 | 
			
		||||
            Text = pongManager.ScoreRight.ToString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public TextScoreBehaviour(bool IsLeft) => this.IsLeft = IsLeft;
 | 
			
		||||
    public TextScoreBehaviour(bool IsLeft, SpriteFont font) : base(font) => this.IsLeft = IsLeft;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class WallScoreBehaviour(Action OnCollision) : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    private Action OnCollision { get; } = OnCollision;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        collider2D.OnCollisionDetected += (_, _1) => OnCollision?.Invoke();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,51 +13,10 @@
 | 
			
		||||
 | 
			
		||||
#---------------------------------- Content ---------------------------------#
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Circle.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
#begin UbuntuMono.spritefont
 | 
			
		||||
/importer:FontDescriptionImporter
 | 
			
		||||
/processor:FontDescriptionProcessor
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Circle.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Circle.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Circle.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Pixel.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Pixel.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Pixel.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Pixel.png
 | 
			
		||||
/processorParam:TextureFormat=Compressed
 | 
			
		||||
/build:UbuntuMono.spritefont
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 3.6 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 546 B  | 
							
								
								
									
										60
									
								
								Game/Content/UbuntuMono.spritefont
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								Game/Content/UbuntuMono.spritefont
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
This file contains an xml description of a font, and will be read by the XNA
 | 
			
		||||
Framework Content Pipeline. Follow the comments to customize the appearance
 | 
			
		||||
of the font in your game, and to change the characters which are available to draw
 | 
			
		||||
with.
 | 
			
		||||
-->
 | 
			
		||||
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
 | 
			
		||||
  <Asset Type="Graphics:FontDescription">
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Modify this string to change the font that will be imported.
 | 
			
		||||
    -->
 | 
			
		||||
    <FontName>Ubuntu Mono</FontName>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Size is a float value, measured in points. Modify this value to change
 | 
			
		||||
    the size of the font.
 | 
			
		||||
    -->
 | 
			
		||||
    <Size>144</Size>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Spacing is a float value, measured in pixels. Modify this value to change
 | 
			
		||||
    the amount of spacing in between characters.
 | 
			
		||||
    -->
 | 
			
		||||
    <Spacing>0</Spacing>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    UseKerning controls the layout of the font. If this value is true, kerning information
 | 
			
		||||
    will be used when placing characters.
 | 
			
		||||
    -->
 | 
			
		||||
    <UseKerning>true</UseKerning>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
 | 
			
		||||
    and "Bold, Italic", and are case sensitive.
 | 
			
		||||
    -->
 | 
			
		||||
    <Style>Bold</Style>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    If you uncomment this line, the default character will be substituted if you draw
 | 
			
		||||
    or measure text that contains characters which were not included in the font.
 | 
			
		||||
    -->
 | 
			
		||||
    <!-- <DefaultCharacter>*</DefaultCharacter> -->
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    CharacterRegions control what letters are available in the font. Every
 | 
			
		||||
    character from Start to End will be built and made available for drawing. The
 | 
			
		||||
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
 | 
			
		||||
    character set. The characters are ordered according to the Unicode standard.
 | 
			
		||||
    See the documentation for more information.
 | 
			
		||||
    -->
 | 
			
		||||
    <CharacterRegions>
 | 
			
		||||
      <CharacterRegion>
 | 
			
		||||
        <Start> </Start>
 | 
			
		||||
        <End>~</End>
 | 
			
		||||
      </CharacterRegion>
 | 
			
		||||
    </CharacterRegions>
 | 
			
		||||
  </Asset>
 | 
			
		||||
</XnaContent>
 | 
			
		||||
@@ -6,10 +6,18 @@ namespace Pong;
 | 
			
		||||
 | 
			
		||||
public static class EngineConverter
 | 
			
		||||
{
 | 
			
		||||
    public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right;
 | 
			
		||||
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2();
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,12 +20,15 @@
 | 
			
		||||
    <EmbeddedResource Include="Icon.bmp" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Apos.Shapes" Version="0.2.3" />
 | 
			
		||||
    <PackageReference Include="LiteNetLib" Version="1.2.0" />
 | 
			
		||||
    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
 | 
			
		||||
    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Engine\Engine.Core\Engine.Core.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Engine\Engine.Input\Engine.Input.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Engine\Engine.Physics2D\Engine.Physics2D.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Target Name="RestoreDotnetTools" BeforeTargets="Restore">
 | 
			
		||||
    <Message Text="Restoring dotnet tools" Importance="High" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 17
 | 
			
		||||
VisualStudioVersion = 17.5.002.0
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{42644486-9F9E-4242-B6C4-AF31BBFA31D2}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "..\Engine\Engine.Core\Engine.Core.csproj", "{EF1FE4A2-40DF-4967-8003-CF6D98010D02}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {AB3225EE-1621-439F-8F83-DF4515922FEF}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
							
								
								
									
										244
									
								
								Game/Game1.cs
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								Game/Game1.cs
									
									
									
									
									
								
							@@ -1,244 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Graphics.TwoDimensional;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong;
 | 
			
		||||
 | 
			
		||||
public class Game1 : Game
 | 
			
		||||
{
 | 
			
		||||
    private GraphicsDeviceManager _graphics = null!;
 | 
			
		||||
    private PhysicsEngine2D engine;
 | 
			
		||||
    private SpriteBatch _spriteBatch = null!;
 | 
			
		||||
    public static GameManager gameManager = null!;
 | 
			
		||||
    public static Sprite spriteBox = null!;
 | 
			
		||||
    private MonoGameCameraBehaviour cameraBehaviour = null!;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public Game1()
 | 
			
		||||
    {
 | 
			
		||||
        engine = new PhysicsEngine2D();
 | 
			
		||||
 | 
			
		||||
        _graphics = new GraphicsDeviceManager(this)
 | 
			
		||||
        {
 | 
			
		||||
            PreferredBackBufferWidth = 1024,
 | 
			
		||||
            PreferredBackBufferHeight = 576
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Content.RootDirectory = "Content";
 | 
			
		||||
        IsMouseVisible = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Initialize()
 | 
			
		||||
    {
 | 
			
		||||
        gameManager = new();
 | 
			
		||||
 | 
			
		||||
        // TODO: Add your initialization logic here
 | 
			
		||||
        gameManager.Initialize();
 | 
			
		||||
 | 
			
		||||
        base.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void LoadContent()
 | 
			
		||||
    {
 | 
			
		||||
        _spriteBatch = new SpriteBatch(GraphicsDevice);
 | 
			
		||||
 | 
			
		||||
        spriteBox = new Sprite() { Texture2D = Content.Load<Texture2D>("Sprites/Pixel") };
 | 
			
		||||
        Sprite spriteBall = new Sprite() { Texture2D = Content.Load<Texture2D>("Sprites/Circle") };
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectCamera = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        gameObjectCamera.Name = "Camera";
 | 
			
		||||
        gameObjectCamera.Transform.Position = Vector2D.Zero;
 | 
			
		||||
 | 
			
		||||
        cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCameraBehaviour>();
 | 
			
		||||
        cameraBehaviour.Viewport = GraphicsDevice.Viewport;
 | 
			
		||||
        gameManager.Camera = cameraBehaviour;
 | 
			
		||||
 | 
			
		||||
        GameObject gameObjectBall = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        gameObjectBall.Name = "Ball";
 | 
			
		||||
        gameObjectBall.Transform.Position = Vector2D.Zero;
 | 
			
		||||
        gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f);
 | 
			
		||||
        engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<MovementBallBehaviour>(new Vector2D(.1f, .1f), 500f);
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBall);
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f);
 | 
			
		||||
        // gameObjectBall = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectBall.Name = "Ball";
 | 
			
		||||
        // gameObjectBall.Transform.Position = Vector2D.UnitY * 30f;
 | 
			
		||||
        // gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<MovementBallBehaviour>(new Vector2D(.1f, .01f), 500f);
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBall);
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f);
 | 
			
		||||
 | 
			
		||||
        // IGameObject gameObjectLeft = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectLeft.Name = "Left";
 | 
			
		||||
        // gameObjectLeft.Transform.Position = new Vector2D(-452, 0f);
 | 
			
		||||
        // gameObjectLeft.Transform.Scale = new Vector2D(10f, 40f);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<MovementBoxBehaviour>(Keys.W, Keys.S, 268f, -268f, 400f);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        // IGameObject gameObjectRight = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectRight.Name = "Right";
 | 
			
		||||
        // gameObjectRight.Transform.Position = new Vector2D(452, 0f);
 | 
			
		||||
        // gameObjectRight.Transform.Scale = new Vector2D(10f, 40f);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<MovementBoxBehaviour>(Keys.Up, Keys.Down, 268f, -268f, 400f);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        IGameObject goPlayAreaTop = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f);
 | 
			
		||||
        goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f);
 | 
			
		||||
        goPlayAreaTop.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaTop.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f));
 | 
			
		||||
        goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f);
 | 
			
		||||
        goPlayAreaBottom.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaBottom.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        IGameObject goPlayAreaRight = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f);
 | 
			
		||||
        goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f);
 | 
			
		||||
        goPlayAreaRight.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaRight.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f);
 | 
			
		||||
        goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f);
 | 
			
		||||
        goPlayAreaLeft.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaLeft.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // goPlayAreaCenter.Transform.Position = new Vector2D(100f, 100f);
 | 
			
		||||
        // goPlayAreaCenter.Transform.Scale = new Vector2D(40f, 40f);
 | 
			
		||||
        // // goPlayAreaCenter.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        // TODO: use this.Content to load your game content here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Update(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
 | 
			
		||||
            Exit();
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.F))
 | 
			
		||||
        {
 | 
			
		||||
            if (_graphics.IsFullScreen)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _graphics.PreferMultiSampling = false;
 | 
			
		||||
            _graphics.PreferredBackBufferWidth = GraphicsDevice.Adapter.CurrentDisplayMode.Width;
 | 
			
		||||
            _graphics.PreferredBackBufferHeight = GraphicsDevice.Adapter.CurrentDisplayMode.Height;
 | 
			
		||||
            _graphics.IsFullScreen = true;
 | 
			
		||||
            _graphics.ApplyChanges();
 | 
			
		||||
 | 
			
		||||
            float previousScreenSize = MathF.Sqrt(MathF.Pow(cameraBehaviour.Viewport.Width, 2f) + MathF.Pow(cameraBehaviour.Viewport.Height, 2f));
 | 
			
		||||
            float currentScreenSize = MathF.Sqrt(MathF.Pow(GraphicsDevice.Viewport.Width, 2f) + MathF.Pow(GraphicsDevice.Viewport.Height, 2f));
 | 
			
		||||
            cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize;
 | 
			
		||||
            cameraBehaviour.Viewport = GraphicsDevice.Viewport;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.U))
 | 
			
		||||
            cameraBehaviour.Zoom += gameTime.ElapsedGameTime.Nanoseconds * 0.00025f;
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.J))
 | 
			
		||||
            cameraBehaviour.Zoom -= gameTime.ElapsedGameTime.Nanoseconds * 0.00025f;
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.Q))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f;
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.E))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f;
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.N))
 | 
			
		||||
        {
 | 
			
		||||
            seconds = 70f;
 | 
			
		||||
            while (physicsTimer + 0.01f < seconds)
 | 
			
		||||
            {
 | 
			
		||||
                physicsTimer += 0.01f;
 | 
			
		||||
                engine.Step(.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.M))
 | 
			
		||||
        {
 | 
			
		||||
            seconds = 0f;
 | 
			
		||||
            while (physicsTimer - 0.01f > seconds)
 | 
			
		||||
            {
 | 
			
		||||
                physicsTimer -= 0.01f;
 | 
			
		||||
                engine.Step(-.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.Space))
 | 
			
		||||
        {
 | 
			
		||||
            seconds += gameTime.ElapsedGameTime.Milliseconds * .005f;
 | 
			
		||||
            while (physicsTimer + 0.01f < seconds)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
                physicsTimer += 0.01f;
 | 
			
		||||
                engine.Step(.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.B))
 | 
			
		||||
        {
 | 
			
		||||
            seconds -= gameTime.ElapsedGameTime.Milliseconds * .005f;
 | 
			
		||||
            while (physicsTimer - 0.01f > seconds)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
                physicsTimer -= 0.01f;
 | 
			
		||||
                engine.Step(-.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds)
 | 
			
		||||
        // {
 | 
			
		||||
        //     Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
        //     physicsTimer += 0.01f;
 | 
			
		||||
        //     engine.Step(.01f);
 | 
			
		||||
        // }
 | 
			
		||||
        gameManager.Update(gameTime.ToEngineTime());
 | 
			
		||||
        base.Update(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
    static float physicsTimer = 0f;
 | 
			
		||||
    static float seconds = 0f;
 | 
			
		||||
 | 
			
		||||
    protected override void Draw(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 });
 | 
			
		||||
 | 
			
		||||
        // gameManager.Camera.Position = gameObjectBall.Transform.Position;
 | 
			
		||||
        // Console.WriteLine($"Pos: {gameManager.Camera.Position}");
 | 
			
		||||
 | 
			
		||||
        // TODO: Add your drawing code here
 | 
			
		||||
        gameManager.PreDraw();
 | 
			
		||||
        gameManager.Camera.Update();
 | 
			
		||||
 | 
			
		||||
        _spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
 | 
			
		||||
        foreach (IGameObject gameObject in gameManager)
 | 
			
		||||
        {
 | 
			
		||||
            if (!gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            displayable.Draw(_spriteBatch);
 | 
			
		||||
        }
 | 
			
		||||
        _spriteBatch.End();
 | 
			
		||||
 | 
			
		||||
        base.Draw(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										197
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Apos.Shapes;
 | 
			
		||||
 | 
			
		||||
using Pong.Behaviours;
 | 
			
		||||
using Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong;
 | 
			
		||||
 | 
			
		||||
public class GamePong : Game
 | 
			
		||||
{
 | 
			
		||||
    private readonly GraphicsDeviceManager graphics = null!;
 | 
			
		||||
    private IPhysicsEngine2D physicsEngine = null!;
 | 
			
		||||
    private SpriteBatch spriteBatch = null!;
 | 
			
		||||
    private ShapeBatch shapeBatch = null!;
 | 
			
		||||
 | 
			
		||||
    private GameManager gameManager = null!;
 | 
			
		||||
    private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
 | 
			
		||||
    private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!;
 | 
			
		||||
    private MonoGameCamera2DBehaviour cameraBehaviour = null!;
 | 
			
		||||
 | 
			
		||||
    private PongManagerBehaviour pongManager = null!;
 | 
			
		||||
 | 
			
		||||
    private float physicsTimer = 0f;
 | 
			
		||||
 | 
			
		||||
    public GamePong()
 | 
			
		||||
    {
 | 
			
		||||
        graphics = new GraphicsDeviceManager(this)
 | 
			
		||||
        {
 | 
			
		||||
            PreferredBackBufferWidth = 1024,
 | 
			
		||||
            PreferredBackBufferHeight = 576,
 | 
			
		||||
            GraphicsProfile = GraphicsProfile.HiDef
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Content.RootDirectory = "Content";
 | 
			
		||||
        IsMouseVisible = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Initialize()
 | 
			
		||||
    {
 | 
			
		||||
        // TODO: Add your initialization logic here
 | 
			
		||||
        gameManager = new();
 | 
			
		||||
        displayableCollector = new(gameManager);
 | 
			
		||||
        displayableShapeCollector = new(gameManager);
 | 
			
		||||
        physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 };
 | 
			
		||||
 | 
			
		||||
        gameManager.Initialize();
 | 
			
		||||
 | 
			
		||||
        base.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void LoadContent()
 | 
			
		||||
    {
 | 
			
		||||
        spriteBatch = new SpriteBatch(GraphicsDevice);
 | 
			
		||||
        shapeBatch = new ShapeBatch(GraphicsDevice, Content);
 | 
			
		||||
        SpriteFont spriteFont = Content.Load<SpriteFont>("UbuntuMono");
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        string[] commandLineArguments = Environment.GetCommandLineArgs();
 | 
			
		||||
        if (commandLineArguments.Length != 1)
 | 
			
		||||
        {
 | 
			
		||||
            if (commandLineArguments[1].Equals("server", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkServer>().Start(8888, 2);
 | 
			
		||||
                Window.Title = "Pong - Server";
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Window.Title = $"Pong - Client -> {commandLineArguments[1]}";
 | 
			
		||||
                gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect(commandLineArguments[1], 8888);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect("127.0.0.1", 8888);
 | 
			
		||||
            Window.Title = $"Pong - Client -> 127.0.0.1";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectNetworkManager = gameManager.InstantiateGameObject().SetGameObject("Network Manager"); ;
 | 
			
		||||
        gameObjectNetworkManager.BehaviourController.AddBehaviour<NetworkManager>();
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ;
 | 
			
		||||
        gameObjectCamera.BehaviourController.AddBehaviour<CameraController>();
 | 
			
		||||
        cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics);
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectPongManager = gameManager.InstantiateGameObject().SetGameObject("Pong Game Manager");
 | 
			
		||||
        pongManager = gameObjectPongManager.BehaviourController.AddBehaviour<PongManagerBehaviour>(5);
 | 
			
		||||
        pongManager.Id = "pongManager";
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectBall = gameManager.InstantiateGameObject().SetGameObject("Ball");
 | 
			
		||||
        gameObjectBall.Transform.SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f));
 | 
			
		||||
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f));
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>().Id = "ball";
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>();
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle");
 | 
			
		||||
        gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f));
 | 
			
		||||
 | 
			
		||||
        gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle";
 | 
			
		||||
        gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle");
 | 
			
		||||
        gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f));
 | 
			
		||||
        gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle";
 | 
			
		||||
        gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectWallTop = gameManager.InstantiateGameObject().SetGameObject("Wall Top");
 | 
			
		||||
        gameObjectWallTop.Transform.SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f));
 | 
			
		||||
        gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectWallBottom = gameManager.InstantiateGameObject().SetGameObject("Wall Bottom");
 | 
			
		||||
        gameObjectWallBottom.Transform.SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f));
 | 
			
		||||
        gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectWallRight = gameManager.InstantiateGameObject().SetGameObject("Wall Right");
 | 
			
		||||
        gameObjectWallRight.Transform.SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f));
 | 
			
		||||
        gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft);
 | 
			
		||||
        gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectWallLeft = gameManager.InstantiateGameObject().SetGameObject("Wall Left");
 | 
			
		||||
        gameObjectWallLeft.Transform.SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f));
 | 
			
		||||
        gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight);
 | 
			
		||||
        gameObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
			
		||||
        gameObjectWallLeft.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectLeftScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Left");
 | 
			
		||||
        gameObjectLeftScoreText.Transform.SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f);
 | 
			
		||||
        gameObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont);
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectRightScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Right");
 | 
			
		||||
        gameObjectRightScoreText.Transform.SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f);
 | 
			
		||||
        gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Update(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
 | 
			
		||||
            Exit();
 | 
			
		||||
 | 
			
		||||
        gameManager.Update(gameTime.ToEngineTime());
 | 
			
		||||
        while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds)
 | 
			
		||||
        {
 | 
			
		||||
            physicsTimer += 0.01f;
 | 
			
		||||
            physicsEngine.Step(.01f);
 | 
			
		||||
        }
 | 
			
		||||
        base.Update(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Draw(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 });
 | 
			
		||||
 | 
			
		||||
        // TODO: Add your drawing code here
 | 
			
		||||
        gameManager.PreDraw();
 | 
			
		||||
 | 
			
		||||
        spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
 | 
			
		||||
        foreach (var displayable in displayableCollector)
 | 
			
		||||
            displayable.Draw(spriteBatch);
 | 
			
		||||
        spriteBatch.End();
 | 
			
		||||
 | 
			
		||||
        shapeBatch.Begin(cameraBehaviour.MatrixTransform);
 | 
			
		||||
        foreach (var displayableShape in displayableShapeCollector)
 | 
			
		||||
            displayableShape.Draw(shapeBatch);
 | 
			
		||||
        shapeBatch.End();
 | 
			
		||||
 | 
			
		||||
        base.Draw(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="ISprite"/> field.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public interface IAssignableSprite : IAssignable
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Callback triggered when the <see cref="ISprite"/> value has has been assigned a new value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    Action<IAssignableSprite>? OnSpriteAssigned { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ISprite" />
 | 
			
		||||
    ISprite Sprite { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Assign a value to the <see cref="ISprite"/> field of this object
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="sprite">New <see cref="ISprite"/> to assign.</param>
 | 
			
		||||
    /// <returns> 
 | 
			
		||||
    /// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
 | 
			
		||||
    /// </returns>
 | 
			
		||||
    bool Assign(ISprite sprite);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
// TODO Probably gonna have to rethink this
 | 
			
		||||
public interface ISprite
 | 
			
		||||
{
 | 
			
		||||
    Action<ISprite>? OnTextureChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    Texture2D Texture2D { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class Sprite : ISprite
 | 
			
		||||
{
 | 
			
		||||
    public Action<ISprite>? OnTextureChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    private Texture2D _texture = null!;
 | 
			
		||||
 | 
			
		||||
    public Texture2D Texture2D
 | 
			
		||||
    {
 | 
			
		||||
        get => _texture;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_texture == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _texture = value;
 | 
			
		||||
            OnTextureChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Graphics.TwoDimensional.Abstract;
 | 
			
		||||
public interface IDisplayableSprite : IDisplayable, IAssignableSprite
 | 
			
		||||
{
 | 
			
		||||
    Action<IDisplayableSprite>? OnSpriteEffectsChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnOriginChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnColorChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnDepthChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    SpriteEffects SpriteEffects { get; set; }
 | 
			
		||||
    Vector2 Origin { get; set; }
 | 
			
		||||
    Color Color { get; set; }
 | 
			
		||||
    float Depth { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Graphics.TwoDimensional.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Graphics.TwoDimensional;
 | 
			
		||||
 | 
			
		||||
public class DisplayableSpriteBehaviour : Behaviour, IDisplayableSprite, IAssignableSprite
 | 
			
		||||
{
 | 
			
		||||
    public Action<IAssignableSprite>? OnSpriteAssigned { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnSpriteEffectsChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnOriginChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnColorChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnDepthChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private ISprite _sprite = null!;
 | 
			
		||||
    private Color _color = Color.White;
 | 
			
		||||
    private float _depth = 0f;
 | 
			
		||||
    private SpriteEffects _spriteEffects = SpriteEffects.None;
 | 
			
		||||
    private Vector2 _origin = Vector2.One * .5f;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public ISprite Sprite => _sprite;
 | 
			
		||||
 | 
			
		||||
    public SpriteEffects SpriteEffects
 | 
			
		||||
    {
 | 
			
		||||
        get => _spriteEffects;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_spriteEffects == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _spriteEffects = value;
 | 
			
		||||
            OnSpriteEffectsChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2 Origin
 | 
			
		||||
    {
 | 
			
		||||
        get => _origin;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_origin == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _origin = value;
 | 
			
		||||
            OnOriginChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Color Color
 | 
			
		||||
    {
 | 
			
		||||
        get => _color;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_color == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _color = value;
 | 
			
		||||
            OnColorChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Depth
 | 
			
		||||
    {
 | 
			
		||||
        get => _depth;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_depth == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _depth = value;
 | 
			
		||||
            OnDepthChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw(SpriteBatch spriteBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.GameObject.StateEnable.Enabled || !StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        ITransform transform = BehaviourController.GameObject.Transform;
 | 
			
		||||
        Vector2D position = transform.Position;
 | 
			
		||||
        Vector2D scale = transform.Scale;
 | 
			
		||||
 | 
			
		||||
        Rectangle rectangle = new((int)position.X, -(int)position.Y, (int)(Sprite.Texture2D.Width * scale.X), (int)(Sprite.Texture2D.Height * scale.Y));
 | 
			
		||||
 | 
			
		||||
        spriteBatch.Draw(Sprite.Texture2D, rectangle, null, Color, transform.Rotation, new Vector2(Sprite.Texture2D.Width, Sprite.Texture2D.Height) * Origin, SpriteEffects, Depth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ISprite sprite)
 | 
			
		||||
    {
 | 
			
		||||
        _sprite = sprite;
 | 
			
		||||
        OnSpriteAssigned?.Invoke(this);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DisplayableSpriteBehaviour() => OnUnassigned += OnUnassign;
 | 
			
		||||
    public DisplayableSpriteBehaviour(
 | 
			
		||||
        Color? color = null,
 | 
			
		||||
        float? depth = null,
 | 
			
		||||
        SpriteEffects? spriteEffects = null,
 | 
			
		||||
        Vector2? origin = null)
 | 
			
		||||
    {
 | 
			
		||||
        OnUnassigned += OnUnassign;
 | 
			
		||||
 | 
			
		||||
        _color = color ?? _color;
 | 
			
		||||
        _depth = depth ?? _depth;
 | 
			
		||||
        _spriteEffects = spriteEffects ?? _spriteEffects;
 | 
			
		||||
        _origin = origin ?? _origin;
 | 
			
		||||
    }
 | 
			
		||||
    private void OnUnassign(IAssignable assignable) => _sprite = null!;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkBehaviour : IBehaviour, INetworkEntity
 | 
			
		||||
{
 | 
			
		||||
    bool IsServer { get; }
 | 
			
		||||
    bool IsClient { get; }
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicator NetworkCommunicator { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    event OnPacketReceivedDelegate? OnPacketReceived;
 | 
			
		||||
 | 
			
		||||
    EventBasedNetListener Listener { get; }
 | 
			
		||||
    NetManager Manager { get; }
 | 
			
		||||
 | 
			
		||||
    void PollEvents();
 | 
			
		||||
    void Stop();
 | 
			
		||||
 | 
			
		||||
    void Send<T>(NetworkPacket<T> Data);
 | 
			
		||||
 | 
			
		||||
    delegate void OnPacketReceivedDelegate(INetworkCommunicator sender, object packet);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								Game/Network/Abstract/INetworkCommunicatorClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Game/Network/Abstract/INetworkCommunicatorClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicatorClient : INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    void Connect(string address, int port, string? password = null);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkCommunicatorServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkCommunicatorServer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicatorServer : INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    string Password { get; }
 | 
			
		||||
    int MaxConnectionCount { get; }
 | 
			
		||||
    int Port { get; }
 | 
			
		||||
 | 
			
		||||
    void Start(int port, int maxConnectionCount, string? password = null);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkEntity
 | 
			
		||||
{
 | 
			
		||||
    event OnNetworkIdChangedDelegate? OnNetworkIdChanged;
 | 
			
		||||
 | 
			
		||||
    uint NetworkId { get; set; }
 | 
			
		||||
 | 
			
		||||
    void ReceiveData<T>(T data);
 | 
			
		||||
 | 
			
		||||
    delegate void OnNetworkIdChangedDelegate(INetworkEntity sender, uint previousId);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkManager
 | 
			
		||||
{
 | 
			
		||||
    // Action<IGameObject>? OnNetworkGameObjectInstantiated { get; set; }
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicator NetworkCommunicator { get; }
 | 
			
		||||
 | 
			
		||||
    // Task<T> Instantiate<T>(params object?[]? args) where T : class, IGameObject;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								Game/Network/Abstract/INetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Game/Network/Abstract/INetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface INetworkPacket : INetSerializable;
 | 
			
		||||
							
								
								
									
										7
									
								
								Game/Network/Abstract/NetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Game/Network/Abstract/NetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
public class NetworkPacket<T>
 | 
			
		||||
{
 | 
			
		||||
    public uint NetworkId { get; set; } = 0;
 | 
			
		||||
    public T Data { get; set; } = default!;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										140
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    public event INetworkCommunicator.OnPacketReceivedDelegate? OnPacketReceived = null;
 | 
			
		||||
 | 
			
		||||
    protected readonly NetPacketProcessor netPacketProcessor = new();
 | 
			
		||||
 | 
			
		||||
    protected readonly Dictionary<uint, INetworkEntity> networkEntities = [];
 | 
			
		||||
 | 
			
		||||
    protected BehaviourCollector<INetworkEntity> networkEntityCollector = null!;
 | 
			
		||||
 | 
			
		||||
    public EventBasedNetListener Listener { get; private set; } = null!;
 | 
			
		||||
    public NetManager Manager { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    public NetworkBase()
 | 
			
		||||
    {
 | 
			
		||||
        Priority = 10;
 | 
			
		||||
 | 
			
		||||
        Listener = new EventBasedNetListener();
 | 
			
		||||
        Manager = new NetManager(Listener);
 | 
			
		||||
 | 
			
		||||
        Listener.NetworkReceiveEvent += NetworkReceiveEvent;
 | 
			
		||||
 | 
			
		||||
        netPacketProcessor.RegisterNestedType<Pong.Behaviours.PaddleBehaviour.PaddleInputs>();
 | 
			
		||||
        RegisterPackets();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RegisterPackets()
 | 
			
		||||
    {
 | 
			
		||||
        var packetTypes = Assembly.GetExecutingAssembly().GetTypes()
 | 
			
		||||
            .Where(t => typeof(INetworkPacket).IsAssignableFrom(t) && !t.IsInterface)
 | 
			
		||||
            .ToList();
 | 
			
		||||
 | 
			
		||||
        MethodInfo[] subscribeMethods = netPacketProcessor.GetType()
 | 
			
		||||
            .GetMethods()
 | 
			
		||||
            .Where(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable))
 | 
			
		||||
            .ToArray();
 | 
			
		||||
 | 
			
		||||
        MethodInfo subscribeMethod = subscribeMethods
 | 
			
		||||
            .FirstOrDefault(m =>
 | 
			
		||||
                m.GetParameters().Length == 1 &&
 | 
			
		||||
                m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>)
 | 
			
		||||
            ) ?? throw new Exception();
 | 
			
		||||
 | 
			
		||||
        MethodInfo[] methodInfos = typeof(NetworkBase)
 | 
			
		||||
            .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);
 | 
			
		||||
 | 
			
		||||
        MethodInfo method = methodInfos
 | 
			
		||||
            .FirstOrDefault(
 | 
			
		||||
                m => m.Name == nameof(OnPacketArrived) &&
 | 
			
		||||
                m.IsGenericMethodDefinition
 | 
			
		||||
            ) ?? throw new Exception();
 | 
			
		||||
 | 
			
		||||
        foreach (var packetType in packetTypes)
 | 
			
		||||
        {
 | 
			
		||||
            var networkPacketType = typeof(NetworkPacket<>).MakeGenericType(packetType);
 | 
			
		||||
            MethodInfo genericSubscribe = subscribeMethod.MakeGenericMethod(networkPacketType, typeof(NetPeer));
 | 
			
		||||
 | 
			
		||||
            Action<object, NetPeer> handler = (packet, peer) =>
 | 
			
		||||
            {
 | 
			
		||||
                MethodInfo handlerMethod = method.MakeGenericMethod(packetType);
 | 
			
		||||
                handlerMethod.Invoke(this, [packet, peer]);
 | 
			
		||||
            };
 | 
			
		||||
            genericSubscribe.Invoke(netPacketProcessor, [handler]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnPacketArrived<T>(NetworkPacket<T> packet, NetPeer peer) where T : INetworkPacket
 | 
			
		||||
    {
 | 
			
		||||
        if (networkEntities.TryGetValue(packet.NetworkId, out INetworkEntity? entity))
 | 
			
		||||
            entity.ReceiveData(packet.Data);
 | 
			
		||||
 | 
			
		||||
        OnPacketReceived?.Invoke(this, packet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        base.OnInitialize();
 | 
			
		||||
 | 
			
		||||
        networkEntityCollector = new(GameObject.GameManager);
 | 
			
		||||
        networkEntityCollector.OnCollected += OnNetworkEntityCollected;
 | 
			
		||||
        networkEntityCollector.OnRemoved += OnNetworkEntityRemoved;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        networkEntityCollector.OnCollected -= OnNetworkEntityCollected;
 | 
			
		||||
        networkEntityCollector.OnRemoved -= OnNetworkEntityRemoved;
 | 
			
		||||
        Stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnNetworkEntityCollected(BehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourCollected)
 | 
			
		||||
    {
 | 
			
		||||
        if (behaviourCollected.NetworkId != 0)
 | 
			
		||||
            networkEntities.Add(behaviourCollected.NetworkId, behaviourCollected);
 | 
			
		||||
 | 
			
		||||
        behaviourCollected.OnNetworkIdChanged += OnNetworkIdChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnNetworkIdChanged(INetworkEntity sender, uint previousId)
 | 
			
		||||
    {
 | 
			
		||||
        if (networkEntities.TryGetValue(previousId, out INetworkEntity? networkEntity) && sender == networkEntity)
 | 
			
		||||
            networkEntities.Remove(previousId);
 | 
			
		||||
 | 
			
		||||
        networkEntities.Add(sender.NetworkId, sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnNetworkEntityRemoved(BehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourRemoved)
 | 
			
		||||
    {
 | 
			
		||||
        networkEntities.Remove(behaviourRemoved.NetworkId);
 | 
			
		||||
        behaviourRemoved.OnNetworkIdChanged -= OnNetworkIdChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            netPacketProcessor.ReadAllPackets(reader, peer);
 | 
			
		||||
        }
 | 
			
		||||
        catch { }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void PollEvents() => Manager.PollEvents();
 | 
			
		||||
    public void Stop() => Manager.Stop();
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate() => PollEvents();
 | 
			
		||||
 | 
			
		||||
    public abstract void Send<T>(NetworkPacket<T> packet);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour
 | 
			
		||||
{
 | 
			
		||||
    public event INetworkEntity.OnNetworkIdChangedDelegate? OnNetworkIdChanged = null;
 | 
			
		||||
 | 
			
		||||
    private uint _networkId = 0;
 | 
			
		||||
    public uint NetworkId
 | 
			
		||||
    {
 | 
			
		||||
        get => _networkId;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (value == _networkId)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            uint previousNetworkId = _networkId;
 | 
			
		||||
            _networkId = value;
 | 
			
		||||
            OnNetworkIdChanged?.Invoke(this, previousNetworkId);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool IsServer { get; private set; } = false;
 | 
			
		||||
    public bool IsClient { get; private set; } = false;
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicator NetworkCommunicator { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>()
 | 
			
		||||
                              ?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>()
 | 
			
		||||
                              ?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}.");
 | 
			
		||||
 | 
			
		||||
        if (NetworkCommunicator is INetworkCommunicatorClient client)
 | 
			
		||||
        {
 | 
			
		||||
            IsClient = true;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IsServer = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void SendData<T>(T data)
 | 
			
		||||
        => NetworkCommunicator.Send(new NetworkPacket<T>() { NetworkId = _networkId, Data = data });
 | 
			
		||||
 | 
			
		||||
    public abstract void ReceiveData<T>(T data);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public class NetworkClient : NetworkBase, INetworkCommunicatorClient
 | 
			
		||||
{
 | 
			
		||||
    private readonly NetDataWriter netDataWriter = new();
 | 
			
		||||
 | 
			
		||||
    public void Connect(string address, int port, string? password = null)
 | 
			
		||||
    {
 | 
			
		||||
        Manager.Start();
 | 
			
		||||
        Manager.Connect(address, port, password ?? string.Empty);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void Send<T>(NetworkPacket<T> packet)
 | 
			
		||||
    {
 | 
			
		||||
        netDataWriter.Reset();
 | 
			
		||||
        netPacketProcessor.Write(netDataWriter, packet);
 | 
			
		||||
        Manager.FirstPeer.Send(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public static class NetworkExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static Vector2D GetVector2D(this NetPacketReader reader)
 | 
			
		||||
        => new(reader.GetFloat(), reader.GetFloat());
 | 
			
		||||
 | 
			
		||||
    public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D)
 | 
			
		||||
        => vector2D = new(reader.GetFloat(), reader.GetFloat());
 | 
			
		||||
 | 
			
		||||
    public static void Put(this NetDataWriter writer, Vector2D vector)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(vector.X);
 | 
			
		||||
        writer.Put(vector.Y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public class NetworkManager : NetworkBehaviour, INetworkManager
 | 
			
		||||
{
 | 
			
		||||
    private BehaviourCollector<INetworkEntity> entities = null!;
 | 
			
		||||
 | 
			
		||||
    private static uint networkIdIndex = 0;
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        base.OnInitialize();
 | 
			
		||||
 | 
			
		||||
        NetworkId = networkIdIndex++;
 | 
			
		||||
 | 
			
		||||
        entities = new(GameObject.GameManager);
 | 
			
		||||
        foreach (var entity in entities)
 | 
			
		||||
            entity.NetworkId = networkIdIndex++;
 | 
			
		||||
 | 
			
		||||
        entities.OnCollected += OnCollected;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity)
 | 
			
		||||
        => entity.NetworkId = networkIdIndex++;
 | 
			
		||||
 | 
			
		||||
    public override void ReceiveData<T>(T data) { }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Network.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public class NetworkServer : NetworkBase, INetworkCommunicatorServer
 | 
			
		||||
{
 | 
			
		||||
    public string Password { get; private set; } = string.Empty;
 | 
			
		||||
    public int MaxConnectionCount { get; private set; } = 2;
 | 
			
		||||
    public int Port { get; private set; } = 8888;
 | 
			
		||||
 | 
			
		||||
    private readonly NetDataWriter netDataWriter = new();
 | 
			
		||||
 | 
			
		||||
    public NetworkServer() : this(8888, 2) { }
 | 
			
		||||
    public NetworkServer(int port, int maxConnectionCount) : base()
 | 
			
		||||
    {
 | 
			
		||||
        MaxConnectionCount = maxConnectionCount;
 | 
			
		||||
        Port = port;
 | 
			
		||||
 | 
			
		||||
        Listener.ConnectionRequestEvent += request =>
 | 
			
		||||
        {
 | 
			
		||||
            if (Manager.ConnectedPeersCount < maxConnectionCount)
 | 
			
		||||
                request.AcceptIfKey(Password);
 | 
			
		||||
            else
 | 
			
		||||
                request.Reject();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        OnPacketReceived += ServerOnPacketReceived;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Start(int port, int maxConnectionCount, string? password = null)
 | 
			
		||||
    {
 | 
			
		||||
        Password = password ?? string.Empty;
 | 
			
		||||
        MaxConnectionCount = maxConnectionCount;
 | 
			
		||||
        Port = port;
 | 
			
		||||
 | 
			
		||||
        Manager.Start(port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void Send<T>(NetworkPacket<T> packet)
 | 
			
		||||
    {
 | 
			
		||||
        netDataWriter.Reset();
 | 
			
		||||
        netPacketProcessor.Write(netDataWriter, packet);
 | 
			
		||||
        Manager.SendToAll(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void ServerOnPacketReceived(INetworkCommunicator sender, object packet)
 | 
			
		||||
    {
 | 
			
		||||
        MethodInfo[] methodInfos = GetType()
 | 
			
		||||
            .GetMethods(BindingFlags.Public | BindingFlags.Instance);
 | 
			
		||||
 | 
			
		||||
        MethodInfo method = methodInfos
 | 
			
		||||
            .FirstOrDefault(
 | 
			
		||||
                m => m.Name == nameof(Send) && m.IsGenericMethod
 | 
			
		||||
            ) ?? throw new Exception();
 | 
			
		||||
 | 
			
		||||
        Type typeArguments = packet.GetType().GetGenericArguments()[0];
 | 
			
		||||
 | 
			
		||||
        MethodInfo methodInfo = method.MakeGenericMethod(typeArguments);
 | 
			
		||||
 | 
			
		||||
        methodInfo.Invoke(this, [packet]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface ICollider2D : IBehaviour, IAssignableTransform
 | 
			
		||||
{
 | 
			
		||||
    Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; }
 | 
			
		||||
 | 
			
		||||
    IRigidBody2D? RigidBody2D { get; }
 | 
			
		||||
 | 
			
		||||
    IList<Vector2D> Vertices { get; }
 | 
			
		||||
 | 
			
		||||
    bool CheckCollision(Vector2D point);
 | 
			
		||||
    void Recalculate();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface ICollisionResolver2D
 | 
			
		||||
{
 | 
			
		||||
    void ResolveCollision(ICollider2D colliderA, ICollider2D colliderB);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IPhysicsEngine2D
 | 
			
		||||
{
 | 
			
		||||
    int IterationCount { get; set; }
 | 
			
		||||
 | 
			
		||||
    void AddRigidBody(IRigidBody2D rigidBody);
 | 
			
		||||
    void RemoveRigidBody(IRigidBody2D rigidBody);
 | 
			
		||||
 | 
			
		||||
    void Step(float deltaTime);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IPhysicsMaterial2D
 | 
			
		||||
{
 | 
			
		||||
    float Friction { get; }
 | 
			
		||||
    float Restitution { get; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IRigidBody2D : IBehaviour, IAssignableTransform
 | 
			
		||||
{
 | 
			
		||||
    IPhysicsMaterial2D Material { get; set; }
 | 
			
		||||
 | 
			
		||||
    Vector2D Velocity { get; set; }
 | 
			
		||||
    float AngularVelocity { get; set; }
 | 
			
		||||
 | 
			
		||||
    float Mass { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D
 | 
			
		||||
{
 | 
			
		||||
    public AABB AABBLocal { get; set; } = null!;
 | 
			
		||||
    public AABB AABBWorld { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    private IRigidBody2D? _rigidBody2D = null;
 | 
			
		||||
    private List<Vector2D> _vertices = new List<Vector2D>(4);
 | 
			
		||||
 | 
			
		||||
    public IRigidBody2D? RigidBody2D
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            if (_rigidBody2D is null)
 | 
			
		||||
                BehaviourController.TryGetBehaviour(out _rigidBody2D);
 | 
			
		||||
 | 
			
		||||
            return _rigidBody2D;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
 | 
			
		||||
    ITransform IAssignableTransform.Transform => Transform;
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
 | 
			
		||||
    public IList<Vector2D> Vertices => _vertices;
 | 
			
		||||
 | 
			
		||||
    public bool CheckCollision(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        return AABBWorld.Overlaps(point);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Recalculate()
 | 
			
		||||
    {
 | 
			
		||||
        AABBWorld = new AABB(
 | 
			
		||||
            AABBLocal.LowerBoundary.Scale(Transform.Scale) + Transform.Position,
 | 
			
		||||
            AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Vertices.Clear();
 | 
			
		||||
        Vertices.Add(AABBWorld.LowerBoundary);
 | 
			
		||||
        Vertices.Add(new Vector2D(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y));
 | 
			
		||||
        Vertices.Add(AABBWorld.UpperBoundary);
 | 
			
		||||
        Vertices.Add(new Vector2D(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y));
 | 
			
		||||
    }
 | 
			
		||||
    public Collider2DAABBBehaviour(Vector2D lowerBoundary, Vector2D upperBoundary)
 | 
			
		||||
    {
 | 
			
		||||
        AABBLocal = new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
        AABBWorld = new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Collider2DAABBBehaviour()
 | 
			
		||||
    {
 | 
			
		||||
        AABBLocal = new(Vector2D.Zero, Vector2D.Zero);
 | 
			
		||||
        AABBWorld = new(Vector2D.Zero, Vector2D.Zero);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record CollisionInformation
 | 
			
		||||
(
 | 
			
		||||
    Vector2 Normal,
 | 
			
		||||
    Vector2 ContactPosition
 | 
			
		||||
);
 | 
			
		||||
@@ -1,75 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class PhysicsEngine2D : IPhysicsEngine2D
 | 
			
		||||
{
 | 
			
		||||
    private List<IRigidBody2D> rigidBodies = new List<IRigidBody2D>(32);
 | 
			
		||||
    private List<ICollider2D> colliders = new List<ICollider2D>(64);
 | 
			
		||||
 | 
			
		||||
    private int _iterationCount = 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; }
 | 
			
		||||
 | 
			
		||||
    public void AddRigidBody(IRigidBody2D rigidBody)
 | 
			
		||||
    {
 | 
			
		||||
        if (rigidBodies.Contains(rigidBody))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        rigidBodies.Add(rigidBody);
 | 
			
		||||
 | 
			
		||||
        foreach (var collider2D in rigidBody.BehaviourController.GetBehaviours<ICollider2D>())
 | 
			
		||||
            colliders.Add(collider2D);
 | 
			
		||||
 | 
			
		||||
        rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
 | 
			
		||||
        rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemoveRigidBody(IRigidBody2D rigidBody)
 | 
			
		||||
    {
 | 
			
		||||
        rigidBodies.Remove(rigidBody);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Step(float deltaTime)
 | 
			
		||||
    {
 | 
			
		||||
        float intervalDeltaTime = deltaTime / IterationCount;
 | 
			
		||||
 | 
			
		||||
        for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var rigidBody in rigidBodies)
 | 
			
		||||
                StepRigidBody(rigidBody, intervalDeltaTime);
 | 
			
		||||
 | 
			
		||||
            foreach (var collider in colliders)
 | 
			
		||||
                collider.Recalculate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime)
 | 
			
		||||
    {
 | 
			
		||||
        rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime;
 | 
			
		||||
        rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (behaviour is not ICollider2D collider2D)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        colliders.Add(collider2D);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (behaviour is not ICollider2D collider2D)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        colliders.Remove(collider2D);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { }
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record PhysicsMaterial2DDefault : PhysicsMaterial2D
 | 
			
		||||
{
 | 
			
		||||
    public PhysicsMaterial2DDefault() : base(.1f, .1f) { }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,118 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public static class PhysicsMath
 | 
			
		||||
{
 | 
			
		||||
    public static Vector2D Scale(this Vector2D original, Vector2D scale)
 | 
			
		||||
        => new Vector2D(original.X * scale.X, original.Y * scale.Y);
 | 
			
		||||
 | 
			
		||||
    public static Triangle ToSuperTriangle(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
        float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
        foreach (Vector2D point in vertices)
 | 
			
		||||
        {
 | 
			
		||||
            minX = MathF.Min(minX, point.X);
 | 
			
		||||
            minY = MathF.Min(minY, point.Y);
 | 
			
		||||
            maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
            maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float dx = maxX - minX;
 | 
			
		||||
        float dy = maxY - minY;
 | 
			
		||||
        float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
        float midX = (minX + maxX) / 2;
 | 
			
		||||
        float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
        Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
        Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
        Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
        return new Triangle(p1, p2, p3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IList<Line> ToLines(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        List<Line> lines = new List<Line>(vertices.Count - 1);
 | 
			
		||||
        ToLines(vertices, lines);
 | 
			
		||||
        return lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void ToLines(this IList<Vector2D> vertices, IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(vertices[i], vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(vertices[^1], vertices[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool LaysOn(this Vector2D point, Line line)
 | 
			
		||||
        => line.Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Given three collinear points p, q, r, the function checks if 
 | 
			
		||||
    // point q lies on line segment 'pr' 
 | 
			
		||||
    public static bool OnSegment(Vector2D p, Vector2D q, Vector2D r)
 | 
			
		||||
    {
 | 
			
		||||
        if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) &&
 | 
			
		||||
            q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // To find orientation of ordered triplet (p, q, r). 
 | 
			
		||||
    // The function returns following values 
 | 
			
		||||
    // 0 --> p, q and r are collinear 
 | 
			
		||||
    // 1 --> Clockwise 
 | 
			
		||||
    // 2 --> Counterclockwise 
 | 
			
		||||
    public static int Orientation(Vector2D p, Vector2D q, Vector2D r)
 | 
			
		||||
    {
 | 
			
		||||
        // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ 
 | 
			
		||||
        // for details of below formula. 
 | 
			
		||||
        float val = (q.Y - p.Y) * (r.X - q.X) -
 | 
			
		||||
                (q.X - p.X) * (r.Y - q.Y);
 | 
			
		||||
 | 
			
		||||
        if (val == 0) return 0; // collinear 
 | 
			
		||||
 | 
			
		||||
        return (val > 0) ? 1 : 2; // clock or counterclock wise 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float IntersectionParameterT(Vector2D p0, Vector2D p1, Vector2D q0, Vector2D q1)
 | 
			
		||||
        => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) /
 | 
			
		||||
            ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(this float a, float b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon)
 | 
			
		||||
        => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon)
 | 
			
		||||
        => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this float a, float b, float epsilon)
 | 
			
		||||
    {
 | 
			
		||||
        if (a == b)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        const float floatNormal = (1 << 23) * float.Epsilon;
 | 
			
		||||
        float absA = MathF.Abs(a);
 | 
			
		||||
        float absB = MathF.Abs(b);
 | 
			
		||||
        float diff = MathF.Abs(a - b);
 | 
			
		||||
 | 
			
		||||
        if (a == 0.0f || b == 0.0f || diff < floatNormal)
 | 
			
		||||
            return diff < (epsilon * floatNormal);
 | 
			
		||||
 | 
			
		||||
        return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
 | 
			
		||||
{
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
        => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X &&
 | 
			
		||||
            point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(AABB other)
 | 
			
		||||
        => LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X &&
 | 
			
		||||
            LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(AABB other)
 | 
			
		||||
        => LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Circle(Vector2D Position, float Radius)
 | 
			
		||||
{
 | 
			
		||||
    public bool Intersects(Circle other)
 | 
			
		||||
    {
 | 
			
		||||
        float distanceSquared = (Position - other.Position).LengthSquared();
 | 
			
		||||
        float radiusSumSquared = Radius * Radius + other.Radius * other.Radius;
 | 
			
		||||
 | 
			
		||||
        return distanceSquared < radiusSumSquared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius;
 | 
			
		||||
    public bool ApproximatelyEquals(Circle other)
 | 
			
		||||
        => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,146 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
{
 | 
			
		||||
    public Line Reversed => new(To, From);
 | 
			
		||||
    public Vector2D Direction => Vector2D.Normalize(To - From);
 | 
			
		||||
    public float Length => (From - To).Length();
 | 
			
		||||
    public float LengthSquared => (From - To).LengthSquared();
 | 
			
		||||
 | 
			
		||||
    public LineEquation LineEquation
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D slopeVector = To - From;
 | 
			
		||||
            float slope = slopeVector.Y / slopeVector.X;
 | 
			
		||||
 | 
			
		||||
            float yOffset = From.Y - (slope * From.X);
 | 
			
		||||
 | 
			
		||||
            return new LineEquation(slope, yOffset);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Vector2D point)
 | 
			
		||||
        => Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
 | 
			
		||||
    public float GetT(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float fromX = MathF.Abs(From.X);
 | 
			
		||||
        float toX = MathF.Abs(To.X);
 | 
			
		||||
        float pointX = MathF.Abs(point.X);
 | 
			
		||||
 | 
			
		||||
        float min = MathF.Min(fromX, toX);
 | 
			
		||||
        float max = MathF.Max(fromX, toX) - min;
 | 
			
		||||
 | 
			
		||||
        pointX -= min;
 | 
			
		||||
 | 
			
		||||
        float t = pointX / max;
 | 
			
		||||
 | 
			
		||||
        // FIXME
 | 
			
		||||
        // I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line
 | 
			
		||||
        // Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason
 | 
			
		||||
        // too unmotivated to find a solution. Future me, find a better way if possible, please.
 | 
			
		||||
        if (!Lerp(t).ApproximatelyEquals(point))
 | 
			
		||||
            return 1f - t;
 | 
			
		||||
        return t;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Exist(List<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D vertexCurrent = vertices[i];
 | 
			
		||||
            Vector2D vertexNext = vertices[i];
 | 
			
		||||
            if (From == vertexCurrent && To == vertexNext) return true;
 | 
			
		||||
            if (From == vertexNext && To == vertexCurrent) return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Vector2D vertexFirst = vertices[0];
 | 
			
		||||
        Vector2D vertexLast = vertices[^1];
 | 
			
		||||
        if (From == vertexFirst && To == vertexLast) return true;
 | 
			
		||||
        if (From == vertexLast && To == vertexFirst) return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float IntersectionParameterT(Line other)
 | 
			
		||||
    {
 | 
			
		||||
        float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X);
 | 
			
		||||
        float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X);
 | 
			
		||||
 | 
			
		||||
        // Lines are parallel
 | 
			
		||||
        if (denominator == 0)
 | 
			
		||||
            return float.NaN;
 | 
			
		||||
 | 
			
		||||
        return numerator / denominator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Lerp(float t)
 | 
			
		||||
        => new Vector2D(
 | 
			
		||||
            From.X + (To.X - From.X) * t,
 | 
			
		||||
            From.Y + (To.Y - From.Y) * t
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    public Vector2D Resolve(float x)
 | 
			
		||||
        => new Vector2D(x, LineEquation.Resolve(x));
 | 
			
		||||
 | 
			
		||||
    public Vector2D ClosestPointTo(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        // Convert edge points to vectors
 | 
			
		||||
        var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y);
 | 
			
		||||
        var pointVector = new Vector2D(point.X - From.X, point.Y - 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 = From.X + t * edgeVector.X;
 | 
			
		||||
        float closestY = From.Y + t * edgeVector.Y;
 | 
			
		||||
 | 
			
		||||
        return new Vector2D((float)closestX, (float)closestY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D IntersectionPoint(Line other)
 | 
			
		||||
        => Vector2D.Lerp(From, To, IntersectionParameterT(other));
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other)
 | 
			
		||||
    {
 | 
			
		||||
        int o1 = PhysicsMath.Orientation(From, To, other.From);
 | 
			
		||||
        int o2 = PhysicsMath.Orientation(From, To, other.To);
 | 
			
		||||
        int o3 = PhysicsMath.Orientation(other.From, other.To, From);
 | 
			
		||||
        int o4 = PhysicsMath.Orientation(other.From, other.To, To);
 | 
			
		||||
 | 
			
		||||
        if (o1 != o2 && o3 != o4)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true;
 | 
			
		||||
        if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true;
 | 
			
		||||
        if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true;
 | 
			
		||||
        if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point)
 | 
			
		||||
    {
 | 
			
		||||
        point = null;
 | 
			
		||||
 | 
			
		||||
        bool result = Intersects(other);
 | 
			
		||||
 | 
			
		||||
        if (result)
 | 
			
		||||
            point = IntersectionPoint(other);
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Line other)
 | 
			
		||||
        => From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record LineEquation(float Slope, float OffsetY)
 | 
			
		||||
{
 | 
			
		||||
    public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b
 | 
			
		||||
    public bool ApproximatelyEquals(LineEquation other)
 | 
			
		||||
        => Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public static class Math
 | 
			
		||||
{
 | 
			
		||||
    public const float RadianToDegree = 57.29577866666166f;
 | 
			
		||||
    public const float DegreeToRadian = 0.01745329277777778f;
 | 
			
		||||
 | 
			
		||||
    public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,68 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Shape(IList<Vector2D> Vertices)
 | 
			
		||||
{
 | 
			
		||||
    public Triangle SuperTriangle
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
            float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
            foreach (Vector2D point in Vertices)
 | 
			
		||||
            {
 | 
			
		||||
                minX = MathF.Min(minX, point.X);
 | 
			
		||||
                minY = MathF.Min(minY, point.Y);
 | 
			
		||||
                maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
                maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            float dx = maxX - minX;
 | 
			
		||||
            float dy = maxY - minY;
 | 
			
		||||
            float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
            float midX = (minX + maxX) / 2;
 | 
			
		||||
            float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
            Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
            Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
            Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
            return new Triangle(p1, p2, p3);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Line> Lines
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            List<Line> lines = new List<Line>(Vertices.Count - 1);
 | 
			
		||||
            GetLinesNonAlloc(lines);
 | 
			
		||||
            return lines;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void GetLinesNonAlloc(IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < Vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(Vertices[i], Vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(Vertices[^1], Vertices[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Shape other)
 | 
			
		||||
    {
 | 
			
		||||
        if (Vertices.Count != other.Vertices.Count)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < Vertices.Count; i++)
 | 
			
		||||
            if (!Vertices[i].ApproximatelyEquals(other.Vertices[i]))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
{
 | 
			
		||||
    public float Area => MathF.Abs((
 | 
			
		||||
            A.X * (B.Y - C.Y) +
 | 
			
		||||
            B.X * (C.Y - A.Y) +
 | 
			
		||||
            C.X * (A.Y - B.Y)
 | 
			
		||||
            ) * .5f);
 | 
			
		||||
 | 
			
		||||
    public Circle CircumCircle
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D midAB = (A + B) / 2;
 | 
			
		||||
            Vector2D midBC = (B + C) / 2;
 | 
			
		||||
 | 
			
		||||
            float slopeAB = (B.Y - A.Y) / (B.X - A.X);
 | 
			
		||||
            float slopeBC = (C.Y - B.Y) / (C.X - B.X);
 | 
			
		||||
 | 
			
		||||
            Vector2D center;
 | 
			
		||||
            if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
            {
 | 
			
		||||
                float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB));
 | 
			
		||||
                float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2;
 | 
			
		||||
                center = new Vector2D(x, y);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                center = (midAB + midBC) * .5f;
 | 
			
		||||
 | 
			
		||||
            return new(center, Vector2D.Distance(center, A));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float originalTriangleArea = Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleArea1 = new Triangle(point, B, C).Area;
 | 
			
		||||
        float pointTriangleArea2 = new Triangle(A, point, C).Area;
 | 
			
		||||
        float pointTriangleArea3 = new Triangle(A, B, point).Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3;
 | 
			
		||||
 | 
			
		||||
        return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Triangle other)
 | 
			
		||||
        => A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class RigidBody2D : BehaviourOverride, IRigidBody2D
 | 
			
		||||
{
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault();
 | 
			
		||||
 | 
			
		||||
    public Vector2D Velocity { get; set; } = Vector2D.Zero;
 | 
			
		||||
    public float AngularVelocity { get; set; } = 0f;
 | 
			
		||||
    public float Mass { get; set; } = 0f;
 | 
			
		||||
 | 
			
		||||
    ITransform IAssignableTransform.Transform => Transform;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
 | 
			
		||||
using var game = new Pong.Game1();
 | 
			
		||||
using var game = new Pong.GamePong();
 | 
			
		||||
game.Run();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								Pong.sln
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Pong.sln
									
									
									
									
									
								
							@@ -11,7 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj",
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine\Engine.Input\Engine.Input.csproj", "{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Graphics", "Engine\Engine.Graphics\Engine.Graphics.csproj", "{7371D9AF-6F4D-4F05-8458-197C4EE66B01}"
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
@@ -34,14 +34,14 @@ Global
 | 
			
		||||
		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(NestedProjects) = preSolution
 | 
			
		||||
		{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user