155 lines
4.6 KiB
C#
155 lines
4.6 KiB
C#
using System;
|
|
|
|
using Microsoft.Xna.Framework.Audio;
|
|
using Microsoft.Xna.Framework.Content;
|
|
|
|
using Syntriax.Engine.Core;
|
|
using Syntriax.Engine.Core.Debug;
|
|
using Syntriax.Engine.Integration.MonoGame;
|
|
using Syntriax.Engine.Network;
|
|
|
|
namespace Pong.Behaviours;
|
|
|
|
public class PongManager : Behaviour, INetworkEntity, IFirstFrameUpdate, ILoadContent,
|
|
IPacketListenerClient<PongManager.StartPacket>,
|
|
IPacketListenerClient<PongManager.ScorePacket>
|
|
{
|
|
public Action<PongManager>? OnReset { get; set; } = null;
|
|
public Action<PongManager>? OnFinished { get; set; } = null;
|
|
public Action<PongManager>? OnScoreUpdated { get; set; } = null;
|
|
|
|
private Random random = new();
|
|
|
|
private INetworkCommunicatorServer? networkServer = null;
|
|
private ILogger? logger = null;
|
|
private SoundEffectInstance? scoreSoundEffect = null;
|
|
private SoundEffectInstance? gameEndSoundEffect = 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 Ball Ball { get; private set; } = null!;
|
|
public bool IsGameInProgress { get; private set; } = false;
|
|
|
|
public PongManager() => WinScore = 5;
|
|
public PongManager(int winScore) => WinScore = winScore;
|
|
|
|
public void FirstActiveFrame()
|
|
{
|
|
Ball = Universe.FindRequiredBehaviour<Ball>();
|
|
networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>();
|
|
logger = Universe.FindBehaviour<ILogger>();
|
|
}
|
|
|
|
public void LoadContent(ContentManager content)
|
|
{
|
|
gameEndSoundEffect = content.Load<SoundEffect>("Audio/Win").CreateInstance();
|
|
scoreSoundEffect = content.Load<SoundEffect>("Audio/Score").CreateInstance();
|
|
}
|
|
|
|
public void ScoreToLeft()
|
|
{
|
|
ScoreLeft++;
|
|
PostScoreUpdate();
|
|
}
|
|
|
|
public void ScoreToRight()
|
|
{
|
|
ScoreRight++;
|
|
PostScoreUpdate();
|
|
}
|
|
|
|
public bool Start()
|
|
{
|
|
if (networkServer is null)
|
|
return false;
|
|
|
|
if (Ball.RigidBody.Velocity.MagnitudeSquared > 0.01f)
|
|
return false;
|
|
|
|
Reset();
|
|
IsGameInProgress = true;
|
|
PostScoreUpdate();
|
|
networkServer.SendToAll(new StartPacket());
|
|
logger?.Log(this, $"Game started");
|
|
return true;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
ScoreLeft = ScoreRight = 0;
|
|
IsGameInProgress = false;
|
|
|
|
Ball.ResetBall();
|
|
|
|
OnReset?.Invoke(this);
|
|
}
|
|
|
|
private void PostScoreUpdate()
|
|
{
|
|
OnScoreUpdated?.Invoke(this);
|
|
Ball.ResetBall();
|
|
|
|
if (networkServer is not null)
|
|
{
|
|
networkServer.SendToAll(new ScorePacket(this));
|
|
logger?.Log(this, $"Sending score update packet to all: {ScoreLeft} - {ScoreRight}");
|
|
}
|
|
|
|
int halfwayScore = (int)(WinScore * .5f);
|
|
if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
|
|
{
|
|
IsGameInProgress = false;
|
|
gameEndSoundEffect?.Play();
|
|
OnFinished?.Invoke(this);
|
|
logger?.Log(this, $"Game finished: {ScoreLeft} - {ScoreRight}");
|
|
return;
|
|
}
|
|
|
|
Ball.LaunchBall(GetBallLaunchDirection());
|
|
}
|
|
|
|
private Vector2D GetBallLaunchDirection()
|
|
{
|
|
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);
|
|
}
|
|
|
|
void IPacketListenerClient<ScorePacket>.OnClientPacketArrived(IConnection sender, ScorePacket packet)
|
|
{
|
|
ScoreLeft = packet.Left;
|
|
ScoreRight = packet.Right;
|
|
|
|
PostScoreUpdate();
|
|
|
|
if (IsGameInProgress && (ScoreLeft != 0 || ScoreRight != 0))
|
|
scoreSoundEffect?.Play();
|
|
|
|
logger?.Log(this, $"Client score update packet arrived: {packet.Left} - {packet.Right}");
|
|
}
|
|
|
|
void IPacketListenerClient<StartPacket>.OnClientPacketArrived(IConnection sender, StartPacket packet)
|
|
{
|
|
IsGameInProgress = true;
|
|
logger?.Log(this, $"Game started");
|
|
}
|
|
|
|
private class StartPacket : INetworkPacket;
|
|
private class ScorePacket : INetworkPacket
|
|
{
|
|
public int Left { get; set; }
|
|
public int Right { get; set; }
|
|
|
|
public ScorePacket() { }
|
|
public ScorePacket(PongManager pongManagerBehaviour)
|
|
{
|
|
Left = pongManagerBehaviour.ScoreLeft;
|
|
Right = pongManagerBehaviour.ScoreRight;
|
|
}
|
|
}
|
|
}
|