frist working version, TODO: trigger the render events

This commit is contained in:
Johannes Schmelz
2024-12-07 01:13:17 +01:00
parent 5f4c6be7b8
commit b4e2beca3a
18 changed files with 757 additions and 357 deletions

View File

@@ -1,5 +1,9 @@
package pp.monopoly.game.client;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.ViewAssetsResponse;
/**
* Represents the active client state in the Monopoly game.
* Extends {@link ClientState}.
@@ -15,4 +19,22 @@ public class ActiveState extends ClientState {
ActiveState(ClientGameLogic logic) {
super(logic);
}
@Override
boolean isTurn() {
return true;
}
@Override
void recivedNextPlayerTurn(NextPlayerTurn msg) {
logic.getBoard().clear();
for (Player player : logic.getPlayerHandler().getPlayers()) {
logic.getBoard().add(player.getFigure());
}
}
@Override
void recivedViewAssetsResponse(ViewAssetsResponse msg) {
}
}

View File

@@ -5,6 +5,7 @@ import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.List;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.BuyPropertyRequest;
@@ -22,7 +23,6 @@ import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board;
import pp.monopoly.model.IntPoint;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.ClientStateEvent;
@@ -33,6 +33,7 @@ import pp.monopoly.notification.GameEvent;
import pp.monopoly.notification.GameEventBroker;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.PopUpEvent;
import pp.monopoly.notification.Sound;
import pp.monopoly.notification.SoundEvent;
@@ -54,7 +55,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
private final List<GameEventListener> listeners = new ArrayList<>();
/** The game board representing the player's current state. */
private Board board;
private Board board = new Board(10, 10, null);
/** The current state of the client game logic. */
private ClientState state = new LobbyState(this);
@@ -121,15 +122,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
return tradeHandler;
}
/**
* Moves the preview figure to the specified position.
*
* @param pos the new position for the preview figure
*/
public void movePreview(IntPoint pos) {
state.movePreview(pos);
}
/**
* Sets the informational text to be displayed to the player.
*
@@ -204,32 +196,21 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.update(delta);
}
/**
* Handles the result of a dice roll.
*
* @param msg the message containing the dice roll result
*/
public boolean isTurn() {
return state.isTurn();
}
@Override
public void received(DiceResult msg) {
playSound(Sound.DICE_ROLL);
notifyListeners(new DiceRollEvent(msg.getRollResult().get(0), msg.getRollResult().get(1)));
}
/**
* Handles drawing an event card.
*
* @param msg the message containing the drawn card details
*/
@Override
public void received(EventDrawCard msg) {
notifyListeners(new EventCardEvent(msg.getCardDescription()));
}
/**
* Handles the game over message.
*
* @param msg the message containing game over details
*/
@Override
public void received(GameOver msg) {
if (msg.isWinner()) {
@@ -241,23 +222,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
}
}
/**
* Handles the start of the game.
*
* @param msg the game start message
*/
@Override
public void received(GameStart msg) {
playerHandler = msg.getPlayerHandler();
setState(new WaitForTurnState(this));
notifyListeners(new ButtonStatusEvent(false));
notifyListeners(new UpdatePlayerView());
}
/**
* Handles jail-related events.
*
* @param msg the message containing jail event details
*/
@Override
public void received(JailEvent msg) {
if (msg.isGoingToJail()) {
@@ -266,11 +238,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
}
}
/**
* Updates the status of a player.
*
* @param msg the message containing player status update details
*/
@Override
public void received(PlayerStatusUpdate msg) {
playerHandler = msg.getPlayerHandler();
@@ -278,31 +245,16 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
notifyListeners(new UpdatePlayerView());
}
/**
* Handles timeout warnings.
*
* @param msg the message containing timeout warning details
*/
@Override
public void received(TimeOutWarning msg) {
notifyListeners(new PopUpEvent("timeout", msg));
}
/**
* Displays the player's assets in response to a server query.
*
* @param msg the message containing the player's assets
*/
@Override
public void received(ViewAssetsResponse msg) {
boardManager = msg.getboard();
}
/**
* Handles trade replies from other players.
*
* @param msg the message containing the trade reply
*/
@Override
public void received(TradeReply msg) {
if (msg.isAccepted()) {
@@ -314,24 +266,15 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
}
}
/**
* Handles trade requests from other players.
*
* @param msg the message containing the trade request details
*/
@Override
public void received(TradeRequest msg) {
tradeHandler = msg.getTradeHandler();
notifyListeners(new PopUpEvent("tradeRequest", msg));
}
/**
* Handles the transition to the next player's turn.
*
* @param msg the message indicating it's the next player's turn
*/
@Override
public void received(NextPlayerTurn msg) {
setState(new ActiveState(this));
notifyListeners(new ButtonStatusEvent(true));
}
@@ -357,4 +300,5 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
notifyListeners(new PopUpEvent("ReceivedRent", msg));
}
}
}

