Compare commits

..

8 Commits

Author SHA1 Message Date
05dfb92bab feat: Paddle Transform Over Network 2024-07-29 23:18:48 +03:00
7f169fc788 feat: Working Network Code 2024-07-29 23:01:27 +03:00
376f18c43a fix: Server Connection Count Default 2024-07-19 21:41:57 +03:00
150deaa618 fix: Network Id Zero 2024-07-19 21:39:50 +03:00
d011bf9a7a Test 2024-07-18 23:07:05 +03:00
19124e733c chore: VSCode Launch Tasks for Multiplayer Tests 2024-07-17 18:14:54 +03:00
c28568d0cb feat: Test Network 2024-07-16 22:56:32 +03:00
91d301677f Test 2024-07-15 17:00:04 +03:00
52 changed files with 1396 additions and 912 deletions

46
.vscode/launch.json vendored Normal file
View 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}"
}
]
}

7
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"cSpell.words": [
"AABB",
"DAABB",
"Syntriax"
]
}

15
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "dotnet",
"task": "build",
"problemMatcher": ["$msCompile"],
"group": {
"kind": "build",
"isDefault": true
},
"label": "build"
}
]
}

2
Engine

@ -1 +1 @@
Subproject commit 6e5b805803ce60f9ad904180406e57de9e9f9c4e Subproject commit ef21cdf2138a2f5107a628c0fe970b88bc03dcfd

View File

