added java docs to view

This commit is contained in:
Hanno Fleischer
2024-12-11 23:58:32 +01:00
parent 67ea9ede18
commit 176affa9c5
29 changed files with 1475 additions and 43 deletions

View File

@@ -55,6 +55,11 @@ public class InputSynchronizer {
setupInput();
}
/**
* Updates the rotation angle based on user input.
*
* @param tpf The time per frame.
*/
public void update(float tpf) {
if (isRotateLeft && isRotateRight) {
return;

View File

@@ -90,6 +90,10 @@ public class MdgaApp extends SimpleApplication {
public static final int DEBUG_MULTIPLIER = 0;
/**
* Constructs a new MdgaApp instance.
* Initializes the network connection and client game logic.
*/
public MdgaApp() {
networkConnection = new NetworkSupport(this);
this.clientGameLogic = new ClientGameLogic(networkConnection);
@@ -272,14 +276,22 @@ public NotificationSynchronizer getNotificationSynchronizer() {
* Prepares the app for a new game cycle.
*/
public void setup() {
}
/**
* Gets the client game logic.
*
* @return the {@link ClientGameLogic} instance
*/
public ClientGameLogic getGameLogic() {
return clientGameLogic;
}
/**
* Gets the executor service.
*
* @return the {@link ExecutorService} instance
*/
public ExecutorService getExecutor() {
if (this.executor == null) {
this.executor = Executors.newCachedThreadPool();
@@ -288,10 +300,23 @@ public ExecutorService getExecutor() {
return this.executor;
}
/**
* Gets the network connection.
*
* @return the {@link ServerConnection} instance
*/
public ServerConnection getNetworkSupport() {
return networkConnection;
}
/**
* Updates the resolution settings.
*
* @param width the new width
* @param height the new height
* @param imageFactor the new image factor
* @param isFullscreen whether the game is in fullscreen mode
*/
public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) {
if (isFullscreen) {
int baseWidth = 1280;
@@ -317,6 +342,9 @@ public void updateResolution(int width, int height, float imageFactor, boolean i
}
}
/**
* Restarts the application.
*/
public static void restartApp() {
try {
String javaBin = System.getProperty("java.home") + "/bin/java";
@@ -335,11 +363,13 @@ public static void restartApp() {
}
}
/**
* Cleans up the application after a game.
*/
public void afterGameCleanup() {
MainView main = (MainView) mainView;
main.getJoinDialog().disconnect();
System.out.println("Disconnecting from server..." + clientGameLogic.isHost());
if (clientGameLogic.isHost()) {
main.getHostDialog().shutdownServer();
}
@@ -347,14 +377,29 @@ public void afterGameCleanup() {
ceremonyView.afterGameCleanup();
}
/**
* Gets the game view.
*
* @return the {@link GameView} instance
*/
public GameView getGameView() {
return gameView;
}
/**
* Gets the timer manager.
*
* @return the {@link TimerManager} instance
*/
public TimerManager getTimerManager() {
return timerManager;
}
/**
* Gets the ceremony view.
*
* @return the {@link CeremonyView} instance
*/
public CeremonyView getCeremonyView() {
return ceremonyView;
}

View File

@@ -8,6 +8,9 @@
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The ModelSynchronizer class is responsible for synchronizing the model state with the view and game logic.
*/
public class ModelSynchronizer {
private static final Logger LOGGER = Logger.getLogger(ModelSynchronizer.class.getName());
private MdgaApp app;
@@ -17,11 +20,19 @@ public class ModelSynchronizer {
private BonusCard card;
private boolean swap;
/**
* Constructor for ModelSynchronizer.
*
* @param app the MdgaApp instance
*/
ModelSynchronizer(MdgaApp app) {
this.app = app;
swap = false;
}
/**
* Handles the end of an animation.
*/
public void animationEnd() {
if (app.getNotificationSynchronizer().waitForAnimation) {
app.getNotificationSynchronizer().waitForAnimation = false;
@@ -30,13 +41,24 @@ public void animationEnd() {
}
}
/**
* Selects a piece or swap based on the current state.
*
* @param a the first UUID
* @param b the second UUID
*/
public void select(UUID a, UUID b) {
if (swap) selectSwap(a, b);
else selectPiece(a);
}
/**
* Selects a swap between two pieces.
*
* @param a the first UUID
* @param b the second UUID
*/
public void selectSwap(UUID a, UUID b) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectPiece");
this.a = a;
this.b = b;
@@ -49,8 +71,12 @@ public void selectSwap(UUID a, UUID b) {
}
}
/**
* Selects a single piece.
*
* @param piece the UUID of the piece
*/
public void selectPiece(UUID piece) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectPiece");
this.a = piece;
@@ -63,8 +89,12 @@ public void selectPiece(UUID piece) {
}
}
/**
* Selects a bonus card.
*
* @param card the BonusCard instance
*/
public void selectCard(BonusCard card) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectCard");
this.card = card;
@@ -78,6 +108,9 @@ public void selectCard(BonusCard card) {
}
}
/**
* Confirms the current selection.
*/
public void confirm() {
LOGGER.log(Level.INFO, "confirm");
@@ -105,54 +138,106 @@ public void confirm() {
gameView.hideNoPower();
}
/**
* Selects a TSK color.
*
* @param color the Color instance
*/
public void selectTsk(Color color) {
app.getGameLogic().selectTsk(color);
}
/**
* Unselects a TSK color.
*
* @param color the Color instance
*/
public void unselectTsk(Color color) {
app.getGameLogic().deselectTSK(color);
}
/**
* Handles the event of rolling dice.
*/
public void rolledDice() {
app.getGameLogic().selectDice();
}
/**
* Sets the player's name.
*
* @param name the player's name
*/
public void setName(String name) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "setName: {0}", name);
app.getGameLogic().selectName(name);
}
/**
* Sets the player's ready status.
*
* @param ready the ready status
*/
public void setReady(boolean ready) {
app.getGameLogic().selectReady(ready);
}
/**
* Sets the host port.
*
* @param port the host port
*/
public void setHost(int port) {
app.getGameLogic().selectJoin("");
}
/**
* Sets the join IP and port.
*
* @param ip the IP address
* @param port the port number
*/
public void setJoin(String ip, int port) {
app.getGameLogic().selectJoin(ip);
}
/**
* Handles the event of leaving the game.
*/
public void leave() {
app.getGameLogic().selectLeave();
}
/**
* Enters a specific game state.
*
* @param state the MdgaState instance
*/
public void enter(MdgaState state) {
LOGGER.log(Level.INFO, "enter: {0}", state);
//app.enter(state);
}
/**
* Proceeds to the next game state.
*/
public void next() {
app.getGameLogic().selectNext();
}
/**
* Sets the swap state.
*
* @param swap the swap state
*/
public void setSwap(boolean swap) {
this.swap = swap;
}
/**
* Forces an action.
*/
public void force() {
// Implementation needed
}
}

View File

@@ -6,23 +6,47 @@
import java.io.IOException;
/**
* The NetworkSupport class provides support for network communication between the client and server.
* It implements the MessageListener and ClientStateListener interfaces to handle incoming messages
* and client state changes, respectively.
*/
public class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
private static final System.Logger LOGGER = System.getLogger(NetworkSupport.class.getName());
private final MdgaApp app;
private Client client;
/**
* Constructor for NetworkSupport.
*
* @param app the MdgaApp instance
*/
public NetworkSupport(MdgaApp app) {
this.app = app;
}
/**
* Returns the MdgaApp instance.
*
* @return the MdgaApp instance
*/
public MdgaApp getApp() {
return this.app;
}
/**
* Returns whether the client is connected to the server.
*
* @return true if the client is connected, false otherwise
*/
public boolean isConnected() {
return this.client != null && this.client.isConnected();
}
/**
* Connects the client to the server.
*/
public void connect() {
if (this.client != null) {
throw new IllegalStateException("trying to join a game again");
@@ -36,6 +60,9 @@ public void connect() {
}
/**
* Disconnects the client from the server.
*/
public void disconnect() {
if (this.client != null) {
this.client.close();
@@ -44,6 +71,13 @@ public void disconnect() {
}
}
/**
* Initializes the network connection to the server.
*
* @param host the server host
* @param port the server port
* @throws IOException if an I/O error occurs
*/
public void initNetwork(String host, int port) throws IOException {
if (this.client != null) {
throw new IllegalStateException("trying to join a game again");
@@ -55,6 +89,12 @@ public void initNetwork(String host, int port) throws IOException {
}
}
/**
* Handles incoming messages from the server.
*
* @param client the client
* @param message the message
*/
public void messageReceived(Client client, Message message) {
LOGGER.log(System.Logger.Level.INFO, "message received from server: {0}", new Object[]{message});
if (message instanceof ServerMessage serverMessage) {
@@ -63,10 +103,21 @@ public void messageReceived(Client client, Message message) {
}
/**
* Handles client connection to the server.
*
* @param client the client
*/
public void clientConnected(Client client) {
LOGGER.log(System.Logger.Level.INFO, "Client connected: {0}", new Object[]{client});
}
/**
* Handles client disconnection from the server.
*
* @param client the client
* @param disconnectInfo the disconnect information
*/
public void clientDisconnected(Client client, ClientStateListener.DisconnectInfo disconnectInfo) {
LOGGER.log(System.Logger.Level.INFO, "Client {0} disconnected: {1}", new Object[]{client, disconnectInfo});
if (this.client != client) {
@@ -78,6 +129,11 @@ public void clientDisconnected(Client client, ClientStateListener.DisconnectInfo
}
}
/**
* Sends a message to the server.
*
* @param message the message
*/
@Override
public void send(ClientMessage message) {
LOGGER.log(System.Logger.Level.INFO, "sending {0}", new Object[]{message});

View File

@@ -15,6 +15,10 @@
import java.util.Timer;
import java.util.TimerTask;
/**
* The NotificationSynchronizer class is responsible for handling and synchronizing notifications
* received from the game logic and updating the application state accordingly.
*/
public class NotificationSynchronizer {
private final MdgaApp app;
@@ -27,10 +31,19 @@ public class NotificationSynchronizer {
public boolean waitForAnimation = false;
/**
* Constructs a NotificationSynchronizer with the specified MdgaApp instance.
*
* @param app the MdgaApp instance
*/
NotificationSynchronizer(MdgaApp app) {
this.app = app;
}
/**
* Updates the notification synchronizer by processing notifications from the game logic.
* Handles different types of notifications based on the current application state.
*/
public void update() {
while (timer.getTimeInSeconds() >= delay) {
if (waitForAnimation) {
@@ -78,6 +91,11 @@ public void update() {
}
}
/**
* Handles notifications when the application is in the MAIN state.
*
* @param notification the notification to handle
*/
private void handleMain(Notification notification) {
if (notification instanceof LobbyDialogNotification) {
app.enter(MdgaState.LOBBY);
@@ -88,6 +106,11 @@ private void handleMain(Notification notification) {
}
}
/**
* Handles notifications when the application is in the LOBBY state.
*
* @param notification the notification to handle
*/
private void handleLobby(Notification notification) {
LobbyView lobbyView = (LobbyView) app.getView();
@@ -108,6 +131,11 @@ private void handleLobby(Notification notification) {
}
}
/**
* Handles notifications when the application is in the GAME state.
*
* @param notification the notification to handle
*/
private void handleGame(Notification notification) {
GameView gameView = (GameView) app.getView();
GuiHandler guiHandler = gameView.getGuiHandler();
@@ -256,6 +284,11 @@ public void run() {
}
}
/**
* Handles notifications when the application is in the CEREMONY state.
*
* @param notification the notification to handle
*/
private void handleCeremony(Notification notification) {
if (notification instanceof StartDialogNotification) {
app.afterGameCleanup();

View File

@@ -5,10 +5,18 @@
public class ActionControl extends InitControl {
private final Runnable runnable;
/**
* Constructs a new ActionControl object with the specified action.
*
* @param runnable The action to be performed.
*/
public ActionControl(Runnable runnable) {
this.runnable = runnable;
}
/**
* Performs the action associated with this control.
*/
protected void action() {
if (null != runnable) {
runnable.run();

View File

@@ -12,6 +12,9 @@
import java.util.List;
import java.util.Random;
/**
* MatrixAnimation class handles the animation of radar and matrix particle effects.
*/
public class MatrixAnimation extends ActionControl {
private MdgaApp app;
private static final Random RANDOM = new Random();
@@ -22,7 +25,9 @@ public class MatrixAnimation extends ActionControl {
private ParticleEmitter radarEmitter = null;
private float timeElapsed = 0f;
/**
* Enum representing the states of the matrix animation.
*/
private enum MatrixState {
RADAR_ON,
RADAR_OFF,
@@ -32,12 +37,22 @@ private enum MatrixState {
private MatrixState state;
/**
* Constructor for MatrixAnimation.
*
* @param app the application instance
* @param radarPos the position of the radar
* @param runnable the runnable action to be executed
*/
public MatrixAnimation(MdgaApp app, Vector3f radarPos, Runnable runnable) {
super(runnable);
this.app = app;
this.radarPos = radarPos;
}
/**
* Initializes the spatial and sets the initial state to RADAR_ON.
*/
@Override
protected void initSpatial() {
state = MatrixState.RADAR_ON;
@@ -46,13 +61,17 @@ protected void initSpatial() {
radar();
}
/**
* Updates the control based on the time per frame (tpf).
*
* @param tpf the time per frame
*/
@Override
protected void controlUpdate(float tpf) {
if (!init) return;
timeElapsed += tpf;
switch (state) {
case RADAR_ON -> {
if (timeElapsed >= 2f) {
@@ -72,7 +91,6 @@ protected void controlUpdate(float tpf) {
timeElapsed = 0;
matrix();
}
}
case MATRIX_ON -> {
if (timeElapsed >= 3f) {
@@ -98,12 +116,18 @@ protected void controlUpdate(float tpf) {
}
}
/**
* Turns off all active particle emitters.
*/
private void turnOff() {
for (ParticleEmitter particleEmitter : activeEmitter) {
particleEmitter.setParticlesPerSec(0f);
}
}
/**
* Initializes the radar particle emitter.
*/
private void radar() {
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
mat.setTexture("Texture", app.getAssetManager().loadTexture("Images/particle/radar_beam.png"));
@@ -128,6 +152,9 @@ private void radar() {
radarEmitter = emitter;
}
/**
* Initializes multiple matrix particle streams.
*/
private void matrix() {
for (int i = 0; i < 5; i++) {
particleStream(
@@ -140,7 +167,15 @@ private void matrix() {
}
}
/**
* Creates a particle stream with the specified parameters.
*
* @param start the start color of the particles
* @param end the end color of the particles
* @param speedVar the speed variation of the particles
* @param pos the position of the particles
* @param spawnVar the spawn rate variation of the particles
*/
private void particleStream(ColorRGBA start, ColorRGBA end, float speedVar, Vector3f pos, float spawnVar) {
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
@@ -165,6 +200,11 @@ private void particleStream(ColorRGBA start, ColorRGBA end, float speedVar, Vect
activeEmitter.add(matrix);
}
/**
* Generates a random position vector.
*
* @return a random position vector
*/
public static Vector3f getRandomPosition() {
// Generate a random angle in radians (0 to 2π)
float angle = (float) (2 * Math.PI * RANDOM.nextDouble());
@@ -180,6 +220,13 @@ public static Vector3f getRandomPosition() {
return new Vector3f(x, y, 0);
}
/**
* Generates a random float between the specified start and end values.
*
* @param start the start value
* @param end the end value
* @return a random float between start and end
*/
public static float getRandomFloat(float start, float end) {
if (start > end) {
throw new IllegalArgumentException("Start must be less than or equal to end.");
@@ -187,6 +234,11 @@ public static float getRandomFloat(float start, float end) {
return start + RANDOM.nextFloat() * (end - start);
}
/**
* Generates a random color for the matrix particles.
*
* @return a random ColorRGBA object
*/
public static ColorRGBA generateMatrixColor() {
// Red is dominant
float red = 0.8f + RANDOM.nextFloat() * 0.2f; // Red channel: 0.8 to 1.0

View File

@@ -18,19 +18,31 @@
import static com.jme3.material.Materials.LIGHTING;
/**
* ShellAnimation class handles the animation of a shell being fired from a tank.
*/
public class ShellAnimation extends ActionControl {
private static final float FLYING_DURATION = 1.25f;
private static final float FLYING_HEIGHT = 12f;
private TankTopControl tankTopControl;
private MdgaApp app;
/**
* Constructor for ShellAnimation.
*
* @param tankTopControl the control for the tank top
* @param app the application instance
* @param actionAfter the action to perform after the animation
*/
public ShellAnimation(TankTopControl tankTopControl, MdgaApp app, Runnable actionAfter) {
super(actionAfter);
this.tankTopControl = tankTopControl;
this.app = app;
}
/**
* Initializes the spatial for the animation.
*/
@Override
protected void initSpatial() {
tankTopControl.rotate(spatial.getLocalTranslation(), this::shoot);
@@ -38,6 +50,11 @@ protected void initSpatial() {
//app.getRootNode().attachChild(createShell());
}
/**
* Calculates the shooting position based on the tank's turret rotation.
*
* @return the shooting position as a Vector3f
*/
private Vector3f getShootPos() {
Vector3f localOffset = new Vector3f(0, -5.4f, 2.9f);
Quaternion turretRotation = tankTopControl.getSpatial().getLocalRotation();
@@ -45,6 +62,9 @@ private Vector3f getShootPos() {
return tankTopControl.getSpatial().getLocalTranslation().add(transformedOffset);
}
/**
* Handles the shooting action, including sound and visual effects.
*/
private void shoot() {
app.getAcousticHandler().playSound(MdgaSound.TANK_SHOOT);
Vector3f shootPos = getShootPos();
@@ -74,6 +94,11 @@ private void shoot() {
shell.addControl(new ShellControl(this::hitExplosion, shootPos, spatial.getLocalTranslation(), FLYING_HEIGHT, FLYING_DURATION, app.getAssetManager()));
}
/**
* Creates the shell model and sets its initial properties.
*
* @return the created shell as a Spatial
*/
private Spatial createShell() {
Spatial model = app.getAssetManager().loadModel(Asset.shell.getModelPath());
model.scale(.16f);
@@ -98,6 +123,9 @@ private Spatial createShell() {
return model;
}
/**
* Handles the explosion effect when the shell hits a target.
*/
private void hitExplosion() {
app.getAcousticHandler().playSound(MdgaSound.TANK_EXPLOSION);
createEffect(
@@ -113,6 +141,21 @@ private void hitExplosion() {
app.getTimerManager().addTask(0.8f, super::action);
}
/**
* Creates a particle effect at the specified position.
*
* @param shootPos the position to create the effect
* @param image the image to use for the particles
* @param x the number of columns in the texture
* @param y the number of rows in the texture
* @param startSize the initial size of the particles
* @param endSize the final size of the particles
* @param velocity the initial velocity of the particles
* @param lowLife the minimum lifetime of the particles
* @param highLife the maximum lifetime of the particles
* @param start the starting color of the particles
* @param end the ending color of the particles
*/
private void createEffect(Vector3f shootPos,
String image,
int x, int y,

View File

@@ -8,6 +8,9 @@
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
/**
* ShellControl is responsible for controlling the movement and visual effects of a shell.
*/
public class ShellControl extends ActionControl {
private final Vector3f shootPos;
private final Vector3f endPos;
@@ -17,6 +20,16 @@ public class ShellControl extends ActionControl {
private ParticleEmitter emitter;
private AssetManager assetManager;
/**
* Constructs a new ShellControl.
*
* @param runnable the action to perform when the shell reaches its destination
* @param shootPos the starting position of the shell
* @param endPos the ending position of the shell
* @param height the height of the shell's trajectory
* @param duration the duration of the shell's flight
* @param assetManager the asset manager to load resources
*/
public ShellControl(Runnable runnable, Vector3f shootPos, Vector3f endPos, float height, float duration, AssetManager assetManager) {
super(runnable);
this.shootPos = shootPos;
@@ -26,6 +39,9 @@ public ShellControl(Runnable runnable, Vector3f shootPos, Vector3f endPos, float
this.assetManager = assetManager;
}
/**
* Initializes the spatial with the necessary controls and particle emitter.
*/
@Override
protected void initSpatial() {
spatial.addControl(new MoveControl(
@@ -47,6 +63,9 @@ protected void initSpatial() {
createEmitter();
}
/**
* Creates and configures the particle emitter for the shell trail.
*/
private void createEmitter() {
emitter = new ParticleEmitter("ShellTrail", ParticleMesh.Type.Triangle, 200);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
@@ -74,6 +93,11 @@ private void createEmitter() {
spatial.getParent().attachChild(emitter);
}
/**
* Updates the control, adjusting the shell's rotation and emitter position.
*
* @param tpf time per frame
*/
@Override
protected void controlUpdate(float tpf) {
Vector3f direction = spatial.getLocalTranslation().subtract(oldPos).normalize();

View File

@@ -5,6 +5,10 @@
import com.jme3.renderer.Camera;
import pp.mdga.client.MdgaApp;
/**
* OutlineOEControl class extends OutlineControl to manage outline colors and widths
* for own and enemy objects, including hover and select states.
*/
public class OutlineOEControl extends OutlineControl{
private static final ColorRGBA OUTLINE_OWN_COLOR = ColorRGBA.White;
private static final ColorRGBA OUTLINE_ENEMY_COLOR = ColorRGBA.Red;
@@ -16,6 +20,13 @@ public class OutlineOEControl extends OutlineControl{
private static final int OUTLINE_HOVER_WIDTH = 8;
private static final int OUTLINE_SELECT_WIDTH = 10;
/**
* Constructor for OutlineOEControl.
*
* @param app the MdgaApp instance
* @param fpp the FilterPostProcessor instance
* @param cam the Camera instance
*/
public OutlineOEControl(MdgaApp app, FilterPostProcessor fpp, Camera cam){
super(app, fpp, cam,
OUTLINE_OWN_COLOR, OUTLINE_HIGHLIGHT_WIDTH,
@@ -24,6 +35,9 @@ public OutlineOEControl(MdgaApp app, FilterPostProcessor fpp, Camera cam){
);
}
/**
* Sets the outline colors and enables selection for own objects.
*/
public void selectableOwn(){
setHighlightColor(OUTLINE_OWN_COLOR);
setHoverColor(OUTLINE_OWN_HOVER_COLOR);
@@ -31,6 +45,9 @@ public void selectableOwn(){
selectableOn();
}
/**
* Sets the outline colors and enables selection for enemy objects.
*/
public void selectableEnemy(){
setHighlightColor(OUTLINE_ENEMY_COLOR);
setHoverColor(OUTLINE_ENEMY_HOVER_COLOR);

View File

@@ -7,6 +7,9 @@
import static pp.mdga.client.Util.linInt;
/**
* Controls the rotation of the tank's top part to face an enemy position.
*/
public class TankTopControl extends InitControl {
private float timer = 0; // Time elapsed
@@ -16,6 +19,11 @@ public class TankTopControl extends InitControl {
private float endAngle = 0;
private Runnable actionAfter = null;
/**
* Updates the control each frame.
*
* @param tpf Time per frame
*/
@Override
protected void controlUpdate(float tpf) {
if (!rotating) return;
@@ -43,6 +51,12 @@ protected void controlUpdate(float tpf) {
}
}
/**
* Initiates the rotation of the tank's top part to face the enemy position.
*
* @param enemyPos The position of the enemy
* @param actionAfter The action to execute after the rotation is complete
*/
public void rotate(Vector3f enemyPos, Runnable actionAfter) {
if (spatial == null) throw new RuntimeException("spatial is null");
@@ -62,6 +76,12 @@ public void rotate(Vector3f enemyPos, Runnable actionAfter) {
this.actionAfter = actionAfter; // Store the action to execute after rotation
}
/**
* Calculates the angle to the enemy position.
*
* @param enemyPos The position of the enemy
* @return The angle to the enemy in degrees
*/
private float getEnemyAngle(Vector3f enemyPos) {
// Direction to the enemy in the XY plane
Vector3f direction = enemyPos.subtract(spatial.getLocalTranslation());
@@ -82,6 +102,11 @@ private float getEnemyAngle(Vector3f enemyPos) {
return (float) Math.toDegrees(angle); // Return the absolute angle in degrees
}
/**
* Calculates the tank's current angle.
*
* @return The tank's current angle in degrees
*/
private float getOwnAngle() {
// Tank's forward direction in the XY plane
Vector3f forward = spatial.getLocalRotation().mult(Vector3f.UNIT_Y);

View File

@@ -13,6 +13,10 @@
import pp.mdga.client.MdgaApp;
import pp.mdga.client.board.OutlineControl;
/**
* CardControl class extends OutlineControl to manage the visual representation
* and behavior of a card in the game.
*/
public class CardControl extends OutlineControl {
private static final ColorRGBA HIGHLIGHT_COLOR = ColorRGBA.Yellow;
@@ -24,10 +28,17 @@ public class CardControl extends OutlineControl {
private static final ColorRGBA SELECT_COLOR = ColorRGBA.Blue;
private static final int SELECT_WIDTH = 13;
private Node root;
private BitmapText num;
/**
* Constructor for CardControl.
*
* @param app the application instance
* @param fpp the FilterPostProcessor instance
* @param cam the Camera instance
* @param root the root Node
*/
public CardControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, Node root) {
super(app, fpp, cam,
HIGHLIGHT_COLOR, HIGHLIGHT_WIDTH,
@@ -37,12 +48,16 @@ public CardControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, Node root)
this.root = root;
Node rootNum = createNum();
rootNum.setLocalTranslation(new Vector3f(0.35f, 0.8f, 0));
root.attachChild(rootNum);
}
/**
* Creates a Node containing a number and a circle geometry.
*
* @return the created Node
*/
private Node createNum() {
Node rootNum = new Node("root Num");
Geometry circle = new Geometry("circle", new Sphere(20, 20, 1));
@@ -63,18 +78,30 @@ private Node createNum() {
return rootNum;
}
/**
* Sets the number displayed on the card.
*
* @param num the number to display
*/
public void setNumCard(int num) {
this.num.setText(String.valueOf(num));
}
/**
* Gets the root Node of the card.
*
* @return the root Node
*/
public Node getRoot() {
return root;
}
/**
* Initializes the spatial properties of the card.
*/
@Override
public void initSpatial() {
}
private final static Vector3f HIGHLIGHT_Y = new Vector3f(0, 0.4f, 0);
}

View File

@@ -22,6 +22,10 @@
import java.util.ArrayList;
import java.util.List;
/**
* CardLayer is an application state that manages the rendering and updating of card objects
* in a separate viewport with post-processing effects.
*/
public class CardLayer extends AbstractAppState {
public static final int SHADOWMAP_SIZE = 1024 * 8;
@@ -40,7 +44,13 @@ public class CardLayer extends AbstractAppState {
DirectionalLight sun;
ComposeFilter compose;
/**
* Constructs a new CardLayer with the specified post-processor, camera, and background texture.
*
* @param fpp the FilterPostProcessor to use for post-processing effects
* @param overlayCam the Camera to use for the overlay
* @param backTexture the Texture2D to use as the background texture
*/
public CardLayer(FilterPostProcessor fpp, Camera overlayCam, Texture2D backTexture) {
this.overlayCam = overlayCam;
this.fpp = fpp;
@@ -58,6 +68,12 @@ public CardLayer(FilterPostProcessor fpp, Camera overlayCam, Texture2D backTextu
root = new Node("Under gui viewport Root");
}
/**
* Initializes the CardLayer, setting up the viewport, filters, and lighting.
*
* @param stateManager the AppStateManager managing this state
* @param app the Application instance
*/
@Override
public void initialize(AppStateManager stateManager, Application app) {
this.app = app;
@@ -84,26 +100,35 @@ public void initialize(AppStateManager stateManager, Application app) {
if (!init) init = true;
}
/**
* Shuts down the CardLayer, removing filters, lights, and clearing buffers.
*/
public void shutdown() {
// view.clearProcessors();
fpp.removeFilter(dlsf);
dlsf = null;
root.removeLight(sun);
fpp.removeFilter(fxaaFilter);
// fpp.removeFilter(compose);
view.detachScene(root);
// app.getRenderManager().removeMainView(view);
cardBuffer.clear();
root.detachAllChildren();
}
/**
* Renders the CardLayer, updating the geometric state of the root node.
*
* @param rm the RenderManager handling the rendering
*/
@Override
public void render(RenderManager rm) {
root.updateGeometricState();
}
/**
* Updates the CardLayer, attaching buffered cards to the root node and updating its logical state.
*
* @param tpf time per frame
*/
@Override
public void update(float tpf) {
if (init && !cardBuffer.isEmpty()) {
@@ -115,19 +140,39 @@ public void update(float tpf) {
root.updateLogicalState(tpf);
}
/**
* Adds a spatial card to the CardLayer.
*
* @param card the Spatial card to add
*/
public void addSpatial(Spatial card) {
if (root == null) cardBuffer.add(card);
else root.attachChild(card);
}
/**
* Deletes a spatial card from the CardLayer.
*
* @param spatial the Spatial card to delete
*/
public void deleteSpatial(Spatial spatial) {
root.detachChild(spatial);
}
/**
* Gets the overlay camera used by the CardLayer.
*
* @return the overlay camera
*/
public Camera getOverlayCam() {
return overlayCam;
}
/**
* Gets the root node of the CardLayer.
*
* @return the root node
*/
public Node getRootNode() {
return root;
}

View File

@@ -15,6 +15,9 @@
import java.util.*;
/**
* Handles the card layer in the GUI, including card management and dice control.
*/
public class CardLayerHandler {
private static final Vector3f START = new Vector3f(-1.8f, -3.5f, 0);
private static final Vector3f MARGIN = new Vector3f(1.8f, 0, 0);
@@ -36,12 +39,21 @@ public class CardLayerHandler {
private BonusCard cardSelect = null;
private boolean show = false;
/**
* Constructs a CardLayerHandler.
*
* @param app the application instance
* @param backTexture the background texture
*/
public CardLayerHandler(MdgaApp app, Texture2D backTexture) {
this.app = app;
this.fpp = new FilterPostProcessor(app.getAssetManager());
this.backTexture = backTexture;
}
/**
* Initializes the card layer and dice control.
*/
public void init() {
cardLayerCamera = createOverlayCam();
cardLayer = new CardLayer(fpp, cardLayerCamera, backTexture);
@@ -51,6 +63,9 @@ public void init() {
diceControl.create(new Vector3f(0, 0, 0), 1f, false);
}
/**
* Shuts down the card layer and clears selectable cards.
*/
public void shutdown() {
clearSelectableCards();
if (cardLayer != null) {
@@ -60,11 +75,20 @@ public void shutdown() {
cardLayer = null;
}
/**
* Rolls the dice with a specified number and action to perform after rolling.
*
* @param rollNum the number to roll (must be between 1 and 6)
* @param actionAfter the action to perform after rolling
*/
public void rollDice(int rollNum, Runnable actionAfter) {
if (!(1 <= rollNum && rollNum <= 6)) throw new RuntimeException("rollNum is not in the range [1,6]");
diceControl.rollDice(rollNum, actionAfter);
}
/**
* Shows the dice on the card layer.
*/
public void showDice() {
if (show) return;
show = true;
@@ -72,11 +96,19 @@ public void showDice() {
diceControl.spin();
}
/**
* Hides the dice from the card layer.
*/
public void hideDice() {
show = false;
diceControl.hide();
}
/**
* Adds a card to the card layer.
*
* @param card the card to add
*/
public void addCard(BonusCard card) {
if (card == BonusCard.HIDDEN) throw new RuntimeException("Can't add hidden card to GUI");
@@ -90,6 +122,11 @@ public void addCard(BonusCard card) {
updateCard();
}
/**
* Removes a card from the card layer.
*
* @param card the card to remove
*/
public void removeCard(BonusCard card) {
if (bonusCardControlMap.containsKey(card)) {
bonusCardIntegerMap.put(card, bonusCardIntegerMap.get(card) - 1);
@@ -102,6 +139,9 @@ public void removeCard(BonusCard card) {
} else throw new RuntimeException("card is not in bonusCardControlMap");
}
/**
* Clears all selectable cards.
*/
public void clearSelectableCards() {
for (CardControl control : selectableCards) {
control.selectableOff();
@@ -110,6 +150,9 @@ public void clearSelectableCards() {
cardSelect = null;
}
/**
* Updates the card layer with the current cards.
*/
private void updateCard() {
for (BonusCard card : bonusCardControlMap.keySet()) {
CardControl control = bonusCardControlMap.get(card);
@@ -126,6 +169,11 @@ private void updateCard() {
}
}
/**
* Sets the selectable cards.
*
* @param select the list of cards to set as selectable
*/
public void setSelectableCards(List<BonusCard> select) {
for (BonusCard card : select) {
selectableCards.add(bonusCardControlMap.get(card));
@@ -135,6 +183,11 @@ public void setSelectableCards(List<BonusCard> select) {
}
}
/**
* Selects a card control.
*
* @param cardControl the card control to select
*/
public void selectCard(CardControl cardControl) {
if (cardControl.isSelected()) {
cardControl.selectOff();
@@ -150,28 +203,48 @@ public void selectCard(CardControl cardControl) {
app.getModelSynchronize().selectCard(cardSelect);
}
/**
* Gets the card layer camera.
*
* @return the card layer camera
*/
public Camera getCardLayerCamera() {
return cardLayerCamera;
}
/**
* Adds a shield symbol to the card layer.
*/
public void shield() {
SymbolControl control = createSymbol(Asset.shieldSymbol);
cardLayer.addSpatial(control.getSpatial());
control.shield();
}
/**
* Adds a swap symbol to the card layer.
*/
public void swap() {
SymbolControl control = createSymbol(Asset.swapSymbol);
cardLayer.addSpatial(control.getSpatial());
control.swap();
}
/**
* Adds a turbo symbol to the card layer.
*/
public void turbo() {
SymbolControl control = createSymbol(Asset.turboSymbol);
cardLayer.addSpatial(control.getSpatial());
control.turbo();
}
/**
* Converts a bonus card to its corresponding asset.
*
* @param card the bonus card
* @return the corresponding asset
*/
private Asset bonusToAsset(BonusCard card) {
return switch (card) {
case TURBO -> Asset.turboCard;
@@ -181,10 +254,21 @@ private Asset bonusToAsset(BonusCard card) {
};
}
/**
* Calculates the next position for a card.
*
* @param i the index of the card
* @return the next position vector
*/
private Vector3f nextPos(int i) {
return START.add(MARGIN.mult(i));
}
/**
* Creates an overlay camera for the card layer.
*
* @return the created overlay camera
*/
private Camera createOverlayCam() {
Camera originalCam = app.getCamera();
Camera overlayCam = new Camera(originalCam.getWidth(), originalCam.getHeight());
@@ -197,6 +281,15 @@ private Camera createOverlayCam() {
return overlayCam;
}
/**
* Gets the key associated with a value in a map.
*
* @param map the map to search
* @param value the value to find the key for
* @param <K> the type of keys in the map
* @param <V> the type of values in the map
* @return the key associated with the value, or null if not found
*/
private <K, V> K getKeyByValue(Map<K, V> map, V value) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (entry.getValue().equals(value)) {
@@ -206,6 +299,9 @@ private <K, V> K getKeyByValue(Map<K, V> map, V value) {
return null;
}
/**
* Test method to add sample cards to the card layer.
*/
public void test() {
addCard(BonusCard.SHIELD);
addCard(BonusCard.SHIELD);
@@ -213,6 +309,13 @@ public void test() {
addCard(BonusCard.SWAP);
}
/**
* Creates a card control for a given asset and position.
*
* @param card the asset representing the card
* @param pos the position to place the card
* @return the created card control
*/
private CardControl createCard(Asset card, Vector3f pos) {
Node rootCard = new Node("Root Card");
Spatial spatial = app.getAssetManager().loadModel(card.getModelPath());
@@ -229,6 +332,12 @@ private CardControl createCard(Asset card, Vector3f pos) {
return control;
}
/**
* Creates a symbol control for a given asset.
*
* @param asset the asset representing the symbol
* @return the created symbol control
*/
private SymbolControl createSymbol(Asset asset) {
Spatial spatial = app.getAssetManager().loadModel(asset.getModelPath());
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
@@ -241,6 +350,11 @@ private SymbolControl createSymbol(Asset asset) {
return control;
}
/**
* Gets the card layer.
*
* @return the card layer
*/
public CardLayer getCardLayer() {
return cardLayer;
}

View File

@@ -16,6 +16,9 @@
import static com.jme3.material.Materials.LIGHTING;
import static com.jme3.material.Materials.UNSHADED;
/**
* DiceControl class handles the rolling and spinning behavior of a dice in the game.
*/
public class DiceControl extends AbstractControl {
private Quaternion targetRotation;
private final Vector3f angularVelocity = new Vector3f();
@@ -31,11 +34,20 @@ public class DiceControl extends AbstractControl {
private final AssetManager assetManager;
private Runnable actionAfter;
/**
* Constructor for DiceControl.
*
* @param assetManager the asset manager to load models and textures
*/
public DiceControl(AssetManager assetManager) {
this.assetManager = assetManager;
}
/**
* Updates the control each frame.
*
* @param tpf time per frame
*/
@Override
protected void controlUpdate(float tpf) {
float clampedTpf = Math.min(tpf, 0.05f); // Max 50 ms per frame
@@ -56,7 +68,6 @@ protected void controlUpdate(float tpf) {
} else {
timeElapsed += clampedTpf * rollDuration;
if (timeElapsed > 1.0f) timeElapsed = 1.0f;
Quaternion interpolated = spatial.getLocalRotation().clone();
interpolated.slerp(targetRotation, timeElapsed);
@@ -74,6 +85,11 @@ protected void controlUpdate(float tpf) {
}
}
/**
* Applies rotational velocity to the dice.
*
* @param tpf time per frame
*/
private void spinWithAngularVelocity(float tpf) {
Quaternion currentRotation = spatial.getLocalRotation();
Quaternion deltaRotation = new Quaternion();
@@ -85,11 +101,22 @@ private void spinWithAngularVelocity(float tpf) {
spatial.setLocalRotation(currentRotation.mult(deltaRotation));
}
/**
* Renders the control.
*
* @param rm the render manager
* @param vp the viewport
*/
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
/**
* Initiates the dice roll.
*
* @param diceNum the number on the dice to roll to
* @param actionAfter the action to perform after the roll
*/
public void rollDice(int diceNum, Runnable actionAfter) {
if (isRolling) return;
spin = false;
@@ -107,6 +134,12 @@ public void rollDice(int diceNum, Runnable actionAfter) {
isRolling = true;
}
/**
* Gets the target rotation for a given dice number.
*
* @param diceNum the number on the dice
* @return the target rotation as a Quaternion
*/
private Quaternion getRotationForDiceNum(int diceNum) {
return switch (diceNum) {
case 1 -> new Quaternion().fromAngleAxis((float) (1 * (Math.PI / 2)), Vector3f.UNIT_X);
@@ -119,10 +152,19 @@ private Quaternion getRotationForDiceNum(int diceNum) {
};
}
/**
* Linear interpolation function.
*
* @param t the interpolation factor
* @return the interpolated value
*/
public static float lerp(float t) {
return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
}
/**
* Sets a random rotation for the dice.
*/
public void randomRotation() {
Quaternion randomRotation = new Quaternion();
randomRotation.fromAngles(
@@ -133,11 +175,17 @@ public void randomRotation() {
spatial.setLocalRotation(randomRotation);
}
/**
* Initiates the dice spin.
*/
public void spin() {
angularVelocity.set(ANGULAR_SPIN, ANGULAR_SPIN, ANGULAR_SPIN);
spin = true;
}
/**
* Hides the dice by removing it from the parent node.
*/
public void hide() {
spatial.removeFromParent();
spin = false;
@@ -145,6 +193,13 @@ public void hide() {
slerp = false;
}
/**
* Creates the dice model and sets its initial properties.
*
* @param pos the position to place the dice
* @param scale the scale of the dice
* @param shadow whether the dice should cast and receive shadows
*/
public void create(Vector3f pos, float scale, boolean shadow) {
Spatial spatial = assetManager.loadModel(Asset.dice.getModelPath());
Material mat;
@@ -163,6 +218,11 @@ public void create(Vector3f pos, float scale, boolean shadow) {
spatial.addControl(this);
}
/**
* Sets the position of the dice.
*
* @param pos the new position
*/
public void setPos(Vector3f pos) {
spatial.setLocalTranslation(pos);
}

View File

@@ -11,6 +11,9 @@
import java.util.List;
/**
* Handles the GUI elements and interactions for the game.
*/
public class GuiHandler {
private final MdgaApp app;
private final CardLayerHandler cardLayerHandler;
@@ -20,6 +23,12 @@ public class GuiHandler {
private FrameBuffer backFrameBuffer;
/**
* Constructs a new GuiHandler.
*
* @param app the application instance
* @param guiNode the GUI node
*/
public GuiHandler(MdgaApp app, Node guiNode) {
this.app = app;
this.ownColor = ownColor;
@@ -34,6 +43,11 @@ public GuiHandler(MdgaApp app, Node guiNode) {
actionTextHandler = new ActionTextHandler(guiNode, app.getAssetManager(), app.getContext().getSettings());
}
/**
* Initializes the GUI handler with the player's color.
*
* @param ownColor the player's color
*/
public void init(Color ownColor) {
cardLayerHandler.init();
playerNameHandler.show();
@@ -41,11 +55,20 @@ public void init(Color ownColor) {
app.getViewPort().setOutputFrameBuffer(backFrameBuffer);
}
/**
* Shuts down the GUI handler.
*/
public void shutdown() {
cardLayerHandler.shutdown();
app.getViewPort().setOutputFrameBuffer(null);
}
/**
* Rolls the dice and handles the result.
*
* @param rollNum the number rolled
* @param mult the multiplier
*/
public void rollDice(int rollNum, int mult) {
cardLayerHandler.rollDice(rollNum, () -> {
if (mult == -1) actionTextHandler.ownDice(rollNum);
@@ -56,43 +79,82 @@ public void rollDice(int rollNum, int mult) {
});
}
/**
* Shows the rolled dice with a multiplier for a specific player.
*
* @param rollNum the number rolled
* @param mult the multiplier
* @param color the player's color
*/
public void showRolledDiceMult(int rollNum, int mult, Color color) {
String name = playerNameHandler.getName(color);
if (mult == -1) actionTextHandler.diceNum(rollNum, name, color);
else actionTextHandler.diceNumMult(rollNum, mult, name, color);
}
/**
* Shows the rolled dice for a specific player.
*
* @param rollNum the number rolled
* @param color the player's color
*/
public void showRolledDice(int rollNum, Color color) {
actionTextHandler.diceNum(rollNum, playerNameHandler.getName(color), color);
}
/**
* Displays the dice on the screen.
*/
public void showDice() {
cardLayerHandler.showDice();
actionTextHandler.diceNow();
}
/**
* Hides the dice from the screen.
*/
public void hideDice() {
cardLayerHandler.hideDice();
}
//add own handCard
/**
* Adds a card to the player's hand.
*
* @param card the card to add
*/
public void addCardOwn(BonusCard card) {
cardLayerHandler.addCard(card);
playerNameHandler.addCard(ownColor);
actionTextHandler.drawCardOwn(ownColor);
}
/**
* Plays a card from the player's hand.
*
* @param card the card to play
*/
public void playCardOwn(BonusCard card) {
getEffectByCard(card);
cardLayerHandler.removeCard(card);
playerNameHandler.removeCard(ownColor);
}
/**
* Plays a card from an enemy player's hand.
*
* @param color the enemy player's color
* @param card the card to play
*/
public void playCardEnemy(Color color, BonusCard card) {
getEffectByCard(card);
playerNameHandler.removeCard(color);
}
/**
* Gets the effect of a card and applies it.
*
* @param bonus the card to get the effect from
*/
private void getEffectByCard(BonusCard bonus) {
switch (bonus) {
case SWAP -> swap();
@@ -102,30 +164,64 @@ private void getEffectByCard(BonusCard bonus) {
}
}
/**
* Clears all selectable cards.
*/
public void clearSelectableCards() {
cardLayerHandler.clearSelectableCards();
}
/**
* Sets the selectable cards.
*
* @param select the list of selectable cards
*/
public void setSelectableCards(List<BonusCard> select) {
cardLayerHandler.setSelectableCards(select);
}
/**
* Selects a card.
*
* @param cardControl the card control to select
*/
public void selectCard(CardControl cardControl) {
cardLayerHandler.selectCard(cardControl);
}
/**
* Gets the camera for the card layer.
*
* @return the card layer camera
*/
public Camera getCardLayerCamera() {
return cardLayerHandler.getCardLayerCamera();
}
/**
* Gets the root node for the card layer.
*
* @return the card layer root node
*/
public Node getCardLayerRootNode() {
return cardLayerHandler.getCardLayer().getRootNode();
}
/**
* Adds a player to the game.
*
* @param color the player's color
* @param name the player's name
*/
public void addPlayer(Color color, String name) {
playerNameHandler.addPlayer(color, name, color == ownColor);
}
/**
* Sets the active player.
*
* @param color the active player's color
*/
public void setActivePlayer(Color color) {
playerNameHandler.setActivePlayer(color);
@@ -133,38 +229,63 @@ public void setActivePlayer(Color color) {
else actionTextHandler.activePlayer(playerNameHandler.getName(color), color);
}
/**
* Applies the shield effect.
*/
public void shield() {
cardLayerHandler.shield();
}
/**
* Applies the swap effect.
*/
public void swap() {
cardLayerHandler.swap();
}
/**
* Applies the turbo effect.
*/
public void turbo() {
cardLayerHandler.turbo();
}
/**
* Hides the action text.
*/
public void hideText() {
actionTextHandler.hide();
}
//addCard Enemy (DrawCardNotification)
/**
* Draws a card for an enemy player.
*
* @param color the enemy player's color
*/
public void drawCard(Color color) {
//Color != ownColor
actionTextHandler.drawCard(playerNameHandler.getName(color), color);
playerNameHandler.addCard(color);
}
/**
* Displays the finish text for a player.
*
* @param color the player's color
*/
public void finish(Color color) {
if (ownColor == color) actionTextHandler.finishTextOwn(color);
else actionTextHandler.finishText(playerNameHandler.getName(color), color);
}
/**
* Displays the ranking result for a player.
*
* @param color the player's color
* @param eye the ranking result
*/
public void rollRankingResult(Color color, int eye) {
if (ownColor == color) actionTextHandler.rollRankingResultOwn(color, eye);
else actionTextHandler.rollRankingResult(playerNameHandler.getName(color), color, eye);
}
}

View File

@@ -15,6 +15,9 @@
import java.util.List;
import java.util.Map;
/**
* Handles the display and management of player names and their associated data.
*/
public class PlayerNameHandler {
private final BitmapFont playerFont;
private final Node playerNameNode;
@@ -37,6 +40,13 @@ public class PlayerNameHandler {
private final Node guiNode;
/**
* Constructs a PlayerNameHandler.
*
* @param guiNode the GUI node to attach player names to
* @param assetManager the asset manager to load resources
* @param appSettings the application settings
*/
public PlayerNameHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings) {
this.guiNode = guiNode;
@@ -49,18 +59,26 @@ public PlayerNameHandler(Node guiNode, AssetManager assetManager, AppSettings ap
this.assetManager = assetManager;
}
/**
* Shows the player names on the GUI.
*/
public void show() {
guiNode.attachChild(playerNameNode);
}
/**
* Hides the player names from the GUI.
*/
public void hide() {
guiNode.detachChild(playerNameNode);
}
/**
* Draws the player names and their associated data on the GUI.
*/
private void drawPlayers() {
playerNameNode.detachAllChildren();
for (int i = 0; i < playerOrder.size(); i++) {
Color color = playerOrder.get(i);
if (!colorNameMap.containsKey(color)) throw new RuntimeException(color + " isn't mapped to a name");
@@ -79,6 +97,14 @@ private void drawPlayers() {
}
}
/**
* Creates a BitmapText object to display the number of cards a player has.
*
* @param num the number of cards
* @param lastWidth the width of the last element
* @param lastX the x position of the last element
* @return a BitmapText object displaying the number of cards
*/
private Spatial createCardNum(int num, float lastWidth, float lastX) {
BitmapText hudText = new BitmapText(playerFont);
//renderedSize = 45
@@ -89,6 +115,12 @@ private Spatial createCardNum(int num, float lastWidth, float lastX) {
return hudText;
}
/**
* Creates a Picture object to display a hand card image.
*
* @param width the width of the previous element
* @return a Picture object displaying a hand card image
*/
private Picture createHandCard(float width) {
Picture pic = new Picture("HUD Picture");
pic.setImage(assetManager, "./Images/handcard.png", true);
@@ -98,6 +130,12 @@ private Picture createHandCard(float width) {
return pic;
}
/**
* Returns the image path for a given color.
*
* @param color the color to get the image path for
* @return the image path for the given color
*/
private String imagePath(Color color) {
String root = "./Images/name_pictures/";
return switch (color) {
@@ -109,6 +147,12 @@ private String imagePath(Color color) {
};
}
/**
* Creates a Picture object to display a color image.
*
* @param color the color to create the image for
* @return a Picture object displaying the color image
*/
private Spatial createColor(Color color) {
Picture pic = new Picture("HUD Picture");
pic.setImage(assetManager, imagePath(color), true);
@@ -118,7 +162,14 @@ private Spatial createColor(Color color) {
return pic;
}
/**
* Creates a BitmapText object to display a player's name.
*
* @param name the player's name
* @param first whether the player is the first in the list
* @param own whether the player is the current user
* @return a BitmapText object displaying the player's name
*/
private BitmapText createName(String name, boolean first, boolean own) {
BitmapText hudText = new BitmapText(playerFont);
//renderedSize = 45
@@ -129,6 +180,13 @@ private BitmapText createName(String name, boolean first, boolean own) {
return hudText;
}
/**
* Adds a player to the handler.
*
* @param color the color associated with the player
* @param name the name of the player
* @param own whether the player is the current user
*/
public void addPlayer(Color color, String name, boolean own) {
if (own) ownColor = color;
colorNameMap.put(color, name);
@@ -136,6 +194,11 @@ public void addPlayer(Color color, String name, boolean own) {
drawPlayers();
}
/**
* Sets the active player.
*
* @param color the color associated with the active player
*/
public void setActivePlayer(Color color) {
if (playerOrder.get(0) == color) return;
Color oldFirst = playerOrder.remove(0);
@@ -146,16 +209,32 @@ public void setActivePlayer(Color color) {
drawPlayers();
}
/**
* Gets the name of a player by their color.
*
* @param color the color associated with the player
* @return the name of the player
*/
public String getName(Color color) {
if (!colorNameMap.containsKey(color)) throw new RuntimeException("color is not in colorNameMap");
return colorNameMap.get(color);
}
/**
* Adds a card to a player.
*
* @param color the color associated with the player
*/
public void addCard(Color color) {
colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) + 1);
drawPlayers();
}
/**
* Removes a card from a player.
*
* @param color the color associated with the player
*/
public void removeCard(Color color) {
if (colorCardMap.containsKey(color)) {
colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) - 1);
@@ -163,6 +242,4 @@ public void removeCard(Color color) {
}
drawPlayers();
}
}

View File

@@ -11,17 +11,34 @@
import com.jme3.texture.FrameBuffer;
/**
* OutlineFilter is a custom filter for rendering outlines around objects.
*/
public class OutlineFilter extends Filter {
private OutlinePreFilter outlinePreFilter;
private ColorRGBA outlineColor = new ColorRGBA(0, 1, 0, 1);
private float outlineWidth = 1;
/**
* Constructs an OutlineFilter with the specified OutlinePreFilter.
*
* @param outlinePreFilter the pre-filter used for outlining
*/
public OutlineFilter(OutlinePreFilter outlinePreFilter) {
super("OutlineFilter");
this.outlinePreFilter = outlinePreFilter;
}
/**
* Initializes the filter with the given parameters.
*
* @param assetManager the asset manager
* @param renderManager the render manager
* @param vp the viewport
* @param w the width of the viewport
* @param h the height of the viewport
*/
@Override
protected void initFilter(AssetManager assetManager, RenderManager renderManager, ViewPort vp, int w, int h) {
MaterialDef matDef = (MaterialDef) assetManager.loadAsset("MatDefs/SelectObjectOutliner/Outline.j3md");
@@ -31,6 +48,11 @@ protected void initFilter(AssetManager assetManager, RenderManager renderManager
material.setFloat("OutlineWidth", outlineWidth);
}
/**
* Called before each frame is rendered.
*
* @param tpf time per frame
*/
@Override
protected void preFrame(float tpf) {
super.preFrame(tpf);
@@ -38,6 +60,14 @@ protected void preFrame(float tpf) {
// System.out.println("OutlineFilter.preFrame()");
}
/**
* Called after each frame is rendered.
*
* @param renderManager the render manager
* @param viewPort the viewport
* @param prevFilterBuffer the previous filter buffer
* @param sceneBuffer the scene buffer
*/
@Override
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
super.postFrame(renderManager, viewPort, prevFilterBuffer, sceneBuffer);
@@ -45,15 +75,30 @@ protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBu
// System.out.println("OutlineFilter.postFrame()");
}
/**
* Returns the material used by this filter.
*
* @return the material
*/
@Override
protected Material getMaterial() {
return material;
}
/**
* Returns the outline color.
*
* @return the outline color
*/
public ColorRGBA getOutlineColor() {
return outlineColor;
}
/**
* Sets the outline color.
*
* @param outlineColor the new outline color
*/
public void setOutlineColor(ColorRGBA outlineColor) {
this.outlineColor = outlineColor;
if (material != null) {
@@ -61,10 +106,20 @@ public void setOutlineColor(ColorRGBA outlineColor) {
}
}
/**
* Returns the outline width.
*
* @return the outline width
*/
public float getOutlineWidth() {
return outlineWidth;
}
/**
* Sets the outline width.
*
* @param outlineWidth the new outline width
*/
public void setOutlineWidth(float outlineWidth) {
this.outlineWidth = outlineWidth;
if (material != null) {
@@ -72,6 +127,11 @@ public void setOutlineWidth(float outlineWidth) {
}
}
/**
* Returns the OutlinePreFilter used by this filter.
*
* @return the OutlinePreFilter
*/
public OutlinePreFilter getOutlinePreFilter() {
return outlinePreFilter;
}

View File

@@ -12,23 +12,36 @@
import com.jme3.texture.Texture;
/**
* OutlinePreFilter is a custom filter used to apply an outline effect to objects.
*/
public class OutlinePreFilter extends Filter {
private Pass normalPass;
private RenderManager renderManager;
/**
* Creates a OutlinePreFilter
* Creates an OutlinePreFilter.
*/
public OutlinePreFilter() {
super("OutlinePreFilter");
}
/**
* Indicates that this filter requires a depth texture.
*
* @return true, indicating that a depth texture is required.
*/
@Override
protected boolean isRequiresDepthTexture() {
return true;
}
/**
* Called after the render queue is processed.
*
* @param queue the render queue.
*/
@Override
protected void postQueue(RenderQueue queue) {
Renderer r = renderManager.getRenderer();
@@ -36,21 +49,47 @@ protected void postQueue(RenderQueue queue) {
renderManager.getRenderer().clearBuffers(true, true, false);
}
/**
* Called after the frame is rendered.
*
* @param renderManager the render manager.
* @param viewPort the viewport.
* @param prevFilterBuffer the previous filter buffer.
* @param sceneBuffer the scene buffer.
*/
@Override
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
super.postFrame(renderManager, viewPort, prevFilterBuffer, sceneBuffer);
}
/**
* Returns the material used by this filter.
*
* @return the material.
*/
@Override
protected Material getMaterial() {
return material;
}
/**
* Returns the texture containing the outline.
*
* @return the outline texture.
*/
public Texture getOutlineTexture() {
return normalPass.getRenderedTexture();
}
/**
* Initializes the filter.
*
* @param manager the asset manager.
* @param renderManager the render manager.
* @param vp the viewport.
* @param w the width.
* @param h the height.
*/
@Override
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
this.renderManager = renderManager;
@@ -59,6 +98,11 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie
material = new Material(manager, "MatDefs/SelectObjectOutliner/OutlinePre.j3md");
}
/**
* Cleans up the filter.
*
* @param r the renderer.
*/
@Override
protected void cleanUpFilter(Renderer r) {
normalPass.cleanup(r);

View File

@@ -10,17 +10,34 @@
import com.jme3.renderer.ViewPort;
import com.jme3.texture.FrameBuffer;
/**
* OutlineProFilter is a custom filter for rendering outlines around objects.
*/
public class OutlineProFilter extends Filter {
private OutlinePreFilter outlinePreFilter;
private ColorRGBA outlineColor = new ColorRGBA(0, 1, 0, 1);
private float outlineWidth = 1;
/**
* Constructs an OutlineProFilter with the specified OutlinePreFilter.
*
* @param outlinePreFilter the pre-filter used for outlining
*/
public OutlineProFilter(OutlinePreFilter outlinePreFilter) {
super("OutlineFilter");
this.outlinePreFilter = outlinePreFilter;
}
/**
* Initializes the filter with the given parameters.
*
* @param assetManager the asset manager
* @param renderManager the render manager
* @param vp the viewport
* @param w the width of the viewport
* @param h the height of the viewport
*/
@Override
protected void initFilter(AssetManager assetManager, RenderManager renderManager, ViewPort vp, int w, int h) {
MaterialDef matDef = (MaterialDef) assetManager.loadAsset("MatDefs/SelectObjectOutliner/OutlinePro.j3md");
@@ -30,29 +47,54 @@ protected void initFilter(AssetManager assetManager, RenderManager renderManager
material.setFloat("OutlineWidth", outlineWidth);
}
/**
* Called before rendering each frame.
*
* @param tpf time per frame
*/
@Override
protected void preFrame(float tpf) {
super.preFrame(tpf);
material.setTexture("OutlineDepthTexture", outlinePreFilter.getOutlineTexture());
// System.out.println("OutlineFilter.preFrame()");
}
/**
* Called after rendering each frame.
*
* @param renderManager the render manager
* @param viewPort the viewport
* @param prevFilterBuffer the previous filter buffer
* @param sceneBuffer the scene buffer
*/
@Override
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
super.postFrame(renderManager, viewPort, prevFilterBuffer, sceneBuffer);
// material.setTexture("OutlineDepthTexture", outlinePreFilter.getDefaultPassDepthTexture());
// System.out.println("OutlineFilter.postFrame()");
}
/**
* Returns the material used by this filter.
*
* @return the material
*/
@Override
protected Material getMaterial() {
return material;
}
/**
* Returns the outline color.
*
* @return the outline color
*/
public ColorRGBA getOutlineColor() {
return outlineColor;
}
/**
* Sets the outline color.
*
* @param outlineColor the new outline color
*/
public void setOutlineColor(ColorRGBA outlineColor) {
this.outlineColor = outlineColor;
if (material != null) {
@@ -60,10 +102,20 @@ public void setOutlineColor(ColorRGBA outlineColor) {
}
}
/**
* Returns the outline width.
*
* @return the outline width
*/
public float getOutlineWidth() {
return outlineWidth;
}
/**
* Sets the outline width.
*
* @param outlineWidth the new outline width
*/
public void setOutlineWidth(float outlineWidth) {
this.outlineWidth = outlineWidth;
if (material != null) {
@@ -71,9 +123,13 @@ public void setOutlineWidth(float outlineWidth) {
}
}
/**
* Returns the OutlinePreFilter.
*
* @return the OutlinePreFilter
*/
public OutlinePreFilter getOutlinePreFilter() {
return outlinePreFilter;
}
}

View File

@@ -9,6 +9,9 @@
import com.jme3.scene.Spatial;
import pp.mdga.client.MdgaApp;
/**
* This class is responsible for outlining selected objects in the scene.
*/
public class SelectObjectOutliner {
private final FilterPostProcessor fpp;
@@ -21,6 +24,15 @@ public class SelectObjectOutliner {
private OutlineProFilter outlineFilter = null;
private final MdgaApp app;
/**
* Constructor for SelectObjectOutliner.
*
* @param fpp the FilterPostProcessor
* @param renderManager the RenderManager
* @param assetManager the AssetManager
* @param cam the Camera
* @param app the MdgaApp instance
*/
public SelectObjectOutliner(FilterPostProcessor fpp, RenderManager renderManager, AssetManager assetManager, Camera cam, MdgaApp app) {
this.selected = false;
this.fpp = fpp;
@@ -30,6 +42,11 @@ public SelectObjectOutliner(FilterPostProcessor fpp, RenderManager renderManager
this.app = app;
}
/**
* Deselects the currently selected object, removing the outline effect.
*
* @param model the Spatial model to deselect
*/
public void deselect(Spatial model) {
if (selected) {
selected = false;
@@ -37,6 +54,12 @@ public void deselect(Spatial model) {
}
}
// /**
// * Selects an object and applies an outline effect.
// *
// * @param model the Spatial model to select
// * @param color the ColorRGBA for the outline
// */
// public void select(Spatial model, ColorRGBA color) {
// if (!selected) {
// selected = true;
@@ -44,6 +67,13 @@ public void deselect(Spatial model) {
// }
// }
/**
* Selects an object and applies an outline effect.
*
* @param model the Spatial model to select
* @param color the ColorRGBA for the outline
* @param width the width of the outline
*/
public void select(Spatial model, ColorRGBA color, int width) {
if (!selected) {
selected = true;
@@ -51,6 +81,11 @@ public void select(Spatial model, ColorRGBA color, int width) {
}
}
/**
* Hides the outline effect from the selected object.
*
* @param model the Spatial model to hide the outline effect from
*/
private void hideOutlineFilterEffect(Spatial model) {
outlineFilter.setEnabled(false);
outlineFilter.getOutlinePreFilter().setEnabled(false);
@@ -61,6 +96,13 @@ private void hideOutlineFilterEffect(Spatial model) {
outlineViewport = null;
}
/**
* Shows the outline effect on the selected object.
*
* @param model the Spatial model to show the outline effect on
* @param width the width of the outline
* @param color the ColorRGBA for the outline
*/
private void showOutlineFilterEffect(Spatial model, int width, ColorRGBA color) {
outlineViewport = renderManager.createPreView("outlineViewport", cam);
FilterPostProcessor outlineFpp = new FilterPostProcessor(assetManager);

View File

@@ -59,7 +59,7 @@ public MdgaServer(int port) {
}
/**
*
* Main method to start the server.
*/
public void run() {
startServer();
@@ -87,6 +87,9 @@ private void startServer() {
}
}
/**
* Process the next message in the queue.
*/
private void processNextMessage() {
try {
ReceivedMessage message = pendingMessages.take(); // This is a blocking call
@@ -97,6 +100,9 @@ private void processNextMessage() {
}
}
/**
* Register serializable classes.
*/
private void initializeSerializables() {
Serializer.registerClass(UUID.class, new UUIDSerializer());
@@ -170,6 +176,9 @@ private void initializeSerializables() {
Serializer.registerClass(BonusCard.class, new EnumSerializer());
}
/**
* Register listeners for the server.
*/
private void registerListeners() {
myServer.addMessageListener(this, AnimationEndMessage.class);
myServer.addMessageListener(this, ClientStartGameMessage.class);

View File

@@ -3,7 +3,16 @@
import pp.mdga.message.client.ClientInterpreter;
import pp.mdga.message.client.ClientMessage;
/**
* Represents a message received from the server.
*/
public record ReceivedMessage(ClientMessage msg, int from) {
/**
* Processes the received message using the specified client interpreter.
*
* @param interpreter the client interpreter to use for processing the message
*/
void process(ClientInterpreter interpreter) {
msg.accept(interpreter, from);
}

View File

@@ -6,7 +6,20 @@
import java.nio.ByteBuffer;
import java.util.UUID;
/**
* Serializer for UUID objects to be used with jME3 networking.
*/
public class UUIDSerializer extends Serializer {
/**
* Reads a UUID object from the given ByteBuffer.
*
* @param data the ByteBuffer containing the serialized UUID
* @param c the class type of the object to be read
* @param <T> the type of the object to be read
* @return the deserialized UUID object, or null if the UUID is a placeholder
* @throws IOException if an I/O error occurs
*/
@Override
public <T> T readObject(ByteBuffer data, Class<T> c) throws IOException {
byte[] uuid = new byte[36];
@@ -19,6 +32,13 @@ public <T> T readObject(ByteBuffer data, Class<T> c) throws IOException {
}
}
/**
* Writes a UUID object to the given ByteBuffer.
*
* @param buffer the ByteBuffer to write the serialized UUID to
* @param object the UUID object to be serialized
* @throws IOException if an I/O error occurs
*/
@Override
public void writeObject(ByteBuffer buffer, Object object) throws IOException {
UUID uuid = (UUID) object;

View File

@@ -19,7 +19,13 @@
import java.util.ArrayList;
/**
* CeremonyView class handles the display and interaction of the ceremony view in the application.
*/
public class CeremonyView extends MdgaView {
/**
* Enum representing the sub-states of the CeremonyView.
*/
private enum SubState {
AWARD_CEREMONY,
STATISTICS,
@@ -39,6 +45,11 @@ private enum SubState {
private AmbientLight ambient = new AmbientLight();
/**
* Constructor for CeremonyView.
*
* @param app The application instance.
*/
public CeremonyView(MdgaApp app) {
super(app);
@@ -52,6 +63,9 @@ public CeremonyView(MdgaApp app) {
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
}
/**
* Method called when entering the CeremonyView.
*/
@Override
public void onEnter() {
rootNode.addLight(ambient);
@@ -98,6 +112,9 @@ public void onEnter() {
enterSub(SubState.AWARD_CEREMONY);
}
/**
* Method called when leaving the CeremonyView.
*/
@Override
public void onLeave() {
backButton.hide();
@@ -116,6 +133,11 @@ public void onLeave() {
rootNode.detachChild(background);
}
/**
* Method called when entering an overlay.
*
* @param overlay The overlay being entered.
*/
@Override
protected void onEnterOverlay(Overlay overlay) {
if (rootNode.hasChild(podest)) {
@@ -123,11 +145,21 @@ protected void onEnterOverlay(Overlay overlay) {
}
}
/**
* Method called when leaving an overlay.
*
* @param overlay The overlay being left.
*/
@Override
protected void onLeaveOverlay(Overlay overlay) {
enterSub(state);
}
/**
* Method called to update the CeremonyView.
*
* @param tpf Time per frame.
*/
@Override
protected void onUpdate(float tpf) {
for (CeremonyButton c : ceremonyButtons) {
@@ -135,6 +167,9 @@ protected void onUpdate(float tpf) {
}
}
/**
* Handles the award ceremony sub-state.
*/
private void awardCeremony() {
continueButton.show();
@@ -145,6 +180,9 @@ private void awardCeremony() {
}
}
/**
* Handles the statistics sub-state.
*/
private void statistics() {
//background = createBackground("Images/b2.png");
//guiNode.attachChild(background);
@@ -154,6 +192,11 @@ private void statistics() {
ceremonyDialog.show();
}
/**
* Enters a sub-state of the CeremonyView.
*
* @param state The sub-state to enter.
*/
private void enterSub(SubState state) {
this.state = state;
@@ -178,6 +221,9 @@ private void enterSub(SubState state) {
}
}
/**
* Handles the forward button action.
*/
public void forward() {
switch (state) {
case AWARD_CEREMONY:
@@ -189,6 +235,9 @@ public void forward() {
}
}
/**
* Handles the back button action.
*/
private void back() {
switch (state) {
case AWARD_CEREMONY:
@@ -200,6 +249,13 @@ private void back() {
}
}
/**
* Adds a participant to the ceremony.
*
* @param color The color of the participant.
* @param pos The position of the participant.
* @param name The name of the participant.
*/
public void addCeremonyParticipant(Color color, int pos, String name) {
CeremonyButton button = new CeremonyButton(app, guiNode, rootNode, color, CeremonyButton.Pos.values()[pos - 1], name);
@@ -211,6 +267,17 @@ public void addCeremonyParticipant(Color color, int pos, String name) {
}
}
/**
* Adds a row of statistics.
*
* @param name The name of the row.
* @param v1 Value 1.
* @param v2 Value 2.
* @param v3 Value 3.
* @param v4 Value 4.
* @param v5 Value 5.
* @param v6 Value 6.
*/
public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) {
ceremonyDialog.addStatisticsRow(name, v1, v2, v3, v4, v5, v6);
@@ -218,6 +285,9 @@ public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5
ceremonyDialog.show();
}
/**
* Cleans up after the game.
*/
public void afterGameCleanup() {
ceremonyDialog.prepare();
}

View File

@@ -12,6 +12,9 @@
import pp.mdga.client.gui.GuiHandler;
import pp.mdga.game.Color;
/**
* Represents the view for the game.
*/
public class GameView extends MdgaView {
private BoardHandler boardHandler;
private CameraHandler camera;
@@ -33,6 +36,11 @@ public class GameView extends MdgaView {
private Node guiHandlerNode = new Node();
/**
* Constructs a new GameView.
*
* @param app the application instance
*/
public GameView(MdgaApp app) {
super(app);
@@ -53,6 +61,9 @@ public GameView(MdgaApp app) {
guiNode.attachChild(guiHandlerNode);
}
/**
* Called when entering the view.
*/
@Override
public void onEnter() {
camera.init(ownColor);
@@ -64,24 +75,36 @@ public void onEnter() {
app.getAcousticHandler().playSound(MdgaSound.START);
}
/**
* Called when leaving the view.
*/
@Override
public void onLeave() {
boardHandler.shutdown();
guiHandler.shutdown();
camera.shutdown();
confirmButton.hide();
noPowerButton.hide();
app.getViewPort().removeProcessor(fpp);
}
/**
* Called to update the view.
*
* @param tpf time per frame
*/
@Override
public void onUpdate(float tpf) {
camera.update(app.getInputSynchronize().getScroll(), app.getInputSynchronize().getRotation());
}
/**
* Called when entering an overlay.
*
* @param overlay the overlay being entered
*/
@Override
protected void onEnterOverlay(Overlay overlay) {
if (overlay == Overlay.SETTINGS) {
@@ -89,6 +112,11 @@ protected void onEnterOverlay(Overlay overlay) {
}
}
/**
* Called when leaving an overlay.
*
* @param overlay the overlay being left
*/
@Override
protected void onLeaveOverlay(Overlay overlay) {
if (overlay == Overlay.SETTINGS) {
@@ -96,26 +124,52 @@ protected void onLeaveOverlay(Overlay overlay) {
}
}
/**
* Leaves the game.
*/
private void leaveGame() {
app.getModelSynchronize().leave();
}
/**
* Gets the board handler.
*
* @return the board handler
*/
public BoardHandler getBoardHandler() {
return boardHandler;
}
/**
* Gets the GUI handler.
*
* @return the GUI handler
*/
public GuiHandler getGuiHandler() {
return guiHandler;
}
/**
* Sets the player's color.
*
* @param ownColor the player's color
*/
public void setOwnColor(Color ownColor) {
this.ownColor = ownColor;
}
/**
* Gets the player's color.
*
* @return the player's color
*/
public Color getOwnColor() {
return ownColor;
}
/**
* Shows the confirm button and hides the no power button.
*/
public void needConfirm() {
noPowerButton.hide();
confirmButton.show();
@@ -123,12 +177,18 @@ public void needConfirm() {
needConfirm = true;
}
/**
* Hides the confirm button.
*/
public void noConfirm() {
confirmButton.hide();
needConfirm = false;
}
/**
* Shows the no power button and hides the confirm button.
*/
public void showNoPower() {
confirmButton.hide();
noPowerButton.show();
@@ -136,11 +196,19 @@ public void showNoPower() {
needNoPower = true;
}
/**
* Hides the no power button.
*/
public void hideNoPower() {
noPowerButton.hide();
needNoPower = false;
}
/**
* Enters the interrupt state with the specified color.
*
* @param color the color to set
*/
public void enterInterrupt(Color color) {
enterOverlay(Overlay.INTERRUPT);
@@ -153,6 +221,9 @@ public void enterInterrupt(Color color) {
interruptDialog.show();
}
/**
* Leaves the interrupt state.
*/
public void leaveInterrupt() {
leaveOverlay(Overlay.INTERRUPT);

View File

@@ -15,6 +15,9 @@
import pp.mdga.client.button.LobbyButton;
import pp.mdga.game.Color;
/**
* Represents the lobby view in the game.
*/
public class LobbyView extends MdgaView {
private Geometry background;
@@ -33,6 +36,11 @@ public class LobbyView extends MdgaView {
private Color own = null;
/**
* Constructs a new LobbyView.
*
* @param app the application instance
*/
public LobbyView(MdgaApp app) {
super(app);
@@ -48,6 +56,9 @@ public LobbyView(MdgaApp app) {
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
}
/**
* Called when entering the lobby view.
*/
@Override
public void onEnter() {
app.getCamera().setParallelProjection(true);
@@ -92,6 +103,9 @@ public void onEnter() {
rootNode.attachChild(background);
}
/**
* Called when leaving the lobby view.
*/
@Override
public void onLeave() {
leaveButton.hide();
@@ -130,6 +144,11 @@ public void onLeave() {
rootNode.detachChild(background);
}
/**
* Called on each frame update.
*
* @param tpf time per frame
*/
@Override
protected void onUpdate(float tpf) {
airforceButton.update(tpf);
@@ -140,14 +159,22 @@ protected void onUpdate(float tpf) {
@Override
protected void onEnterOverlay(Overlay overlay) {
// No implementation needed
}
@Override
protected void onLeaveOverlay(Overlay overlay) {
// No implementation needed
}
/**
* Sets the taken status of a color.
*
* @param color the color
* @param isTaken whether the color is taken
* @param isSelf whether the color is taken by the player
* @param name the name of the player who took the color
*/
public void setTaken(Color color, boolean isTaken, boolean isSelf, String name) {
LobbyButton.Taken taken;
@@ -182,6 +209,12 @@ public void setTaken(Color color, boolean isTaken, boolean isSelf, String name)
}
}
/**
* Sets the ready status of a color.
*
* @param color the color
* @param isReady whether the color is ready
*/
public void setReady(Color color, boolean isReady) {
LobbyButton button = switch (color) {
case CYBER -> cyberButton;
@@ -206,6 +239,11 @@ public void setReady(Color color, boolean isReady) {
}
}
/**
* Toggles the task selection for a color.
*
* @param color the color
*/
private void toggleTsk(Color color) {
LobbyButton.Taken taken = LobbyButton.Taken.NOT;
@@ -241,6 +279,9 @@ private void toggleTsk(Color color) {
}
}
/**
* Sets the player as ready.
*/
public void ready() {
if (own == null) {
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
@@ -254,6 +295,9 @@ public void ready() {
app.getModelSynchronize().setReady(!isReady);
}
/**
* Leaves the lobby.
*/
private void leaveLobby() {
app.getModelSynchronize().leave();
}

View File

@@ -7,7 +7,13 @@
import pp.mdga.client.dialog.JoinDialog;
import pp.mdga.client.dialog.StartDialog;
/**
* MainView class that extends MdgaView and manages the main view of the application.
*/
public class MainView extends MdgaView {
/**
* Enum representing the different sub-states of the MainView.
*/
private enum SubState {
HOST,
JOIN,
@@ -22,6 +28,11 @@ private enum SubState {
private JoinDialog joinDialog;
private HostDialog hostDialog;
/**
* Constructor for MainView.
*
* @param app the MdgaApp instance
*/
public MainView(MdgaApp app) {
super(app);
@@ -32,6 +43,9 @@ public MainView(MdgaApp app) {
background = createBackground("Images/startmenu.png");
}
/**
* Called when the view is entered.
*/
@Override
public void onEnter() {
app.setup();
@@ -41,6 +55,9 @@ public void onEnter() {
enterSub(SubState.MAIN);
}
/**
* Called when the view is left.
*/
@Override
public void onLeave() {
startDialog.hide();
@@ -50,6 +67,11 @@ public void onLeave() {
guiNode.detachChild(background);
}
/**
* Called to update the view.
*
* @param tpf time per frame
*/
@Override
public void onUpdate(float tpf) {
startDialog.update();
@@ -57,18 +79,31 @@ public void onUpdate(float tpf) {
hostDialog.update();
}
/**
* Called when an overlay is entered.
*
* @param overlay the overlay being entered
*/
@Override
protected void onEnterOverlay(Overlay overlay) {
guiNode.detachChild(background);
settingsNode.attachChild(background);
}
/**
* Called when an overlay is left.
*
* @param overlay the overlay being left
*/
@Override
protected void onLeaveOverlay(Overlay overlay) {
settingsNode.detachChild(background);
guiNode.attachChild(background);
}
/**
* Shows the join menu.
*/
private void joinMenu() {
startDialog.hide();
hostDialog.hide();
@@ -76,6 +111,9 @@ private void joinMenu() {
joinDialog.show();
}
/**
* Shows the host menu.
*/
private void hostMenu() {
startDialog.hide();
joinDialog.hide();
@@ -83,6 +121,9 @@ private void hostMenu() {
hostDialog.show();
}
/**
* Shows the main menu.
*/
private void mainMenu() {
joinDialog.hide();
hostDialog.hide();
@@ -90,6 +131,9 @@ private void mainMenu() {
startDialog.show();
}
/**
* Attempts to host a game.
*/
private void tryHost() {
int port = 0;
String text = hostDialog.getPort();
@@ -117,6 +161,9 @@ private void tryHost() {
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
}
/**
* Attempts to join a game.
*/
private void tryJoin() {
int port = 0;
String ip = joinDialog.getIpt();
@@ -146,6 +193,12 @@ private void tryJoin() {
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
}
/**
* Validates an IP address.
*
* @param ip the IP address to validate
* @return true if the IP address is valid, false otherwise
*/
private boolean isValidIpAddress(String ip) {
String ipRegex =
"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\." +
@@ -156,6 +209,11 @@ private boolean isValidIpAddress(String ip) {
return ip != null && ip.matches(ipRegex);
}
/**
* Enters a sub-state.
*
* @param state the sub-state to enter
*/
private void enterSub(SubState state) {
this.state = state;
@@ -176,6 +234,9 @@ private void enterSub(SubState state) {
}
}
/**
* Forwards the state based on the current sub-state.
*/
public void forward() {
switch (state) {
case HOST:
@@ -189,6 +250,11 @@ public void forward() {
}
}
/**
* Forwards the state based on the current sub-state and a boolean flag.
*
* @param host a boolean flag indicating whether to host or join
*/
public void forward(boolean host) {
switch (state) {
case HOST:
@@ -209,6 +275,9 @@ public void forward(boolean host) {
}
}
/**
* Goes back to the main menu from the current sub-state.
*/
public void back() {
switch (state) {
case HOST:
@@ -225,12 +294,21 @@ public void back() {
}
}
/**
* Gets the JoinDialog instance.
*
* @return the JoinDialog instance
*/
public JoinDialog getJoinDialog() {
return joinDialog;
}
/**
* Gets the HostDialog instance.
*
* @return the HostDialog instance
*/
public HostDialog getHostDialog() {
return hostDialog;
}
}

View File

@@ -18,7 +18,13 @@
import pp.mdga.client.dialog.SettingsDialog;
import pp.mdga.client.dialog.VideoSettingsDialog;
/**
* Abstract class representing a view in the MDGA application.
*/
public abstract class MdgaView {
/**
* Enum representing different types of overlays.
*/
public enum Overlay {
INTERRUPT,
SETTINGS,
@@ -40,6 +46,11 @@ public enum Overlay {
private int settingsDepth = 0;
/**
* Constructor for MdgaView.
*
* @param app the application instance
*/
public MdgaView(MdgaApp app) {
this.app = app;
settingsButton = new SettingsButton(app, guiNode, this::enterSettings);
@@ -49,6 +60,9 @@ public MdgaView(MdgaApp app) {
audioSettingsDialog = new AudioSettingsDialog(app, settingsNode, this);
}
/**
* Method to enter the view.
*/
public void enter() {
app.getRootNode().attachChild(rootNode);
app.getGuiNode().attachChild(guiNode);
@@ -58,6 +72,9 @@ public void enter() {
onEnter();
}
/**
* Method to leave the view.
*/
public void leave() {
onLeave();
@@ -71,18 +88,33 @@ public void leave() {
app.getGuiNode().detachChild(guiNode);
}
/**
* Method to enter an overlay.
*
* @param overlay the overlay to enter
*/
public void enterOverlay(Overlay overlay) {
app.getGuiNode().detachChild(guiNode);
onEnterOverlay(overlay);
}
/**
* Method to leave an overlay.
*
* @param overlay the overlay to leave
*/
public void leaveOverlay(Overlay overlay) {
app.getGuiNode().attachChild(guiNode);
onLeaveOverlay(overlay);
}
/**
* Method to update the view.
*
* @param tpf time per frame
*/
public void update(float tpf) {
videoSettingsDialog.update();
audioSettingsDialog.update();
@@ -95,17 +127,44 @@ public void update(float tpf) {
onUpdate(tpf);
}
/**
* Abstract method to handle entering the view.
*/
protected abstract void onEnter();
/**
* Abstract method to handle leaving the view.
*/
protected abstract void onLeave();
/**
* Method to handle updating the view.
*
* @param tpf time per frame
*/
protected void onUpdate(float tpf) {
}
/**
* Abstract method to handle entering an overlay.
*
* @param overlay the overlay to enter
*/
protected abstract void onEnterOverlay(Overlay overlay);
/**
* Abstract method to handle leaving an overlay.
*
* @param overlay the overlay to leave
*/
protected abstract void onLeaveOverlay(Overlay overlay);
/**
* Method to create a background geometry with a texture.
*
* @param texturePath the path to the texture
* @return the created background geometry
*/
protected Geometry createBackground(String texturePath) {
TextureKey key = new TextureKey(texturePath, true);
Texture backgroundTexture = app.getAssetManager().loadTexture(key);
@@ -122,6 +181,9 @@ protected Geometry createBackground(String texturePath) {
return background;
}
/**
* Method to enter the settings view.
*/
public void enterSettings() {
enterOverlay(Overlay.SETTINGS);
@@ -132,6 +194,9 @@ public void enterSettings() {
settingsDepth++;
}
/**
* Method to leave the settings view.
*/
public void leaveSettings() {
leaveOverlay(Overlay.SETTINGS);
@@ -142,6 +207,9 @@ public void leaveSettings() {
settingsDepth--;
}
/**
* Method to enter the video settings view.
*/
public void enterVideoSettings() {
settingsDialog.hide();
videoSettingsDialog.show();
@@ -149,6 +217,9 @@ public void enterVideoSettings() {
settingsDepth++;
}
/**
* Method to leave the video settings view.
*/
public void leaveVideoSettings() {
settingsDialog.show();
videoSettingsDialog.hide();
@@ -156,6 +227,9 @@ public void leaveVideoSettings() {
settingsDepth--;
}
/**
* Method to enter the audio settings view.
*/
public void enterAudioSettings() {
settingsDialog.hide();
audioSettingsDialog.show();
@@ -163,6 +237,9 @@ public void enterAudioSettings() {
settingsDepth++;
}
/**
* Method to leave the audio settings view.
*/
public void leaveAudioSettings() {
settingsDialog.show();
audioSettingsDialog.hide();
@@ -170,6 +247,9 @@ public void leaveAudioSettings() {
settingsDepth--;
}
/**
* Method to leave advanced settings.
*/
private void leaveAdvanced() {
settingsDialog.show();
audioSettingsDialog.hide();
@@ -177,6 +257,9 @@ private void leaveAdvanced() {
settingsDepth--;
}
/**
* Method to handle pressing the escape key.
*/
public void pressEscape() {
if (settingsDepth == 0) {
enterSettings();
@@ -187,6 +270,9 @@ public void pressEscape() {
}
}
/**
* Method to handle pressing the forward key.
*/
public void pressForward() {
if (this instanceof MainView mainView) {
mainView.forward(false);
@@ -212,6 +298,12 @@ public void pressForward() {
}
}
/**
* Method to show information on the view.
*
* @param error the error message
* @param isError flag indicating if it is an error
*/
public void showInfo(String error, boolean isError) {
infoTimer.reset();