View File

@@ -11,7 +11,11 @@ import java.io.File;
import java.io.IOException;
import java.lang.System.Logger.Level;
import pp.monopoly.model.IntPoint;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.message.server.ViewAssetsResponse;
/**
* Defines the behavior and state transitions for the client-side game logic in Monopoly.
@@ -54,17 +58,39 @@ abstract class ClientState {
*
* @return true if the player's turn should be shown, false otherwise
*/
boolean showTurn() {
boolean isTurn() {
return false;
}
/**
* Moves the preview figure to the specified position on the game board.
* Starts the battle based on the server message.
*
* @param pos the new position for the preview figure
* @param msg the message indicating whose turn it is to shoot
*/
void movePreview(IntPoint pos) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "movePreview has no effect in {0}", getName()); //NON-NLS
void receivedGameStart(GameStart msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "receivedGameStart not allowed in {0}", getName()); //NON-NLS
}
/**
* Updateds the view based on the new player status.
*
* @param msg the message containing the new player status
*/
void recivedPlayerStatusUpdate(PlayerStatusUpdate msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedPlayerStatusUpdate not allowed in {0}", getName()); //NON-NLS
}
void recivedNextPlayerTurn(NextPlayerTurn msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedNextPlayerTurn not allowed in {0}", getName()); //NON-NLS
}
void recivedNotificationMessage(NotificationMessage msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedNotificationMessage not allowed in {0}", getName()); //NON-NLS
}
void recivedViewAssetsResponse(ViewAssetsResponse msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedViewAssetsResponse not allowed in {0}", getName()); //NON-NLS
}
/**

View File

@@ -1,5 +1,7 @@
package pp.monopoly.game.client;
import pp.monopoly.message.server.GameStart;
/**
* Represents the lobby state of the client in the Monopoly game.
* Extends {@link ClientState}.
@@ -14,4 +16,9 @@ public class LobbyState extends ClientState {
LobbyState(ClientGameLogic logic) {
super(logic);
}
@Override
void receivedGameStart(GameStart msg) {
logic.setState(new WaitForTurnState(logic));
}
}

View File

@@ -1,5 +1,7 @@
package pp.monopoly.game.client;
import pp.monopoly.message.server.NextPlayerTurn;
/**
* Represents the state where the client is waiting for their turn in the Monopoly game.
* Extends {@link ClientState}.
@@ -14,4 +16,14 @@ public class WaitForTurnState extends ClientState {
WaitForTurnState(ClientGameLogic logic) {
super(logic);
}
@Override
boolean isTurn() {
return true;
}
@Override
void recivedNextPlayerTurn(NextPlayerTurn msg) {
logic.setState(new ActiveState(logic));
}
}

View File

@@ -91,16 +91,16 @@ public interface ServerInterpreter {
void received(NextPlayerTurn msg);
/**
* Handles a NextPlayerTurn message received from the server.
* Handles a BuyPropertyRequest message received from the server.
*
* @param msg the NextPlayerTurn message received
* @param msg the BuyPropertyRequest message received
*/
void received(BuyPropertyRequest msg);
/**
* Handles a NextPlayerTurn message received from the server.
* Handles a NotificationMessage message received from the server.
*
* @param msg the NextPlayerTurn message received
* @param msg the NotificationMessage message received
*/
void received(NotificationMessage msg);
}

View File