@ -3,31 +3,31 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"dotnet-mgcb": { "dotnet-mgcb": {
"version": "3.8.2.1105", "version": "3.8.1.303",
"commands": [ "commands": [
"mgcb" "mgcb"
] ]
}, },
"dotnet-mgcb-editor": { "dotnet-mgcb-editor": {
"version": "3.8.2.1105", "version": "3.8.1.303",
"commands": [ "commands": [
"mgcb-editor" "mgcb-editor"
] ]
}, },
"dotnet-mgcb-editor-linux": { "dotnet-mgcb-editor-linux": {
"version": "3.8.2.1105", "version": "3.8.1.303",
"commands": [ "commands": [
"mgcb-editor-linux" "mgcb-editor-linux"
] ]
}, },
"dotnet-mgcb-editor-windows": { "dotnet-mgcb-editor-windows": {
"version": "3.8.2.1105", "version": "3.8.1.303",
"commands": [ "commands": [
"mgcb-editor-windows" "mgcb-editor-windows"
] ]
}, },
"dotnet-mgcb-editor-mac": { "dotnet-mgcb-editor-mac": {
"version": "3.8.2.1105", "version": "3.8.1.303",
"commands": [ "commands": [
"mgcb-editor-mac" "mgcb-editor-mac"
] ]

View File

View File

@ -1,6 +1,6 @@
using Apos.Shapes; using Apos.Shapes;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core.Abstract;
public interface IDisplayableShape public interface IDisplayableShape
{ {

View File

@ -1,6 +1,6 @@
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core.Abstract;
public interface IDisplayableSprite public interface IDisplayableSprite
{ {

View File

@ -2,10 +2,11 @@ using System;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D;
using Syntriax.Engine.Physics2D.Abstract;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class BallBehaviour : Behaviour2D public class BallBehaviour : BehaviourOverride
{ {
public Vector2D StartDirection { get; private set; } = Vector2D.Zero; public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
public float Speed { get; set; } = 500f; public float Speed { get; set; } = 500f;
@ -16,10 +17,16 @@ public class BallBehaviour : Behaviour2D
protected override void OnFirstActiveFrame() protected override void OnFirstActiveFrame()
{ {
BehaviourController.GetRequiredBehaviour<ICollider2D>().OnCollisionDetected += OnCollisionDetected; if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody))
rigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>(); 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}.");
if (UniverseObject.Universe.TryFindBehaviour(out PongManagerBehaviour? pongManager)) foundCollider.OnCollisionDetected += OnCollisionDetected;
rigidBody = foundRigidBody;
if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager))
{ {
pongManager.OnReset += ResetBall; pongManager.OnReset += ResetBall;
pongManager.OnScored += ResetBall; pongManager.OnScored += ResetBall;
@ -29,14 +36,14 @@ public class BallBehaviour : Behaviour2D
private void DisableBall(PongManagerBehaviour pongManager) private void DisableBall(PongManagerBehaviour pongManager)
{ {
Transform.Position = Vector2D.Zero; BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
rigidBody.Velocity = Vector2D.Zero; rigidBody.Velocity = Vector2D.Zero;
} }
private void ResetBall(PongManagerBehaviour pongManager) private void ResetBall(PongManagerBehaviour pongManager)
{ {
StateEnable.Enabled = true; StateEnable.Enabled = true;
Transform.Position = Vector2D.Zero; BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
rigidBody.Velocity = GetRandomDirection() * Speed; rigidBody.Velocity = GetRandomDirection() * Speed;
} }
@ -53,14 +60,14 @@ public class BallBehaviour : Behaviour2D
if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) if (rigidBody.Velocity.MagnitudeSquared <= 0.01f)
return; return;
Vector2D speedUp = rigidBody.Velocity.Normalized * Universe.Time.DeltaTime; Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame;
rigidBody.Velocity += speedUp * SpeedUpMultiplier; rigidBody.Velocity += speedUp * SpeedUpMultiplier;
} }
private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information)
{ {
if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25)
rigidBody.Velocity = information.Detected.Transform.Position.FromTo(information.Detector.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
else else
rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
} }

View File

@ -1,11 +1,11 @@
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Systems.Input; using Syntriax.Engine.Input;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class CameraController : Behaviour public class CameraController : BehaviourOverride
{ {
private MonoGameCamera2DBehaviour cameraBehaviour = null!; private MonoGameCamera2DBehaviour cameraBehaviour = null!;
private IButtonInputs<Keys> buttonInputs = null!; private IButtonInputs<Keys> buttonInputs = null!;
@ -14,9 +14,15 @@ public class CameraController : Behaviour
protected override void OnFirstActiveFrame() protected override void OnFirstActiveFrame()
{ {
cameraBehaviour ??= BehaviourController.GetRequiredBehaviour<MonoGameCamera2DBehaviour>(); if (BehaviourController.TryGetBehaviour(out MonoGameCamera2DBehaviour? foundCameraBehaviour))
buttonInputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>(); 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.F, SwitchToFullScreen);
buttonInputs.RegisterOnPress(Keys.R, ResetCamera); buttonInputs.RegisterOnPress(Keys.R, ResetCamera);
} }
@ -24,21 +30,21 @@ public class CameraController : Behaviour
protected override void OnUpdate() protected override void OnUpdate()
{ {
if (buttonInputs.IsPressed(Keys.U)) if (buttonInputs.IsPressed(Keys.U))
cameraBehaviour.Zoom += Universe.Time.DeltaTime * 5f; cameraBehaviour.Zoom += Time.Elapsed.Nanoseconds * 0.00025f;
if (buttonInputs.IsPressed(Keys.J)) if (buttonInputs.IsPressed(Keys.J))
cameraBehaviour.Zoom -= Universe.Time.DeltaTime * 5f; cameraBehaviour.Zoom -= Time.Elapsed.Nanoseconds * 0.00025f;
if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.Transform.LocalPosition += Vector2D.Up * Universe.Time.DeltaTime * 500f; 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.Transform.LocalPosition -= Vector2D.Up * Universe.Time.DeltaTime * 500f; 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.Transform.LocalPosition += Vector2D.Right * Universe.Time.DeltaTime * 500f; 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.Transform.LocalPosition -= Vector2D.Right * Universe.Time.DeltaTime * 500f; if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame;
if (buttonInputs.IsPressed(Keys.Q)) if (buttonInputs.IsPressed(Keys.Q))
cameraBehaviour.Transform.Rotation += Universe.Time.DeltaTime * 45f; cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += Time.Elapsed.Nanoseconds * 0.0025f;
if (buttonInputs.IsPressed(Keys.E)) if (buttonInputs.IsPressed(Keys.E))
cameraBehaviour.Transform.Rotation -= Universe.Time.DeltaTime * 45f; cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= Time.Elapsed.Nanoseconds * 0.0025f;
} }
private void SwitchToFullScreen(IButtonInputs<Keys> inputs, Keys keys) private void SwitchToFullScreen(IButtonInputs<Keys> inputs, Keys keys)
@ -62,7 +68,7 @@ public class CameraController : Behaviour
private void ResetCamera(IButtonInputs<Keys> inputs, Keys keys) private void ResetCamera(IButtonInputs<Keys> inputs, Keys keys)
{ {
cameraBehaviour.Zoom = defaultZoomLevel; cameraBehaviour.Zoom = defaultZoomLevel;
cameraBehaviour.Transform.LocalPosition = Vector2D.Zero; Transform.Position = Vector2D.Zero;
cameraBehaviour.Transform.LocalRotation = 0f; Transform.Rotation = 0f;
} }
} }

View File

@ -2,7 +2,8 @@ using Microsoft.Xna.Framework;
using Apos.Shapes; using Apos.Shapes;
using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Physics2D.Primitives;
namespace Pong.Behaviours; namespace Pong.Behaviours;

View File

@ -4,14 +4,14 @@ using System.Collections.Generic;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Systems.Input; using Syntriax.Engine.Input;
namespace Pong.Platforms.Desktop; namespace Pong.Behaviours;
public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys> public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
{ {
private readonly Dictionary<Keys, IButtonInputs<Keys>.ButtonCallbackEventHandler> OnPressed = new(256); private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>> OnPressed = new(256);
private readonly Dictionary<Keys, IButtonInputs<Keys>.ButtonCallbackEventHandler> OnReleased = new(256); private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>> OnReleased = new(256);
private int cachePressedCurrentlyCount = 0; private int cachePressedCurrentlyCount = 0;
private readonly Keys[] cachePressedCurrently = new Keys[256]; private readonly Keys[] cachePressedCurrently = new Keys[256];
@ -19,10 +19,7 @@ public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>
private int cachePressedPreviouslyCount = 0; private int cachePressedPreviouslyCount = 0;
private readonly Keys[] cachePressedPreviously = new Keys[256]; private readonly Keys[] cachePressedPreviously = new Keys[256];
public event IButtonInputs<Keys>.ButtonCallbackEventHandler? OnAnyButtonPressed = null; public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
public event IButtonInputs<Keys>.ButtonCallbackEventHandler? OnAnyButtonReleased = null;
public void RegisterOnPress(Keys key, IButtonInputs<Keys>.ButtonCallbackEventHandler callback)
{ {
if (OnPressed.TryGetValue(key, out var action)) if (OnPressed.TryGetValue(key, out var action))
{ {
@ -33,13 +30,13 @@ public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>
OnPressed.Add(key, callback); OnPressed.Add(key, callback);
} }
public void UnregisterOnPress(Keys key, IButtonInputs<Keys>.ButtonCallbackEventHandler callback) public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
{ {
if (OnPressed.TryGetValue(key, out var action)) if (OnPressed.TryGetValue(key, out var action))
action -= callback; action -= callback;
} }
public void RegisterOnRelease(Keys key, IButtonInputs<Keys>.ButtonCallbackEventHandler callback) public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
{ {
if (OnReleased.TryGetValue(key, out var action)) if (OnReleased.TryGetValue(key, out var action))
{ {
@ -50,7 +47,7 @@ public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>
OnReleased.Add(key, callback); OnReleased.Add(key, callback);
} }
public void UnregisterOnRelease(Keys key, IButtonInputs<Keys>.ButtonCallbackEventHandler callback) public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
{ {
if (OnReleased.TryGetValue(key, out var action)) if (OnReleased.TryGetValue(key, out var action))
action -= callback; action -= callback;
@ -72,8 +69,7 @@ public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>
if (WasPressed(currentlyPressedKey)) if (WasPressed(currentlyPressedKey))
continue; continue;
action.InvokeSafe(this, currentlyPressedKey); action.Invoke(this, currentlyPressedKey);
OnAnyButtonPressed?.InvokeSafe(this, currentlyPressedKey);
} }
for (int i = 0; i < cachePressedPreviouslyCount; i++) for (int i = 0; i < cachePressedPreviouslyCount; i++)
@ -86,8 +82,7 @@ public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>
if (IsPressed(previouslyPressedKey)) if (IsPressed(previouslyPressedKey))
continue; continue;
action.InvokeSafe(this, previouslyPressedKey); action.Invoke(this, previouslyPressedKey);
OnAnyButtonReleased?.InvokeSafe(this, previouslyPressedKey);
} }
Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);

View File

@ -2,10 +2,11 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behaviour2D, ICamera2D public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D
{ {
public event OnMatrixTransformChangedDelegate? OnMatrixTransformChanged = null; public event OnMatrixTransformChangedDelegate? OnMatrixTransformChanged = null;
public event OnViewportChangedDelegate? OnViewportChanged = null; public event OnViewportChangedDelegate? OnViewportChanged = null;
@ -27,7 +28,7 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
return; return;
_matrixTransform = value; _matrixTransform = value;
OnMatrixTransformChanged?.InvokeSafe(this); OnMatrixTransformChanged?.Invoke(this);
} }
} }
@ -46,7 +47,7 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
return; return;
_viewport = value; _viewport = value;
OnViewportChanged?.InvokeSafe(this); OnViewportChanged?.Invoke(this);
} }
} }
@ -61,7 +62,7 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
return; return;
_zoom = newValue; _zoom = newValue;
OnZoomChanged?.InvokeSafe(this); OnZoomChanged?.Invoke(this);
} }
} }
@ -71,6 +72,10 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
set => Transform.Rotation = value; 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 // TODO This causes delay since OnPreDraw calls assuming this is called in in Update
public Vector2D ScreenToWorldPosition(Vector2D screenPosition) public Vector2D ScreenToWorldPosition(Vector2D screenPosition)
{ {

View File

@ -1,9 +1,12 @@
using System;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D;
using Syntriax.Engine.Physics2D.Abstract;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class MovementBallBehaviour : Behaviour2D public class MovementBallBehaviour : BehaviourOverride
{ {
public Vector2D StartDirection { get; private set; } = Vector2D.Zero; public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
public float Speed { get; set; } = 500f; public float Speed { get; set; } = 500f;
@ -13,10 +16,15 @@ public class MovementBallBehaviour : Behaviour2D
protected override void OnFirstActiveFrame() protected override void OnFirstActiveFrame()
{ {
rigidBody = BehaviourController.GetRequiredBehaviour<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;
BehaviourController.GetRequiredBehaviour<ICollider2D>().OnCollisionDetected += OnCollisionDetected; foundCollider.OnCollisionDetected += OnCollisionDetected;
rigidBody = foundRigidBody;
} }
protected override void OnUpdate() protected override void OnUpdate()
@ -24,14 +32,14 @@ public class MovementBallBehaviour : Behaviour2D
if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) if (rigidBody.Velocity.MagnitudeSquared <= 0.01f)
return; return;
Vector2D speedUp = rigidBody.Velocity.Normalized * Universe.Time.DeltaTime; Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame;
rigidBody.Velocity += speedUp * SpeedUpMultiplier; rigidBody.Velocity += speedUp * SpeedUpMultiplier;
} }
private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information)
{ {
if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25)
rigidBody.Velocity = information.Detector.Transform.Position.FromTo(information.Detected.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
else else
rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
} }

