Added game state, allow paddle movement
This commit is contained in:
parent
462e27c88a
commit
a4e22a4c52
@ -1,6 +1,6 @@
|
||||
namespace PongGame;
|
||||
|
||||
public enum GameState {
|
||||
public enum GameStatus {
|
||||
WaitingForPlayers,
|
||||
InProgress,
|
||||
Finished,
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace PongGame.Hubs;
|
||||
|
||||
public interface IPongClient {
|
||||
Task GameStateChanged(GameState state);
|
||||
Task GameStateChanged(GameStatus state);
|
||||
Task UsernameChanged(string value);
|
||||
}
|
35
PongGame/Hubs/PongGameState.cs
Normal file
35
PongGame/Hubs/PongGameState.cs
Normal file
@ -0,0 +1,35 @@
|
||||
namespace PongGame.Hubs;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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; }
|
||||
}
|
||||
}
|
@ -30,6 +30,12 @@ public class PongHub : Hub<IPongClient> {
|
||||
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<string> CreateRoom() {
|
||||
AssertNotInRoom();
|
||||
var room = Lobby.CreateRoom(Player);
|
||||
@ -42,6 +48,15 @@ public class PongHub : Hub<IPongClient> {
|
||||
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;
|
||||
|
7
PongGame/Hubs/PongPaddleDirection.cs
Normal file
7
PongGame/Hubs/PongPaddleDirection.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace PongGame;
|
||||
|
||||
public enum PongPaddleDirection {
|
||||
Up = -1,
|
||||
Stop,
|
||||
Down,
|
||||
}
|
@ -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.");
|
||||
}
|
||||
}
|
@ -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!";
|
||||
|
Loading…
Reference in New Issue
Block a user