Development #37

Merged
j23f0779 merged 20 commits from development into dev/server_h 2024-12-07 15:36:25 +01:00
16 changed files with 609 additions and 68 deletions
Showing only changes of commit d39f85fbe9 - Show all commits

View File

@@ -10,6 +10,10 @@
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound; import pp.mdga.client.acoustic.MdgaSound;
/**
* The {@code Explosion} class represents an explosion effect in a 3D environment.
* It manages the creation, configuration, and triggering of particle emitters for fire and smoke effects.
*/
public class Explosion { public class Explosion {
private final Node rootNode; private final Node rootNode;
@@ -23,11 +27,11 @@ public class Explosion {
private final Material mat; private final Material mat;
/** /**
* Konstruktor r die Explosion. * Constructor for the {@code Explosion} class.
* *
* @param app Die Hauptanwendung. * @param app The main application managing the explosion.
* @param rootNode Der Root-Knoten, an den die Explosion angefügt wird. * @param rootNode The root node to which the explosion effects will be attached.
* @param location Der Ort der Explosion in World-Koordinaten. * @param location The location of the explosion in world coordinates.
*/ */
public Explosion(MdgaApp app, Node rootNode, Vector3f location) { public Explosion(MdgaApp app, Node rootNode, Vector3f location) {
this.app = app; this.app = app;
@@ -38,7 +42,8 @@ public Explosion(MdgaApp app, Node rootNode, Vector3f location) {
} }
/** /**
* Initialisiert den Partikel-Emitter r die Explosion. * Initializes the particle emitters for the explosion effect.
* Configures the fire and smoke emitters with appearance, behavior, and lifespan.
*/ */
private void initializeEmitter() { private void initializeEmitter() {
fire = new ParticleEmitter("Effect", Type.Triangle,50); fire = new ParticleEmitter("Effect", Type.Triangle,50);
@@ -77,7 +82,8 @@ private void initializeEmitter() {
} }
/** /**
* Löst die Explosion aus. * Triggers the explosion effect by attaching and activating the particle emitters for fire and smoke.
* Both emitters are automatically detached after a predefined duration.
*/ */
public void trigger() { public void trigger() {
if (!triggered) { if (!triggered) {

View File

@@ -17,28 +17,33 @@
import java.util.UUID; import java.util.UUID;
/**
* The {@code JetAnimation} class handles the animation of a jet model in a 3D environment.
* It creates a jet model, animates its movement along a curved path, triggers an explosion at a target point,
* and performs additional actions upon animation completion.
*/
public class JetAnimation { public class JetAnimation {
private final MdgaApp app; // Referenz auf die Hauptanwendung private final MdgaApp app;
private final Node rootNode; // Root-Knoten, an dem die Animation hängt private final Node rootNode;
private Spatial jetModel; // Das Model des "jet" private Spatial jetModel;
private final Vector3f spawnPoint; // Spawnpunkt des Jets private final Vector3f spawnPoint;
private final Vector3f nodePoint; // Punkt des überflogenen Knotens private final Vector3f nodePoint;
private final Vector3f despawnPoint; // Punkt, an dem der Jet despawnt private final Vector3f despawnPoint;
private final float curveHeight; // Maximale Höhe der Kurve private final float curveHeight;
private final float animationDuration; // Dauer der Animation private final float animationDuration;
private Explosion explosion; private Explosion explosion;
private final UUID id; private final UUID id;
/** /**
* Konstruktor r die ThrowAnimation-Klasse. * Constructor for the {@code JetAnimation} class.
* *
* @param app Die Hauptanwendung * @param app The main application managing the jet animation.
* @param rootNode Der Root-Knoten, an dem der Jet angefügt wird * @param rootNode The root node to which the jet model will be attached.
* @param uuid Die UUID des pieces * @param uuid A unique identifier for the animation.
* @param targetPoint Der Punkt, an dem der Jet spawnt * @param targetPoint The target point where the explosion will occur.
* @param curveHeight Die maximale Höhe der Flugkurve * @param curveHeight The height of the curve for the jet's flight path.
* @param animationDuration Die Gesamtdauer der Animation in Sekunden * @param animationDuration The total duration of the jet animation.
*/ */
public JetAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f targetPoint, float curveHeight, float animationDuration) { public JetAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f targetPoint, float curveHeight, float animationDuration) {
Vector3f spawnPoint = targetPoint.add(170, 50, 50); Vector3f spawnPoint = targetPoint.add(170, 50, 50);
@@ -61,7 +66,7 @@ public JetAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f targetPoint,
} }
/** /**
* Startet die Animation. * Starts the jet animation by spawning the jet model and initiating its movement along the predefined path.
*/ */
public void start() { public void start() {
app.getAcousticHandler().playSound(MdgaSound.JET); app.getAcousticHandler().playSound(MdgaSound.JET);
@@ -70,7 +75,7 @@ public void start() {
} }
/** /**
* Spawnt den Jet an der spezifizierten Position. * Spawns the jet model at the designated spawn point, applying material, scaling, and rotation.
*/ */
private void spawnJet() { private void spawnJet() {
jetModel = app.getAssetManager().loadModel(Asset.jet.getModelPath()); jetModel = app.getAssetManager().loadModel(Asset.jet.getModelPath());
@@ -86,7 +91,8 @@ private void spawnJet() {
} }
/** /**
* Animiert den Jet entlang einer Kurve und lässt ihn anschließend verschwinden. * Animates the jet along a Bezier curve path, triggers the explosion effect at the appropriate time,
* and performs cleanup operations after the animation completes.
*/ */
private void animateJet() { private void animateJet() {
Vector3f controlPoint1 = spawnPoint.add(0, curveHeight, 0); Vector3f controlPoint1 = spawnPoint.add(0, curveHeight, 0);
@@ -126,18 +132,25 @@ protected void controlUpdate(float tpf) {
} }
@Override @Override
protected void controlRender(RenderManager rm, ViewPort vp) { protected void controlRender(RenderManager rm, ViewPort vp) {}
// Wird hier nicht benötigt
}
}); });
} }
/** /**
* Repräsentiert eine 3D-Bezier-Kurve mit vier Kontrollpunkten. * The {@code BezierCurve3f} class represents a 3D cubic Bezier curve.
* It provides methods to interpolate positions and derivatives along the curve.
*/ */
private static class BezierCurve3f { private static class BezierCurve3f {
private final Vector3f p0, p1, p2, p3; private final Vector3f p0, p1, p2, p3;
/**
* Constructor for the {@code BezierCurve3f} class.
*
* @param p0 The starting point of the curve.
* @param p1 The first control point influencing the curve's shape.
* @param p2 The second control point influencing the curve's shape.
* @param p3 The endpoint of the curve.
*/
public BezierCurve3f(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) { public BezierCurve3f(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
this.p0 = p0; this.p0 = p0;
this.p1 = p1; this.p1 = p1;
@@ -145,6 +158,12 @@ public BezierCurve3f(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
this.p3 = p3; this.p3 = p3;
} }
/**
* Interpolates a position along the curve at a given progress value {@code t}.
*
* @param t The progress value (0.0 to 1.0) along the curve.
* @return The interpolated position on the curve.
*/
public Vector3f interpolate(float t) { public Vector3f interpolate(float t) {
float u = 1 - t; float u = 1 - t;
float tt = t * t; float tt = t * t;
@@ -159,6 +178,12 @@ public Vector3f interpolate(float t) {
return point; return point;
} }
/**
* Computes the derivative at a given progress value {@code t}, representing the direction along the curve.
*
* @param t The progress value (0.0 to 1.0) along the curve.
* @return The derivative (direction vector) at the specified progress.
*/
public Vector3f interpolateDerivative(float t) { public Vector3f interpolateDerivative(float t) {
float u = 1 - t; float u = 1 - t;
float tt = t * t; float tt = t * t;

View File

@@ -16,25 +16,30 @@
import java.util.UUID; import java.util.UUID;
/**
* The {@code MissileAnimation} class handles the animation of a missile moving along a parabolic path
* towards a target point in a 3D environment. It also triggers an explosion at the target upon impact.
*/
public class MissileAnimation { public class MissileAnimation {
private final Node rootNode; // Root-Knoten, an den die Animation gehängt wird private final Node rootNode;
private final MdgaApp app; // Referenz auf die Hauptanwendung private final MdgaApp app;
private final Vector3f start; // Startpunkt der Rakete private final Vector3f start;
private final Vector3f target; // Zielpunkt der Rakete private final Vector3f target;
private final float flightTime; // Gesamtdauer des Flugs private final float flightTime;
private Explosion explosion; private Explosion explosion;
private Spatial missileModel; // 3D-Modell der Rakete private Spatial missileModel;
private UUID id; private UUID id;
/** /**
* Konstruktor r die MissileAnimation. * Constructor for the {@code MissileAnimation} class.
* *
* @param app Die Hauptanwendung. * @param app The main application managing the missile animation.
* @param rootNode Der Root-Knoten, an den die Animation gehängt wird. * @param rootNode The root node to which the missile model will be attached.
* @param target Der Zielpunkt der Rakete. * @param uuid A unique identifier for the missile animation.
* @param flightTime Die Zeit, die die Rakete für den gesamten Flug benötigt. * @param target The target point where the missile will explode.
* @param flightTime The total flight time of the missile.
*/ */
public MissileAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f target, float flightTime) { public MissileAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f target, float flightTime) {
this.app = app; this.app = app;
@@ -52,7 +57,7 @@ public MissileAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f target,
} }
/** /**
* Startet die Raketenanimation. * Starts the missile animation by loading the missile model and initiating its parabolic movement.
*/ */
public void start() { public void start() {
loadMissile(); loadMissile();
@@ -61,21 +66,22 @@ public void start() {
} }
/** /**
* Lädt das Raketenmodell und setzt es auf den Startpunkt. * Loads the missile model into the scene, applies scaling, material, and sets its initial position.
*/ */
private void loadMissile() { private void loadMissile() {
missileModel = app.getAssetManager().loadModel(Asset.missile.getModelPath()); // Lade das Missile-Modell missileModel = app.getAssetManager().loadModel(Asset.missile.getModelPath());
missileModel.scale(Asset.missile.getSize()); missileModel.scale(Asset.missile.getSize());
missileModel.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); missileModel.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md"); Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(Asset.missile.getDiffPath())); mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(Asset.missile.getDiffPath()));
missileModel.setMaterial(mat); missileModel.setMaterial(mat);
missileModel.setLocalTranslation(start); // Setze Startposition missileModel.setLocalTranslation(start);
rootNode.attachChild(missileModel); // Füge das Modell zur Szene hinzu rootNode.attachChild(missileModel);
} }
/** /**
* Animiert die Rakete entlang einer Parabel. * Animates the missile along a parabolic path, triggers the explosion near the target,
* and removes the missile model after the animation completes.
*/ */
private void animateMissile() { private void animateMissile() {
missileModel.addControl(new AbstractControl() { missileModel.addControl(new AbstractControl() {
@@ -93,44 +99,39 @@ protected void controlUpdate(float tpf) {
if (progress >= 1) { if (progress >= 1) {
explosion.trigger(); explosion.trigger();
// Flug abgeschlossen rootNode.detachChild(missileModel);
rootNode.detachChild(missileModel); // Entferne Rakete nach dem Ziel this.spatial.removeControl(this);
this.spatial.removeControl(this); // Entferne die Steuerung
return; return;
} }
// Berechne die aktuelle Position entlang der Parabel
Vector3f currentPosition = computeParabolicPath(start, target, progress); Vector3f currentPosition = computeParabolicPath(start, target, progress);
missileModel.setLocalTranslation(currentPosition); missileModel.setLocalTranslation(currentPosition);
// Passe die Ausrichtung an (Nase der Rakete zeigt in Flugrichtung)
Vector3f direction = computeParabolicPath(start, target, progress + 0.01f) Vector3f direction = computeParabolicPath(start, target, progress + 0.01f)
.subtract(currentPosition) .subtract(currentPosition)
.normalizeLocal(); .normalizeLocal();
missileModel.lookAt(currentPosition.add(direction), Vector3f.UNIT_Y); // Z ist oben, Y ist "Up" missileModel.lookAt(currentPosition.add(direction), Vector3f.UNIT_Y);
missileModel.rotate(0, FastMath.HALF_PI, 0); missileModel.rotate(0, FastMath.HALF_PI, 0);
} }
@Override @Override
protected void controlRender(RenderManager rm, ViewPort vp) { protected void controlRender(RenderManager rm, ViewPort vp) {
// Keine Render-Logik benötigt
} }
}); });
} }
/** /**
* Berechnet eine Parabelbewegung von `start` zu `target`. * Computes a position along a parabolic path at a given progress value {@code t}.
* *
* @param start Der Startpunkt der Rakete. * @param start The starting point of the missile's flight.
* @param target Der Zielpunkt der Rakete. * @param target The target point of the missile's flight.
* @param t Der Fortschritt des Flugs (0 bis 1). * @param t The progress value (0.0 to 1.0) along the flight path.
* @return Die Position der Rakete entlang der Parabel. * @return The interpolated position along the parabolic path.
*/ */
private Vector3f computeParabolicPath(Vector3f start, Vector3f target, float t) { private Vector3f computeParabolicPath(Vector3f start, Vector3f target, float t) {
Vector3f midPoint = start.add(target).multLocal(0.5f); // Berechne die Mitte zwischen Start und Ziel Vector3f midPoint = start.add(target).multLocal(0.5f);
midPoint.addLocal(0, 0, 20); // Erhöhe den Scheitelpunkt der Parabel entlang der Z-Achse midPoint.addLocal(0, 0, 20);
// Quadratische Interpolation (Parabel)
Vector3f startToMid = FastMath.interpolateLinear(t, start, midPoint); Vector3f startToMid = FastMath.interpolateLinear(t, start, midPoint);
Vector3f midToTarget = FastMath.interpolateLinear(t, midPoint, target); Vector3f midToTarget = FastMath.interpolateLinear(t, midPoint, target);
return FastMath.interpolateLinear(t, startToMid, midToTarget); return FastMath.interpolateLinear(t, startToMid, midToTarget);

View File

@@ -218,16 +218,38 @@ private Spatial displayAsset(AssetOnMap assetOnMap) {
return createModel(assetOnMap.asset(), gridToWorld(x, y), assetOnMap.rot()); return createModel(assetOnMap.asset(), gridToWorld(x, y), assetOnMap.rot());
} }
/**
* Adds a visual representation of an asset to the scene, attaches a control to it, and returns the control.
*
* @param assetOnMap The asset to be displayed in the 3D environment.
* @param control The control to be added to the spatial representing the asset.
* @param <T> The type of control, extending {@code AbstractControl}.
* @return The control that was added to the spatial.
*/
private <T extends AbstractControl> T displayAndControl(AssetOnMap assetOnMap, T control) { private <T extends AbstractControl> T displayAndControl(AssetOnMap assetOnMap, T control) {
Spatial spatial = displayAsset(assetOnMap); Spatial spatial = displayAsset(assetOnMap);
spatial.addControl(control); spatial.addControl(control);
return control; return control;
} }
/**
* Moves a piece in the 3D environment to the location of a specified node.
*
* @param pieceControl The control managing the piece to be moved.
* @param nodeControl The control managing the target node to which the piece will move.
*/
private void movePieceToNode(PieceControl pieceControl, NodeControl nodeControl){ private void movePieceToNode(PieceControl pieceControl, NodeControl nodeControl){
pieceControl.setLocation(nodeControl.getLocation()); pieceControl.setLocation(nodeControl.getLocation());
} }
/**
* Adds a home node for a specific player color, attaching it to the map of home nodes.
*
* @param map The map storing lists of home nodes by player color.
* @param color The color associated with the home nodes to be added.
* @param assetOnMap The asset representing the home node in the 3D environment.
* @throws RuntimeException if more than 4 home nodes are added for a single color.
*/
private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOnMap assetOnMap){ private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOnMap assetOnMap){
List<NodeControl> homeNodes = addItemToMapList(map, color, displayAndControl(assetOnMap, new NodeControl(app, fpp))); List<NodeControl> homeNodes = addItemToMapList(map, color, displayAndControl(assetOnMap, new NodeControl(app, fpp)));
if (homeNodes.size() > 4) throw new RuntimeException("too many homeNodes for " + color); if (homeNodes.size() > 4) throw new RuntimeException("too many homeNodes for " + color);
@@ -271,6 +293,16 @@ private void movePieceRek(UUID uuid, int curIndex, int moveIndex){
movePieceRek(uuid, curIndex, moveIndex); movePieceRek(uuid, curIndex, moveIndex);
} }
/**
* Adds an item to a list in a map. If the key does not exist in the map, a new list is created.
*
* @param map The map containing lists of items.
* @param key The key associated with the list in the map.
* @param item The item to be added to the list.
* @param <T> The type of items in the list.
* @param <E> The type of the key in the map.
* @return The updated list associated with the specified key.
*/
private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){ private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){
List<T> list = map.getOrDefault(key, new ArrayList<>()); List<T> list = map.getOrDefault(key, new ArrayList<>());
list.add(item); list.add(item);
@@ -278,12 +310,27 @@ private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){
return list; return list;
} }
/**
* Removes an item from a list in a map. If the key does not exist in the map, a new list is created.
*
* @param map The map containing lists of items.
* @param key The key associated with the list in the map.
* @param item The item to be removed from the list.
* @param <T> The type of items in the list.
* @param <E> The type of the key in the map.
*/
private <T, E> void removeItemFromMapList(Map<E,List<T>> map, E key, T item){ private <T, E> void removeItemFromMapList(Map<E,List<T>> map, E key, T item){
List<T> list = map.getOrDefault(key, new ArrayList<>()); List<T> list = map.getOrDefault(key, new ArrayList<>());
list.remove(item); list.remove(item);
map.put(key, list); map.put(key, list);
} }
/**
* Calculates the mean position of the waiting nodes for a specific color.
*
* @param color The color associated with the waiting nodes.
* @return The mean position of the waiting nodes as a {@code Vector3f}.
*/
private Vector3f getWaitingPos(Color color){ private Vector3f getWaitingPos(Color color){
return getMeanPosition(waitingNodesMap.get(color).stream().map(NodeControl::getLocation).toList()); return getMeanPosition(waitingNodesMap.get(color).stream().map(NodeControl::getLocation).toList());
} }

View File

@@ -18,17 +18,37 @@ public class OutlineControl extends InitControl {
private static final int THICKNESS_DEFAULT = 6; private static final int THICKNESS_DEFAULT = 6;
private MdgaApp app; private MdgaApp app;
/**
* Constructs an {@code OutlineControl} with default thickness for the object outline.
*
* @param app The main application managing the outline control.
* @param fpp The {@code FilterPostProcessor} used for post-processing effects.
*/
public OutlineControl(MdgaApp app, FilterPostProcessor fpp){ public OutlineControl(MdgaApp app, FilterPostProcessor fpp){
this.app = app; this.app = app;
outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), app.getCamera(), app); outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), app.getCamera(), app);
} }
/**
* Constructs an {@code OutlineControl} with default thickness, allowing a custom camera to be specified.
*
* @param app The main application managing the outline control.
* @param fpp The {@code FilterPostProcessor} used for post-processing effects.
* @param cam The camera used for rendering the outlined objects.
*/
public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam){ public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam){
this.app = app; this.app = app;
outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), cam, app); outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), cam, app);
} }
/**
* Constructs an {@code OutlineControl} with a specified thickness and custom camera.
*
* @param app The main application managing the outline control.
* @param fpp The {@code FilterPostProcessor} used for post-processing effects.
* @param cam The camera used for rendering the outlined objects.
* @param thickness The thickness of the outline.
*/
public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, int thickness){ public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, int thickness){
this.app = app; this.app = app;
outlineOwn = new SelectObjectOutliner(thickness, fpp, app.getRenderManager(), app.getAssetManager(), cam, app); outlineOwn = new SelectObjectOutliner(thickness, fpp, app.getRenderManager(), app.getAssetManager(), cam, app);
@@ -61,6 +81,11 @@ public void deOutline(){
outlineOwn.deselect(spatial); outlineOwn.deselect(spatial);
} }
/**
* Retrieves the instance of the {@code MdgaApp} associated with this control.
*
* @return The {@code MdgaApp} instance.
*/
public MdgaApp getApp() { public MdgaApp getApp() {
return app; return app;
} }