@@ -1,10 +1,3 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.model;
import java.util.ArrayList;
@@ -66,7 +59,34 @@ public class Board {
*/
private void addItem(Item item) {
items.add(item);
notifyListeners((GameEvent) new ItemAddedEvent(item, null));
notifyListeners((GameEvent) new ItemAddedEvent(this, item));
}
/**
* Adds a figure to the map and triggers an item addition event.
*
* @param figure the figure to be added to the map
*/
public void add(Figure figure) {
addItem(figure);
}
/**
* Adds a house to the map and triggers an item addition event.
*
* @param house the house to be added to the map
*/
public void add(House house) {
addItem(house);
}
/**
* Adds a hotel to the map and triggers an item addition event.
*
* @param hotel the hotel to be added to the map
*/
public void add(Hotel hotel) {
addItem(hotel);
}
/**
@@ -76,7 +96,7 @@ public class Board {
*/
public void remove(Item item) {
items.remove(item);
notifyListeners((GameEvent) new ItemRemovedEvent(item, null)); // Falls es ein entsprechendes ItemRemovedEvent gibt
notifyListeners((GameEvent) new ItemRemovedEvent(this, item));
}
/**
@@ -96,6 +116,33 @@ public class Board {
private <T extends Item> Stream<T> getItems(Class<T> clazz) {
return items.stream().filter(clazz::isInstance).map(clazz::cast);
}
/**
* Returns a stream of all figures currently on the map.
*
* @return a stream of all figures on the map
*/
public Stream<Figure> getFigures() {
return getItems(Figure.class);
}
/**
* Returns a stream of all houses currently on the map.
*
* @return a stream of all houses on the map
*/
public Stream<House> getHouses() {
return getItems(House.class);
}
/**
* Returns a stream of all hotels currently on the map.
*
* @return a stream of all hotels on the map
*/
public Stream<Hotel> getHotels() {
return getItems(Hotel.class);
}
/**
* Returns an unmodifiable list of all items currently on the map.
@@ -124,28 +171,6 @@ public class Board {
return height;
}
/**
* Validates whether the specified position is within the map boundaries.
*
* @param pos the position to validate
* @return true if the position is within the map, false otherwise
*/
public boolean isValid(IntPosition pos) {
return isValid(pos.getX(), pos.getY());
}
/**
* Checks if the specified coordinates are within the map boundaries.
*
* @param x the x-coordinate to validate
* @param y the y-coordinate to validate
* @return true if the coordinates are valid, false otherwise
*/
public boolean isValid(int x, int y) {
return x >= 0 && x < width &&
y >= 0 && y < height;
}
/**
* Returns a string representation of the map.
*

View File

@@ -0,0 +1,93 @@
package pp.monopoly.model;
import com.jme3.math.Vector3f;
public class Hotel implements Item{
/**
* The ID of the field the hotel is on.
*/
private final int fieldID;
/**
* Creates a new hotel with fieldID 0.
*/
private Hotel() {
this.fieldID = 0;
}
/**
* Creates a new hotel on the given field.
*
* @param fieldID the ID of the field the hotel is on
*/
public Hotel(int fieldID) {
this.fieldID = fieldID;
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
@Override
public void accept(VoidVisitor visitor) {
visitor.visit(this);
}
/**
* Returns the position of the building on the field.
*
* @return the position of the building on the field
*/
public Vector3f getBuildingPosition() {
float baseX = 0.0f;
float baseZ = 0.0f;
switch (fieldID) {
case 0: baseX = -8.4f; baseZ = -7.7f; break;
case 1: baseX = -6.3f; baseZ = -7.7f; break;
case 2: baseX = -4.7f; baseZ = -7.7f; break;
case 3: baseX = -3.1f; baseZ = -7.7f; break;
case 4: baseX = -1.4f; baseZ = -7.7f; break;
case 5: baseX = 0.2f; baseZ = -7.7f; break;
case 6: baseX = 1.8f; baseZ = -7.7f; break;
case 7: baseX = 3.5f; baseZ = -7.7f; break;
case 8: baseX = 5.1f; baseZ = -7.7f; break;
case 9: baseX = 6.7f; baseZ = -7.7f; break;
case 10: baseX = 8.2f; baseZ = -7.7f; break;
case 11: baseX = 8.2f; baseZ = -6.5f; break; //passt
case 12: baseX = 8.2f; baseZ = -4.9f; break; //passt
case 13: baseX = 8.2f; baseZ = -3.3f; break; //passt
case 14: baseX = 8.2f; baseZ = -1.6f; break; //passt
case 15: baseX = 8.2f; baseZ = 0.0f; break; //passt
case 16: baseX = 8.2f; baseZ = 1.6f; break; //passt
case 17: baseX = 8.2f; baseZ = 3.3f; break; //passt
case 18: baseX = 8.2f; baseZ = 4.9f; break; //passt
case 19: baseX = 8.2f; baseZ = 6.5f; break; //passt
case 20: baseX = 8.2f; baseZ = 7.7f; break;
case 21: baseX = 6.5f; baseZ = 7.7f; break;
case 22: baseX = 4.9f; baseZ = 7.7f; break;
case 23: baseX = 3.3f; baseZ = 7.7f; break;
case 24: baseX = 1.6f; baseZ = 7.7f; break;
case 25: baseX = 0.0f; baseZ = 7.7f; break;
case 26: baseX = -1.6f; baseZ = 7.7f; break;
case 27: baseX = -3.3f; baseZ = 7.7f; break;
case 28: baseX = -4.9f; baseZ = 7.7f; break;
case 29: baseX = -6.5f; baseZ = 7.7f; break;
case 30: baseX = -7.2f; baseZ = 7.7f; break;
case 31: baseX = -7.2f; baseZ = 6.5f; break;
case 32: baseX = -7.2f; baseZ = 4.9f; break;
case 33: baseX = -7.2f; baseZ = 3.3f; break;
case 34: baseX = -7.2f; baseZ = 1.6f; break;
case 35: baseX = -7.2f; baseZ = 0.0f; break;
case 36: baseX = -7.2f; baseZ = -1.6f; break;
case 37: baseX = -7.2f; baseZ = -3.3f; break;
case 38: baseX = -7.2f; baseZ = -4.9f; break;
case 39: baseX = -7.2f; baseZ = -6.5f; break;
default: throw new IllegalArgumentException("Ungültige Feld-ID: " + fieldID);
}
return new Vector3f(baseX, 0, baseZ);
}
}

View File

@@ -0,0 +1,110 @@
package pp.monopoly.model;
import com.jme3.math.Vector3f;
import com.jme3.network.serializing.Serializable;
/**
* A class representing a house in the Monopoly game.
*/
@Serializable
public class House implements Item{
/**
* The stage of the house.
*/
private final int stage;
private final int fieldID;
/**
* Creates a new house with stage 0.
*/
public House() {
this.stage = 0;
this.fieldID = 0;
}
/**
* Creates a new house with the given stage.
*
* @param stage the stage of the house
*/
public House(int stage, int fieldID) {
this.stage = stage;
this.fieldID = fieldID;
}
/**
* Returns the stage of the house.
*
* @return the stage of the house
*/
public int getStage() {
return stage;
}
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
@Override
public void accept(VoidVisitor visitor) {
visitor.visit(this);
}
/**
* Returns the position of the building on the field.
*
* @return the position of the building on the field
*/
public Vector3f getBuildingPosition() {
float baseX = 0.0f;
float baseZ = 0.0f;
switch (fieldID) {
case 0: baseX = -8.4f; baseZ = -7.7f; break;
case 1: baseX = -6.3f; baseZ = -7.7f; break;
case 2: baseX = -4.7f; baseZ = -7.7f; break;
case 3: baseX = -3.1f; baseZ = -7.7f; break;
case 4: baseX = -1.4f; baseZ = -7.7f; break;
case 5: baseX = 0.2f; baseZ = -7.7f; break;
case 6: baseX = 1.8f; baseZ = -7.7f; break;
case 7: baseX = 3.5f; baseZ = -7.7f; break;
case 8: baseX = 5.1f; baseZ = -7.7f; break;
case 9: baseX = 6.7f; baseZ = -7.7f; break;
case 10: baseX = 8.2f; baseZ = -7.7f; break;
case 11: baseX = 8.2f; baseZ = -6.5f; break; //passt
case 12: baseX = 8.2f; baseZ = -4.9f; break; //passt
case 13: baseX = 8.2f; baseZ = -3.3f; break; //passt
case 14: baseX = 8.2f; baseZ = -1.6f; break; //passt
case 15: baseX = 8.2f; baseZ = 0.0f; break; //passt
case 16: baseX = 8.2f; baseZ = 1.6f; break; //passt
case 17: baseX = 8.2f; baseZ = 3.3f; break; //passt
case 18: baseX = 8.2f; baseZ = 4.9f; break; //passt
case 19: baseX = 8.2f; baseZ = 6.5f; break; //passt
case 20: baseX = 8.2f; baseZ = 7.7f; break;
case 21: baseX = 6.5f; baseZ = 7.7f; break;
case 22: baseX = 4.9f; baseZ = 7.7f; break;
case 23: baseX = 3.3f; baseZ = 7.7f; break;
case 24: baseX = 1.6f; baseZ = 7.7f; break;
case 25: baseX = 0.0f; baseZ = 7.7f; break;
case 26: baseX = -1.6f; baseZ = 7.7f; break;
case 27: baseX = -3.3f; baseZ = 7.7f; break;
case 28: baseX = -4.9f; baseZ = 7.7f; break;
case 29: baseX = -6.5f; baseZ = 7.7f; break;
case 30: baseX = -7.2f; baseZ = 7.7f; break;
case 31: baseX = -7.2f; baseZ = 6.5f; break;
case 32: baseX = -7.2f; baseZ = 4.9f; break;
case 33: baseX = -7.2f; baseZ = 3.3f; break;
case 34: baseX = -7.2f; baseZ = 1.6f; break;
case 35: baseX = -7.2f; baseZ = 0.0f; break;
case 36: baseX = -7.2f; baseZ = -1.6f; break;
case 37: baseX = -7.2f; baseZ = -3.3f; break;
case 38: baseX = -7.2f; baseZ = -4.9f; break;
case 39: baseX = -7.2f; baseZ = -6.5f; break;
default: throw new IllegalArgumentException("Ungültige Feld-ID: " + fieldID);
}
return new Vector3f(baseX, 0, baseZ);
}
}

View File

@@ -1,10 +1,3 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.model;
/**
@@ -22,4 +15,20 @@ public interface Visitor<T> {
*/
T visit(Figure figure);
/**
* Visits a Hotel element.
*
* @param hotel the Hotel element to visit
* @return the result of visiting the hotel element
*/
T visit(Hotel hotel);
/**
* Visits a house element.
*
* @param house the House element to visit
* @return the result of visiting the house element
*/
T visit(House figure);
}

