Verbesserung TestWorld

This commit is contained in:
Luca Puderbach 2024-11-18 06:54:38 +01:00
parent 6fd9209336
commit 5fde7451c8
11 changed files with 207 additions and 183 deletions

View File

@ -7,6 +7,10 @@
package pp.monopoly.client; package pp.monopoly.client;
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.Application;
import com.jme3.app.state.AbstractAppState; import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager; import com.jme3.app.state.AppStateManager;
@ -14,13 +18,9 @@ import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetNotFoundException; import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioData; import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.SoundEvent; import pp.monopoly.notification.SoundEvent;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.prefs.Preferences;
import static pp.util.PreferencesUtils.getPreferences; import static pp.util.PreferencesUtils.getPreferences;
/** /**

View File

@ -15,6 +15,7 @@ import com.simsilica.lemur.style.BaseStyles;
import pp.dialog.DialogBuilder; import pp.dialog.DialogBuilder;
import pp.dialog.DialogManager; import pp.dialog.DialogManager;
import pp.graphics.Draw;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.TestWorld; import pp.monopoly.client.gui.TestWorld;
import pp.monopoly.game.client.ClientGameLogic; import pp.monopoly.game.client.ClientGameLogic;
@ -31,24 +32,18 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed); private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed);
private final DialogManager dialogManager = new DialogManager(this); private final DialogManager dialogManager = new DialogManager(this);
private final ExecutorService executor = Executors.newCachedThreadPool(); private final ExecutorService executor = Executors.newCachedThreadPool();
private final Draw draw;
private SettingsMenu settingsMenu; private SettingsMenu settingsMenu;
private TestWorld testWorld;
/**
* 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
private boolean isSettingsMenuOpen = false; private boolean isSettingsMenuOpen = false;
private boolean inputBlocked = false;
public static void main(String[] args) { public static void main(String[] args) {
new MonopolyApp().start(); new MonopolyApp().start();
} }
public MonopolyApp() { public MonopolyApp() {
this.draw = new Draw(assetManager);
config = new MonopolyAppConfig(); config = new MonopolyAppConfig();
serverConnection = new NetworkSupport(this); serverConnection = new NetworkSupport(this);
logic = new ClientGameLogic(serverConnection); logic = new ClientGameLogic(serverConnection);
@ -67,10 +62,6 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
return logic; return logic;
} }
public ExecutorService getExecutor() {
return executor;
}
private AppSettings makeSettings() { private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true); final AppSettings settings = new AppSettings(true);
settings.setTitle("Monopoly Game"); settings.setTitle("Monopoly Game");
@ -79,29 +70,21 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
return settings; return settings;
} }
public boolean isSettingsMenuOpen() {
return isSettingsMenuOpen;
}
public void setSettingsMenuOpen(boolean isOpen) {
this.isSettingsMenuOpen = isOpen;
}
@Override @Override
public void simpleInitApp() { public void simpleInitApp() {
GuiGlobals.initialize(this); GuiGlobals.initialize(this);
BaseStyles.loadStyleResources(STYLES_SCRIPT); BaseStyles.loadGlassStyle();
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS GuiGlobals.getInstance().getStyles().setDefaultStyle("glass");
final BitmapFont normalFont = assetManager.loadFont(FONT);
setupInput(); setupInput();
setupGui(); setupGui();
// Initialisiere das Startmenü // Zeige das Startmenü
StartMenu.createStartMenu(this); StartMenu.createStartMenu(this);
} }
private void setupGui() { private void setupGui() {
BitmapFont normalFont = assetManager.loadFont(FONT); BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
topText = new BitmapText(normalFont); topText = new BitmapText(normalFont);
topText.setLocalTranslation(10, settings.getHeight() - 10, 0); topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
guiNode.attachChild(topText); guiNode.attachChild(topText);
@ -116,10 +99,15 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
private void handleEscape(boolean isPressed) { private void handleEscape(boolean isPressed) {
if (isPressed) { if (isPressed) {
if (isSettingsMenuOpen && settingsMenu != null) { if (settingsMenu != null && isSettingsMenuOpen) {
// Schließe das SettingsMenu
System.out.println("Schließe SettingsMenu...");
settingsMenu.close(); settingsMenu.close();
settingsMenu = null;
setSettingsMenuOpen(false); setSettingsMenuOpen(false);
} else { } else {
// Öffne das SettingsMenu
System.out.println("Öffne SettingsMenu...");
settingsMenu = new SettingsMenu(this); settingsMenu = new SettingsMenu(this);
settingsMenu.open(); settingsMenu.open();
setSettingsMenuOpen(true); setSettingsMenuOpen(true);
@ -127,6 +115,25 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
} }
} }
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;
}
}
public void setInfoText(String text) { public void setInfoText(String text) {
topText.setText(text); topText.setText(text);
} }
@ -147,6 +154,14 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
return dialogManager; return dialogManager;
} }
public Draw getDraw() {
return draw;
}
public ExecutorService getExecutor() {
return executor;
}
public void closeApp() { public void closeApp() {
stop(); stop();
} }
@ -160,20 +175,25 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
.open(); .open();
} }
/** public void setSettingsMenuOpen(boolean isOpen) {
* Wechselt zur TestWorld. this.isSettingsMenuOpen = isOpen;
*/ }
public void startTestWorld() {
guiNode.detachAllChildren(); // GUI entfernen @Override
stop(); // MonopolyApp anhalten public void simpleUpdate(float tpf) {
TestWorld.startTestWorld(); // TestWorld starten 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
} }
/**
* Kehrt zum Hauptmenü zurück.
*/
public void returnToMenu() { public void returnToMenu() {
guiNode.detachAllChildren(); guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
} }
} }