View File

@@ -7,6 +7,11 @@
import pp.mdga.client.button.SliderButton; import pp.mdga.client.button.SliderButton;
import pp.mdga.client.view.MdgaView; import pp.mdga.client.view.MdgaView;
/**
* The {@code AudioSettingsDialog} class represents a dialog for adjusting audio settings in the application.
* It provides controls for managing main volume, music volume, and sound effect volume, and includes
* a button to return to the previous menu.
*/
public class AudioSettingsDialog extends Dialog { public class AudioSettingsDialog extends Dialog {
private final MdgaView view; private final MdgaView view;
@@ -18,6 +23,13 @@ public class AudioSettingsDialog extends Dialog {
private boolean active = false; private boolean active = false;
/**
* Constructs an {@code AudioSettingsDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The current view, used for navigation and interaction with the dialog.
*/
public AudioSettingsDialog(MdgaApp app, Node node, MdgaView view) { public AudioSettingsDialog(MdgaApp app, Node node, MdgaView view) {
super(app, node); super(app, node);
@@ -42,6 +54,9 @@ public AudioSettingsDialog(MdgaApp app, Node node, MdgaView view) {
backButton.setPos(new Vector2f(0, 1.8f)); backButton.setPos(new Vector2f(0, 1.8f));
} }
/**
* Called when the dialog is shown. Initializes and displays the volume controls and back button.
*/
@Override @Override
protected void onShow() { protected void onShow() {
active = true; active = true;
@@ -57,6 +72,9 @@ protected void onShow() {
soundVolume.show(); soundVolume.show();
} }
/**
* Called when the dialog is hidden. Hides all volume controls and the back button.
*/
@Override @Override
protected void onHide() { protected void onHide() {
active = false; active = false;
@@ -68,6 +86,10 @@ protected void onHide() {
soundVolume.hide(); soundVolume.hide();
} }
/**
* Updates the application audio settings based on the current values of the sliders.
* This method is called continuously while the dialog is active.
*/
public void update() { public void update() {
if(!active) { if(!active) {
return; return;

View File

@@ -10,17 +10,30 @@
import java.util.ArrayList; import java.util.ArrayList;
/**
* The {@code CeremonyDialog} class displays a dialog containing statistical data in a tabular format.
* It allows adding rows of statistics and manages their visibility when shown or hidden.
*/
public class CeremonyDialog extends Dialog { public class CeremonyDialog extends Dialog {
private ArrayList<ArrayList<LabelButton>> labels; private ArrayList<ArrayList<LabelButton>> labels;
float offsetX; float offsetX;
/**
* Constructs a {@code CeremonyDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
*/
public CeremonyDialog(MdgaApp app, Node node) { public CeremonyDialog(MdgaApp app, Node node) {
super(app, node); super(app, node);
prepare(); prepare();
} }
/**
* Called when the dialog is shown. Makes all label buttons in the table visible.
*/
@Override @Override
protected void onShow() { protected void onShow() {
for (ArrayList<LabelButton> row : labels) { for (ArrayList<LabelButton> row : labels) {
@@ -30,6 +43,9 @@ protected void onShow() {
} }
} }
/**
* Called when the dialog is hidden. Hides all label buttons in the table.
*/
@Override @Override
protected void onHide() { protected void onHide() {
for (ArrayList<LabelButton> row : labels) { for (ArrayList<LabelButton> row : labels) {
@@ -39,6 +55,17 @@ protected void onHide() {
} }
} }
/**
* Adds a row of statistical data to the dialog.
*
* @param name The name of the player or category for the row.
* @param v1 The value for the first column.
* @param v2 The value for the second column.
* @param v3 The value for the third column.
* @param v4 The value for the fourth column.
* @param v5 The value for the fifth column.
* @param v6 The value for the sixth column.
*/
public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) { public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) {
float offsetYSmall = 0.5f; float offsetYSmall = 0.5f;
@@ -76,6 +103,9 @@ public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5
labels.add(row); labels.add(row);
} }
/**
* Prepares the initial layout of the dialog, including header labels.
*/
public void prepare() { public void prepare() {
offsetX = 0.5f; offsetX = 0.5f;

View File

@@ -4,30 +4,53 @@
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
/**
* The {@code Dialog} class serves as an abstract base class for dialogs in the application.
* It provides functionality for showing and hiding the dialog and defines abstract methods
* for custom behavior when the dialog is shown or hidden.
*/
public abstract class Dialog { public abstract class Dialog {
protected final MdgaApp app; protected final MdgaApp app;
protected final Node node = new Node(); protected final Node node = new Node();
private final Node root; private final Node root;
/**
* Constructs a {@code Dialog}.
*
* @param app The main application managing the dialog.
* @param node The root node to which the dialog's node will be attached.
*/
Dialog(MdgaApp app, Node node) { Dialog(MdgaApp app, Node node) {
this.app = app; this.app = app;
this.root = node; this.root = node;
} }
/**
* Shows the dialog by attaching its node to the root node and invoking the {@code onShow} method.
*/
public void show() { public void show() {
root.attachChild(node); root.attachChild(node);
onShow(); onShow();
} }
/**
* Hides the dialog by detaching its node from the root node and invoking the {@code onHide} method.
*/
public void hide() { public void hide() {
root.detachChild(node); root.detachChild(node);
onHide(); onHide();
} }
/**
* Called when the dialog is shown. Subclasses must implement this method to define custom behavior.
*/
protected abstract void onShow(); protected abstract void onShow();
/**
* Called when the dialog is hidden. Subclasses must implement this method to define custom behavior.
*/
protected abstract void onHide(); protected abstract void onHide();
} }

View File

@@ -12,6 +12,10 @@
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
/**
* The {@code HostDialog} class represents a dialog for hosting a network game session.
* It allows users to input a port number, start hosting a server, and navigate back to the previous view.
*/
public class HostDialog extends NetworkDialog { public class HostDialog extends NetworkDialog {
private InputButton portInput; private InputButton portInput;
@@ -22,6 +26,13 @@ public class HostDialog extends NetworkDialog {
private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class); private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
/**
* Constructs a {@code HostDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The main view used for navigation and interaction with the dialog.
*/
public HostDialog(MdgaApp app, Node node, MainView view) { public HostDialog(MdgaApp app, Node node, MainView view) {
super(app, node, (NetworkSupport) app.getNetworkSupport()); super(app, node, (NetworkSupport) app.getNetworkSupport());
@@ -39,6 +50,9 @@ public HostDialog(MdgaApp app, Node node, MainView view) {
offset += 1.5f; offset += 1.5f;
} }
/**
* Called when the dialog is shown. Displays all input fields and buttons.
*/
@Override @Override
protected void onShow() { protected void onShow() {
portInput.show(); portInput.show();
@@ -46,6 +60,9 @@ protected void onShow() {
backButton.show(); backButton.show();
} }
/**
* Called when the dialog is hidden. Hides all input fields and buttons.
*/
@Override @Override
protected void onHide() { protected void onHide() {
portInput.hide(); portInput.hide();
@@ -53,27 +70,44 @@ protected void onHide() {
backButton.hide(); backButton.hide();
} }
/**
* Updates the state of the port input field.
* This method is called periodically to synchronize the dialog state.
*/
public void update() { public void update() {
portInput.update(); portInput.update();
} }
/**
* Retrieves the currently entered port number, saves it to preferences, and sets it as the active port.
*
* @return The port number as a string.
*/
public String getPort() { public String getPort() {
prefs.put("hostPort", portInput.getString()); prefs.put("hostPort", portInput.getString());
setPortNumber(Integer.parseInt(portInput.getString())); setPortNumber(Integer.parseInt(portInput.getString()));
return portInput.getString(); return portInput.getString();
} }
/**
* Resets the port input field to its default value and updates preferences accordingly.
*/
public void resetPort() { public void resetPort() {
portInput.reset(); portInput.reset();
prefs.put("hostPort", "11111"); prefs.put("hostPort", "11111");
} }
/**
* Starts the server to host a network game.
*/
public void hostServer() { public void hostServer() {
startServer(); startServer();
} }
/**
* Connects to the server as a client.
*/
public void connectServerAsClient() { public void connectServerAsClient() {
connectServer(); connectServer();
} }
} }

View File

@@ -10,6 +10,10 @@
import pp.mdga.client.view.MdgaView; import pp.mdga.client.view.MdgaView;
import pp.mdga.game.Color; import pp.mdga.game.Color;
/**
* The {@code InterruptDialog} class represents a dialog that interrupts the game flow,
* providing a message and the option to force an action if the user is a host.
*/
public class InterruptDialog extends Dialog { public class InterruptDialog extends Dialog {
private ButtonRight forceButton; private ButtonRight forceButton;
@@ -17,6 +21,12 @@ public class InterruptDialog extends Dialog {
private String text = ""; private String text = "";
/**
* Constructs an {@code InterruptDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
*/
public InterruptDialog(MdgaApp app, Node node) { public InterruptDialog(MdgaApp app, Node node) {
super(app, node); super(app, node);
@@ -29,6 +39,10 @@ public InterruptDialog(MdgaApp app, Node node) {
label.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); label.setPos(new Vector2f(0, MenuButton.VERTICAL - offset));
} }
/**
* Called when the dialog is shown. Displays the label and optionally the force button if the user is the host.
*/
@Override @Override
protected void onShow() { protected void onShow() {
if(app.getGameLogic().isHost()) { if(app.getGameLogic().isHost()) {
@@ -38,12 +52,20 @@ protected void onShow() {
label.show(); label.show();
} }
/**
* Called when the dialog is hidden. Hides the label and the force button.
*/
@Override @Override
protected void onHide() { protected void onHide() {
forceButton.hide(); forceButton.hide();
label.hide(); label.hide();
} }
/**
* Sets the displayed text based on the specified color.
*
* @param color The color used to determine the text (e.g., "Luftwaffe" for AIRFORCE).
*/
public void setColor(Color color) { public void setColor(Color color) {
switch (color) { switch (color) {
case AIRFORCE: case AIRFORCE:

View File

@@ -13,6 +13,10 @@
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
/**
* The {@code JoinDialog} class represents a dialog for joining a network game.
* It allows users to input an IP address and port number, connect to a server, or navigate back to the previous view.
*/
public class JoinDialog extends NetworkDialog { public class JoinDialog extends NetworkDialog {
private InputButton ipInput; private InputButton ipInput;
private InputButton portInput; private InputButton portInput;
@@ -24,6 +28,13 @@ public class JoinDialog extends NetworkDialog {
private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class); private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
/**
* Constructs a {@code JoinDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The main view used for navigation and interaction with the dialog.
*/
public JoinDialog(MdgaApp app, Node node, MainView view) { public JoinDialog(MdgaApp app, Node node, MainView view) {
super(app, node, (NetworkSupport) app.getNetworkSupport()); super(app, node, (NetworkSupport) app.getNetworkSupport());
@@ -46,6 +57,9 @@ public JoinDialog(MdgaApp app, Node node, MainView view) {
offset += 1.5f; offset += 1.5f;
} }
/**
* Called when the dialog is shown. Displays all input fields and buttons.
*/
@Override @Override
protected void onShow() { protected void onShow() {
ipInput.show(); ipInput.show();
@@ -54,6 +68,9 @@ protected void onShow() {
backButton.show(); backButton.show();
} }
/**
* Called when the dialog is hidden. Hides all input fields and buttons.
*/
@Override @Override
protected void onHide() { protected void onHide() {
ipInput.hide(); ipInput.hide();
@@ -62,37 +79,62 @@ protected void onHide() {
backButton.hide(); backButton.hide();
} }
/**
* Updates the state of the input fields. This method is called periodically to synchronize the dialog state.
*/
public void update() { public void update() {
ipInput.update(); ipInput.update();
portInput.update(); portInput.update();
} }
/**
* Retrieves the currently entered IP address, saves it to preferences, and sets it as the hostname.
*
* @return The IP address as a string.
*/
public String getIpt() { public String getIpt() {
prefs.put("joinIp", ipInput.getString()); prefs.put("joinIp", ipInput.getString());
setHostname(ipInput.getString()); setHostname(ipInput.getString());
return ipInput.getString(); return ipInput.getString();
} }
/**
* Resets the IP input field to its default value and updates preferences accordingly.
*/
public void resetIp() { public void resetIp() {
ipInput.reset(); ipInput.reset();
prefs.put("joinIp", ""); prefs.put("joinIp", "");
} }
/**
* Retrieves the currently entered port number, saves it to preferences, and sets it as the active port.
*
* @return The port number as a string.
*/
public String getPort() { public String getPort() {
prefs.put("joinPort", portInput.getString()); prefs.put("joinPort", portInput.getString());
setPortNumber(Integer.parseInt(portInput.getString())); setPortNumber(Integer.parseInt(portInput.getString()));
return portInput.getString(); return portInput.getString();
} }
/**
* Resets the port input field to its default value and updates preferences accordingly.
*/
public void resetPort() { public void resetPort() {
portInput.reset(); portInput.reset();
prefs.put("joinPort", "11111"); prefs.put("joinPort", "11111");
} }
/**
* Connects to the server using the current IP address and port number.
*/
public void connectToServer() { public void connectToServer() {
connectServer(); connectServer();
} }
/**
* Disconnects from the server if a network connection exists.
*/
public void disconnect() { public void disconnect() {
NetworkSupport network = getNetwork(); NetworkSupport network = getNetwork();
if (network != null) { if (network != null) {
@@ -104,4 +146,3 @@ public void disconnect() {
} }
} }
} }

View File

@@ -8,6 +8,11 @@
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
/**
* The {@code NetworkDialog} class serves as an abstract base class for dialogs
* that involve network-related functionalities, such as connecting to a server or hosting a game.
* It provides methods for initializing, connecting to, and managing a network server.
*/
public abstract class NetworkDialog extends Dialog { public abstract class NetworkDialog extends Dialog {
private NetworkSupport network; private NetworkSupport network;
@@ -17,19 +22,41 @@ public abstract class NetworkDialog extends Dialog {
private MdgaServer serverInstance; private MdgaServer serverInstance;
private Thread serverThread; private Thread serverThread;
/**
* Constructs a {@code NetworkDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param network The network support instance for managing network interactions.
*/
public NetworkDialog(MdgaApp app, Node node, NetworkSupport network) { public NetworkDialog(MdgaApp app, Node node, NetworkSupport network) {
super(app, node); super(app, node);
this.network = network; this.network = network;
} }
/**
* Sets the hostname for the network connection.
*
* @param hostname The hostname or IP address of the server.
*/
public void setHostname(String hostname) { public void setHostname(String hostname) {
this.hostname = hostname; this.hostname = hostname;
} }
/**
* Sets the port number for the network connection.
*
* @param portNumber The port number to use for the connection.
*/
public void setPortNumber(int portNumber) { public void setPortNumber(int portNumber) {
this.portNumber = portNumber; this.portNumber = portNumber;
} }
/**
* Initializes the network connection using the current hostname and port number.
*
* @return {@code null} if successful, otherwise throws an exception.
*/
protected Object initNetwork() { protected Object initNetwork() {
try { try {
this.network.initNetwork(this.hostname, this.portNumber); this.network.initNetwork(this.hostname, this.portNumber);
@@ -39,6 +66,9 @@ protected Object initNetwork() {
} }
} }
/**
* Starts the process of connecting to a server asynchronously.
*/
protected void connectServer() { protected void connectServer() {
try { try {
connectionFuture = this.network.getApp().getExecutor().submit(this::initNetwork); connectionFuture = this.network.getApp().getExecutor().submit(this::initNetwork);
@@ -47,6 +77,9 @@ protected void connectServer() {
} }
} }
/**
* Starts hosting a server in a separate thread.
*/
protected void startServer() { protected void startServer() {
serverThread = new Thread(() -> { serverThread = new Thread(() -> {
try { try {
@@ -60,6 +93,9 @@ protected void startServer() {
serverThread.start(); serverThread.start();
} }
/**
* Shuts down the hosted server and cleans up resources.
*/
public void shutdownServer() { public void shutdownServer() {
try { try {
@@ -85,6 +121,11 @@ public void shutdownServer() {
} }
} }
/**
* Updates the state of the connection process.
*
* @param delta The time elapsed since the last update call.
*/
public void update(float delta) { public void update(float delta) {
if (this.connectionFuture != null && this.connectionFuture.isDone()) { if (this.connectionFuture != null && this.connectionFuture.isDone()) {
try { try {
@@ -97,6 +138,11 @@ public void update(float delta) {
} }
} }
/**
* Retrieves the {@code NetworkSupport} instance associated with this dialog.
*
* @return The {@code NetworkSupport} instance.
*/
public NetworkSupport getNetwork() { public NetworkSupport getNetwork() {
return network; return network;
} }

View File

@@ -8,6 +8,10 @@
import pp.mdga.client.view.MainView; import pp.mdga.client.view.MainView;
import pp.mdga.client.view.MdgaView; import pp.mdga.client.view.MdgaView;
/**
* The {@code SettingsDialog} class represents a dialog for navigating to various settings sections,
* such as video and audio settings, or returning to the previous view.
*/
public class SettingsDialog extends Dialog { public class SettingsDialog extends Dialog {
private MenuButton videoButton; private MenuButton videoButton;
private MenuButton audioButton; private MenuButton audioButton;
@@ -15,6 +19,13 @@ public class SettingsDialog extends Dialog {
private final MdgaView view; private final MdgaView view;
/**
* Constructs a {@code SettingsDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The view managing navigation and interaction with the settings dialog.
*/
public SettingsDialog(MdgaApp app, Node node, MdgaView view) { public SettingsDialog(MdgaApp app, Node node, MdgaView view) {
super(app, node); super(app, node);
@@ -34,6 +45,9 @@ public SettingsDialog(MdgaApp app, Node node, MdgaView view) {
backButton.setPos(new Vector2f(0, 1.8f)); backButton.setPos(new Vector2f(0, 1.8f));
} }
/**
* Called when the dialog is shown. Displays all buttons for video settings, audio settings, and back navigation.
*/
@Override @Override
protected void onShow() { protected void onShow() {
videoButton.show(); videoButton.show();
@@ -41,6 +55,9 @@ protected void onShow() {
backButton.show(); backButton.show();
} }
/**
* Called when the dialog is hidden. Hides all buttons for video settings, audio settings, and back navigation.
*/
@Override @Override
protected void onHide() { protected void onHide() {
videoButton.hide(); videoButton.hide();

View File

@@ -14,6 +14,10 @@
import java.util.Random; import java.util.Random;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
/**
* The {@code StartDialog} class represents the initial dialog in the application,
* allowing the user to input their name, host or join a game, or exit the application.
*/
public class StartDialog extends Dialog { public class StartDialog extends Dialog {
private InputButton nameInput; private InputButton nameInput;
@@ -23,6 +27,13 @@ public class StartDialog extends Dialog {
private final MainView view; private final MainView view;
/**
* Constructs a {@code StartDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The main view used for navigation and interaction with the dialog.
*/
public StartDialog(MdgaApp app, Node node, MainView view) { public StartDialog(MdgaApp app, Node node, MainView view) {
super(app, node); super(app, node);
@@ -48,6 +59,9 @@ public StartDialog(MdgaApp app, Node node, MainView view) {
endButton.setPos(new Vector2f(0, 1.8f)); endButton.setPos(new Vector2f(0, 1.8f));
} }
/**
* Called when the dialog is shown. Displays the name input field and all buttons.
*/
@Override @Override
protected void onShow() { protected void onShow() {
nameInput.show(); nameInput.show();
@@ -57,6 +71,9 @@ protected void onShow() {
endButton.show(); endButton.show();
} }
/**
* Called when the dialog is hidden. Hides the name input field and all buttons.
*/
@Override @Override
protected void onHide () protected void onHide ()
{ {
@@ -67,10 +84,18 @@ protected void onHide ()
endButton.hide(); endButton.hide();
} }
/**
* Updates the state of the name input field. This method is called periodically to synchronize the dialog state.
*/
public void update() { public void update() {
nameInput.update(); nameInput.update();
} }
/**
* Retrieves the name entered by the user. If no name is provided, a random name is generated.
*
* @return The user's name or a randomly generated name.
*/
public String getName() { public String getName() {
String name = nameInput.getString(); String name = nameInput.getString();

View File

@@ -11,6 +11,11 @@
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
/**
* The {@code VideoSettingsDialog} class represents a dialog for configuring video settings,
* such as resolution and fullscreen mode. It also provides an option to restart the application
* when certain settings are changed.
*/
public class VideoSettingsDialog extends Dialog { public class VideoSettingsDialog extends Dialog {
private static Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class); private static Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
@@ -29,6 +34,13 @@ public class VideoSettingsDialog extends Dialog {
private boolean active = false; private boolean active = false;
/**
* Constructs a {@code VideoSettingsDialog}.
*
* @param app The main application managing the dialog.
* @param node The root node for attaching UI elements.
* @param view The view managing navigation and interaction with the video settings dialog.
*/
public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) { public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) {
super(app, node); super(app, node);
@@ -67,6 +79,9 @@ public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) {
backButton.setPos(new Vector2f(0, 1.8f)); backButton.setPos(new Vector2f(0, 1.8f));
} }
/**
* Called when the dialog is shown. Displays all buttons and marks the dialog as active.
*/
@Override @Override
protected void onShow() { protected void onShow() {
active = true; active = true;
@@ -83,6 +98,9 @@ protected void onShow() {
backButton.show(); backButton.show();
} }
/**
* Called when the dialog is hidden. Hides all buttons and marks the dialog as inactive.
*/
@Override @Override
protected void onHide() { protected void onHide() {
active = false; active = false;
@@ -100,12 +118,23 @@ protected void onHide() {
restartButton.hide(); restartButton.hide();
} }
/**
* Updates the dialog's state. This method can be used for periodic updates while the dialog is active.
*/
public void update() { public void update() {
if(!active) { if(!active) {
return; return;
} }
} }
/**
* Updates the resolution settings and optionally triggers the restart button if changes are detected.
*
* @param width The width of the resolution.
* @param height The height of the resolution.
* @param imageFactor The scaling factor for the resolution.
* @param isFullscreen {@code true} if fullscreen mode is enabled, {@code false} otherwise.
*/
public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) { public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) {
if(width != prefs.getInt("width", 1280) || height != prefs.getInt("height", 720) || isFullscreen != prefs.getBoolean("fullscreen", false)) { if(width != prefs.getInt("width", 1280) || height != prefs.getInt("height", 720) || isFullscreen != prefs.getBoolean("fullscreen", false)) {
restartButton.show(); restartButton.show();

View File

@@ -10,12 +10,25 @@
import pp.mdga.client.animation.ZoomControl; import pp.mdga.client.animation.ZoomControl;
import pp.mdga.game.Color; import pp.mdga.game.Color;
/**
* The {@code ActionTextHandler} class manages the display of animated and stylized text messages in the game's UI.
* It supports dynamic text creation with spacing, color, and effects, such as dice rolls, player actions, and rankings.
*/
class ActionTextHandler { class ActionTextHandler {
private Node root; private Node root;
private BitmapFont font; private BitmapFont font;
private AppSettings appSettings; private AppSettings appSettings;
private int ranking; private int ranking;
float paddingRanked = 100;
/**
* Constructs an {@code ActionTextHandler}.
*
* @param guiNode The GUI node where the text messages will be displayed.
* @param assetManager The asset manager used to load fonts and other assets.
* @param appSettings The application settings for positioning and sizing.
*/
ActionTextHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){ ActionTextHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){
root = new Node("actionTextRoot"); root = new Node("actionTextRoot");
guiNode.attachChild(root); guiNode.attachChild(root);
@@ -26,6 +39,16 @@ class ActionTextHandler {
ranking = 0; ranking = 0;
} }
/**
* Creates a {@code Node} containing text with specified spacing, size, and colors for each segment of the text.
*
* @param textArr An array of strings representing the text to be displayed.
* @param spacing The spacing between individual characters.
* @param size The size of the text.
* @param colorArr An array of {@code ColorRGBA} representing the color for each string in {@code textArr}.
* @return A {@code Node} containing the styled text with spacing and color applied.
* @throws RuntimeException if the lengths of {@code textArr} and {@code colorArr} do not match.
*/
private Node createTextWithSpacing(String[] textArr, float spacing, float size, ColorRGBA[] colorArr) { private Node createTextWithSpacing(String[] textArr, float spacing, float size, ColorRGBA[] colorArr) {
if(textArr.length != colorArr.length) throw new RuntimeException("text and color are not the same length"); if(textArr.length != colorArr.length) throw new RuntimeException("text and color are not the same length");
@@ -52,18 +75,55 @@ private Node createTextWithSpacing(String[] textArr, float spacing, float size,
return textNode; return textNode;
} }
/**
* Creates a {@code Node} containing text with specified spacing, size, and a single color.
*
* @param text The text to be displayed.
* @param spacing The spacing between individual characters.
* @param size The size of the text.
* @param color The color of the text.
* @return A {@code Node} containing the styled text.
*/
private Node createTextWithSpacing(String text, float spacing, float size, ColorRGBA color) { private Node createTextWithSpacing(String text, float spacing, float size, ColorRGBA color) {
return createTextWithSpacing(new String[]{text}, spacing, size, new ColorRGBA[]{color}); return createTextWithSpacing(new String[]{text}, spacing, size, new ColorRGBA[]{color});
} }
/**
* Calculates the center position of a rectangle given its width, height, and an origin position.
*
* @param width The width of the rectangle.
* @param height The height of the rectangle.
* @param pos The origin position of the rectangle.
* @return A {@code Vector3f} representing the center position.
*/
private Vector3f center(float width, float height, Vector3f pos){ private Vector3f center(float width, float height, Vector3f pos){
return new Vector3f(pos.x+width/2, pos.y+height/2,0); return new Vector3f(pos.x+width/2, pos.y+height/2,0);
} }
/**
* Creates and positions a single-line text at the top of the screen with a specified vertical offset.
*
* @param name The text to be displayed.
* @param spacing The spacing between individual characters.
* @param size The size of the text.
* @param color The color of the text.
* @param top The vertical offset from the top of the screen.
* @return A {@code Node} containing the styled text positioned at the top.
*/
private Node createTopText(String name, float spacing, float size, ColorRGBA color, float top){ private Node createTopText(String name, float spacing, float size, ColorRGBA color, float top){
return createTopText(new String[]{name}, spacing, size, new ColorRGBA[]{color}, top); return createTopText(new String[]{name}, spacing, size, new ColorRGBA[]{color}, top);
} }
/**
* Creates and positions multi-line text at the top of the screen with specified vertical offset, spacing, and colors.
*
* @param name An array of strings representing the text to be displayed.
* @param spacing The spacing between individual characters.
* @param size The size of the text.
* @param color An array of {@code ColorRGBA} representing the color for each string in {@code name}.
* @param top The vertical offset from the top of the screen.
* @return A {@code Node} containing the styled text positioned at the top.
*/
private Node createTopText(String[] name, float spacing, float size, ColorRGBA color[], float top){ private Node createTopText(String[] name, float spacing, float size, ColorRGBA color[], float top){
Node text = createTextWithSpacing(name, spacing, size, color); Node text = createTextWithSpacing(name, spacing, size, color);
text.setLocalTranslation(0, (appSettings.getHeight()/2f)*0.8f-top,0); text.setLocalTranslation(0, (appSettings.getHeight()/2f)*0.8f-top,0);
@@ -71,18 +131,44 @@ private Node createTopText(String[] name, float spacing, float size, ColorRGBA c
return text; return text;
} }
/**
* Calculates the center position of a rectangle with negative width offset.
*
* @param width The negative width of the rectangle.
* @param height The height of the rectangle.
* @param pos The origin position of the rectangle.
* @return A {@code Vector3f} representing the center position.
*/
private Vector3f centerText(float width, float height, Vector3f pos){ private Vector3f centerText(float width, float height, Vector3f pos){
return center(-width, height, pos); return center(-width, height, pos);
} }
/**
* Displays a message indicating the active player.
*
* @param name The name of the active player.
* @param color The color representing the player's team.
*/
void activePlayer(String name, Color color){ void activePlayer(String name, Color color){
createTopText(new String[]{name," ist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{name," ist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Displays a message indicating that the current player is active.
*
* @param color The color representing the player's team.
*/
void ownActive(Color color){ void ownActive(Color color){
createTopText(new String[]{"Du"," bist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{"Du"," bist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Displays a dice roll result for a player.
*
* @param diceNum The number rolled on the dice.
* @param name The name of the player.
* @param color The color representing the player's team.
*/
void diceNum(int diceNum, String name, Color color){ void diceNum(int diceNum, String name, Color color){
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0); createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
@@ -90,38 +176,84 @@ void diceNum(int diceNum, String name, Color color){
} }
/**
* Displays a dice roll result with a multiplier for a player.
*
* @param diceNum The number rolled on the dice.
* @param mult The multiplier applied to the dice result.
* @param name The name of the player.
* @param color The color representing the player's team.
*/
void diceNumMult(int diceNum,int mult, String name, Color color){ void diceNumMult(int diceNum,int mult, String name, Color color){
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0); createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 100); createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 100);
} }
/**
* Displays the dice roll result for the current player.
*
* @param diceNum The number rolled on the dice.
*/
void ownDice(int diceNum){ void ownDice(int diceNum){
createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 0); createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 0);
} }
/**
* Displays the dice roll result with a multiplier for the current player.
*
* @param diceNum The number rolled on the dice.
* @param mult The multiplier applied to the dice result.
*/
void ownDiceMult(int diceNum, int mult){ void ownDiceMult(int diceNum, int mult){
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 0); createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 0);
} }
/**
* Displays a message indicating that a specified player received a bonus card.
*
* @param name The name of the player who received the bonus card.
* @param color The color representing the player's team.
*/
void drawCard(String name, Color color){ void drawCard(String name, Color color){
createTopText(new String[]{name," erhält eine Bonuskarte"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{name," erhält eine Bonuskarte"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Displays a message indicating that the current player received a bonus card.
*
* @param color The color representing the player's team.
*/
void drawCardOwn(Color color){ void drawCardOwn(Color color){
createTopText(new String[]{"Du"," erhälst eine Bonuskarte"}, 5,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{"Du"," erhälst eine Bonuskarte"}, 5,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Displays a message indicating that a specified player has completed their turn or action.
*
* @param name The name of the player who finished.
* @param color The color representing the player's team.
*/
void finishText(String name, Color color){ void finishText(String name, Color color){
createTopText(new String[]{name," ist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{name," ist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Displays a message indicating that the current player has completed their turn or action.
*
* @param color The color representing the player's team.
*/
void finishTextOwn(Color color){ void finishTextOwn(Color color){
createTopText(new String[]{"Du", " bist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl()); createTopText(new String[]{"Du", " bist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
} }
/**
* Converts a player's team color to a corresponding {@code ColorRGBA}.
*
* @param color The player's team color.
* @return The corresponding {@code ColorRGBA}.
* @throws RuntimeException if the color is invalid.
*/
private ColorRGBA playerColorToColorRGBA(Color color){ private ColorRGBA playerColorToColorRGBA(Color color){
return switch (color){ return switch (color){
case ARMY -> ColorRGBA.Green; case ARMY -> ColorRGBA.Green;
@@ -132,25 +264,41 @@ private ColorRGBA playerColorToColorRGBA(Color color){
}; };
} }
/**
* Hides all text messages displayed by the handler and resets the ranking counter.
*/
void hide(){ void hide(){
ranking = 0; ranking = 0;
root.detachAllChildren(); root.detachAllChildren();
} }
float paddingRanked = 100; /**
* Displays a ranked dice roll result for a specified player.
*
* @param name The name of the player.
* @param color The color representing the player's team.
* @param eye The dice roll result.
*/
void rollRankingResult(String name, Color color, int eye){ void rollRankingResult(String name, Color color, int eye){
createTopText(new String[]{name,": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking); createTopText(new String[]{name,": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking);
ranking++; ranking++;
} }
/**
* Displays a ranked dice roll result for the current player.
*
* @param color The color representing the player's team.
* @param eye The dice roll result.
*/
void rollRankingResultOwn(Color color, int eye){ void rollRankingResultOwn(Color color, int eye){
createTopText(new String[]{"Du",": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking); createTopText(new String[]{"Du",": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking);
ranking++; ranking++;
} }
/**
* Displays a message prompting the player to roll the dice.
*/
void diceNow(){ void diceNow(){
createTopText("Klicke zum Würfeln", 5, 80, ColorRGBA.White, 0); createTopText("Klicke zum Würfeln", 5, 80, ColorRGBA.White, 0);
} }
} }