This commit is contained in:
Johannes Schmelz 2024-11-18 16:53:11 +01:00
commit 4279d130dd
8 changed files with 222 additions and 78 deletions

View File

@ -1,5 +1,6 @@
// Styling of Lemur components
// For documentation, see:
// For documentation, see:
// https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling
import com.simsilica.lemur.*
import com.simsilica.lemur.component.QuadBackgroundComponent
@ -9,7 +10,6 @@ import com.simsilica.lemur.Command
import com.simsilica.lemur.HAlignment
import com.simsilica.lemur.Insets3f
import com.simsilica.lemur.component.QuadBackgroundComponent
import com.simsilica.lemur.component.TbtQuadBackgroundComponent
def bgColor = color(1, 1, 1, 1)
def buttonEnabledColor = color(0, 0, 0, 1)
@ -17,17 +17,15 @@ def buttonDisabledColor = color(0.8, 0.9, 1, 0.2)
def buttonBgColor = color(1, 1, 1, 1)
def sliderColor = color(0.6, 0.8, 0.8, 1)
def sliderBgColor = color(0.5, 0.75, 0.75, 1)
def gradientColor = color(0.5, 0.75, 0.85, 0.5)
def gradientColor = color(1, 1, 1, 1)
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white
def gradient = TbtQuadBackgroundComponent.create(
texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png",
generateMips: false),
1, 1, 1, 126, 126,
1f, false)
texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png", generateMips: false),
1, 1, 1, 126, 126, 1f, false)
def doubleGradient = new QuadBackgroundComponent(gradientColor)
doubleGradient.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png",
@ -44,26 +42,24 @@ selector("pp") {
font = font("Interface/Fonts/Metropolis/Metropolis-Regular-32.fnt")
}
selector("label", "pp") {
insets = new Insets3f(2, 2, 2, 2)
color = buttonEnabledColor
}
selector("header", "pp") {
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")
insets = new Insets3f(2, 2, 2, 2)
color = color(1, 0.5, 0, 1)
// Titel für "Einstellungen"
selector("settings-title", "pp") {
color = color(1, 1, 1, 1)
fontSize = 48
textHAlignment = HAlignment.Center
insets = new Insets3f(5, 5, 5, 5)
}
// Container Stil
selector("container", "pp") {
background = solidWhiteBackground.clone()
background.setColor(bgColor)
}
// Slider Stil
selector("slider", "pp") {
background = gradient.clone()
background.setColor(bgColor)
insets = new Insets3f(5, 10, 5, 10) // Abstand
background = new QuadBackgroundComponent(sliderBgColor)
}
def pressedCommand = new Command<Button>() {
@ -84,30 +80,6 @@ def enabledCommand = new Command<Button>() {
}
}
def repeatCommand = new Command<Button>() {
private long startTime
private long lastClick
void execute(Button source) {
// Only do the repeating click while the mouse is
// over the button (and pressed of course)
if (source.isPressed() && source.isHighlightOn()) {
long elapsedTime = System.currentTimeMillis() - startTime
// After half a second pause, click 8 times a second
if (elapsedTime > 500 && elapsedTime > lastClick + 125) {
source.click()
// Try to quantize the last click time to prevent drift
lastClick = ((elapsedTime - 500) / 125) * 125 + 500
}
}
else {
startTime = System.currentTimeMillis()
lastClick = 0
}
}
}
def stdButtonCommands = [
(ButtonAction.Down) : [pressedCommand],
(ButtonAction.Up) : [pressedCommand],

View File

@ -1,30 +1,26 @@
////////////////////////////////////////
// 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;
import java.lang.System.Logger.Level;
import java.util.prefs.Preferences;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
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;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.SoundEvent;
import static pp.util.PreferencesUtils.getPreferences;
/**
* An application state that plays sounds.
* An application state that plays sounds based on game events.
*/
public class GameSound extends AbstractAppState implements GameEventListener {
private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
@ -53,7 +49,6 @@ 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.
*/
@ -61,37 +56,35 @@ 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); //NON-NLS
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled);
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
}
/**
* Initializes the sound effects for the game.
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
* Initializes the sound effects for the game and stores the application reference.
*
* @param stateManager The state manager
* @param app The application
* @param app The application instance
*/
@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(Application app, String name) {
private AudioNode loadSound(String name) {
try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false);
sound.setPositional(false);
return sound;
}
catch (AssetLoadException | AssetNotFoundException ex) {
} catch (Exception ex) {
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
}
return null;
@ -126,4 +119,4 @@ public class GameSound extends AbstractAppState implements GameEventListener {
switch (event.sound()) {
}
}
}
}//heloo

View File