View File

@ -0,0 +1,55 @@
package pp.monopoly.client.gui;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
/**
* CameraController steuert die Bewegung der Kamera in einem Kreis um eine Zielposition.
*/
public class CameraController {
private final Camera camera; // Die Kamera, die gesteuert wird
private final Vector3f target; // Zielpunkt, den die Kamera fokussieren soll
private final float radius; // Radius des Kreises
private final float height; // Höhe der Kamera über dem Zielpunkt
private final float speed; // Geschwindigkeit der Bewegung in Radiant pro Sekunde
private float angle = 0; // Aktueller Winkel der Kamera in Radiant
/**
* Erstellt einen neuen CameraController.
*
* @param camera Die Kamera, die gesteuert wird
* @param target Der Punkt, auf den die Kamera ausgerichtet wird
* @param radius Der Radius des Kreises, auf dem sich die Kamera bewegt
* @param height Die Höhe der Kamera über dem Zielpunkt
* @param speed Die Geschwindigkeit der Bewegung in Radiant pro Sekunde
*/
public CameraController(Camera camera, Vector3f target, float radius, float height, float speed) {
this.camera = camera;
this.target = target;
this.radius = radius;
this.height = height;
this.speed = speed;
}
/**
* Aktualisiert die Kameraposition basierend auf der verstrichenen Zeit.
*
* @param tpf Zeit pro Frame
*/
public void update(float tpf) {
angle += speed * tpf; // Winkel basierend auf Geschwindigkeit und Zeit erhöhen
if (angle > FastMath.TWO_PI) {
angle -= FastMath.TWO_PI; // Zurücksetzen, um Überlauf zu vermeiden
}
// Berechne die neue Kameraposition auf der Kreisbahn
float x = FastMath.cos(angle) * radius;
float z = FastMath.sin(angle) * radius;
// Setze die neue Position der Kamera
camera.setLocation(new Vector3f(x, height, z));
camera.lookAt(target, Vector3f.UNIT_Y); // Kamera bleibt auf das Ziel fokussiert
}
}

View File

