mirror of
https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
synced 2025-08-03 13:07:43 +02:00
Merge remote-tracking branch 'origin/gui' into gui
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
////////////////////////////////////////
|
||||
// Programming project code
|
||||
// UniBw M, 2022, 2023, 2024
|
||||
// www.unibw.de/inf2
|
||||
// (c) Mark Minas (mark.minas@unibw.de)
|
||||
////////////////////////////////////////
|
||||
|
||||
package pp.monopoly.client;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
@@ -7,6 +14,8 @@ import java.util.prefs.Preferences;
|
||||
import com.jme3.app.Application;
|
||||
import com.jme3.app.state.AbstractAppState;
|
||||
import com.jme3.app.state.AppStateManager;
|
||||
import com.jme3.asset.AssetLoadException;
|
||||
import com.jme3.asset.AssetNotFoundException;
|
||||
import com.jme3.audio.AudioData;
|
||||
import com.jme3.audio.AudioNode;
|
||||
|
||||
@@ -15,14 +24,16 @@ import pp.monopoly.notification.SoundEvent;
|
||||
import static pp.util.PreferencesUtils.getPreferences;
|
||||
|
||||
/**
|
||||
* An application state that plays sounds based on game events.
|
||||
* An application state that plays sounds.
|
||||
*/
|
||||
public class GameSound extends AbstractAppState implements GameEventListener {
|
||||
private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
|
||||
private static final Preferences PREFERENCES = getPreferences(GameSound.class);
|
||||
private static final String ENABLED_PREF = "enabled";
|
||||
private static final String ENABLED_PREF = "enabled"; //NON-NLS
|
||||
|
||||
private Application app; // Feld zum Speichern der Application-Instanz
|
||||
private AudioNode splashSound;
|
||||
private AudioNode shipDestroyedSound;
|
||||
private AudioNode explosionSound;
|
||||
|
||||
/**
|
||||
* Checks if sound is enabled in the preferences.
|
||||
@@ -42,6 +53,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
|
||||
|
||||
/**
|
||||
* Sets the enabled state of this AppState.
|
||||
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
|
||||
*
|
||||
* @param enabled {@code true} to enable the AppState, {@code false} to disable it.
|
||||
*/
|
||||
@@ -49,52 +61,69 @@ public class GameSound extends AbstractAppState implements GameEventListener {
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (isEnabled() == enabled) return;
|
||||
super.setEnabled(enabled);
|
||||
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled);
|
||||
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
|
||||
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the sound effects for the game and stores the application reference.
|
||||
* Initializes the sound effects for the game.
|
||||
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
|
||||
*
|
||||
* @param stateManager The state manager
|
||||
* @param app The application instance
|
||||
* @param app The application
|
||||
*/
|
||||
@Override
|
||||
public void initialize(AppStateManager stateManager, Application app) {
|
||||
super.initialize(stateManager, app);
|
||||
this.app = app; // Speichert die Application-Instanz
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a sound from the specified file.
|
||||
*
|
||||
* @param app The application
|
||||
* @param name The name of the sound file.
|
||||
* @return The loaded AudioNode.
|
||||
*/
|
||||
private AudioNode loadSound(String name) {
|
||||
private AudioNode loadSound(Application app, String name) {
|
||||
try {
|
||||
AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
||||
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
||||
sound.setLooping(false);
|
||||
sound.setPositional(false);
|
||||
return sound;
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (AssetLoadException | AssetNotFoundException ex) {
|
||||
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sound-related game events to play specific sounds.
|
||||
*
|
||||
* @param event The sound event received.
|
||||
* Plays the splash sound effect.
|
||||
*/
|
||||
public void splash() {
|
||||
if (isEnabled() && splashSound != null)
|
||||
splashSound.playInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the explosion sound effect.
|
||||
*/
|
||||
public void explosion() {
|
||||
if (isEnabled() && explosionSound != null)
|
||||
explosionSound.playInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays sound effect when a ship has been destroyed.
|
||||
*/
|
||||
public void shipDestroyed() {
|
||||
if (isEnabled() && shipDestroyedSound != null)
|
||||
shipDestroyedSound.playInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receivedEvent(SoundEvent event) {
|
||||
if (isEnabled()) {
|
||||
AudioNode sound = loadSound(event.getSoundFileName());
|
||||
if (sound != null) {
|
||||
sound.play();
|
||||
}
|
||||
switch (event.sound()) {
|
||||
}
|
||||
}
|
||||
}//heloo
|
||||
}
|
||||
|
@@ -9,12 +9,7 @@ import com.jme3.font.BitmapText;
|
||||
import com.jme3.input.KeyInput;
|
||||
import com.jme3.input.controls.ActionListener;
|
||||
import com.jme3.input.controls.KeyTrigger;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.system.AppSettings;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.simsilica.lemur.GuiGlobals;
|
||||
import com.simsilica.lemur.style.BaseStyles;
|
||||
|
||||
@@ -22,6 +17,7 @@ import pp.dialog.DialogBuilder;
|
||||
import pp.dialog.DialogManager;
|
||||
import pp.graphics.Draw;
|
||||
import pp.monopoly.client.gui.SettingsMenu;
|
||||
import pp.monopoly.client.gui.TestWorld;
|
||||
import pp.monopoly.game.client.ClientGameLogic;
|
||||
import pp.monopoly.game.client.MonopolyClient;
|
||||
import pp.monopoly.game.client.ServerConnection;
|
||||
@@ -36,10 +32,20 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
|
||||
private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed);
|
||||
private final DialogManager dialogManager = new DialogManager(this);
|
||||
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
private SettingsMenu settingsMenu;
|
||||
private final Draw draw;
|
||||
|
||||
private SettingsMenu settingsMenu;
|
||||
private TestWorld testWorld;
|
||||
private boolean isSettingsMenuOpen = false;
|
||||
private boolean inputBlocked = false;
|
||||
/**
|
||||
* Path to the styles script for GUI elements.
|
||||
*/
|
||||
private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS
|
||||
/**
|
||||
* Path to the font resource used in the GUI.
|
||||
*/
|
||||
private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
new MonopolyApp().start();
|
||||
@@ -73,24 +79,17 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
|
||||
return settings;
|
||||
}
|
||||
|
||||
public boolean isSettingsMenuOpen() {
|
||||
return isSettingsMenuOpen;
|
||||
}
|
||||
|
||||
public void setSettingsMenuOpen(boolean isOpen) {
|
||||
this.isSettingsMenuOpen = isOpen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
GuiGlobals.initialize(this);
|
||||
BaseStyles.loadGlassStyle();
|
||||
GuiGlobals.getInstance().getStyles().setDefaultStyle("glass");
|
||||
GuiGlobals.initialize(this);
|
||||
BaseStyles.loadStyleResources(STYLES_SCRIPT);
|
||||
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
|
||||
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
|
||||
|
||||
setupInput();
|
||||
setupGui();
|
||||
|
||||
// Initialisiere das Startmenü
|
||||
// Zeige das Startmenü
|
||||
StartMenu.createStartMenu(this);
|
||||
}
|
||||
|
||||
@@ -107,23 +106,45 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
|
||||
inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
|
||||
inputManager.addListener(escapeListener, "ESC");
|
||||
}
|
||||
|
||||
|
||||
private void handleEscape(boolean isPressed) {
|
||||
if (isPressed) {
|
||||
if (isSettingsMenuOpen && settingsMenu != null) {
|
||||
if (settingsMenu != null && isSettingsMenuOpen) {
|
||||
// Schließe das SettingsMenu
|
||||
System.out.println("Schließe SettingsMenu...");
|
||||
settingsMenu.close();
|
||||
settingsMenu = null;
|
||||
setSettingsMenuOpen(false);
|
||||
} else {
|
||||
// Öffne das SettingsMenu
|
||||
System.out.println("Öffne SettingsMenu...");
|
||||
settingsMenu = new SettingsMenu(this);
|
||||
settingsMenu.open();
|
||||
setSettingsMenuOpen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void blockInputs() {
|
||||
if (!inputBlocked) {
|
||||
System.out.println("Blockiere Eingaben...");
|
||||
inputManager.setCursorVisible(true); // Cursor sichtbar machen
|
||||
inputManager.clearMappings(); // Alle Mappings entfernen
|
||||
inputBlocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void unblockInputs() {
|
||||
if (inputBlocked) {
|
||||
System.out.println("Aktiviere Eingaben...");
|
||||
setupInput(); // Standard-Eingaben neu registrieren
|
||||
inputBlocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
void setInfoText(String text) {
|
||||
public void setInfoText(String text) {
|
||||
topText.setText(text);
|
||||
}
|
||||
|
||||
@@ -163,35 +184,26 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
|
||||
.build()
|
||||
.open();
|
||||
}
|
||||
//altes Fenster beim Start von TestWorld schließen
|
||||
public void startTestWorld() {
|
||||
// Entferne die aktuelle GUI
|
||||
guiNode.detachAllChildren();
|
||||
|
||||
// Erstelle ein Quadrat mit Textur
|
||||
Box box = new Box(1, 0.01f, 1); // Dünnes Quadrat
|
||||
Geometry geom = new Geometry("Box", box);
|
||||
|
||||
// Setze das Material mit Textur
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
Texture texture = assetManager.loadTexture("Pictures/board.png");
|
||||
mat.setTexture("ColorMap", texture);
|
||||
geom.setMaterial(mat);
|
||||
|
||||
// Füge das Quadrat zur Szene hinzu
|
||||
rootNode.attachChild(geom);
|
||||
|
||||
// Setze die Kameraposition
|
||||
cam.setLocation(new Vector3f(0, 0, 3));
|
||||
cam.lookAt(geom.getLocalTranslation(), Vector3f.UNIT_Y);
|
||||
}
|
||||
public void returnToMenu() {
|
||||
// Entferne die Testszene
|
||||
rootNode.detachAllChildren();
|
||||
|
||||
// Zeige das Startmenü erneut
|
||||
StartMenu.createStartMenu(this);
|
||||
}
|
||||
|
||||
|
||||
public void setSettingsMenuOpen(boolean isOpen) {
|
||||
this.isSettingsMenuOpen = isOpen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(float tpf) {
|
||||
if (testWorld != null) {
|
||||
testWorld.update(tpf); // Aktualisiere die Kamera in der TestWorld
|
||||
}
|
||||
}
|
||||
|
||||
public void startTestWorld() {
|
||||
guiNode.detachAllChildren(); // Entferne GUI
|
||||
testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld
|
||||
testWorld.initializeScene(); // Initialisiere die Szene
|
||||
}
|
||||
|
||||
public void returnToMenu() {
|
||||
guiNode.detachAllChildren(); // Entferne die GUI
|
||||
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,3 @@
|
||||
////////////////////////////////////////
|
||||
// Programming project code
|
||||
// UniBw M, 2022, 2023, 2024
|
||||
// www.unibw.de/inf2
|
||||
// (c) Mark Minas (mark.minas@unibw.de)
|
||||
////////////////////////////////////////
|
||||
|
||||
package pp.monopoly.client;
|
||||
|
||||
import com.jme3.math.ColorRGBA;
|
||||
@@ -194,4 +187,4 @@ public class MonopolyAppConfig extends MonopolyClientConfig {
|
||||
public ColorRGBA getTopColor() {
|
||||
return topColor;
|
||||
}
|
||||
}
|
||||
}
|
@@ -81,4 +81,4 @@ public abstract class MonopolyAppState extends AbstractAppState {
|
||||
* Called when the state is disabled. Override to define specific behavior.
|
||||
*/
|
||||
protected abstract void disableState();
|
||||
}
|
||||
}
|
@@ -142,4 +142,5 @@ class NetworkDialog extends SimpleDialog {
|
||||
network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen.");
|
||||
network.getApp().setInfoText(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -141,4 +141,4 @@ class NetworkSupport implements MessageListener<Client>, ClientStateListener, Se
|
||||
client.send(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ import com.simsilica.lemur.Axis;
|
||||
import com.simsilica.lemur.Button;
|
||||
import com.simsilica.lemur.Container;
|
||||
import com.simsilica.lemur.HAlignment;
|
||||
import com.simsilica.lemur.Label;
|
||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
|
||||
import com.simsilica.lemur.component.SpringGridLayout;
|
||||
|
||||
@@ -20,9 +19,12 @@ import pp.monopoly.client.gui.SettingsMenu;
|
||||
|
||||
/**
|
||||
* Constructs the startup menu dialog for the Monopoly application.
|
||||
import pp.monopoly.client.gui.GameMenu;
|
||||
*/
|
||||
public class StartMenu extends Dialog {
|
||||
private final MonopolyApp app;
|
||||
private Container logoContainer;
|
||||
private Container unibwLogoContainer;
|
||||
|
||||
/**
|
||||
* Constructs the Startup Menu dialog for the Monopoly application.
|
||||
@@ -52,6 +54,9 @@ public class StartMenu extends Dialog {
|
||||
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
|
||||
app.getGuiNode().attachChild(background);
|
||||
|
||||
createMonopolyLogo(app);
|
||||
createUnibwLogo(app);
|
||||
|
||||
// Center container for title and play button
|
||||
Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X));
|
||||
|
||||
@@ -60,14 +65,6 @@ public class StartMenu extends Dialog {
|
||||
startButton.setFontSize(40); // Set the font size for the button text
|
||||
startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
|
||||
|
||||
// Set a custom border and background color
|
||||
ColorRGBA borderColor = ColorRGBA.Orange; // Example: White border
|
||||
ColorRGBA backgroundColor = ColorRGBA.LightGray; // Example: light gray background
|
||||
QuadBackgroundComponent backgroundColorSp = new QuadBackgroundComponent(backgroundColor);
|
||||
backgroundColorSp.setMargin(2, 2); // Optional: Adjust margin for the border
|
||||
backgroundColorSp.setColor(borderColor); // Set border color
|
||||
startButton.setBackground(backgroundColorSp);
|
||||
|
||||
startButton.addClickCommands(source -> startGame(app));
|
||||
centerMenu.addChild(startButton);
|
||||
|
||||
@@ -82,7 +79,7 @@ public class StartMenu extends Dialog {
|
||||
lowerLeftMenu.setLocalTranslation(new Vector3f(100, 90, 0));
|
||||
Button quitButton = new Button("Spiel beenden");
|
||||
quitButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
|
||||
quitButton.setFontSize(20);
|
||||
quitButton.setFontSize(18);
|
||||
quitButton.addClickCommands(source -> quitGame());
|
||||
lowerLeftMenu.addChild(quitButton);
|
||||
app.getGuiNode().attachChild(lowerLeftMenu);
|
||||
@@ -92,12 +89,74 @@ public class StartMenu extends Dialog {
|
||||
lowerRightMenu.setLocalTranslation(new Vector3f(screenWidth - 200, 90, 0));
|
||||
Button settingsButton = new Button("Einstellungen");
|
||||
settingsButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
|
||||
settingsButton.setFontSize(20); // Increase the font size for the text
|
||||
settingsButton.setFontSize(18); // Increase the font size for the text
|
||||
settingsButton.addClickCommands(source -> openSettings(app));
|
||||
lowerRightMenu.addChild(settingsButton);
|
||||
app.getGuiNode().attachChild(lowerRightMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and positions the Monopoly logo container in the center of the screen.
|
||||
*/
|
||||
private static void createMonopolyLogo(MonopolyApp app) {
|
||||
int screenWidth = app.getContext().getSettings().getWidth();
|
||||
int screenHeight = app.getContext().getSettings().getHeight();
|
||||
|
||||
// Load the Monopoly logo as a texture
|
||||
Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png");
|
||||
|
||||
// Create a container for the logo
|
||||
Container logoContainer = new Container();
|
||||
QuadBackgroundComponent logoBackground = new QuadBackgroundComponent(logoTexture);
|
||||
logoContainer.setBackground(logoBackground);
|
||||
|
||||
// Set the size of the container to fit the logo
|
||||
float logoWidth = 512; // Adjust these values based on the logo dimensions
|
||||
float logoHeight = 128; // Adjust these values based on the logo dimensions
|
||||
logoContainer.setPreferredSize(new Vector3f(logoWidth, logoHeight, 0));
|
||||
|
||||
// Position the container at the center of the screen
|
||||
logoContainer.setLocalTranslation(new Vector3f(
|
||||
screenWidth / 2f - logoWidth / 2f,
|
||||
screenHeight / 2f + 200, // Adjust this value for vertical position
|
||||
0
|
||||
));
|
||||
|
||||
// Attach the container to the GUI node
|
||||
app.getGuiNode().attachChild(logoContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and positions the Unibw logo container in the center of the screen.
|
||||
*/
|
||||
private static void createUnibwLogo(MonopolyApp app) {
|
||||
int screenWidth = app.getContext().getSettings().getWidth();
|
||||
int screenHeight = app.getContext().getSettings().getHeight();
|
||||
|
||||
// Load the Unibw logo as a texture
|
||||
Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png");
|
||||
|
||||
// Create a container for the Unibw logo
|
||||
Container unibwContainer = new Container();
|
||||
QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
|
||||
unibwContainer.setBackground(unibwBackground);
|
||||
|
||||
// Set the size of the container to fit the Unibw logo
|
||||
float unibwWidth = 512; // Adjust these values based on the logo dimensions
|
||||
float unibwHeight = 128; // Adjust these values based on the logo dimensions
|
||||
unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
|
||||
|
||||
// Position the container slightly below the Monopoly logo
|
||||
unibwContainer.setLocalTranslation(new Vector3f(
|
||||
screenWidth / 2f - unibwWidth / 2f,
|
||||
screenHeight / 2f + 100, // Adjust this value for vertical position
|
||||
0
|
||||
));
|
||||
|
||||
// Attach the container to the GUI node
|
||||
app.getGuiNode().attachChild(unibwContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the game by transitioning to the CreateGameMenu.
|
||||
*/
|
||||
@@ -120,4 +179,4 @@ public class StartMenu extends Dialog {
|
||||
private static void quitGame() {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,7 +17,7 @@ import pp.view.ModelViewSynchronizer;
|
||||
* are accurately reflected in the view.
|
||||
*/
|
||||
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
|
||||
private final Board board;
|
||||
protected final Board board;
|
||||
|
||||
/**
|
||||
* Constructs a new BoardSynchronizer.
|
||||
|
@@ -0,0 +1,59 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Camera;
|
||||
|
||||
/**
|
||||
* Steuert die Kamerabewegung in der Szene.
|
||||
*/
|
||||
public class CameraController {
|
||||
private final Camera camera;
|
||||
private final Vector3f center; // Fokuspunkt der Kamera
|
||||
private final float radius; // Radius der Kreisbewegung
|
||||
private final float height; // Höhe der Kamera über dem Spielfeld
|
||||
private final float speed; // Geschwindigkeit der Kamerabewegung
|
||||
private float angle; // Aktueller Winkel in der Kreisbewegung
|
||||
|
||||
/**
|
||||
* Konstruktor für den CameraController.
|
||||
*
|
||||
* @param camera Die Kamera, die gesteuert werden soll
|
||||
* @param center Der Mittelpunkt der Kreisbewegung (Fokuspunkt)
|
||||
* @param radius Der Radius der Kreisbewegung
|
||||
* @param height Die Höhe der Kamera über dem Fokuspunkt
|
||||
* @param speed Die Geschwindigkeit der Kamerabewegung
|
||||
*/
|
||||
public CameraController(Camera camera, Vector3f center, float radius, float height, float speed) {
|
||||
this.camera = camera;
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
this.height = height;
|
||||
this.speed = speed;
|
||||
this.angle = 0; // Starte bei Winkel 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die Kameraposition und -ausrichtung.
|
||||
*
|
||||
* @param tpf Zeit pro Frame
|
||||
*/
|
||||
public void update(float tpf) {
|
||||
// Aktualisiere den Winkel basierend auf der Geschwindigkeit
|
||||
angle += speed * tpf;
|
||||
if (angle >= FastMath.TWO_PI) {
|
||||
angle -= FastMath.TWO_PI; // Winkel zurücksetzen, um Überläufe zu vermeiden
|
||||
}
|
||||
|
||||
// Berechne die neue Position der Kamera
|
||||
float x = center.x + radius * FastMath.cos(angle);
|
||||
float z = center.z + radius * FastMath.sin(angle);
|
||||
float y = center.y + height;
|
||||
|
||||
// Setze die Kameraposition
|
||||
camera.setLocation(new Vector3f(x, y, z));
|
||||
|
||||
// Lasse die Kamera auf den Fokuspunkt blicken
|
||||
camera.lookAt(center, Vector3f.UNIT_Y);
|
||||
}
|
||||
}
|
@@ -23,6 +23,11 @@ public class CreateGameMenu {
|
||||
private final Container menuContainer;
|
||||
private Geometry background;
|
||||
|
||||
/**
|
||||
* Konstruktor für das CreateGameMenu.
|
||||
*
|
||||
* @param app Die Hauptanwendung (MonopolyApp)
|
||||
*/
|
||||
public CreateGameMenu(MonopolyApp app) {
|
||||
this.app = app;
|
||||
|
||||
@@ -43,12 +48,12 @@ public class CreateGameMenu {
|
||||
inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
|
||||
|
||||
inputContainer.addChild(new Label("Server-Adresse:"));
|
||||
TextField playerNameField = inputContainer.addChild(new TextField("localhost"));
|
||||
playerNameField.setPreferredWidth(400); // Breite des Textfelds
|
||||
TextField serverAddressField = inputContainer.addChild(new TextField("localhost"));
|
||||
serverAddressField.setPreferredWidth(400); // Breite des Textfelds
|
||||
|
||||
inputContainer.addChild(new Label("Port:"));
|
||||
TextField serverAddressField = inputContainer.addChild(new TextField("42069"));
|
||||
serverAddressField.setPreferredWidth(400); // Breite des Textfelds
|
||||
TextField portField = inputContainer.addChild(new TextField("42069"));
|
||||
portField.setPreferredWidth(400); // Breite des Textfelds
|
||||
|
||||
// Button-Container
|
||||
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
|
||||
@@ -64,15 +69,14 @@ public class CreateGameMenu {
|
||||
Button hostButton = buttonContainer.addChild(new Button("Spiel hosten"));
|
||||
hostButton.setPreferredSize(new Vector3f(120, 40, 0));
|
||||
hostButton.addClickCommands(source -> {
|
||||
closeCreateGameMenu(); // Schließt das Menü
|
||||
app.startTestWorld(); // Startet die Testwelt in der Hauptanwendung
|
||||
});
|
||||
|
||||
closeCreateGameMenu(); // Schließt das Menü
|
||||
app.startTestWorld(); // Starte die TestWorld im selben Fenster
|
||||
});
|
||||
|
||||
// "Beitreten"-Button
|
||||
Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
|
||||
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
|
||||
// joinButton.addClickCommands(source -> joinGame()); // Placeholder for joining logic
|
||||
// Placeholder für die Beitrittslogik
|
||||
|
||||
// Zentrierung des Containers
|
||||
menuContainer.setLocalTranslation(
|
||||
@@ -103,27 +107,15 @@ public class CreateGameMenu {
|
||||
* Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
|
||||
*/
|
||||
private void goBackToStartMenu() {
|
||||
app.getGuiNode().detachChild(menuContainer);
|
||||
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
|
||||
StartMenu.createStartMenu(app);
|
||||
}
|
||||
/*
|
||||
* Link zwischen createGame und TestWorld
|
||||
*/
|
||||
|
||||
private void startTestWorld() {
|
||||
// Entfernt das Menü
|
||||
app.getGuiNode().detachChild(menuContainer);
|
||||
app.getGuiNode().detachChild(background);
|
||||
|
||||
// Startet die Testszene
|
||||
TestWorld.startTestWorld();
|
||||
closeCreateGameMenu(); // Schließt das Menü
|
||||
StartMenu.createStartMenu(app); // Zeige das Startmenü
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt das CreateGameMenu und dessen Hintergrund.
|
||||
*/
|
||||
private void closeCreateGameMenu() {
|
||||
app.getGuiNode().detachChild(menuContainer); // Entfernt den Menü-Container
|
||||
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
|
||||
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,124 @@
|
||||
////////////////////////////////////////
|
||||
// Programming project code
|
||||
// UniBw M, 2022, 2023, 2024
|
||||
// www.unibw.de/inf2
|
||||
// (c) Mark Minas (mark.minas@unibw.de)
|
||||
////////////////////////////////////////
|
||||
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.shape.Box;
|
||||
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
import pp.monopoly.game.server.PlayerColor;
|
||||
import pp.monopoly.model.Board;
|
||||
import pp.monopoly.model.Figure;
|
||||
import pp.monopoly.model.Rotation;
|
||||
import static pp.util.FloatMath.HALF_PI;
|
||||
import static pp.util.FloatMath.PI;
|
||||
|
||||
/**
|
||||
* The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical
|
||||
* representation of the ships and shots on the sea map with the underlying data model.
|
||||
* It extends the {@link BoardSynchronizer} to provide specific synchronization
|
||||
* logic for the sea map.
|
||||
*/
|
||||
class GameBoardSynchronizer extends BoardSynchronizer {
|
||||
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
|
||||
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
|
||||
private static final String COLOR = "Color"; //NON-NLS
|
||||
private static final String FIGURE = "figure"; //NON-NLS
|
||||
|
||||
private final MonopolyApp app;
|
||||
private final ParticleEffectFactory particleFactory;
|
||||
|
||||
/**
|
||||
* Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map.
|
||||
*
|
||||
* @param app the Battleship application
|
||||
* @param root the root node to which graphical elements will be attached
|
||||
* @param map the ship map containing the ships and shots
|
||||
*/
|
||||
public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) {
|
||||
super(board, root);
|
||||
this.app = app;
|
||||
this.particleFactory = new ParticleEffectFactory(app);
|
||||
addExisting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a {@link Battleship} and creates a graphical representation of it.
|
||||
* The representation is either a 3D model or a simple box depending on the
|
||||
* type of battleship.
|
||||
*
|
||||
* @param ship the battleship to be represented
|
||||
* @return the node containing the graphical representation of the battleship
|
||||
*/
|
||||
public Spatial visit(Figure figure) {
|
||||
final Node node = new Node(FIGURE);
|
||||
node.attachChild(createBox(figure));
|
||||
// compute the center of the ship in world coordinates
|
||||
final float x = 1;
|
||||
final float z = 1;
|
||||
node.setLocalTranslation(x, 0f, z);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple box to represent a battleship that is not of the "King George V" type.
|
||||
*
|
||||
* @param ship the battleship to be represented
|
||||
* @return the geometry representing the battleship as a box
|
||||
*/
|
||||
private Spatial createBox(Figure figure) {
|
||||
final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f,
|
||||
0.3f,
|
||||
0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f);
|
||||
final Geometry geometry = new Geometry(FIGURE, box);
|
||||
geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor()));
|
||||
geometry.setShadowMode(ShadowMode.CastAndReceive);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Material} with the specified color.
|
||||
* If the color includes transparency (i.e., alpha value less than 1),
|
||||
* the material's render state is set to use alpha blending, allowing for
|
||||
* semi-transparent rendering.
|
||||
*
|
||||
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
|
||||
* of the color is less than 1, the material will support transparency.
|
||||
* @return a {@link Material} instance configured with the specified color and,
|
||||
* if necessary, alpha blending enabled.
|
||||
*/
|
||||
private Material createColoredMaterial(ColorRGBA color) {
|
||||
final Material material = new Material(app.getAssetManager(), UNSHADED);
|
||||
if (color.getAlpha() < 1f)
|
||||
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||
material.setColor(COLOR, color);
|
||||
return material;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the rotation angle for the specified rotation.
|
||||
*
|
||||
* @param rot the rotation of the battleship
|
||||
* @return the rotation angle in radians
|
||||
*/
|
||||
private static float calculateRotationAngle(Rotation rot) {
|
||||
return switch (rot) {
|
||||
case RIGHT -> HALF_PI;
|
||||
case DOWN -> 0f;
|
||||
case LEFT -> -HALF_PI;
|
||||
case UP -> PI;
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.simsilica.lemur.Button;
|
||||
import com.simsilica.lemur.Label;
|
||||
import com.simsilica.lemur.style.ElementId;
|
||||
|
||||
import pp.dialog.Dialog;
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
|
||||
public class GameMenu extends Dialog {
|
||||
private final MonopolyApp app;
|
||||
|
||||
/**
|
||||
* Constructs the SettingsMenu dialog for the Monopoly application.
|
||||
*
|
||||
* @param app the MonopolyApp instance
|
||||
*/
|
||||
public GameMenu(MonopolyApp app) {
|
||||
super(app.getDialogManager());
|
||||
this.app = app;
|
||||
|
||||
// Add a title label for Settings
|
||||
Label settingsTitle = new Label("Einstellungen", new ElementId("settings-title"));
|
||||
settingsTitle.setFontSize(48); // Set font size for the title
|
||||
settingsTitle.setColor(ColorRGBA.White);
|
||||
|
||||
// Add any settings-related components here, such as volume control, toggles, etc.
|
||||
|
||||
// Add a back button to return to StartMenu
|
||||
Button backButton = new Button("Zurück", new ElementId("menu-button"));
|
||||
backButton.setColor(ColorRGBA.White);
|
||||
backButton.setFontSize(24);
|
||||
backButton.addClickCommands(source -> returnToStartMenu());
|
||||
|
||||
// Add components to this dialog
|
||||
addChild(settingsTitle);
|
||||
addChild(backButton);
|
||||
|
||||
// You can add more settings components here, like checkboxes or sliders.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns to the StartMenu when the back button is clicked.
|
||||
*/
|
||||
private void returnToStartMenu() {
|
||||
app.getDialogManager().close(this); // Close the current settings dialog
|
||||
//TODO return zum Ausgangsmenü
|
||||
}
|
||||
}
|
@@ -55,7 +55,7 @@ class MapView {
|
||||
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||
Geometry background = new Geometry("MapBackground", new Quad(board.getWidth() * FIELD_SIZE, board.getHeight() * FIELD_SIZE));
|
||||
background.setMaterial(mat);
|
||||
background.setLocalTranslation(0f, 0f, BACKGROUND_DEPTH);
|
||||
background.setLocalTranslation(0f, 1f, BACKGROUND_DEPTH);
|
||||
background.setCullHint(CullHint.Never);
|
||||
mapNode.attachChild(background);
|
||||
}
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.scene.Spatial;
|
||||
|
||||
import pp.monopoly.model.Figure;
|
||||
|
||||
/**
|
||||
* Synchronizes the visual representation of the board with the game model.
|
||||
* Handles updates for items on the board.
|
||||
@@ -33,4 +37,9 @@ class MapViewSynchronizer extends BoardSynchronizer {
|
||||
protected void disableState() {
|
||||
view.getNode().detachAllChildren(); // Entfernt alle visuellen Elemente vom Knoten
|
||||
}
|
||||
|
||||
|
||||
public Spatial visit(Figure figure) {
|
||||
return figure.accept(this);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.effect.ParticleMesh.Type;
|
||||
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
|
||||
/**
|
||||
* Factory class responsible for creating particle effects used in the game.
|
||||
* This centralizes the creation of various types of particle emitters.
|
||||
*/
|
||||
public class ParticleEffectFactory {
|
||||
private static final int COUNT_FACTOR = 1;
|
||||
private static final float COUNT_FACTOR_F = 1f;
|
||||
private static final boolean POINT_SPRITE = true;
|
||||
private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
|
||||
|
||||
private final MonopolyApp app;
|
||||
|
||||
ParticleEffectFactory(MonopolyApp app) {
|
||||
this.app = app;
|
||||
}
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.shape.Quad;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.simsilica.lemur.Button;
|
||||
import com.simsilica.lemur.Checkbox;
|
||||
import com.simsilica.lemur.Container;
|
||||
@@ -16,122 +16,85 @@ import com.simsilica.lemur.style.ElementId;
|
||||
import pp.dialog.Dialog;
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
|
||||
/**
|
||||
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
|
||||
*/
|
||||
public class SettingsMenu extends Dialog {
|
||||
private final MonopolyApp app;
|
||||
private final Geometry overlayBackground;
|
||||
private final Container settingsContainer;
|
||||
private Geometry blockLayer;
|
||||
private final Node savedGuiNodeContent = new Node("SavedGuiNodeContent");
|
||||
|
||||
public SettingsMenu(MonopolyApp app) {
|
||||
super(app.getDialogManager());
|
||||
this.app = app;
|
||||
|
||||
// Blockierungsebene hinzufügen
|
||||
addBlockLayer();
|
||||
|
||||
// Hintergrundbild
|
||||
addBackgroundImage();
|
||||
// Halbtransparentes Overlay hinzufügen
|
||||
overlayBackground = createOverlayBackground();
|
||||
app.getGuiNode().attachChild(overlayBackground);
|
||||
|
||||
// Hauptcontainer für das Menü
|
||||
settingsContainer = new Container();
|
||||
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
|
||||
|
||||
// Hintergrundfarbe für das Container-Element setzen, um es undurchsichtig zu machen
|
||||
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.8f))); // Teiltransparent, falls gewünscht
|
||||
|
||||
// Titel "Einstellungen"
|
||||
// Titel
|
||||
Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title")));
|
||||
settingsTitle.setFontSize(48);
|
||||
settingsTitle.setColor(ColorRGBA.White);
|
||||
|
||||
// Effekt Sound mit Slider und Checkbox
|
||||
// Effekt-Sound: Slider und Checkbox
|
||||
Container effectSoundContainer = settingsContainer.addChild(new Container());
|
||||
Label effectSoundLabel = effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label")));
|
||||
effectSoundLabel.setFontSize(24);
|
||||
effectSoundLabel.setColor(ColorRGBA.White);
|
||||
effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label")));
|
||||
effectSoundContainer.addChild(new Slider());
|
||||
effectSoundContainer.addChild(new Checkbox("Aktivieren")).setChecked(true);
|
||||
|
||||
Slider effectSoundSlider = effectSoundContainer.addChild(new Slider());
|
||||
effectSoundSlider.setPreferredSize(new com.jme3.math.Vector3f(300, 30, 0));
|
||||
|
||||
Checkbox effectSoundCheckbox = effectSoundContainer.addChild(new Checkbox(""));
|
||||
effectSoundCheckbox.setChecked(true);
|
||||
|
||||
// Hintergrund Musik mit Slider und Checkbox
|
||||
// Hintergrundmusik: Slider und Checkbox
|
||||
Container backgroundMusicContainer = settingsContainer.addChild(new Container());
|
||||
Label backgroundMusicLabel = backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
|
||||
backgroundMusicLabel.setFontSize(24);
|
||||
backgroundMusicLabel.setColor(ColorRGBA.White);
|
||||
backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
|
||||
backgroundMusicContainer.addChild(new Slider());
|
||||
backgroundMusicContainer.addChild(new Checkbox("Aktivieren")).setChecked(true);
|
||||
|
||||
Slider backgroundMusicSlider = backgroundMusicContainer.addChild(new Slider());
|
||||
backgroundMusicSlider.setPreferredSize(new com.jme3.math.Vector3f(300, 30, 0));
|
||||
|
||||
Checkbox backgroundMusicCheckbox = backgroundMusicContainer.addChild(new Checkbox(""));
|
||||
backgroundMusicCheckbox.setChecked(true);
|
||||
|
||||
// Beenden Button
|
||||
// Beenden-Button
|
||||
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button")));
|
||||
quitButton.setFontSize(32);
|
||||
quitButton.setColor(ColorRGBA.White);
|
||||
quitButton.addClickCommands(source -> app.stop());
|
||||
|
||||
// Zentrieren des Containers
|
||||
// Zentriere das Menü
|
||||
settingsContainer.setLocalTranslation(
|
||||
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
|
||||
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
|
||||
1 // Höhere Z-Ebene für den Vordergrund
|
||||
1
|
||||
);
|
||||
|
||||
app.getGuiNode().attachChild(settingsContainer);
|
||||
}
|
||||
|
||||
private void addBlockLayer() {
|
||||
// Sichern des aktuellen GUI-Inhalts
|
||||
for (var child : app.getGuiNode().getChildren()) {
|
||||
savedGuiNodeContent.attachChild(child);
|
||||
}
|
||||
app.getGuiNode().detachAllChildren();
|
||||
|
||||
// Blockierungsebene erstellen und hinzufügen
|
||||
blockLayer = new Geometry("BlockLayer", new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()));
|
||||
blockLayer.setMaterial(createTransparentMaterial());
|
||||
blockLayer.setLocalTranslation(0, 0, 0); // Platzierung unterhalb des SettingsMenu
|
||||
app.getGuiNode().attachChild(blockLayer);
|
||||
}
|
||||
|
||||
private com.jme3.material.Material createTransparentMaterial() {
|
||||
com.jme3.material.Material material = new com.jme3.material.Material(
|
||||
app.getAssetManager(),
|
||||
"Common/MatDefs/Misc/Unshaded.j3md"
|
||||
);
|
||||
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
|
||||
material.getAdditionalRenderState().setBlendMode(com.jme3.material.RenderState.BlendMode.Alpha);
|
||||
return material;
|
||||
}
|
||||
|
||||
private void addBackgroundImage() {
|
||||
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
|
||||
/**
|
||||
* Erstellt einen halbtransparenten Hintergrund für das Menü.
|
||||
*
|
||||
* @return Geometrie des Overlays
|
||||
*/
|
||||
private Geometry createOverlayBackground() {
|
||||
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
|
||||
Geometry background = new Geometry("Background", quad);
|
||||
com.jme3.material.Material backgroundMaterial = new com.jme3.material.Material(
|
||||
app.getAssetManager(),
|
||||
"Common/MatDefs/Misc/Unshaded.j3md"
|
||||
);
|
||||
backgroundMaterial.setTexture("ColorMap", backgroundImage);
|
||||
background.setMaterial(backgroundMaterial);
|
||||
background.setLocalTranslation(0, 0, -1); // Platzierung hinter dem SettingsMenu
|
||||
app.getGuiNode().attachChild(background);
|
||||
Geometry overlay = new Geometry("Overlay", quad);
|
||||
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
|
||||
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||
overlay.setMaterial(material);
|
||||
overlay.setLocalTranslation(0, 0, 0);
|
||||
return overlay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schließt das Menü und entfernt die GUI-Elemente.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
// Entfernt das SettingsMenu und die Blockierungsebene
|
||||
app.getGuiNode().detachChild(settingsContainer);
|
||||
app.getGuiNode().detachChild(blockLayer);
|
||||
|
||||
// Stellt die ursprüngliche GUI wieder her
|
||||
for (var child : savedGuiNodeContent.getChildren()) {
|
||||
app.getGuiNode().attachChild(child);
|
||||
}
|
||||
savedGuiNodeContent.detachAllChildren();
|
||||
|
||||
app.setSettingsMenuOpen(false);
|
||||
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
|
||||
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü
|
||||
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
|
||||
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren
|
||||
app.unblockInputs(); // Eingaben wieder aktivieren
|
||||
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,39 +1,107 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.texture.Texture;
|
||||
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
|
||||
/**
|
||||
* TestWorld zeigt eine einfache Szene mit einem texturierten Quadrat.
|
||||
* Die Kamera wird durch den CameraController gesteuert.
|
||||
*/
|
||||
public class TestWorld extends SimpleApplication {
|
||||
public class TestWorld {
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
private final MonopolyApp app;
|
||||
private CameraController cameraController; // Steuert die Kamera
|
||||
private Geometry cube; // Spielfigur
|
||||
|
||||
/**
|
||||
* Konstruktor für TestWorld.
|
||||
*
|
||||
* @param app Die Hauptanwendung (MonopolyApp)
|
||||
*/
|
||||
public TestWorld(MonopolyApp app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert die Szene und startet die Kamerabewegung.
|
||||
*/
|
||||
public void initializeScene() {
|
||||
app.getGuiNode().detachAllChildren(); // Entferne GUI
|
||||
app.getRootNode().detachAllChildren(); // Entferne andere Szenenobjekte
|
||||
|
||||
setSkyColor(); // Setze den Himmel auf hellblau
|
||||
createBoard(); // Erstelle das Spielfeld
|
||||
createCube(); // Füge den Würfel hinzu
|
||||
|
||||
// Erstelle den CameraController
|
||||
cameraController = new CameraController(
|
||||
app.getCamera(), // Die Kamera der App
|
||||
Vector3f.ZERO, // Fokus auf die Mitte des Spielfelds
|
||||
5, // Radius des Kreises
|
||||
3, // Höhe der Kamera
|
||||
0.5f // Geschwindigkeit der Bewegung
|
||||
);
|
||||
|
||||
// Füge die Toolbar hinzu
|
||||
new Toolbar(app, cube);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die Kameraposition.
|
||||
*
|
||||
* @param tpf Zeit pro Frame
|
||||
*/
|
||||
public void update(float tpf) {
|
||||
if (cameraController != null) {
|
||||
cameraController.update(tpf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Hintergrundfarbe der Szene auf hellblau.
|
||||
*/
|
||||
private void setSkyColor() {
|
||||
app.getViewPort().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f)); // Hellblauer Himmel
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstelle das Spielfeld.
|
||||
*/
|
||||
private void createBoard() {
|
||||
// Erstelle ein Quadrat
|
||||
Box box = new Box(1, 0.01f, 1); // Dünnes Quadrat für die Textur
|
||||
Geometry geom = new Geometry("Box", box);
|
||||
Geometry geom = new Geometry("Board", box);
|
||||
|
||||
// Setze das Material mit Textur
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
Texture texture = assetManager.loadTexture("Pictures/board.png"); // Ersetze durch den Pfad zum gewünschten Bild
|
||||
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
Texture texture = app.getAssetManager().loadTexture("Pictures/board.png");
|
||||
mat.setTexture("ColorMap", texture);
|
||||
geom.setMaterial(mat);
|
||||
|
||||
// Füge das Quadrat zur Szene hinzu
|
||||
rootNode.attachChild(geom);
|
||||
|
||||
// Setze die Kameraposition, um das Quadrat zu fokussieren
|
||||
cam.setLocation(new Vector3f(0, 0, 3)); // Kamera auf der Z-Achse, nah am Quadrat
|
||||
cam.lookAt(geom.getLocalTranslation(), Vector3f.UNIT_Y);
|
||||
app.getRootNode().attachChild(geom);
|
||||
}
|
||||
|
||||
public static void startTestWorld() {
|
||||
TestWorld testWorldApp = new TestWorld();
|
||||
testWorldApp.start();
|
||||
/**
|
||||
* Erstellt den Würfel (Spielfigur) in der Szene.
|
||||
*/
|
||||
private void createCube() {
|
||||
Box box = new Box(0.05f, 0.05f, 0.05f); // Kleinere Größe für Spielfigur
|
||||
cube = new Geometry("Cube", box);
|
||||
|
||||
// Setze das Material für den Würfel
|
||||
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
mat.setColor("Color", ColorRGBA.Blue); // Blau gefärbter Würfel
|
||||
cube.setMaterial(mat);
|
||||
|
||||
// Setze den Startpunkt des Würfels
|
||||
cube.setLocalTranslation(0.8999999f, 0.1f, -0.9f);
|
||||
|
||||
app.getRootNode().attachChild(cube);
|
||||
}
|
||||
}
|
||||
|
@@ -1,80 +0,0 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.jme3.system.JmeCanvasContext;
|
||||
import com.jme3.system.AppSettings;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
public class TestWorldWithMenu extends SimpleApplication {
|
||||
|
||||
public static void createAndShowGUI() {
|
||||
// Create JFrame
|
||||
JFrame frame = new JFrame("Test World with Menu");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setLayout(new BorderLayout());
|
||||
frame.setSize(800, 600);
|
||||
|
||||
// Create Menu Bar
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
JMenuItem exitItem = new JMenuItem(new AbstractAction("Exit") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
fileMenu.add(exitItem);
|
||||
menuBar.add(fileMenu);
|
||||
frame.setJMenuBar(menuBar);
|
||||
|
||||
// Create Canvas for jMonkey
|
||||
AppSettings settings = new AppSettings(true);
|
||||
settings.setWidth(800);
|
||||
settings.setHeight(600);
|
||||
|
||||
TestWorldWithMenu app = new TestWorldWithMenu();
|
||||
app.setSettings(settings);
|
||||
app.createCanvas(); // Create a canvas for embedding
|
||||
JmeCanvasContext ctx = (JmeCanvasContext) app.getContext();
|
||||
ctx.setSystemListener(app);
|
||||
Canvas canvas = ctx.getCanvas();
|
||||
canvas.setSize(800, 600);
|
||||
|
||||
// Add the canvas to JFrame
|
||||
frame.add(canvas, BorderLayout.CENTER);
|
||||
|
||||
// Show the frame
|
||||
frame.setVisible(true);
|
||||
|
||||
// Start the jMonkeyEngine application
|
||||
app.startCanvas();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
// Erstelle ein Quadrat
|
||||
Box box = new Box(1, 0.01f, 1); // Dünnes Quadrat für die Textur
|
||||
Geometry geom = new Geometry("Box", box);
|
||||
|
||||
// Setze das Material mit Textur
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
Texture texture = assetManager.loadTexture("Pictures/board.png"); // Replace with the path to your image
|
||||
mat.setTexture("ColorMap", texture);
|
||||
geom.setMaterial(mat);
|
||||
|
||||
// Füge das Quadrat zur Szene hinzu
|
||||
rootNode.attachChild(geom);
|
||||
|
||||
// Setze die Kameraposition, um das Quadrat zu fokussieren
|
||||
cam.setLocation(new Vector3f(0, 0, 3)); // Kamera auf der Z-Achse, nah am Quadrat
|
||||
cam.lookAt(geom.getLocalTranslation(), Vector3f.UNIT_Y);
|
||||
}
|
||||
}
|
@@ -0,0 +1,168 @@
|
||||
package pp.monopoly.client.gui;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.jme3.font.BitmapText;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.simsilica.lemur.Axis;
|
||||
import com.simsilica.lemur.Button;
|
||||
import com.simsilica.lemur.Container;
|
||||
import com.simsilica.lemur.component.SpringGridLayout;
|
||||
|
||||
import pp.monopoly.client.MonopolyApp;
|
||||
|
||||
/**
|
||||
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
|
||||
* Die Buttons bewegen den Würfel auf dem Spielfeld.
|
||||
*/
|
||||
public class Toolbar {
|
||||
|
||||
private final MonopolyApp app;
|
||||
private final Container toolbarContainer;
|
||||
private final Geometry cube; // Referenz auf den Würfel
|
||||
private final BitmapText positionText; // Anzeige für die aktuelle Position
|
||||
private final float boardLimit = 0.95f; // Grenzen des Bretts
|
||||
private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
|
||||
private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
|
||||
private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
|
||||
private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
|
||||
|
||||
/**
|
||||
* Konstruktor für die Toolbar.
|
||||
*
|
||||
* @param app Die Hauptanwendung (MonopolyApp)
|
||||
* @param cube Der Würfel, der bewegt werden soll
|
||||
*/
|
||||
public Toolbar(MonopolyApp app, Geometry cube) {
|
||||
this.app = app;
|
||||
this.cube = cube;
|
||||
|
||||
// Erstelle die Toolbar
|
||||
toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
|
||||
|
||||
// Setze die Position am unteren Rand und die Breite
|
||||
toolbarContainer.setLocalTranslation(
|
||||
0, // Links bündig
|
||||
100, // Höhe über dem unteren Rand
|
||||
0 // Z-Ebene
|
||||
);
|
||||
toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
|
||||
|
||||
// Füge Buttons zur Toolbar hinzu
|
||||
initializeButtons();
|
||||
|
||||
// Füge die Toolbar zur GUI hinzu
|
||||
app.getGuiNode().attachChild(toolbarContainer);
|
||||
|
||||
// Erstelle die Position-Anzeige
|
||||
positionText = createPositionDisplay();
|
||||
updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert die Buttons in der Toolbar.
|
||||
*/
|
||||
private void initializeButtons() {
|
||||
addButton("Vorwärts", 1); // Bewegung nach vorne
|
||||
addButton("Rückwärts", -1); // Bewegung nach hinten
|
||||
addDiceRollButton(); // Würfel-Button
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt einen Button mit einer Bewegung hinzu.
|
||||
*
|
||||
* @param label Der Text des Buttons
|
||||
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts)
|
||||
*/
|
||||
private void addButton(String label, int step) {
|
||||
Button button = new Button(label);
|
||||
button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
|
||||
button.addClickCommands(source -> moveCube(step));
|
||||
toolbarContainer.addChild(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
|
||||
*/
|
||||
private void addDiceRollButton() {
|
||||
Button diceButton = new Button("Würfeln");
|
||||
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
|
||||
diceButton.addClickCommands(source -> rollDice());
|
||||
toolbarContainer.addChild(diceButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
|
||||
*/
|
||||
private void rollDice() {
|
||||
int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
|
||||
System.out.println("Gewürfelt: " + diceRoll);
|
||||
moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
|
||||
}
|
||||
|
||||
/**
|
||||
* Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
|
||||
*
|
||||
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
|
||||
*/
|
||||
private void moveCube(int step) {
|
||||
currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
|
||||
Vector3f newPosition = calculatePosition(currentPosition);
|
||||
cube.setLocalTranslation(newPosition);
|
||||
updatePositionDisplay(); // Aktualisiere die Positionsanzeige
|
||||
System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
|
||||
*
|
||||
* @param position Aktuelle Position auf dem Spielfeld
|
||||
* @return Die berechnete Position als Vector3f
|
||||
*/
|
||||
private Vector3f calculatePosition(int position) {
|
||||
int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
|
||||
int offset = position % positionsPerSide; // Position auf der aktuellen Seite
|
||||
|
||||
switch (side) {
|
||||
case 0: // Unten (positive x-Achse)
|
||||
return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
|
||||
case 1: // Rechts (positive z-Achse)
|
||||
return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
|
||||
case 2: // Oben (negative x-Achse)
|
||||
return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
|
||||
case 3: // Links (negative z-Achse)
|
||||
return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
|
||||
default:
|
||||
throw new IllegalArgumentException("Ungültige Position: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die Anzeige für die aktuelle Position.
|
||||
*
|
||||
* @return Das BitmapText-Objekt für die Anzeige
|
||||
*/
|
||||
private BitmapText createPositionDisplay() {
|
||||
BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
|
||||
text.setSize(20); // Schriftgröße
|
||||
text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
|
||||
app.getGuiNode().attachChild(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die Anzeige für die aktuelle Position.
|
||||
*/
|
||||
private void updatePositionDisplay() {
|
||||
positionText.setText("Feld-ID: " + currentPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt die Toolbar.
|
||||
*/
|
||||
public void remove() {
|
||||
app.getGuiNode().detachChild(toolbarContainer);
|
||||
app.getGuiNode().detachChild(positionText);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 484 KiB |
Binary file not shown.
After Width: | Height: | Size: 144 KiB |
Reference in New Issue
Block a user