View 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);
}
}
}

View File

@ -3,11 +3,10 @@ using System;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Systems.Input;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class PongManagerBehaviour : Behaviour public class PongManagerBehaviour : BehaviourOverride
{ {
public Action<PongManagerBehaviour>? OnReset { get; set; } = null; public Action<PongManagerBehaviour>? OnReset { get; set; } = null;
public Action<PongManagerBehaviour>? OnFinished { get; set; } = null; public Action<PongManagerBehaviour>? OnFinished { get; set; } = null;
@ -24,7 +23,11 @@ public class PongManagerBehaviour : Behaviour
protected override void OnFirstActiveFrame() protected override void OnFirstActiveFrame()
{ {
var buttonInputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>(); KeyboardInputsBehaviour? buttonInputs = null!;
if (!BehaviourController.TryGetBehaviour(out buttonInputs))
buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset()); buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset());
} }
@ -32,7 +35,7 @@ public class PongManagerBehaviour : Behaviour
public void ScoreToLeft() public void ScoreToLeft()
{ {
ScoreLeft++; ScoreLeft++;
OnScored?.InvokeSafe(this); OnScored?.Invoke(this);
CheckFinish(); CheckFinish();
} }
@ -40,7 +43,7 @@ public class PongManagerBehaviour : Behaviour
public void ScoreToRight() public void ScoreToRight()
{ {
ScoreRight++; ScoreRight++;
OnScored?.InvokeSafe(this); OnScored?.Invoke(this);
CheckFinish(); CheckFinish();
} }
@ -48,7 +51,7 @@ public class PongManagerBehaviour : Behaviour
public void Reset() public void Reset()
{ {
ScoreLeft = ScoreRight = 0; ScoreLeft = ScoreRight = 0;
OnReset?.InvokeSafe(this); OnReset?.Invoke(this);
} }
private void CheckFinish() private void CheckFinish()
@ -56,6 +59,6 @@ public class PongManagerBehaviour : Behaviour
int halfwayScore = (int)(WinScore * .5f); int halfwayScore = (int)(WinScore * .5f);
if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore) if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
OnFinished?.InvokeSafe(this); OnFinished?.Invoke(this);
} }
} }

