using System; using Microsoft.Xna.Framework.Input; using Syntriax.Engine.Core; using Syntriax.Engine.Network; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Systems.Input; namespace Pong.Behaviours; public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : Behaviour2D, IFirstFrameUpdate, IPostPhysicsUpdate, IPacketListenerServer, IPacketListenerClient { 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 inputs = null!; private INetworkCommunicatorClient? networkClient = null!; private INetworkCommunicatorServer? networkServer = null; private IRigidBody2D rigidBody = null!; private IPhysicsEngine2D physicsEngine2D = null!; public void PostPhysicsUpdate(float delta) { Transform.Position = new Vector2D(Transform.Position.X, MathF.Max(MathF.Min(Transform.Position.Y, High), Low)); } public void FirstActiveFrame() { physicsEngine2D = Universe.GetRequiredUniverseObject(); inputs = Universe.FindRequired>(); networkClient = Universe.Find(); networkServer = Universe.Find(); rigidBody = BehaviourController.GetRequiredBehaviour(); 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 sender, IButtonInputs.ButtonCallbackArguments args) { isUpPressed = true; UpdateVelocity(); networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } private void OnUpReleased(IButtonInputs sender, IButtonInputs.ButtonCallbackArguments args) { isUpPressed = false; UpdateVelocity(); networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } private void OnDownPressed(IButtonInputs sender, IButtonInputs.ButtonCallbackArguments args) { isDownPressed = true; UpdateVelocity(); networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } private void OnDownReleased(IButtonInputs sender, IButtonInputs.ButtonCallbackArguments args) { isDownPressed = false; UpdateVelocity(); networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } private void UpdateVelocity() { if (isUpPressed) rigidBody.Velocity = Vector2D.Up * Speed; else if (isDownPressed) rigidBody.Velocity = -Vector2D.Up * Speed; else rigidBody.Velocity = Vector2D.Zero; } public void OnServerPacketArrived(string sender, PaddleKeyStatePacket packet) { isUpPressed = packet.IsUpPressed; isDownPressed = packet.IsDownPressed; UpdateVelocity(); networkServer?.SendToClient("*", new PaddleKeyStatePacket(this)); } public void OnClientPacketArrived(PaddleKeyStatePacket packet) { isUpPressed = packet.IsUpPressed; isDownPressed = packet.IsDownPressed; Transform.Position = packet.Position; UpdateVelocity(); physicsEngine2D.StepIndividual(rigidBody, new DateTime(DateTime.UtcNow.Ticks - packet.Timestamp).Second); } public class PaddleKeyStatePacket : IEntityNetworkPacket { public string EntityId { get; set; } = default!; public Vector2D Position { get; set; } = default!; public bool IsUpPressed { get; set; } = default!; public bool IsDownPressed { get; set; } = default!; public long Timestamp { get; set; } = 0; public PaddleKeyStatePacket Set(PaddleBehaviour paddleBehaviour) { EntityId = paddleBehaviour.Id; Position = paddleBehaviour.Transform.Position; IsUpPressed = paddleBehaviour.isUpPressed; IsDownPressed = paddleBehaviour.isDownPressed; Timestamp = DateTime.UtcNow.Ticks; return this; } public PaddleKeyStatePacket() { } public PaddleKeyStatePacket(PaddleBehaviour paddleBehaviour) => Set(paddleBehaviour); } }