@ -23,6 +23,11 @@ public class CreateGameMenu {
private final Container menuContainer; private final Container menuContainer;
private Geometry background; private Geometry background;
/**
* Konstruktor für das CreateGameMenu.
*
* @param app Die Hauptanwendung (MonopolyApp)
*/
public CreateGameMenu(MonopolyApp app) { public CreateGameMenu(MonopolyApp app) {
this.app = app; this.app = app;
@ -43,12 +48,12 @@ public class CreateGameMenu {
inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
inputContainer.addChild(new Label("Server-Adresse:")); inputContainer.addChild(new Label("Server-Adresse:"));
TextField playerNameField = inputContainer.addChild(new TextField("localhost")); TextField serverAddressField = inputContainer.addChild(new TextField("localhost"));
playerNameField.setPreferredWidth(400); // Breite des Textfelds serverAddressField.setPreferredWidth(400); // Breite des Textfelds
inputContainer.addChild(new Label("Port:")); inputContainer.addChild(new Label("Port:"));
TextField serverAddressField = inputContainer.addChild(new TextField("42069")); TextField portField = inputContainer.addChild(new TextField("42069"));
serverAddressField.setPreferredWidth(400); // Breite des Textfelds portField.setPreferredWidth(400); // Breite des Textfelds
// Button-Container // Button-Container
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); 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")); Button hostButton = buttonContainer.addChild(new Button("Spiel hosten"));
hostButton.setPreferredSize(new Vector3f(120, 40, 0)); hostButton.setPreferredSize(new Vector3f(120, 40, 0));
hostButton.addClickCommands(source -> { hostButton.addClickCommands(source -> {
closeCreateGameMenu(); // Schließt das Menü closeCreateGameMenu(); // Schließt das Menü
app.startTestWorld(); // Startet die Testwelt in der Hauptanwendung app.startTestWorld(); // Starte die TestWorld im selben Fenster
}); });
// "Beitreten"-Button // "Beitreten"-Button
Button joinButton = buttonContainer.addChild(new Button("Beitreten")); Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
joinButton.setPreferredSize(new Vector3f(120, 40, 0)); joinButton.setPreferredSize(new Vector3f(120, 40, 0));
// joinButton.addClickCommands(source -> joinGame()); // Placeholder for joining logic // Placeholder für die Beitrittslogik
// Zentrierung des Containers // Zentrierung des Containers
menuContainer.setLocalTranslation( menuContainer.setLocalTranslation(
@ -103,27 +107,15 @@ public class CreateGameMenu {
* Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird. * Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
*/ */
private void goBackToStartMenu() { private void goBackToStartMenu() {
app.getGuiNode().detachChild(menuContainer); closeCreateGameMenu(); // Schließt das Menü
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild StartMenu.createStartMenu(app); // Zeige das Startmenü
StartMenu.createStartMenu(app);
} }
/*
* Link zwischen createGame und TestWorld /**
* Entfernt das CreateGameMenu und dessen Hintergrund.
*/ */
private void startTestWorld() {
// Entfernt das Menü
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background);
// Startet die Testszene
TestWorld.startTestWorld();
}
private void closeCreateGameMenu() { private void closeCreateGameMenu() {
app.getGuiNode().detachChild(menuContainer); // Entfernt den Menü-Container app.getGuiNode().detachChild(menuContainer); // Entfernt den Menü-Container
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
} }
} }

View File

@ -21,7 +21,6 @@ import pp.monopoly.game.server.PlayerColor;
import pp.monopoly.model.Board; import pp.monopoly.model.Board;
import pp.monopoly.model.Figure; import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation; import pp.monopoly.model.Rotation;
import static pp.util.FloatMath.HALF_PI; import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI; import static pp.util.FloatMath.PI;
@ -62,7 +61,6 @@ class GameBoardSynchronizer extends BoardSynchronizer {
* @param ship the battleship to be represented * @param ship the battleship to be represented
* @return the node containing the graphical representation of the battleship * @return the node containing the graphical representation of the battleship
*/ */
@Override
public Spatial visit(Figure figure) { public Spatial visit(Figure figure) {
final Node node = new Node(FIGURE); final Node node = new Node(FIGURE);
node.attachChild(createBox(figure)); node.attachChild(createBox(figure));

View File

@ -55,7 +55,7 @@ class MapView {
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
Geometry background = new Geometry("MapBackground", new Quad(board.getWidth() * FIELD_SIZE, board.getHeight() * FIELD_SIZE)); Geometry background = new Geometry("MapBackground", new Quad(board.getWidth() * FIELD_SIZE, board.getHeight() * FIELD_SIZE));
background.setMaterial(mat); background.setMaterial(mat);
background.setLocalTranslation(0f, 0f, BACKGROUND_DEPTH); background.setLocalTranslation(0f, 1f, BACKGROUND_DEPTH);
background.setCullHint(CullHint.Never); background.setCullHint(CullHint.Never);
mapNode.attachChild(background); mapNode.attachChild(background);
} }

View File

@ -38,7 +38,7 @@ class MapViewSynchronizer extends BoardSynchronizer {
view.getNode().detachAllChildren(); // Entfernt alle visuellen Elemente vom Knoten view.getNode().detachAllChildren(); // Entfernt alle visuellen Elemente vom Knoten
} }
@Override
public Spatial visit(Figure figure) { public Spatial visit(Figure figure) {
return figure.accept(this); return figure.accept(this);
} }

View File

@ -1,12 +1,7 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type; import com.jme3.effect.ParticleMesh.Type;
import com.jme3.effect.shapes.EmitterSphereShape;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
/** /**

View File

@ -88,8 +88,13 @@ public class SettingsMenu extends Dialog {
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(settingsContainer); System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(overlayBackground); app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü
app.setSettingsMenuOpen(false); 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
} }
} }

View File

@ -1,39 +1,78 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import pp.monopoly.client.MonopolyApp;
/** /**
* TestWorld zeigt eine einfache Szene mit einem texturierten Quadrat. * 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 private final MonopolyApp app;
public void simpleInitApp() { private CameraController cameraController; // Steuert die Kamera
/**
* 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
createBoard(); // Erstelle das Spielfeld
// 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
);
// Deaktiviere den Maus-Cursor
app.enqueue(() -> app.getInputManager().setCursorVisible(false));
}
/**
* Aktualisiert die Kameraposition.
*
* @param tpf Zeit pro Frame
*/
public void update(float tpf) {
if (cameraController != null) {
cameraController.update(tpf);
}
}
/**
* Erstelle das Spielfeld.
*/
private void createBoard() {
// Erstelle ein Quadrat // Erstelle ein Quadrat
Box box = new Box(1, 0.01f, 1); // Dünnes Quadrat für die Textur 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("Box", box);
// Setze das Material mit Textur // Setze das Material mit Textur
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
Texture texture = assetManager.loadTexture("Pictures/board.png"); // Ersetze durch den Pfad zum gewünschten Bild Texture texture = app.getAssetManager().loadTexture("Pictures/board.png");
mat.setTexture("ColorMap", texture); mat.setTexture("ColorMap", texture);
geom.setMaterial(mat); geom.setMaterial(mat);
// Füge das Quadrat zur Szene hinzu app.getRootNode().attachChild(geom);
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);
}
public static void startTestWorld() {
TestWorld testWorldApp = new TestWorld();
testWorldApp.start();
} }
} }

View File

@ -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);
}
}