View File

@ -3,12 +3,14 @@ using Microsoft.Xna.Framework;
using Apos.Shapes; using Apos.Shapes;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Physics2D; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Systems.Input; using Syntriax.Engine.Input;
using Syntriax.Engine.Physics2D.Abstract;
using Syntriax.Engine.Physics2D.Primitives;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class ShapeAABBBehaviour : Behaviour2D, IDisplayableShape public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape
{ {
private IShapeCollider2D? shapeCollider = null; private IShapeCollider2D? shapeCollider = null;

View File

@ -2,7 +2,8 @@ using Microsoft.Xna.Framework;
using Apos.Shapes; using Apos.Shapes;
using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Physics2D.Primitives;
namespace Pong.Behaviours; namespace Pong.Behaviours;
@ -25,8 +26,8 @@ public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour
shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color); shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color);
} }
public ShapeBehaviour(Shape2D shape) : base(shape) { } public ShapeBehaviour(Shape shape) : base(shape) { }
public ShapeBehaviour(Shape2D shape, float thickness) : base(shape) { Thickness = thickness; } public ShapeBehaviour(Shape shape, float thickness) : base(shape) { Thickness = thickness; }
public ShapeBehaviour(Shape2D shape, Color color) : base(shape) { Color = color; } public ShapeBehaviour(Shape shape, Color color) : base(shape) { Color = color; }
public ShapeBehaviour(Shape2D shape, Color color, float thickness) : base(shape) { Thickness = thickness; Color = color; } public ShapeBehaviour(Shape shape, Color color, float thickness) : base(shape) { Thickness = thickness; Color = color; }
} }

