using Syntriax.Engine.Core; using Syntriax.Engine.Network; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Systems.Tween; namespace Pong.Behaviours; public class BallBehaviour : Behaviour2D, IPhysicsUpdate, INetworkEntity, IPacketListenerClient { public float Speed { get; set; } = 500f; public float SpeedUpMultiplier { get; set; } = .0125f; public IRigidBody2D RigidBody { get; private set; } = null!; private IPhysicsEngine2D physicsEngine2D = null!; private ITweenManager tweenManager = null!; private INetworkCommunicatorServer? networkServer = null; protected override void OnFirstActiveFrame() { BehaviourController.GetRequiredBehaviour().OnCollisionDetected += OnCollisionDetected; physicsEngine2D = Universe.GetRequiredUniverseObject(); tweenManager = Universe.GetRequiredUniverseObject(); RigidBody = BehaviourController.GetRequiredBehaviour(); networkServer = Universe.Find(); } public void LaunchBall(Vector2D launchDirection) { ResetBall(); RigidBody.Velocity = launchDirection * Speed; networkServer?.SendToClient("*", new BallUpdatePacket(this)); } public void ResetBall() { Transform.Position = Vector2D.Zero; RigidBody.Velocity = Vector2D.Zero; } public void PhysicsUpdate(float delta) { if (RigidBody.Velocity.MagnitudeSquared <= 0.01f) return; Vector2D direction = RigidBody.Velocity.Normalized; RigidBody.Velocity += direction * delta * SpeedUpMultiplier; } private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) { if (Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) RigidBody.Velocity = information.Detected.Transform.Position.FromTo(information.Detector.Transform.Position).Normalized * RigidBody.Velocity.Magnitude; else RigidBody.Velocity = RigidBody.Velocity.Reflect(information.Normal); networkServer?.SendToClient("*", new BallUpdatePacket(this)); } public BallBehaviour() { } public BallBehaviour(float speed) => Speed = speed; void IPacketListenerClient.OnClientPacketArrived(BallUpdatePacket packet) { Transform.TweenPositionAdditive(tweenManager, .25f, Transform.Position.FromTo(packet.Position)); RigidBody.Velocity = packet.Velocity; physicsEngine2D.StepIndividual(RigidBody, new System.DateTime(System.DateTime.UtcNow.Ticks - packet.Timestamp).Second); } private class BallUpdatePacket : INetworkPacket { public Vector2D Position { get; set; } = Vector2D.Zero; public Vector2D Velocity { get; set; } = Vector2D.Zero; public long Timestamp { get; set; } = 0; public BallUpdatePacket() { } public BallUpdatePacket(BallBehaviour ballBehaviour) { Position = ballBehaviour.Transform.Position; Velocity = ballBehaviour.RigidBody.Velocity; Timestamp = System.DateTime.UtcNow.Ticks; } } }