diff --git a/PongGame/Hubs/GameState.cs b/PongGame/Hubs/GameState.cs
index d878289..786a769 100644
--- a/PongGame/Hubs/GameState.cs
+++ b/PongGame/Hubs/GameState.cs
@@ -1,6 +1,6 @@
namespace PongGame;
-public enum GameState {
+public enum GameStatus {
WaitingForPlayers,
InProgress,
Finished,
diff --git a/PongGame/Hubs/IPongClient.cs b/PongGame/Hubs/IPongClient.cs
index 4a7b51b..77117d5 100644
--- a/PongGame/Hubs/IPongClient.cs
+++ b/PongGame/Hubs/IPongClient.cs
@@ -1,6 +1,6 @@
namespace PongGame.Hubs;
public interface IPongClient {
- Task GameStateChanged(GameState state);
+ Task GameStateChanged(GameStatus state);
Task UsernameChanged(string value);
}
\ No newline at end of file
diff --git a/PongGame/Hubs/PongGameState.cs b/PongGame/Hubs/PongGameState.cs
new file mode 100644
index 0000000..2981cb9
--- /dev/null
+++ b/PongGame/Hubs/PongGameState.cs
@@ -0,0 +1,35 @@
+namespace PongGame.Hubs;
+
+///
+/// Pong game state saving the positions of the paddles and the ball.
+/// The Pong board has aspect ratio 1:2 with height 500 and width 1000.
+///
+public struct PongGameState {
+ private const double HEIGHT = 500.0d;
+ private const double WIDTH = 2 * HEIGHT;
+ private const double PADDLE_LENGTH = HEIGHT / 10;
+ private const double BALL_SPEED = 8;
+ public static readonly PongGameState Initial = new() {
+ BallPosition = PongBallPosition.Initial,
+ P1Height = HEIGHT / 2,
+ P2Height = HEIGHT / 2,
+ P1Direction = PongPaddleDirection.Stop,
+ P2Direction = PongPaddleDirection.Stop,
+ Status = GameStatus.WaitingForPlayers
+ };
+ public double P1Height { get; set; }
+ public double P2Height { get; set; }
+ public PongBallPosition BallPosition { get; set; }
+ public GameStatus Status { get; set; }
+ public PongPaddleDirection P1Direction { get; set; }
+ public PongPaddleDirection P2Direction { get; set; }
+
+ public struct PongBallPosition {
+ public static readonly PongBallPosition Initial = new() {
+ X = WIDTH / 2,
+ Y = HEIGHT / 2
+ };
+ public double X { get; set; }
+ public double Y { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/PongGame/Hubs/PongHub.cs b/PongGame/Hubs/PongHub.cs
index b5c98d2..f9fc32d 100644
--- a/PongGame/Hubs/PongHub.cs
+++ b/PongGame/Hubs/PongHub.cs
@@ -30,6 +30,12 @@ public class PongHub : Hub {
throw new HubException($"User is already connected to room [{currentRoom}]");
}
+ private PongRoom AssertInRoom() {
+ if (Player.ConnectedRoom is not PongRoom currentRoom)
+ throw new HubException($"User is not in any room!");
+ return currentRoom;
+ }
+
public Task CreateRoom() {
AssertNotInRoom();
var room = Lobby.CreateRoom(Player);
@@ -42,6 +48,15 @@ public class PongHub : Hub {
return Task.FromResult(room.ID);
}
+ public Task MovePaddle(int dir) {
+ var room = AssertInRoom();
+ var direction = (PongPaddleDirection)dir;
+ if (!Enum.IsDefined(direction))
+ throw new HubException($"Invalid direction: {dir}!");
+ room.MovePaddle(Player, direction);
+ return Task.CompletedTask;
+ }
+
public Task LeaveRoom() {
Lobby.LeaveRoom(Player);
return Task.CompletedTask;
diff --git a/PongGame/Hubs/PongPaddleDirection.cs b/PongGame/Hubs/PongPaddleDirection.cs
new file mode 100644
index 0000000..fd42c1c
--- /dev/null
+++ b/PongGame/Hubs/PongPaddleDirection.cs
@@ -0,0 +1,7 @@
+namespace PongGame;
+
+public enum PongPaddleDirection {
+ Up = -1,
+ Stop,
+ Down,
+}
\ No newline at end of file
diff --git a/PongGame/Hubs/PongRoom.cs b/PongGame/Hubs/PongRoom.cs
index 25b8de4..26ee9c8 100644
--- a/PongGame/Hubs/PongRoom.cs
+++ b/PongGame/Hubs/PongRoom.cs
@@ -5,6 +5,9 @@ namespace PongGame.Hubs;
public class PongRoom {
public string ID { get; }
private readonly ILogger Logger;
+ private const string JOIN_LOG_TEMPLATE = "[{ID}] {Player} joined pong room as player {Number}!";
+ private const string LEAVE_LOG_TEMPLATE = "[{ID}] Player {Number} {Player} left pong room!";
+ private const string DIRECTION_LOG_TEMPLATE = "[{ID}] Player {Number} {player} moves paddle in direction: {direction}!";
public PongRoom(string id, ILogger logger) {
ID = id;
@@ -13,16 +16,16 @@ public class PongRoom {
public PongPlayer? Player1 { get; private set; }
public PongPlayer? Player2 { get; private set; }
- public GameState State { get; private set; } = GameState.WaitingForPlayers;
+ private PongGameState State = PongGameState.Initial;
public void Join(PongPlayer player) {
// TODO: synchronize this
if (Player1 is null) {
Player1 = player;
- Logger.LogInformation($"[{ID}] {player} joined pong room as player 1!");
+ Logger.LogInformation(JOIN_LOG_TEMPLATE, ID, player, 1);
} else if (Player2 is null) {
Player2 = player;
- Logger.LogInformation($"[{ID}] {player} joined pong room as player 2!");
+ Logger.LogInformation(JOIN_LOG_TEMPLATE, ID, player, 1);
} else
throw new HubException($"Lobby [{ID}] is already full!");
_ = Task.Run(PlayersChanged);
@@ -32,10 +35,10 @@ public class PongRoom {
public void Leave(PongPlayer player) {
if (Player1 == player) {
Player1 = null;
- Logger.LogInformation($"[{ID}] Player 1 {player} left pong room!");
+ Logger.LogInformation(LEAVE_LOG_TEMPLATE, ID, 1, player);
} else if (Player2 == player) {
Player2 = null;
- Logger.LogInformation($"[{ID}] Player 2 {player} left pong room!");
+ Logger.LogInformation(LEAVE_LOG_TEMPLATE, ID, 2, player);
}
player.ConnectedRoom = null;
_ = Task.Run(PlayersChanged);
@@ -52,14 +55,27 @@ public class PongRoom {
}
private void ResumeGame(PongPlayer player1, PongPlayer player2) {
- Logger.LogInformation($"[{ID}] Pong game started: {player1} vs. {player2}");
- State = GameState.InProgress;
- player1.Client.GameStateChanged(State);
- player2.Client.GameStateChanged(State);
+ Logger.LogInformation("[{ID}] Pong game started: {player1} vs. {player2}", ID, player1, player2);
+ State.Status = GameStatus.InProgress;
+ player1.Client.GameStateChanged(State.Status);
+ player2.Client.GameStateChanged(State.Status);
}
- private void PauseGame() => State = GameState.WaitingForPlayers;
- private void CloseRoom() => State = GameState.Finished;
+ private void PauseGame() => State.Status = GameStatus.WaitingForPlayers;
+ private void CloseRoom() => State.Status = GameStatus.Finished;
public override string ToString() => $"[{ID}]";
+
+ public void MovePaddle(PongPlayer player, PongPaddleDirection direction) {
+ if (Player1 == player) {
+ State.P1Direction = direction;
+ Logger.LogInformation(DIRECTION_LOG_TEMPLATE, ID, 1, player, direction);
+ return;
+ } else if (Player2 == player) {
+ State.P2Direction = direction;
+ Logger.LogInformation(DIRECTION_LOG_TEMPLATE, ID, 2, player, direction);
+ return;
+ }
+ throw new InvalidOperationException("Player is not in this room, but moved! Assumably players room wasn't deleted.");
+ }
}
\ No newline at end of file
diff --git a/PongGame/wwwroot/js/pong.js b/PongGame/wwwroot/js/pong.js
index 465062e..966ba8b 100644
--- a/PongGame/wwwroot/js/pong.js
+++ b/PongGame/wwwroot/js/pong.js
@@ -79,6 +79,16 @@ leavelobby.addEventListener("click", function (event) {
event.preventDefault();
});
+function movePaddle(direction) {
+ connection.invoke("MovePaddle", direction).catch(function (err) {
+ return console.error(err.toString());
+ });
+}
+
+function moveUp() { return movePaddle(-1); }
+function stopPaddle() { return movePaddle(0); }
+function moveDown() { return movePaddle(1); }
+
connection.start().then(function () {
console.info(`Connected!`);
connectionStatus.textContent = "Connected!";