View File

@ -2,10 +2,11 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class TextBehaviour : Behaviour2D, IDisplayableSprite public class TextBehaviour : BehaviourOverride, IDisplayableSprite
{ {
public SpriteFont? Font { get; set; } = null; public SpriteFont? Font { get; set; } = null;
public int Size { get; set; } = 16; public int Size { get; set; } = 16;

View File

@ -11,7 +11,7 @@ public class TextScoreBehaviour : TextBehaviour
protected override void OnFirstActiveFrame() protected override void OnFirstActiveFrame()
{ {
if (!UniverseObject.Universe.TryFindBehaviour(out pongManager)) if (!GameObject.GameManager.TryFindBehaviour(out pongManager))
return; return;
pongManager.OnScored += UpdateScores; pongManager.OnScored += UpdateScores;

View File

@ -1,11 +1,11 @@
using System; using System;
using Syntriax.Engine.Core; using Syntriax.Engine.Core;
using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D.Abstract;
namespace Pong.Behaviours; namespace Pong.Behaviours;
public class WallScoreBehaviour(Action OnCollision) : Behaviour2D public class WallScoreBehaviour(Action OnCollision) : BehaviourOverride
{ {
private Action OnCollision { get; } = OnCollision; private Action OnCollision { get; } = OnCollision;
@ -14,6 +14,6 @@ public class WallScoreBehaviour(Action OnCollision) : Behaviour2D
if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D)) if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D))
return; return;
collider2D.OnCollisionDetected += (_, _1) => OnCollision?.InvokeSafe(); collider2D.OnCollisionDetected += (_, _1) => OnCollision?.Invoke();
} }
} }

View File