View File

@@ -1,10 +1,3 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.model;
/**
@@ -19,4 +12,18 @@ public interface VoidVisitor {
*/
void visit(Figure figure);
/**
* Visits a Hotel element.
*
* @param hotel the Hotel element to visit
*/
void visit(Hotel hotel);
/**
* Visits a House element.
*
* @param house the House element to visit
*/
void visit(House house);
}

View File

@@ -6,36 +6,10 @@ import pp.monopoly.model.Item;
/**
* Event that is triggered when an item is added to a board.
*/
public class ItemAddedEvent {
private final Item item;
private final Board board;
public record ItemAddedEvent(Board board, Item item) implements GameEvent {
/**
* Constructs a new ItemAddedEvent.
*
* @param item the item that was added
* @param board the board to which the item was added
*/
public ItemAddedEvent(Item item, Board board) {
this.item = item;
this.board = board;
}
/**
* Gets the item that was added.
*
* @return the added item
*/
public Item getItem() {
return item;
}
/**
* Gets the board to which the item was added.
*
* @return the board
*/
public Board getBoard() {
return board;
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}

View File

@@ -1,35 +1,15 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.notification;
import pp.monopoly.model.Board;
import pp.monopoly.model.Item;
/**
* Event when an item gets removed.
*
* Event that is triggered when an item is removed from a board.
*/
public class ItemRemovedEvent {
private final Item item;
private final Board board;
public record ItemRemovedEvent(Board board, Item item) implements GameEvent {
public ItemRemovedEvent(Item item, Board board) {
this.item = item;
this.board = board;
}
public Item getItem() {
return item;
}
public Board getBoard() {
return board;
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}