@ -3,6 +3,9 @@ package pp.monopoly.client;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
@ -10,6 +13,7 @@ import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.system.AppSettings;
import com.jme3.texture.Texture;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles;
@ -20,10 +24,12 @@ 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.MonopolyClient;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
private BitmapText topText;
private final ServerConnection serverConnection;
@ -51,10 +57,13 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
new MonopolyApp().start();
}
public MonopolyApp() {
this.draw = new Draw(assetManager);
public MonopolyApp() {
this.draw = new Draw(assetManager);
config = new MonopolyAppConfig();
serverConnection = new NetworkSupport(this);
serverConnection = new NetworkSupport(this);
logic = new ClientGameLogic(serverConnection);
logic.addListener(this);
setShowSettings(config.getShowSettings());
@ -97,6 +106,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
topText = new BitmapText(normalFont);
topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
guiNode.attachChild(topText);
}
@ -105,6 +115,9 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
inputManager.setCursorVisible(true);
inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addListener(escapeListener, "ESC");
inputManager.setCursorVisible(true);
inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addListener(escapeListener, "ESC");
}
private void handleEscape(boolean isPressed) {
@ -151,12 +164,14 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
@Override
public void receivedEvent(InfoTextEvent event) {
setInfoText(event.key());
setInfoText(event.key());
}
@Override
public void stop(boolean waitFor) {
if (executor != null) executor.shutdownNow();
serverConnection.disconnect();
serverConnection.disconnect();
super.stop(waitFor);
}
@ -206,4 +221,35 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
}
//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);
}
}

View File

@ -2,31 +2,44 @@ package pp.monopoly.client;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.dialog.Dialog;
import pp.monopoly.client.gui.CreateGameMenu;
import pp.monopoly.client.gui.SettingsMenu;
/**
* Constructs the startup menu dialog for the Monopoly application.
import pp.monopoly.client.gui.CreateGameMenu;
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.
* Constructs the Startup Menu dialog for the Monopoly application.
*
* @param app the MonopolyApp instance
@ -36,6 +49,20 @@ public class StartMenu extends Dialog {
this.app = app;
}
/**
* Creates and displays the Start Menu with buttons for starting the game,
* opening settings, and quitting the application.
*/
public static void createStartMenu(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Set up the background image
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(screenWidth, screenHeight);
Geometry background = new Geometry("Background", quad);
}
/**
* Creates and displays the Start Menu with buttons for starting the game,
* opening settings, and quitting the application.
@ -50,8 +77,10 @@ public class StartMenu extends Dialog {
Geometry background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
app.getGuiNode().attachChild(background);
createMonopolyLogo(app);
@ -173,6 +202,11 @@ public class StartMenu extends Dialog {
new SettingsMenu(app);
}
/**
* Quits the game application.
*/
private static void quitGame() {
System.exit(0);
/**
* Quits the game application.
*/

View File

@ -3,8 +3,10 @@ package pp.monopoly.client.gui;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.monopoly.model.Board;
import pp.monopoly.model.Item;
import pp.monopoly.model.Item;
import pp.monopoly.model.Visitor;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.ItemAddedEvent;
@ -24,10 +26,14 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
*
* @param board the game board to synchronize
* @param root the root node to which the view representations of the board items are attached
* @param board the game board to synchronize
* @param root the root node to which the view representations of the board items are attached
*/
protected BoardSynchronizer(Board board, Node root) {
protected BoardSynchronizer(Board board, Node root) {
super(root);
this.board = board;
this.board = board;
}
/**
@ -42,6 +48,7 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
}
/**
* Adds the existing items from the board to the view during initialization.
* Adds the existing items from the board to the view during initialization.
*/
protected void addExisting() {
@ -49,26 +56,36 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
}
/**
* Handles the event when an item is removed from the board.
* Handles the event when an item is removed from the board.
*
* @param event the event indicating that an item has been removed from the board
* @param event the event indicating that an item has been removed from the board
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (board == event.getBoard()) {
delete(event.getItem());
}
if (board == event.getBoard()) {
delete(event.getItem());
}
}
/**
* Handles the event when an item is added to the board.
* Handles the event when an item is added to the board.
*
* @param event the event indicating that an item has been added to the board
* @param event the event indicating that an item has been added to the board
*/
@Override
public void receivedEvent(ItemAddedEvent event) {
if (board == event.getBoard()) {
add(event.getItem());
}
if (board == event.getBoard()) {
add(event.getItem());
}
}
}

View File

@ -5,6 +5,8 @@ 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.
* Synchronizes the visual representation of the board with the game model.
* Handles updates for items on the board.
*/
@ -17,6 +19,7 @@ class MapViewSynchronizer extends BoardSynchronizer {
* @param view the MapView to synchronize with the game model
*/
public MapViewSynchronizer(MapView view) {
super(view.getBoard(), view.getNode());
super(view.getBoard(), view.getNode());
this.view = view;
addExisting();

View File

@ -0,0 +1,80 @@
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);
}
}

View File

@ -1,26 +1,25 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.notification;
/**
* Event when an item is added to a map.
* Event when a sound needs to be played.
*
* @param sound the sound to be played
* @param soundFileName the sound file to be played
*/
public record SoundEvent(Sound sound) implements GameEvent {
public class SoundEvent implements GameEvent {
private final String soundFileName;
public SoundEvent(Sound sound) {
this.soundFileName = sound.getFileName(); // Angenommen, Sound hat eine Methode getFileName()
}
public String getSoundFileName() {
return soundFileName;
}
/**
* Notifies the game event listener of this event.
*
* @param listener the game event listener
*/
@Override
public void notifyListener(GameEventListener listener) {
listener.receivedEvent(this);
}
}