@ -9,7 +9,7 @@ public static class EngineConverter
public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UniverseTime ToUniverseTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -6,7 +6,6 @@
<PublishReadyToRun>false</PublishReadyToRun> <PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation> <TieredCompilation>false</TieredCompilation>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Pong.Platforms.Desktop</RootNamespace>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
@ -17,28 +16,19 @@
<None Remove="Icon.bmp" /> <None Remove="Icon.bmp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Icon.ico"> <EmbeddedResource Include="Icon.ico" />
<LogicalName>Icon.ico</LogicalName> <EmbeddedResource Include="Icon.bmp" />
</EmbeddedResource>
<EmbeddedResource Include="Icon.bmp">
<LogicalName>Icon.bmp</LogicalName>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" /> <PackageReference Include="Apos.Shapes" Version="0.2.3" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.2.1105" /> <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>
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../Shared/Shared.csproj" /> <ProjectReference Include="..\Engine\Engine.Core\Engine.Core.csproj" />
</ItemGroup> <ProjectReference Include="..\Engine\Engine.Input\Engine.Input.csproj" />
<ProjectReference Include="..\Engine\Engine.Physics2D\Engine.Physics2D.csproj" />
<ItemGroup>
<MonoGameContentReference Include="../../Shared/Content/Content.mgcb">
<Link>Content/Content.mgcb</Link>
</MonoGameContentReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../Shared/Shared.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore"> <Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" /> <Message Text="Restoring dotnet tools" Importance="High" />

197
Game/GamePong.cs Normal file
View 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);
}
}

View File

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

View File

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View 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; }
}

View 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);
}

View File

@ -0,0 +1,6 @@
namespace Syntriax.Engine.Network.Abstract;
public interface INetworkCommunicatorClient : INetworkCommunicator
{
void Connect(string address, int port, string? password = null);
}

View 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);
}

View 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);
}

View 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;
}

View File

@ -0,0 +1,5 @@
using LiteNetLib.Utils;
namespace Syntriax.Engine.Network.Abstract;
public interface INetworkPacket : INetSerializable;

View 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
View 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);
}

View 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);
}

View 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);
}
}

View 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);
}
}

View 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) { }
}

View 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]);
}
}

3
Game/Program.cs Normal file
View File

@ -0,0 +1,3 @@

using var game = new Pong.GamePong();
game.Run();

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Desktop"/> <assemblyIdentity version="1.0.0.0" name="Game"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security> <security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">

View File

@ -1,15 +0,0 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#

View File

@ -1,7 +0,0 @@
using Pong.Platforms.Desktop;
using Syntriax.Engine.Core;
Syntriax.Engine.Core.IUniverseObject universeObject = Syntriax.Engine.Core.Factory.UniverseObjectFactory.Instantiate().SetUniverseObject("Desktop HO");
universeObject.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
using var game = new Pong.GamePong(universeObject);
game.Run();

View File

@ -7,57 +7,41 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{F7F626
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine\Engine.Core\Engine.Core.csproj", "{990CA10C-1EBB-4395-A43A-456B7029D8C9}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine\Engine.Core\Engine.Core.csproj", "{990CA10C-1EBB-4395-A43A-456B7029D8C9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj", "{500E1B05-39D7-4232-8051-E7351D745306}"
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.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine\Engine.csproj", "{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platforms", "Platforms", "{FECFFD54-338F-4060-9161-1E5770D1DC33}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop", "Platforms\Desktop\Desktop.csproj", "{2B627F66-5A61-4F69-B479-62EEAB603D01}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine\Engine.Systems\Engine.Systems.csproj", "{8863A1BA-2E83-419F-BACB-D4A4156EC71C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU {990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU
{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.Build.0 = Debug|Any CPU
{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.ActiveCfg = Release|Any CPU
{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.Build.0 = Release|Any CPU
{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|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}.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.ActiveCfg = Release|Any CPU
{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU {0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU
{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.Build.0 = Release|Any CPU
{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.Build.0 = Release|Any CPU
{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.Build.0 = Release|Any CPU
{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401} {990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
{0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401} {0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
{2F6B1E26-1217-4EFD-874C-05ADEE4C7969} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
{2B627F66-5A61-4F69-B479-62EEAB603D01} = {FECFFD54-338F-4060-9161-1E5770D1DC33}
{8863A1BA-2E83-419F-BACB-D4A4156EC71C} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -1,36 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.2.1105",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.2.1105",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.2.1105",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.2.1105",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.2.1105",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View File

@ -1,60 +0,0 @@
using System;
using Microsoft.Xna.Framework.Input;
using Syntriax.Engine.Core;
using Syntriax.Engine.Systems.Input;
namespace Pong.Behaviours;
public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : Behaviour2D
{
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)
Transform.Position = Transform.Position + Vector2D.Up * Universe.Time.DeltaTime * Speed;
else if (isDownPressed)
Transform.Position = Transform.Position + -Vector2D.Up * Universe.Time.DeltaTime * Speed;
Transform.Position = new Vector2D(Transform.Position.X, MathF.Max(MathF.Min(Transform.Position.Y, High), Low));
}
protected override void OnFirstActiveFrame()
{
inputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>();
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;
}

Binary file not shown.

View File

@ -1,164 +0,0 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Pong.Behaviours;
using Apos.Shapes;
using Syntriax.Engine.Core;
using Syntriax.Engine.Physics2D;
namespace Pong;
public class GamePong : Game
{
private readonly IUniverseObject platformSpecificUniverseObject = null!;
private readonly GraphicsDeviceManager graphics = null!;
private SpriteBatch spriteBatch = null!;
private ShapeBatch shapeBatch = null!;
private Universe universe = null!;
private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!;
private MonoGameCamera2DBehaviour cameraBehaviour = null!;
private PongManagerBehaviour pongManager = null!;
public GamePong(IUniverseObject platformSpecificUniverseObject)
{
this.platformSpecificUniverseObject = platformSpecificUniverseObject;
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
universe = new();
displayableCollector = new(universe);
displayableShapeCollector = new(universe);
universe.Initialize();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
shapeBatch = new ShapeBatch(GraphicsDevice, Content);
SpriteFont spriteFont = Content.Load<SpriteFont>("UbuntuMono");
universe.Register(platformSpecificUniverseObject);
universe.InstantiateUniverseObject<PhysicsEngine2D>().SetUniverseObject("Physics Engine 2D");
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectCamera = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Camera"); ;
UniverseObjectCamera.BehaviourController.AddBehaviour<Transform2D>();
UniverseObjectCamera.BehaviourController.AddBehaviour<CameraController>();
cameraBehaviour = UniverseObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics);
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectPongManager = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Pong Game Manager");
pongManager = UniverseObjectPongManager.BehaviourController.AddBehaviour<PongManagerBehaviour>(5);
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectBall = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Ball");
UniverseObjectBall.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f));
UniverseObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f));
UniverseObjectBall.BehaviourController.AddBehaviour<BallBehaviour>();
UniverseObjectBall.BehaviourController.AddBehaviour<RigidBody2D>();
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectLeftPaddle = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Left Paddle");
UniverseObjectLeftPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f));
UniverseObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f);
UniverseObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
IUniverseObject UniverseObjectRightPaddle = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Right Paddle");
UniverseObjectRightPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f));
UniverseObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f);
UniverseObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectWallTop = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Wall Top");
UniverseObjectWallTop.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f));
UniverseObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
IUniverseObject UniverseObjectWallBottom = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Wall Bottom");
UniverseObjectWallBottom.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f));
UniverseObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
IUniverseObject UniverseObjectWallRight = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Wall Right");
UniverseObjectWallRight.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f));
UniverseObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft);
UniverseObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
IUniverseObject UniverseObjectWallLeft = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Wall Left");
UniverseObjectWallLeft.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f));
UniverseObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight);
UniverseObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square);
UniverseObjectWallLeft.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
////////////////////////////////////////////////////////////////////////////////////
IUniverseObject UniverseObjectLeftScoreText = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Score Left");
UniverseObjectLeftScoreText.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f);
UniverseObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont);
IUniverseObject UniverseObjectRightScoreText = universe.InstantiateUniverseObject<UniverseObject>().SetUniverseObject("Score Right");
UniverseObjectRightScoreText.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f);
UniverseObjectRightScoreText.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();
universe.Update(gameTime.ToUniverseTime());
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
universe.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);
}
}

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Apos.Shapes" Version="0.2.3" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Engine/Engine/Engine.csproj" />
</ItemGroup>
</Project>