47 Commits

Author SHA1 Message Date
Felix Koppe
c4e5b7f7c8 Merge main 2024-11-28 15:02:41 +01:00
Felix
35cf092d5c Merge commit 2024-11-27 08:44:29 +01:00
Felix
06e2d831ef Fix errors 2024-11-27 08:42:45 +01:00
Felix
75b53f8309 Fix model compile errors 2024-11-27 08:39:50 +01:00
Felix
58f94e73db Merge commit 2024-11-26 20:23:23 +01:00
Fleischer Hanno
46a6552bca refactored the whole client package structure 2024-11-26 11:12:58 +01:00
Fleischer Hanno
1d95146272 refactored the model to incoporate a correct folder structure 2024-11-26 11:12:56 +01:00
Benjamin Feyer
9859d52e02 edted some tests with null tests 2024-11-26 11:12:55 +01:00
Benjamin Feyer
e18ea15efa added javadocs 2024-11-26 11:12:54 +01:00
Benjamin Feyer
461a497353 added some more testmethods 2024-11-26 11:12:54 +01:00
Benjamin Feyer
4c3099ddf2 corrected testmethods in clientStateTest 2024-11-26 11:12:54 +01:00
Benjamin Feyer
b0ab870451 added tests in the serverStateTest
added the testmethods for rolldice and movepiece
2024-11-26 11:12:54 +01:00
Benjamin Feyer
993c94c306 edited some tests in ServerStateTest 2024-11-26 11:12:54 +01:00
Benjamin Feyer
e52af59cac minor changes 2024-11-26 11:12:54 +01:00
Benjamin Feyer
40f1bdb51f added some testmethods and corrected other in the clientStatemachineTests 2024-11-26 11:12:54 +01:00
Benjamin Feyer
436dae4ebc added some testmethods for the client testing the statechanges in the dialogs 2024-11-26 11:12:54 +01:00
Benjamin Feyer
1b2d4df96f added some mor testcases for the clientstatemachine 2024-11-26 11:12:54 +01:00
Benjamin Feyer
f3ca9f01c0 added the empty testmethods in serverstateTest and edited the testmethods for substates of choocePiece in Client into MovePiece 2024-11-26 11:12:54 +01:00
Benjamin Feyer
3c97cdae38 edited a test in the clientStateTest 2024-11-26 11:12:54 +01:00
Benjamin Feyer
227d4286e5 editet tests for the server and client statemachines 2024-11-26 11:12:54 +01:00
Benjamin Feyer
9939ec2861 added empty serverstatetests 2024-11-26 11:12:54 +01:00
Benjamin Feyer
1a6a460f9f initial test commit,
added all testclasses except Playertest, Viewtest, Cameratest, SettingsTest, SoundTest, ReactionTest and ClientStateTest. And filled all created testclasses with empty testmethods, except ServerStateTest.
2024-11-26 11:12:54 +01:00
Daniel Grigencha
ec58e9c85f added import statement with the refactored server messages 2024-11-26 11:12:54 +01:00
Daniel Grigencha
cf6777023f added mdga server controller 2024-11-26 11:12:54 +01:00
Daniel Grigencha
739279d3df added new server state chart 2024-11-26 11:12:52 +01:00
Daniel Grigencha
b6bf25671f reverted server messages 2024-11-26 11:12:50 +01:00
Daniel Grigencha
5a9fd2a939 deleted server state automaton 2024-11-26 11:12:49 +01:00
Hanno Fleischer
e1b21de718 added two Pieces in RequestPlayCard in order to differentiate between own and enemy pieces 2024-11-26 11:12:39 +01:00
Hanno Fleischer
f321608132 added two lists in PossiblePiece in order to differentiate between own and enemy pieces 2024-11-26 11:12:39 +01:00
Hanno Fleischer
dd7a27629b added static methods to construct a PlayCard message for each card type 2024-11-26 11:12:39 +01:00
Hanno Fleischer
eba681c350 added getter for ArrayList Player in Game and created a flag for ready status in Player 2024-11-26 11:12:39 +01:00
Daniel Grigencha
f97eea3e5e added default constructor for serialization purposes 2024-11-26 11:12:39 +01:00
Hanno Fleischer
1582038dfe added an ArrayList of Player in game and added the received methods in clientgamelogic 2024-11-26 11:12:39 +01:00
Daniel Grigencha
798e996a8d fixed sonarlint errors and deleted map playerConnectionID 2024-11-26 11:12:39 +01:00
Fleischer Hanno
472d87b0c9 refactored ceremony message 2024-11-26 11:12:39 +01:00
Fleischer Hanno
7cfb863e5c corrected refactoring mistake, ich which RankingResponce was renamed to RankingResponse 2024-11-26 11:12:35 +01:00
Fleischer Hanno
7e1d2e833e added getter for dialogstatemachine in dialogs 2024-11-26 11:12:30 +01:00
Fleischer Hanno
67a87ffa81 made all con structors of clients states public 2024-11-26 11:12:30 +01:00
Daniel Grigencha
12fbf4e77e added javadocs to all server messages 2024-11-26 11:12:30 +01:00
Daniel Grigencha
f6d16a81bf added javadocs to all client messages 2024-11-26 11:12:30 +01:00
Fleischer Hanno
6938ce16b7 added the constructors for all client states and their statemachines 2024-11-26 11:12:30 +01:00
Daniel Grigencha
85ea4d340c added more logic for the server state diagram 2024-11-26 11:12:30 +01:00
Fleischer Hanno
e3d5d8e2e9 added message contents to the messages
addedn the conentents for all messages regarding the BPMN diagramm and own interpretation.
also created an identifier for pieces to be used for network communication between server and client so that they talk about the same piece.
2024-11-26 11:12:30 +01:00
Daniel Grigencha
6dfb2980fa added more logic for the server state diagram 2024-11-26 11:12:26 +01:00
Fleischer Hanno
f3894a5058 added a method to check if a player has pieces in his waiting area 2024-11-26 11:11:51 +01:00
Hanno Fleischer
787d8b558c added the method tryMove and the methods used by it into serverstate 2024-11-26 11:11:51 +01:00
Daniel Grigencha
3949a00932 added more logic for the server state diagram 2024-11-26 11:11:51 +01:00
349 changed files with 3636 additions and 94009 deletions

View File

@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MdgaApp" type="Application" factoryName="Application" singleton="false" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="pp.mdga.client.MdgaApp" />
<module name="Projekte.mdga.client.main" />
<option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties -ea" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.mdga.client.board.Outline.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,133 +1,76 @@
package pp.mdga.client; package pp.mdga.client;
/**
* Represents different assets in the application. Each asset may have an associated model path,
* diffuse texture path, and a size factor. The enum provides multiple constructors to handle
* varying levels of detail for different assets.
*/
public enum Asset { public enum Asset {
bigTent, bigTent,
cardStack, cardStack,
cir("Models/cir/cir_newOrigin.obj"), cir,
heer("Models/heer/heer_newOrigin.obj"), heer,
jet, jet,
lw("Models/lw/lw_newOrigin.obj"), lw,
marine("Models/marine/marine_newOrigin.obj"), marine,
node_home_blue("Models/node_home/node_home.j3o", "Models/node_home/node_home_blue_diff.png"), node_home_blue("./node_home/node_home.j3o", "./node_home/node_home_blue_diff.png"),
node_wait_blue("Models/node_home/node_home.j3o", "Models/node_home/node_home_blue_diff.png"), node_wait_blue("./node_home/node_home.j3o", "./node_home/node_home_blue_diff.png"),
node_home_black("Models/node_home/node_home.j3o", "Models/node_home/node_home_black_diff.png"), node_home_black("./node_home/node_home.j3o", "./node_home/node_home_black_diff.png"),
node_wait_black("Models/node_home/node_home.j3o", "Models/node_home/node_home_black_diff.png"), node_wait_black("./node_home/node_home.j3o", "./node_home/node_home_black_diff.png"),
node_home_green("Models/node_home/node_home.j3o", "Models/node_home/node_home_green_diff.png"), node_home_green("./node_home/node_home.j3o", "./node_home/node_home_green_diff.png"),
node_wait_green("Models/node_home/node_home.j3o", "Models/node_home/node_home_green_diff.png"), node_wait_green("./node_home/node_home.j3o", "./node_home/node_home_green_diff.png"),
node_home_yellow("Models/node_home/node_home.j3o", "Models/node_home/node_home_orange_diff.png"), node_home_yellow("./node_home/node_home.j3o", "./node_home/node_home_orange_diff.png"),
node_wait_yellow("Models/node_home/node_home.j3o", "Models/node_home/node_home_orange_diff.png"), node_wait_yellow("./node_home/node_home.j3o", "./node_home/node_home_orange_diff.png"),
node_normal, node_normal,
node_start("Models/node_normal/node_normal.j3o", "Models/node_normal/node_start_diff.png"), node_start("./node_normal/node_normal.j3o", "./node_normal/node_start_diff.png"),
node_bonus("Models/node_normal/node_normal.j3o", "Models/node_normal/node_bonus_diff.png"), node_bonus("./node_normal/node_normal.j3o", "./node_normal/node_bonus_diff.png"),
radar, radar,
ship(0.8f), ship(0.8f),
smallTent, smallTent,
tank, tank,
world("Models/world_new/world_export_new.obj", "Models/world_new/world_new_diff.png", 1.2f), // world(1.2f),
shield_ring("Models/shield_ring/shield_ring.obj", null), world("./world_new/world_export_new.obj", "./world_new/world_new_diff.png", 1.2f),
tree_small("Models/tree_small/tree_small.obj", "Models/tree_small/tree_small_diff.png"), shield_ring("./shield_ring/shield_ring.obj", null),
tree_big("Models/tree_big/tree_big.obj", "Models/tree_big/tree_big_diff.png"), tree_small("./tree_small/tree_small.obj", "./tree_small/tree_small_diff.png"),
turboCard("Models/turboCard/turboCard.obj", "Models/turboCard/turboCard_diff.png"), tree_big("./tree_big/tree_big.obj", "./tree_big/tree_big_diff.png"),
turboSymbol("Models/turboCard/turboSymbol.obj", "Models/turboCard/turboCard_diff.png"), turboCard,
swapCard("Models/swapCard/swapCard.obj", "Models/swapCard/swapCard_diff.png"), swapCard,
swapSymbol("Models/swapCard/swapSymbol.obj", "Models/swapCard/swapCard_diff.png"), shieldCard
shieldCard("Models/shieldCard/shieldCard.obj", "Models/shieldCard/shieldCard_diff.png"),
shieldSymbol("Models/shieldCard/shieldSymbol.obj", "Models/shieldCard/shieldCard_diff.png"),
dice("Models/dice/dice.obj", "Models/dice/dice_diff.jpeg")
; ;
private final String modelPath; private final String modelPath;
private final String diffPath; private final String diffPath;
private final float size; private final float size;
private static final String root = "Models/";
/**
* Default constructor. Initializes modelPath and diffPath based on the enum name and sets default size to 1.0.
*/
Asset() { Asset() {
String folderFileName = "./" + root + name() + "/" + name(); String folderFileName = "./" + name() + "/" + name();
this.modelPath = folderFileName + ".j3o"; this.modelPath = folderFileName + ".j3o";
this.diffPath = folderFileName + "_diff.png"; this.diffPath = folderFileName + "_diff.png";
this.size = 1f; this.size = 1f;
} }
/**
* Constructor with specific model path and diffuse texture path.
*
* @param modelPath Path to the 3D model file.
* @param diffPath Path to the diffuse texture file.
*/
Asset(String modelPath, String diffPath) { Asset(String modelPath, String diffPath) {
this.modelPath = modelPath; this.modelPath = modelPath;
this.diffPath = diffPath; this.diffPath = diffPath;
this.size = 1f; this.size = 1f;
} }
/**
* Constructor with specific model path. Diffuse texture path is derived based on enum name.
*
* @param modelPath Path to the 3D model file.
*/
Asset(String modelPath) {
String folderFileName = "./" + root + name() + "/" + name();
this.modelPath = modelPath;
this.diffPath = folderFileName + "_diff.png";;
this.size = 1f;
}
/**
* Constructor with specific size. Model and texture paths are derived based on enum name.
*
* @param size Scaling factor for the asset.
*/
Asset(float size) { Asset(float size) {
String folderFileName = "./" + root + name() + "/" + name(); String folderFileName = "./" + name() + "/" + name();
this.modelPath = folderFileName + ".j3o"; this.modelPath = folderFileName + ".j3o";
this.diffPath = folderFileName + "_diff.png"; this.diffPath = folderFileName + "_diff.png";
this.size = size; this.size = size;
} }
/**
* Constructor with specific model path, diffuse texture path, and size.
*
* @param modelPath Path to the 3D model file.
* @param diffPath Path to the diffuse texture file.
* @param size Scaling factor for the asset.
*/
Asset(String modelPath, String diffPath, float size){ Asset(String modelPath, String diffPath, float size){
this.modelPath = modelPath; this.modelPath = modelPath;
this.diffPath = diffPath; this.diffPath = diffPath;
this.size = size; this.size = size;
} }
/**
* Gets the model path for the asset.
*
* @return Path to the 3D model file.
*/
public String getModelPath() { public String getModelPath() {
return modelPath; return modelPath;
} }
/**
* Gets the diffuse texture path for the asset.
*
* @return Path to the diffuse texture file, or null if not applicable.
*/
public String getDiffPath() { public String getDiffPath() {
return diffPath; return diffPath;
} }
/**
* Gets the scaling factor for the asset.
*
* @return The size of the asset.
*/
public float getSize() { public float getSize() {
return size; return size;
} }

View File

@@ -1,288 +0,0 @@
package pp.mdga.client;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.*;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import pp.mdga.client.board.NodeControl;
import pp.mdga.client.board.OutlineControl;
import pp.mdga.client.board.PieceControl;
import pp.mdga.client.gui.CardControl;
import pp.mdga.client.view.GameView;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import pp.mdga.game.Piece;
import pp.mdga.notification.SelectableCardsNotification;
import java.util.List;
public class InputSynchronizer {
private MdgaApp app;
private InputManager inputManager;
protected boolean rightMousePressed = false;
private float rotationAngle = 180f;
private int scrollValue = 0;
private CardControl hoverCard;
private PieceControl hoverPiece;
/**
* Constructor initializes the InputSynchronizer with the application context.
* Sets up input mappings and listeners for user interactions.
*
* @param app The application instance
*/
InputSynchronizer(MdgaApp app) {
this.app = app;
this.inputManager = app.getInputManager();
hoverCard = null;
hoverPiece = null;
setupInput();
}
/**
* Configures input mappings for various actions and binds them to listeners.
*/
private void setupInput() {
inputManager.addMapping("Settings", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_RETURN));
inputManager.addMapping("RotateRightMouse", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addMapping("MouseLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); // Left movement
inputManager.addMapping("MouseRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); // Right movement
inputManager.addMapping("MouseVertical", new MouseAxisTrigger(MouseInput.AXIS_Y, false), new MouseAxisTrigger(MouseInput.AXIS_Y, true)); //Mouse Up Down movement
inputManager.addMapping("MouseScrollUp", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); // Scroll up
inputManager.addMapping("MouseScrollDown", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); // Scroll down
inputManager.addMapping("Test", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, "Settings", "Forward", "RotateRightMouse", "Click", "Test");
inputManager.addListener(analogListener, "MouseLeft", "MouseRight", "MouseScrollUp", "MouseScrollDown");
}
private boolean test = false;
/**
* Handles action-based input events such as key presses and mouse clicks.
*/
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("Settings") && isPressed) {
app.getView().pressEscape();
}
if (name.equals("Forward") && isPressed) {
app.getView().pressForward();
}
if (name.equals("RotateRightMouse")) {
rightMousePressed = isPressed;
}
if(name.equals("Click") && isPressed) {
if (app.getView() instanceof GameView gameView) {
CardControl cardLayerSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), CardControl.class);
OutlineControl boardSelect = checkHover(app.getCamera(), app.getRootNode(), OutlineControl.class);
if(cardLayerSelect != null) {
//cardSelect
if(cardLayerSelect.isSelectable()) gameView.getGuiHandler().selectCard(cardLayerSelect);
}
else if(boardSelect != null) {
//boardSelect
if(boardSelect instanceof PieceControl pieceControl){
if(pieceControl.isSelectable()) gameView.getBoardHandler().pieceSelect(pieceControl);
}
if(boardSelect instanceof NodeControl nodeControl){
//
}
}
else {
//both null
}
}
}
if(name.equals("Test") &&isPressed){
if(app.getView() instanceof GameView gameView){
app.getNotificationSynchronizer().addTestNotification(new SelectableCardsNotification(List.of(BonusCard.SHIELD)));
}
}
}
};
/**
* Handles analog-based input events such as mouse movement and scrolling.
*/
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
if (name.equals("MouseLeft") && rightMousePressed) {
rotationAngle -= value * 360f;
}
else if (name.equals("MouseRight") && rightMousePressed) {
rotationAngle += value * 360f;
}
else if (name.equals("MouseScrollUp")) {
scrollValue = Math.max(1, scrollValue - 5);
}
else if (name.equals("MouseScrollDown")) {
scrollValue = Math.min(100, scrollValue + 5);
}
else if (name.equals("MouseLeft") || name.equals("MouseRight") || name.equals("MouseVertical")){
hoverPiece();
hoverCard();
}
}
};
/**
* Detects the hovered piece and updates its hover state.
*/
private <T extends AbstractControl> T checkHover(Camera cam, Node root, Class<T> controlType) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), getMousePos(cam).subtract(cam.getLocation()).normalize());
root.collideWith(ray, results);
for(CollisionResult collisionResult : results){
if(collisionResult.getGeometry().getControl(controlType) != null) return collisionResult.getGeometry().getControl(controlType);
}
return null;
}
/**
* Detects the hovered card and updates its hover state.
*/
private <T extends AbstractControl> T checkHoverOrtho(Camera cam, Node root, Class<T> controlType) {
CollisionResults results = new CollisionResults();
Vector3f mousePos = getMousePos(cam);
mousePos.setZ(cam.getLocation().getZ());
Ray ray = new Ray(mousePos, getMousePos(cam).subtract(mousePos).normalize());
root.collideWith(ray, results);
if (results.size() > 0) {
for(CollisionResult res : results ){
T control = res.getGeometry().getControl(controlType);
if(control != null) return control;
}
}
return null;
}
/**
* Handles the hover state for a piece in the game.
* Checks if a piece is being hovered over, updates the hover state, and triggers hover effects.
*/
private void hoverPiece() {
if (app.getView() instanceof GameView gameView) {
PieceControl control = checkPiece();
if (control != null) {
if (control != hoverPiece) {
pieceOff();
hoverPiece = control;
hoverPiece.hover();
}
} else {
pieceOff();
}
}
}
/**
* Handles the hover state for a card in the game.
* Checks if a card is being hovered over, updates the hover state, and triggers hover effects.
*/
private void hoverCard() {
if (app.getView() instanceof GameView gameView) {
CardControl control = checkCard(gameView);
if (control != null) {
if (control != hoverCard) {
cardOff();
hoverCard = control;
hoverCard.hover();
}
} else {
cardOff();
}
}
}
/**
* Checks if a piece is being hovered over in the 3D game world.
*
* @return The PieceControl of the hovered piece, or null if no piece is hovered.
*/
private PieceControl checkPiece() {
return checkHover(app.getCamera(), app.getRootNode(), PieceControl.class);
}
/**
* Checks if a card is being hovered over in the 2D card layer.
*
* @param gameView The current game view.
* @return The CardControl of the hovered card, or null if no card is hovered.
*/
private CardControl checkCard(GameView gameView) {
return checkHoverOrtho(
gameView.getGuiHandler().getCardLayerCamera(),
gameView.getGuiHandler().getCardLayerRootNode(),
CardControl.class
);
}
/**
* Disables the hover effect on the currently hovered piece, if any.
*/
private void pieceOff() {
if (hoverPiece != null) hoverPiece.hoverOff();
hoverPiece = null;
}
/**
* Disables the hover effect on the currently hovered card, if any.
*/
private void cardOff() {
if (hoverCard != null) hoverCard.hoverOff();
hoverCard = null;
}
/**
* Retrieves the current mouse position in the 3D world using the specified camera.
*
* @param cam The camera used for determining the mouse position.
* @return A Vector3f representing the mouse position in the 3D world.
*/
private Vector3f getMousePos(Camera cam) {
Vector2f mousePositionScreen = inputManager.getCursorPosition();
Vector3f world = cam.getWorldCoordinates(mousePositionScreen, 0);
if (cam.isParallelProjection()) world.setZ(0);
return world;
}
/**
* Gets the current rotation angle of the game element.
*
* @return The rotation angle in degrees, normalized to 360 degrees.
*/
public float getRotation() {
return (rotationAngle / 2) % 360;
}
/**
* Gets the current scroll value.
*
* @return The scroll value as an integer.
*/
public int getScroll() {
return scrollValue;
}
}

View File

@@ -0,0 +1,72 @@
package pp.mdga.client;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.*;
public class InputSyncronizer {
private MdgaApp app;
private InputManager inputManager;
protected boolean rightMousePressed = false;
private float rotationAngle = 180f;
private int scrollValue = 0;
InputSyncronizer(MdgaApp app) {
this.app = app;
this.inputManager = app.getInputManager();
setupInput();
}
private void setupInput() {
inputManager.addMapping("Settings", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping("RotateRightMouse", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addMapping("MouseLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); // Left movement
inputManager.addMapping("MouseRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); // Right movement
inputManager.addMapping("MouseScrollUp", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); // Scroll up
inputManager.addMapping("MouseScrollDown", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); // Scroll down
inputManager.addListener(actionListener, "Settings", "RotateRightMouse");
inputManager.addListener(analogListener, "MouseLeft", "MouseRight", "MouseScrollUp", "MouseScrollDown");
}
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("Settings") && isPressed) {
app.getView().pressEscape();
}
if (name.equals("RotateRightMouse")) {
rightMousePressed = isPressed;
}
}
};
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
if (name.equals("MouseLeft") && rightMousePressed) {
rotationAngle -= value * 360f;
} else if (name.equals("MouseRight") && rightMousePressed) {
rotationAngle += value * 360f;
} else if (name.equals("MouseScrollUp")) {
scrollValue = Math.max(1, scrollValue - 5);
} else if (name.equals("MouseScrollDown")) {
scrollValue = Math.min(100, scrollValue + 5);
}
}
};
public float getRotation() {
return (rotationAngle / 2) % 360;
}
public int getScroll() {
return scrollValue;
}
}

View File

@@ -7,60 +7,29 @@
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import pp.mdga.client.view.*; import pp.mdga.client.view.*;
/**
* Main application class for the MdgaApp game.
* This class extends {@link SimpleApplication} and manages the game's lifecycle, states, and main components.
*/
public class MdgaApp extends SimpleApplication { public class MdgaApp extends SimpleApplication {
/** Handles animations in the application. */
private AnimationHandler animationHandler; private AnimationHandler animationHandler;
/** Handles acoustic effects and state-based sounds. */
private AcousticHandler acousticHandler; private AcousticHandler acousticHandler;
/** Synchronizes notifications throughout the application. */
private NotificationSynchronizer notificationSynchronizer; private NotificationSynchronizer notificationSynchronizer;
private InputSyncronizer inputSyncronizer;
private ModelSyncronizer modelSyncronizer;
/** Manages input events and synchronization. */ MdgaView view = null;
private InputSynchronizer inputSynchronizer; private MdgaState state = MdgaState.MAIN;
/** Synchronizes game models. */ private static float resolutionFactor = 1.8f;
private ModelSynchronizer modelSynchronizer;
/** The currently active view in the application. */
private MdgaView view = null;
/** The current state of the application. */
private MdgaState state = null;
/** Scale for rendering images. */
private static final float IMAGE_SCALE = 1.5f;
/** The main menu view. */
private MdgaView mainView;
/** The lobby view. */
private MdgaView lobbyView;
/** The game view. */
private MdgaView gameView;
/** The ceremony view. */
private MdgaView ceremonyView;
/**
* Main entry point for the application.
* Configures settings and starts the application.
*
* @param args command-line arguments (not used)
*/
public static void main(String[] args) { public static void main(String[] args) {
AppSettings settings = new AppSettings(true); AppSettings settings = new AppSettings(true);
settings.setSamples(128); settings.setSamples(128);
settings.setCenterWindow(true); settings.setCenterWindow(true);
settings.setWidth(1920);
settings.setHeight(1080); int width = (int)(1280 * resolutionFactor);
int height = (int)(720 * resolutionFactor);
settings.setWidth(width);
settings.setHeight(height);
settings.setVSync(false); settings.setVSync(false);
MdgaApp app = new MdgaApp(); MdgaApp app = new MdgaApp();
@@ -69,51 +38,33 @@ public static void main(String[] args) {
app.start(); app.start();
} }
/**
* Initializes the application by setting up handlers, views, and entering the default state.
*/
@Override @Override
public void simpleInitApp() { public void simpleInitApp() {
GuiGlobals.initialize(this);
inputManager.deleteMapping("SIMPLEAPP_Exit");
flyCam.setEnabled(false);
animationHandler = new AnimationHandler(this); animationHandler = new AnimationHandler(this);
acousticHandler = new AcousticHandler(this); acousticHandler = new AcousticHandler(this);
notificationSynchronizer = new NotificationSynchronizer(this); notificationSynchronizer = new NotificationSynchronizer(this);
inputSynchronizer = new InputSynchronizer(this); inputSyncronizer = new InputSyncronizer(this);
modelSynchronizer = new ModelSynchronizer(this); modelSyncronizer = new ModelSyncronizer(this);
mainView = new MainView(this); inputManager.deleteMapping("SIMPLEAPP_Exit");
lobbyView = new LobbyView(this); inputManager.deleteMapping("FLYCAM_ZoomIn");
gameView = new GameView(this); inputManager.deleteMapping("FLYCAM_ZoomOut");
ceremonyView = new CeremonyView(this); inputManager.deleteMapping("FLYCAM_RotateDrag");
flyCam.setEnabled(false);
GuiGlobals.initialize(this);
enter(MdgaState.MAIN); enter(state);
} }
/**
* Updates the application on each frame. Updates the view, acoustic handler, and notifications.
*
* @param tpf time per frame, used for smooth updating
*/
@Override @Override
public void simpleUpdate(float tpf) { public void simpleUpdate(float tpf) {
view.update(tpf); view.update();
acousticHandler.update(); acousticHandler.update();
notificationSynchronizer.update(); notificationSynchronizer.update();
} }
/**
* Transitions the application to a new state.
*
* @param state the new state to enter
* @throws RuntimeException if attempting to enter the {@link MdgaState#NONE} state
*/
public void enter(MdgaState state) { public void enter(MdgaState state) {
if (null != view) { if(null != view) {
view.leave(); view.leave();
} }
@@ -121,19 +72,19 @@ public void enter(MdgaState state) {
switch (state) { switch (state) {
case MAIN: case MAIN:
view = mainView; view = new MainView(this);
break; break;
case LOBBY: case LOBBY:
view = lobbyView; view = new LobbyView(this);
break; break;
case GAME: case GAME:
view = gameView; view = new GameView(this);
break; break;
case CEREMONY: case CEREMONY:
view = ceremonyView; view = new CeremonyView(this);
break; break;
case NONE: case NONE:
throw new RuntimeException("Cannot enter state NONE"); throw new RuntimeException("cant enter state NONE");
} }
acousticHandler.playState(state); acousticHandler.playState(state);
@@ -141,83 +92,31 @@ public void enter(MdgaState state) {
view.enter(); view.enter();
} }
/** public void afteGameCleanup() {
* Gets the animation handler. //TODO
* }
* @return the {@link AnimationHandler} instance
*/
public AnimationHandler getAnimationHandler() { public AnimationHandler getAnimationHandler() {
return animationHandler; return animationHandler;
} }
/**
* Gets the acoustic handler.
*
* @return the {@link AcousticHandler} instance
*/
public AcousticHandler getAcousticHandler() { public AcousticHandler getAcousticHandler() {
return acousticHandler; return acousticHandler;
} }
/** public MdgaState getState() {return state; }
* Gets the current state of the application.
* public float getResolutionFactor() {
* @return the current {@link MdgaState} return resolutionFactor;
*/
public MdgaState getState() {
return state;
} }
/**
* Gets the image scaling factor.
*
* @return the image scale as a float
*/
public float getImageScale() {
return IMAGE_SCALE;
}
/**
* Gets the currently active view.
*
* @return the active {@link MdgaView}
*/
public MdgaView getView() { public MdgaView getView() {
return view; return view;
} }
/** public ModelSyncronizer getModelSyncronizer() {
* Gets the model synchronizer. return modelSyncronizer;
*
* @return the {@link ModelSynchronizer} instance
*/
public ModelSynchronizer getModelSynchronize() {
return modelSynchronizer;
} }
/** public InputSyncronizer getInputSyncronizer() { return inputSyncronizer; }
* Gets the input synchronizer.
*
* @return the {@link InputSynchronizer} instance
*/
public InputSynchronizer getInputSynchronize() {
return inputSynchronizer;
}
/**
* Gets the notification synchronizer.
*
* @return the {@link NotificationSynchronizer} instance
*/
public NotificationSynchronizer getNotificationSynchronizer() {
return notificationSynchronizer;
}
/**
* Prepares the app for a new game cycle.
*/
public void setup() {
}
} }

View File

@@ -1,35 +1,9 @@
package pp.mdga.client; package pp.mdga.client;
/**
* Enum representing the various states of the MdgaApp application.
* Each state corresponds to a distinct phase or mode of the application.
*/
public enum MdgaState { public enum MdgaState {
/**
* Represents an undefined or uninitialized state.
* This state should not be entered during normal application execution.
*/
NONE, NONE,
/**
* Represents the main menu state.
* This is typically the first state entered when the application starts.
*/
MAIN, MAIN,
/**
* Represents the lobby state where players can prepare or wait before starting a game.
*/
LOBBY, LOBBY,
/**
* Represents the main gameplay state where the core game mechanics take place.
*/
GAME, GAME,
/**
* Represents the ceremony state, typically used for post-game events or celebrations.
*/
CEREMONY; CEREMONY;
} }

View File

@@ -1,187 +0,0 @@
package pp.mdga.client;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.view.CeremonyView;
import pp.mdga.client.view.GameView;
import pp.mdga.client.view.LobbyView;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import pp.mdga.message.client.LobbyReadyMessage;
import pp.mdga.notification.AcquireCardNotification;
import pp.mdga.notification.DrawCardNotification;
import pp.mdga.notification.TskSelectNotification;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ModelSynchronizer {
private static final Logger LOGGER = Logger.getLogger(ModelSynchronizer.class.getName());
private MdgaApp app;
private UUID a;
private UUID b;
private BonusCard card;
ModelSynchronizer(MdgaApp app) {
this.app = app;
}
private Color testColor;
private int test = 0;
public void animationEnd() {
}
public void selectSwap(UUID a, UUID b) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectPiece");
this.a = a;
this.b = b;
GameView gameView = (GameView) app.getView();
if(a != null && b != null) {
gameView.needConfirm();
} else {
gameView.noConfirm();
}
}
public void selectPiece(UUID piece) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectPiece");
this.a = piece;
GameView gameView = (GameView) app.getView();
if(piece != null) {
gameView.needConfirm();
} else {
gameView.noConfirm();
}
}
public void selectCard(BonusCard card) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectCard");
this.card = card;
GameView gameView = (GameView) app.getView();
if(card != null) {
gameView.needConfirm();
} else {
gameView.noConfirm();
}
}
public void confirm() {
LOGGER.log(Level.INFO, "confirm");
GameView gameView = (GameView) app.getView();
if(a != null && b != null) {
//swap
gameView.getBoardHandler().clearSelectable();
} else if (a != null) {
//piece
gameView.getBoardHandler().clearSelectable();
} else if (card != null){
//card
gameView.getGuiHandler().clearSelectableCards();
} else {
throw new RuntimeException("nothing to confirm");
}
gameView.noConfirm();
}
public void selectTsk(Color color) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "selectTsk: {0}", color);
LobbyView view = (LobbyView) app.getView();
view.setTaken(color, true, true, "OwnPlayerName");
testColor = color;
}
public void unselectTsk() {
// TODO call from somewhere
LOGGER.log(Level.INFO, "unselectTsk");
}
public void rolledDice() {
// TODO call from somewhere
LOGGER.log(Level.INFO, "rolledDice");
}
public void setName(String name) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "setName: {0}", name);
}
public void setReady(boolean ready) {
LOGGER.log(Level.INFO, "setReady");
LobbyView view = (LobbyView) app.getView();
view.setReady(testColor, ready);
test++;
if(test > 2) {
testColor = null;
test = 0;
enter(MdgaState.GAME);
}
}
public void setHost(int port) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "setHost: {0}", port);
enter(MdgaState.LOBBY);
}
public void setJoin(String ip, int port) {
// TODO call from somewhere
LOGGER.log(Level.INFO, "setJoin with IP: {0}, Port: {1}", new Object[]{ip, port});
enter(MdgaState.LOBBY);
}
public void leave() {
LOGGER.log(Level.INFO, "leave");
app.getAcousticHandler().playSound(MdgaSound.LEAVE);
enter(MdgaState.MAIN);
}
public void enter(MdgaState state) {
LOGGER.log(Level.INFO, "enter: {0}", state);
app.enter(state);
if (state == MdgaState.CEREMONY) {
CeremonyView ceremonyView = (CeremonyView) app.getView();
ceremonyView.addCeremonyParticipant(Color.AIRFORCE, 1, "ugidffdg");
ceremonyView.addCeremonyParticipant(Color.ARMY, 2, "ugidffdg");
ceremonyView.addCeremonyParticipant(Color.NAVY, 3, "ugidffdg");
ceremonyView.addCeremonyParticipant(Color.CYBER, 4, "ugidffdg");
ceremonyView.addStatisticsRow("player sdgsd", 1, 2, 3, 4, 5, 6);
ceremonyView.addStatisticsRow("player sdgsd", 1, 2, 3, 4, 5, 6);
ceremonyView.addStatisticsRow("player sdgsd", 1, 2, 3, 4, 5, 6);
ceremonyView.addStatisticsRow("player sdgsd", 1, 2, 3, 4, 5, 6);
ceremonyView.addStatisticsRow("Gesamt", 1, 2, 3, 4, 5, 6);
}
if (state == MdgaState.GAME) {
GameView gameView = (GameView) app.getView();
//app.getNotificationSynchronizer().addTestNotification(new DrawCardNotification(Color.AIRFORCE, BonusCard.SHIELD));
selectPiece(UUID.randomUUID());
}
if (state == MdgaState.LOBBY) {
LobbyView lobbyView = (LobbyView) app.getView();
app.getNotificationSynchronizer().addTestNotification(new TskSelectNotification(Color.CYBER, "blablabupp", false));
app.getNotificationSynchronizer().addTestNotification(new TskSelectNotification(Color.ARMY, "Spieler 2", false));
lobbyView.setReady(Color.ARMY, true);
}
}
}

View File

@@ -0,0 +1,72 @@
package pp.mdga.client;
import pp.mdga.client.view.LobbyView;
import pp.mdga.game.Color;
public class ModelSyncronizer {
private MdgaApp app;
ModelSyncronizer(MdgaApp app) {
this.app = app;
}
public void selectPiece() {
//TODO call from somewhere
System.out.println("selectPiece");
}
public void selectCard() {
//TODO call from somewhere
System.out.println("selectCard");
}
public void selectTsk(Color color) {
//TODO call from somewhere
System.out.println("selectTsk: " + color);
LobbyView view = (LobbyView) app.getView();
view.setTaken(color, true, true, "OwnPlayerName");
}
public void unselectTsk() {
//TODO call from somewhere
System.out.println("unselectTsk");
}
public void rolledDice() {
//TODO call from somewhere
System.out.println("rolledDice");
}
public void setName(String name) {
//TODO call from somewhere
System.out.println("setName:" + name);
}
public void setReady() {
//TODO call from somewhere
System.out.println("setReady");
app.enter(MdgaState.GAME);
}
public void setHost(int port) {
//TODO call from somewhere
System.out.println("setHost: " + port);
app.enter(MdgaState.LOBBY);
}
public void setJoin(String ip, int port) {
//TODO call from somewhere
System.out.println("setJoin");
app.enter(MdgaState.LOBBY);
}
public void leave() {
System.out.println("leave");
app.enter(MdgaState.MAIN);
}
public void enter(MdgaState state) {
System.out.println("enter:" + state);
app.enter(state);
}
}

View File

@@ -1,11 +1,7 @@
package pp.mdga.client; package pp.mdga.client;
import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.gui.GuiHandler;
import pp.mdga.client.view.CeremonyView;
import pp.mdga.client.view.GameView; import pp.mdga.client.view.GameView;
import pp.mdga.client.view.LobbyView; import pp.mdga.client.view.LobbyView;
import pp.mdga.game.Color;
import pp.mdga.notification.*; import pp.mdga.notification.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -25,6 +21,7 @@ public void addTestNotification(Notification n) {
public void update() { public void update() {
//TODO fetch model notifications //TODO fetch model notifications
for (Notification n : notifications) { for (Notification n : notifications) {
switch (app.getState()) { switch (app.getState()) {
case MAIN: case MAIN:
@@ -43,7 +40,6 @@ public void update() {
throw new RuntimeException("no notification expected: " + n.toString()); throw new RuntimeException("no notification expected: " + n.toString());
} }
} }
notifications.clear();
} }
private void handleMain(Notification notification) { private void handleMain(Notification notification) {
@@ -57,14 +53,13 @@ private void handleMain(Notification notification) {
private void handleLobby(Notification notification) { private void handleLobby(Notification notification) {
LobbyView lobbyView = (LobbyView) app.getView(); LobbyView lobbyView = (LobbyView) app.getView();
if (notification instanceof TskSelectNotification n) { if (notification instanceof TskSelectNotification) {
TskSelectNotification n = (TskSelectNotification)notification;
lobbyView.setTaken(n.getColor(), true, n.isSelf(), n.getName()); lobbyView.setTaken(n.getColor(), true, n.isSelf(), n.getName());
lobbyView.setTaken(n.getColor(), true, false, n.getName()); } else if (notification instanceof TskUnselectNotification) {
} else if (notification instanceof TskUnselectNotification n) { TskUnselectNotification n = (TskUnselectNotification)notification;
lobbyView.setTaken(n.getColor(), false, false, null); lobbyView.setTaken(n.getColor(), false, false, null);
//} else if(notification instanceof LobbyReadyNotification lobbyReadyNotification) { } else if (notification instanceof GameNotification) {
//lobbyView.setReady(lobbyReadyNotification.getColor(), lobbyReadyNotification.isReady()):
} else if (notification instanceof GameNotification n) {
app.enter(MdgaState.GAME); app.enter(MdgaState.GAME);
} else { } else {
throw new RuntimeException("notification not expected: " + notification.toString()); throw new RuntimeException("notification not expected: " + notification.toString());
@@ -73,105 +68,59 @@ private void handleLobby(Notification notification) {
private void handleGame(Notification notification) { private void handleGame(Notification notification) {
GameView gameView = (GameView) app.getView(); GameView gameView = (GameView) app.getView();
GuiHandler guiHandler = gameView.getGuiHandler();
BoardHandler boardHandler = gameView.getBoardHandler();
if (notification instanceof AcquireCardNotification n) { if (notification instanceof AcquireCardNotification) {
guiHandler.addCard(n.getBonusCard()); // Handle AcquireCardNotification
} else if (notification instanceof ActivePlayerNotification n) { } else if (notification instanceof ActivePlayerNotification) {
gameView.getGuiHandler().setActivePlayer(n.getColor()); // Handle ActivePlayerNotification
} else if (notification instanceof CeremonyNotification ceremonyNotification) { } else if (notification instanceof CeremonyNotification) {
app.enter(MdgaState.CEREMONY); app.enter(MdgaState.CEREMONY);
CeremonyView ceremonyView = (CeremonyView) app.getView();
int size = ceremonyNotification.getNames().size();
if (ceremonyNotification.getPiecesThrown().size() != size ||
ceremonyNotification.getPiecesLost().size() != size ||
ceremonyNotification.getBonusCardsPlayed().size() != size ||
ceremonyNotification.getSixes().size() != size ||
ceremonyNotification.getNodesMoved().size() != size ||
ceremonyNotification.getBonusNodes().size() != size) {
throw new IllegalArgumentException("All data lists in CeremonyNotification must have the same size.");
}
for (int i = 0; i < size; i++) {
Color color = ceremonyNotification.getColors().get(i);
String name = ceremonyNotification.getNames().get(i);
int v1 = ceremonyNotification.getPiecesThrown().get(i);
int v2 = ceremonyNotification.getPiecesLost().get(i);
int v3 = ceremonyNotification.getBonusCardsPlayed().get(i);
int v4 = ceremonyNotification.getSixes().get(i);
int v5 = ceremonyNotification.getNodesMoved().get(i);
int v6 = ceremonyNotification.getBonusNodes().get(i);
ceremonyView.addCeremonyParticipant(color, i, name);
ceremonyView.addStatisticsRow(name, v1, v2, v3, v4, v5, v6);
}
} else if (notification instanceof DiceNowNotification) { } else if (notification instanceof DiceNowNotification) {
guiHandler.showDice(); // Handle DiceNowNotification
} else if (notification instanceof DicingNotification n) { } else if (notification instanceof DicingNotification) {
//TODO ??? // Handle DicingNotification
} else if (notification instanceof DrawCardNotification n) { } else if (notification instanceof DrawCardNotification) {
guiHandler.drawCard(n.getColor()); // Handle DrawCardNotification
} else if (notification instanceof HomeMoveNotification home) { } else if (notification instanceof HomeMoveNotification) {
boardHandler.moveHomePiece(home.getPieceId(), home.getHomeIndex()); HomeMoveNotification n = (HomeMoveNotification)notification;
guiHandler.hideText(); gameView.getBoardHandler().moveHomePiece(n.getPieceId(), n.getHomeIndex());
} else if (notification instanceof InterruptNotification) { } else if (notification instanceof InterruptNotification) {
app.enter(MdgaState.LOBBY); // Handle InterruptNotification
} else if (notification instanceof MovePieceNotification n) { } else if (notification instanceof MovePieceNotification) {
if(n.isMoveStart()) { MovePieceNotification n = (MovePieceNotification)notification;
//StartMove //gameView.getBoardHandler().movePiece(n.get); //TODO
boardHandler.movePieceStart(n.getPiece(), n.getMoveIndex()); } else if (notification instanceof MoveThrowPieceNotification) {
} MoveThrowPieceNotification n = (MoveThrowPieceNotification)notification;
else { //gameView.getBoardHandler().throwPiece(n.); //TODO
//InfieldMove } else if (notification instanceof NoShieldNotification) {
boardHandler.movePiece(n.getPiece(), n.getStartIndex(), n.getMoveIndex()); NoShieldNotification n = (NoShieldNotification)notification;
} gameView.getBoardHandler().unshieldPiece(n.getPieceId());
} else if (notification instanceof ThrowPieceNotification n) { } else if (notification instanceof PieceInGameNotification) {
boardHandler.throwPiece(n.getPieceId()); // Handle PieceInGameNotification
} else if (notification instanceof NoShieldNotification n) { } else if (notification instanceof PlayCardNotification) {
boardHandler.unshieldPiece(n.getPieceId()); // Handle PlayCardNotification
} else if (notification instanceof PlayCardNotification n) { } else if (notification instanceof PlayerInGameNotification) {
switch(n.getCard()){ // Handle PlayerInGameNotification
case SWAP -> guiHandler.swap();
case TURBO -> guiHandler.turbo();
case SHIELD -> guiHandler.shield();
default -> throw new RuntimeException("invalid card");
}
} else if (notification instanceof PlayerInGameNotification n) {
boardHandler.addPlayer(n.getColor(),n.getPiecesList());
guiHandler.addPlayer(n.getColor(),n.getName());
} else if (notification instanceof ResumeNotification) { } else if (notification instanceof ResumeNotification) {
//TODO // Handle ResumeNotification
} else if (notification instanceof RollDiceNotification n) { } else if (notification instanceof RollDiceNotification) {
if(n.getColor() == gameView.getOwnColor()){ // Handle RollDiceNotification
guiHandler.rollDice(n.getEyes(), n.isTurbo() ? n.getMultiplier() : -1); } else if (notification instanceof SelectableCardsNotification) {
} // Handle SelectableCardsNotification
else { } else if (notification instanceof SelectablePiecesNotification) {
if (n.isTurbo()) guiHandler.showRolledDiceMult(n.getEyes(), n.getMultiplier(), n.getColor()); // Handle SelectablePiecesNotification
else guiHandler.showRolledDice(n.getEyes(), n.getColor()); } else if (notification instanceof ShieldActiveNotification) {
} ShieldActiveNotification n = (ShieldActiveNotification)notification;
} else if (notification instanceof SelectableCardsNotification n) { gameView.getBoardHandler().shieldPiece(n.getPieceId());
guiHandler.setSelectableCards(n.getCards()); } else if (notification instanceof ShieldSuppressedNotification) {
} else if (notification instanceof ShieldActiveNotification n) { ShieldSuppressedNotification n = (ShieldSuppressedNotification)notification;
boardHandler.shieldPiece(n.getPieceId()); gameView.getBoardHandler().suppressShield(n.getPieceId());
} else if (notification instanceof ShieldSuppressedNotification n) {
boardHandler.suppressShield(n.getPieceId());
} else if (notification instanceof StartDialogNotification) { } else if (notification instanceof StartDialogNotification) {
app.enter(MdgaState.MAIN); app.enter(MdgaState.MAIN);
} else if (notification instanceof SwapPieceNotification n) { } else if (notification instanceof SwapPieceNotification) {
boardHandler.swapPieces(n.getFirstPiece(), n.getSecondPiece()); // Handle SwapPieceNotification
guiHandler.swap();
} else if (notification instanceof WaitMoveNotification) { } else if (notification instanceof WaitMoveNotification) {
//TODO ??? // Handle WaitMoveNotification
} else if (notification instanceof SelectableMoveNotification n) {
boardHandler.outlineMove(n.getPieces(), n.getMoveIndexe(), n.getHomeMoves());
} else if (notification instanceof SelectableSwapNotification n) {
boardHandler.outlineSwap(n.getOwnPieces(), n.getEnemyPieces());
} else if (notification instanceof SelectableShieldNotification n) {
boardHandler.outlineShield(n.getPieces());
} else if (notification instanceof TurboActiveNotification){
guiHandler.turbo();
} else { } else {
throw new RuntimeException("notification not expected: " + notification.toString()); throw new RuntimeException("notification not expected: " + notification.toString());
} }

View File

@@ -5,7 +5,6 @@
import pp.mdga.client.MdgaState; import pp.mdga.client.MdgaState;
import java.util.*; import java.util.*;
import java.util.prefs.Preferences;
public class AcousticHandler { public class AcousticHandler {
private MdgaApp app; private MdgaApp app;
@@ -24,20 +23,14 @@ public class AcousticHandler {
private GameMusic scheduled = null; // Scheduled track to play next private GameMusic scheduled = null; // Scheduled track to play next
private GameMusic old = null; // Old track being faded out private GameMusic old = null; // Old track being faded out
private float mainVolume = 0.0f; private float mainVolume = 1.0f;
private float musicVolume = 1.0f; private float musicVolume = 1.0f;
private float soundVolume = 1.0f; private float soundVolume = 1.0f;
private ArrayList<GameSound> sounds = new ArrayList<>(); private ArrayList<GameSound> sounds = new ArrayList<>();
private Preferences prefs = Preferences.userNodeForPackage(AcousticHandler.class);
public AcousticHandler(MdgaApp app) { public AcousticHandler(MdgaApp app) {
this.app = app; this.app = app;
mainVolume = prefs.getFloat("mainVolume", 1.0f);
musicVolume = prefs.getFloat("musicVolume", 1.0f);
soundVolume = prefs.getFloat("soundVolume", 1.0f);
} }
/** /**
@@ -74,42 +67,10 @@ public void playSound(MdgaSound sound) {
assets.add(new SoundAssetDelayVolume(SoundAsset.LOST, 1.0f, 0.0f)); assets.add(new SoundAssetDelayVolume(SoundAsset.LOST, 1.0f, 0.0f));
break; break;
case VICTORY: case VICTORY:
assets.add(new SoundAssetDelayVolume(SoundAsset.VICTORY, 1.0f, 0.0f)); assets.add(new SoundAssetDelayVolume(SoundAsset.VICTORY, 1.0f, 2.0f));
break;
case BUTTON_PRESSED:
assets.add(new SoundAssetDelayVolume(SoundAsset.BUTTON_PRESS, 0.7f, 0.0f));
break;
case WRONG_INPUT:
assets.add(new SoundAssetDelayVolume(SoundAsset.ERROR, 1.0f, 0.0f));
break;
case UI_CLICK:
assets.add(new SoundAssetDelayVolume(SoundAsset.UI_CLICK, 0.8f, 0.0f));
break;
case START:
assets.add(new SoundAssetDelayVolume(SoundAsset.START, 0.8f, 0.5f));
break;
case THROW:
assets.add(new SoundAssetDelayVolume(SoundAsset.LAUGHT, 1.0f, 0.2f));
break;
case POWERUP:
assets.add(new SoundAssetDelayVolume(SoundAsset.POWERUP, 1.0f, 0.2f));
break;
case SELF_READY:
assets.add(new SoundAssetDelayVolume(SoundAsset.ROBOT_READY, 1.0f, 0.0f));
break;
case OTHER_READY:
assets.add(new SoundAssetDelayVolume(SoundAsset.UNIT_READY, 1.0f, 0.0f));
break;
case OTHER_CONNECTED:
assets.add(new SoundAssetDelayVolume(SoundAsset.CONNECTED, 1.0f, 0.0f));
break;
case NOT_READY:
assets.add(new SoundAssetDelayVolume(SoundAsset.UI_SOUND, 1.0f, 0.0f));
break;
case LEAVE:
assets.add(new SoundAssetDelayVolume(SoundAsset.UI_SOUND2, 0.6f, 0.0f));
break; break;
default: default:
break; break;
} }
@@ -401,7 +362,6 @@ public float getSoundVolume() {
*/ */
public void setMainVolume(float mainVolume) { public void setMainVolume(float mainVolume) {
this.mainVolume = mainVolume; this.mainVolume = mainVolume;
prefs.putFloat("mainVolume", mainVolume);
} }
/** /**
@@ -411,7 +371,6 @@ public void setMainVolume(float mainVolume) {
*/ */
public void setMusicVolume(float musicVolume) { public void setMusicVolume(float musicVolume) {
this.musicVolume = musicVolume; this.musicVolume = musicVolume;
prefs.putFloat("musicVolume", musicVolume);
} }
/** /**
@@ -421,7 +380,6 @@ public void setMusicVolume(float musicVolume) {
*/ */
public void setSoundVolume(float soundVolume) { public void setSoundVolume(float soundVolume) {
this.soundVolume = soundVolume; this.soundVolume = soundVolume;
prefs.putFloat("soundVolume", soundVolume);
} }
/** /**

View File

@@ -19,16 +19,5 @@ public enum MdgaSound {
DESELECT, DESELECT,
HURRY, HURRY,
VICTORY, VICTORY,
LOST, LOST
BUTTON_PRESSED,
WRONG_INPUT,
UI_CLICK,
START,
THROW,
POWERUP,
SELF_READY,
OTHER_READY,
OTHER_CONNECTED,
NOT_READY,
LEAVE,
} }

View File

@@ -20,7 +20,6 @@ enum MusicAsset {
private final String path; private final String path;
private final boolean loop; private final boolean loop;
private final float subVolume; private final float subVolume;
private static final String root = "Music/";
/** /**
* Constructs a new MusicAsset object with the specified name and sub-volume. * Constructs a new MusicAsset object with the specified name and sub-volume.
@@ -30,7 +29,7 @@ enum MusicAsset {
* @param subVolume A relative volume that modifies the base volume of the track (typically a percentage). * @param subVolume A relative volume that modifies the base volume of the track (typically a percentage).
*/ */
MusicAsset(String name, float subVolume) { MusicAsset(String name, float subVolume) {
this.path = root + name; this.path = "music/" + name;
this.loop = false; this.loop = false;
this.subVolume = subVolume; this.subVolume = subVolume;
} }
@@ -43,7 +42,7 @@ enum MusicAsset {
* @param subVolume A relative volume that modifies the base volume of the track (typically a percentage). * @param subVolume A relative volume that modifies the base volume of the track (typically a percentage).
*/ */
MusicAsset(String name, boolean loop, float subVolume) { MusicAsset(String name, boolean loop, float subVolume) {
this.path = root + name; this.path = "music/" + name;
this.loop = loop; this.loop = loop;
this.subVolume = subVolume; this.subVolume = subVolume;
} }

View File

@@ -17,18 +17,7 @@ enum SoundAsset {
DESELECT(""), DESELECT(""),
HURRY(""), HURRY(""),
VICTORY("LevelUp2.wav"), VICTORY("LevelUp2.wav"),
LOST("GameOver.wav"), LOST("GameOver.wav");
BUTTON_PRESS("menu_button.ogg"),
ERROR("buzzer.wav"),
UI_SOUND("ui_sound.ogg"),
UI_SOUND2("ui_swoosch.wav"),
UI_CLICK("uiclick.ogg"),
START("gamestart.ogg"),
LAUGHT("laughter.wav"),
POWERUP("powerup.wav"),
ROBOT_READY("robotReady.wav"),
UNIT_READY("unitReady.wav"),
CONNECTED("connected.wav");
private final String path; private final String path;
@@ -38,7 +27,7 @@ enum SoundAsset {
* @param name The name of the sound file. * @param name The name of the sound file.
*/ */
SoundAsset(String name) { SoundAsset(String name) {
this.path = "Sounds/" + name; this.path = "sound/" + name;
} }
/** /**

View File

@@ -9,7 +9,6 @@
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.Asset; import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.gui.DiceControl;
import pp.mdga.game.Color; import pp.mdga.game.Color;
import java.util.*; import java.util.*;
@@ -17,10 +16,13 @@
public class BoardHandler { public class BoardHandler {
private static final float GRID_SIZE = 1.72f; private static final float GRID_SIZE = 1.72f;
private static final float GRID_ELEVATION = 0.0f; private static final float GRID_ELEVATION = 0.0f;
private static final String MAP_NAME = "Maps/map.mdga"; private static final String MAP_NAME = "map.mdga";
private final MdgaApp app; private final MdgaApp app;
private PileControl drawPile = null;
private PileControl discardPile = null;
private ArrayList<NodeControl> infield; private ArrayList<NodeControl> infield;
private Map<UUID, PieceControl> pieces; private Map<UUID, PieceControl> pieces;
@@ -30,45 +32,18 @@ public class BoardHandler {
private Map<Color, List<PieceControl>> waitingPiecesMap; private Map<Color, List<PieceControl>> waitingPiecesMap;
private Map<UUID, Color> pieceColor; private Map<UUID, Color> pieceColor;
private Node rootNodeBoard; private Node node;
private final Node rootNode;
private final FilterPostProcessor fpp; private FilterPostProcessor fpp;
private boolean isInitialised; private boolean init;
private List<PieceControl> selectableOwnPieces; public BoardHandler(MdgaApp app, FilterPostProcessor fpp) {
private List<PieceControl> selectableEnemyPieces;
private List<NodeControl> outlineNodes;
private PieceControl selectedOwnPiece;
private PieceControl selectedEnemyPiece;
private DiceControl diceControl;
public BoardHandler(MdgaApp app, Node rootNode, FilterPostProcessor fpp) {
if(app == null) throw new RuntimeException("app is null"); if(app == null) throw new RuntimeException("app is null");
this.init = false;
this.app = app; this.app = app;
this.fpp = fpp; this.fpp = fpp;
rootNodeBoard = new Node("Board Root Node");
this.rootNode = rootNode;
isInitialised = false;
}
public void init() {
isInitialised = true;
selectableOwnPieces = new ArrayList<>();
selectableEnemyPieces = new ArrayList<>();
outlineNodes = new ArrayList<>();
selectedOwnPiece = null;
selectedEnemyPiece = null;
initMap();
rootNode.attachChild(rootNodeBoard);
}
public void shutdown(){
clearSelectable();
isInitialised = false;
rootNode.detachChild(rootNodeBoard);
} }
private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) { private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) {
@@ -77,15 +52,19 @@ private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) {
} }
private void initMap() { private void initMap() {
pieces = new HashMap<>(); if (init) return;
colorAssetsMap = new HashMap<>();
infield = new ArrayList<>(40); this.init = true;
homeNodesMap = new HashMap<>(); this.node = new Node("Asset Node");
waitingNodesMap = new HashMap<>(); app.getRootNode().attachChild(node);
waitingPiecesMap = new HashMap<>();
pieceColor = new HashMap<>(); this.pieces = new HashMap<>();
diceControl = new DiceControl(app.getAssetManager()); this.colorAssetsMap = new HashMap<>();
diceControl.create(new Vector3f(0,0,0), 0.7f, true); this.infield = new ArrayList<>(40);
this.homeNodesMap = new HashMap<>();
this.waitingNodesMap = new HashMap<>();
this.waitingPiecesMap = new HashMap<>();
this.pieceColor = new HashMap<>();
List<AssetOnMap> assetOnMaps = MapLoader.loadMap(MAP_NAME); List<AssetOnMap> assetOnMaps = MapLoader.loadMap(MAP_NAME);
@@ -96,7 +75,7 @@ private void initMap() {
case cir -> addFigureToPlayerMap(assetToColor(Asset.cir), assetOnMap); case cir -> addFigureToPlayerMap(assetToColor(Asset.cir), assetOnMap);
case marine -> addFigureToPlayerMap(assetToColor(Asset.marine), assetOnMap); case marine -> addFigureToPlayerMap(assetToColor(Asset.marine), assetOnMap);
case node_normal, node_bonus, node_start -> case node_normal, node_bonus, node_start ->
infield.add(displayAndControl(assetOnMap, new NodeControl(app, fpp))); infield.add(displayAndControl(assetOnMap, new NodeControl()));
case node_home_black -> addHomeNode(homeNodesMap, Color.AIRFORCE, assetOnMap); case node_home_black -> addHomeNode(homeNodesMap, Color.AIRFORCE, assetOnMap);
case node_home_blue -> addHomeNode(homeNodesMap, Color.NAVY, assetOnMap); case node_home_blue -> addHomeNode(homeNodesMap, Color.NAVY, assetOnMap);
case node_home_green -> addHomeNode(homeNodesMap, Color.ARMY, assetOnMap); case node_home_green -> addHomeNode(homeNodesMap, Color.ARMY, assetOnMap);
@@ -132,8 +111,8 @@ private Spatial createModel(Asset asset, Vector3f pos, float rot) {
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md"); Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName)); mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat); model.setMaterial(mat);
rootNodeBoard.attachChild(model); node.attachChild(model);
// app.getRootNode().attachChild(model);
return model; return model;
} }
@@ -158,22 +137,20 @@ private void movePieceToNode(PieceControl pieceControl, NodeControl nodeControl)
} }
private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOnMap assetOnMap){ private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOnMap assetOnMap){
List<NodeControl> homeNodes = addItemToMapList(map, color, displayAndControl(assetOnMap, new NodeControl(app, fpp))); List<NodeControl> homeNodes = addItemToMapList(map, color, displayAndControl(assetOnMap, new NodeControl()));
if (homeNodes.size() > 4) throw new RuntimeException("too many homeNodes for " + color); if (homeNodes.size() > 4) throw new RuntimeException("too many homeNodes for " + color);
} }
private float getRotationMove(Vector3f prev, Vector3f next) { private float getRotationMove(Vector3f prev, Vector3f next) {
Vector3f direction = next.subtract(prev).normalizeLocal(); Vector3f direction = next.subtract(prev).normalizeLocal();
//I had to reverse dir.y, because then it worked. //I had to reverse dir.y, because then it worked.
float newRot = (float) Math.toDegrees(Math.atan2(direction.x, -direction.y)); return (float) Math.toDegrees(Math.atan2(direction.x, -direction.y));
if(newRot < 0) newRot += 360;
return newRot;
} }
private void movePieceRek(UUID uuid, int curIndex, int moveIndex){ private void movePiece_rek(UUID uuid, int curIndex, int moveIndex){
if (curIndex == moveIndex) return; if (curIndex == moveIndex) return;
curIndex = (curIndex + 1) % infield.size(); curIndex = (curIndex + 1) % 40;
PieceControl pieceControl = pieces.get(uuid); PieceControl pieceControl = pieces.get(uuid);
NodeControl nodeControl = infield.get(curIndex); NodeControl nodeControl = infield.get(curIndex);
@@ -182,7 +159,7 @@ private void movePieceRek(UUID uuid, int curIndex, int moveIndex){
movePieceToNode(pieceControl, nodeControl); movePieceToNode(pieceControl, nodeControl);
movePieceRek(uuid, curIndex, moveIndex); movePiece_rek(uuid, curIndex, moveIndex);
} }
private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){ private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){
@@ -192,29 +169,16 @@ private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){
return list; return list;
} }
private <T, E> void removeItemFromMapList(Map<E,List<T>> map, E key, T item){ private <T, E> List<T> removeItemFromMapList(Map<E,List<T>> map, E key, T item){
List<T> list = map.getOrDefault(key, new ArrayList<>()); List<T> list = map.getOrDefault(key, new ArrayList<>());
list.remove(item); list.remove(item);
map.put(key, list); map.put(key, list);
} return list;
private Vector3f getWaitingPos(Color color){
return getMeanPosition(waitingNodesMap.get(color).stream().map(NodeControl::getLocation).toList());
}
public static Vector3f getMeanPosition(List<Vector3f> vectors) {
if (vectors.isEmpty()) return new Vector3f(0, 0, 0);
Vector3f sum = new Vector3f(0, 0, 0);
for (Vector3f v : vectors) {
sum.addLocal(v);
}
return sum.divide(vectors.size());
} }
//public methods**************************************************************************************************** //public methods****************************************************************************************************
public void addPlayer(Color color, List<UUID> uuid) { public void addPlayer(Color color, List<UUID> uuid) {
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
List<AssetOnMap> playerAssets = colorAssetsMap.get(color); List<AssetOnMap> playerAssets = colorAssetsMap.get(color);
if (playerAssets == null) throw new RuntimeException("Assets for Player color are not defined"); if (playerAssets == null) throw new RuntimeException("Assets for Player color are not defined");
@@ -227,7 +191,6 @@ public void addPlayer(Color color, List<UUID> uuid) {
for (int i = 0; i < playerAssets.size(); i++){ for (int i = 0; i < playerAssets.size(); i++){
AssetOnMap assetOnMap = playerAssets.get(i); AssetOnMap assetOnMap = playerAssets.get(i);
PieceControl pieceControl = displayAndControl(assetOnMap, new PieceControl(assetOnMap.rot(), app.getAssetManager(), app, fpp)); PieceControl pieceControl = displayAndControl(assetOnMap, new PieceControl(assetOnMap.rot(), app.getAssetManager(), app, fpp));
pieceControl.setRotation(assetOnMap.rot());
movePieceToNode(pieceControl, waitNodes.get(i)); movePieceToNode(pieceControl, waitNodes.get(i));
pieces.put(uuid.get(i), pieceControl); pieces.put(uuid.get(i), pieceControl);
@@ -239,7 +202,7 @@ public void addPlayer(Color color, List<UUID> uuid) {
} }
public void moveHomePiece(UUID uuid, int index){ public void moveHomePiece(UUID uuid, int index){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
Color color = pieceColor.get(uuid); Color color = pieceColor.get(uuid);
if(color == null) throw new RuntimeException("uuid is not mapped to a color"); if(color == null) throw new RuntimeException("uuid is not mapped to a color");
@@ -260,7 +223,7 @@ public void moveHomePiece(UUID uuid, int index){
} }
public void movePieceStart(UUID uuid, int nodeIndex){ public void movePieceStart(UUID uuid, int nodeIndex){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
Color color = pieceColor.get(uuid); Color color = pieceColor.get(uuid);
if(color == null) throw new RuntimeException("uuid is not mapped to a color"); if(color == null) throw new RuntimeException("uuid is not mapped to a color");
@@ -272,13 +235,13 @@ public void movePieceStart(UUID uuid, int nodeIndex){
} }
public void movePiece(UUID uuid, int curIndex, int moveIndex){ public void movePiece(UUID uuid, int curIndex, int moveIndex){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
movePieceRek(uuid, curIndex, moveIndex); movePiece_rek(uuid, curIndex, moveIndex);
} }
public void throwPiece(UUID uuid){ public void throwPiece(UUID uuid){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
Color color = pieceColor.get(uuid); Color color = pieceColor.get(uuid);
if(color == null) throw new RuntimeException("uuid is not mapped to a color"); if(color == null) throw new RuntimeException("uuid is not mapped to a color");
@@ -293,189 +256,68 @@ public void throwPiece(UUID uuid){
} }
public void shieldPiece(UUID uuid){ public void shieldPiece(UUID uuid){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
pieces.get(uuid).activateShield(); pieces.get(uuid).activateShield();
} }
public void unshieldPiece(UUID uuid){ public void unshieldPiece(UUID uuid){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
pieces.get(uuid).deactivateShield(); pieces.get(uuid).deactivateShield();
} }
public void suppressShield(UUID uuid){ public void suppressShield(UUID uuid){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
pieces.get(uuid).suppressShield(); pieces.get(uuid).suppressShield();
} }
public void swapPieces(UUID piece1, UUID piece2){ public void swapPieces(UUID piece1, UUID piece2){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
PieceControl piece1Control = pieces.get(piece1); PieceControl piece1_control = pieces.get(piece1);
PieceControl piece2Control = pieces.get(piece2); PieceControl piece2_control = pieces.get(piece2);
if(piece1Control == null) throw new RuntimeException("piece1 UUID is not valid"); if(piece1_control == null) throw new RuntimeException("piece1 UUID is not valid");
if(piece2Control == null) throw new RuntimeException("piece2 UUID is not valid"); if(piece2_control == null) throw new RuntimeException("piece2 UUID is not valid");
float rot1 = piece1Control.getRotation(); float rot1 = piece1_control.getRotation();
float rot2 = piece2Control.getRotation(); float rot2 = piece2_control.getRotation();
piece1Control.setRotation(rot2); piece1_control.setRotation(rot2);
piece2Control.setRotation(rot1); piece2_control.setRotation(rot1);
Vector3f pos1 = piece1Control.getLocation().clone(); Vector3f pos1 = piece1_control.getLocation().clone();
Vector3f pos2 = piece2Control.getLocation().clone(); Vector3f pos2 = piece2_control.getLocation().clone();
piece1Control.setLocation(pos2); piece1_control.setLocation(pos2);
piece2Control.setLocation(pos1); piece2_control.setLocation(pos1);
} }
public void init(){
initMap();
}
public void shutdown(){
if (!init) return;
init = false;
app.getRootNode().detachChild(node);
}
//List<Pieces>
//List<NodesIndexe>
public void highlight(UUID uuid, boolean bool){ public void highlight(UUID uuid, boolean bool){
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized"); if (!init) throw new RuntimeException("BoardHandler is not initialized");
pieces.get(uuid).highlight(bool);
pieces.get(uuid).setSelectable(bool);
pieces.get(uuid).outline(bool);
} }
//called when (dice) moveNum is received from server to display the movable pieces and corresponding moveNodes public void unHighlight(UUID uuid){
public void outlineMove(List<UUID> pieces, List<Integer> moveIndexe, List<Boolean> homeMoves) { if (!init) throw new RuntimeException("BoardHandler is not initialized");
if(pieces.size() != moveIndexe.size() || pieces.size() != homeMoves.size()) throw new RuntimeException("arrays are not the same size");
selectableEnemyPieces.clear(); pieces.get(uuid).deOutline();
selectableOwnPieces.clear();
selectedOwnPiece = null;
selectedEnemyPiece = null;
for (int i = 0; i < pieces.size(); i++) {
UUID uuid = pieces.get(i);
PieceControl pieceControl = this.pieces.get(uuid);
NodeControl nodeControl;
if (homeMoves.get(i)) {
Color color = pieceColor.get(uuid);
nodeControl = homeNodesMap.get(color).get(moveIndexe.get(i));
}
else {
nodeControl = infield.get(moveIndexe.get(i));
}
nodeControl.highlight();
pieceControl.highlight(false);
pieceControl.setHoverable(true);
pieceControl.setSelectable(true);
outlineNodes.add(nodeControl);
selectableOwnPieces.add(pieceControl);
}
} }
//called when swap notification is received to highlight and select own/enemy pieces
public void outlineSwap(List<UUID> ownPieces, List<UUID> enemyPieces){
selectableEnemyPieces.clear();
selectableOwnPieces.clear();
selectedOwnPiece = null;
selectedEnemyPiece = null;
for(UUID uuid : ownPieces) {
PieceControl p = pieces.get(uuid);
p.highlight(false);
p.setHoverable(true);
p.setSelectable(true);
selectableOwnPieces.add(p);
}
for(UUID uuid : enemyPieces) {
PieceControl p = pieces.get(uuid);
p.highlight(true);
p.setHoverable(true);
p.setSelectable(true);
selectableEnemyPieces.add(p);
}
}
public void outlineShield(List<UUID> pieces){
selectableOwnPieces.clear();
selectableEnemyPieces.clear();
selectedOwnPiece = null;
selectedEnemyPiece = null;
for (UUID uuid : pieces){
PieceControl p = this.pieces.get(uuid);
p.highlight(false);
p.setHoverable(true);
p.setSelectable(true);
selectableOwnPieces.add(p);
}
}
//called from inputSynchronizer when a piece is selectable
public void pieceSelect(PieceControl pieceSelected) {
boolean isSelected = pieceSelected.isSelected();
if(selectableOwnPieces.contains(pieceSelected)){
for(PieceControl p : selectableOwnPieces) {
p.unSelect();
}
if (!isSelected) {
pieceSelected.select();
selectedOwnPiece = pieceSelected;
}
else {
pieceSelected.unSelect();
selectedOwnPiece = null;
}
}
else if(selectableEnemyPieces.contains(pieceSelected)) {
for(PieceControl p : selectableEnemyPieces) {
p.unSelect();
}
if (!isSelected) {
pieceSelected.select();
selectedEnemyPiece = pieceSelected;
}
else {
pieceSelected.unSelect();
selectedEnemyPiece = null;
}
}
else throw new RuntimeException("pieceSelected is not in own/enemySelectablePieces");
}
//called when view is no longer needed to select pieces
public void clearSelectable(){
for(PieceControl p : selectableEnemyPieces) {
p.unSelect();
p.unHighlight();
p.setSelectable(false);
}
for(PieceControl p : selectableOwnPieces) {
p.unSelect();
p.unHighlight();
p.setSelectable(false);
}
for(NodeControl n : outlineNodes){
n.deOutline();
}
outlineNodes.clear();
selectableEnemyPieces.clear();
selectableOwnPieces.clear();
selectedEnemyPiece = null;
selectedOwnPiece = null;
}
public void enableHover(UUID uuid){
pieces.get(uuid).setHoverable(true);
}
public void showDice(Color color){
rootNodeBoard.attachChild(diceControl.getSpatial());
diceControl.setPos(getWaitingPos(color).add(new Vector3f(0,0,4)));
diceControl.spin();
}
public void hideDice(){
diceControl.hide();
}
} }

View File

@@ -4,14 +4,9 @@
import com.jme3.light.DirectionalLight; import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor; import com.jme3.post.FilterPostProcessor;
import com.jme3.scene.Spatial;
import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.shadow.DirectionalLightShadowFilter;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.util.SkyFactory;
import com.jme3.util.SkyFactory.EnvMapType;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
public class CameraHandler { public class CameraHandler {
@@ -22,21 +17,8 @@ public class CameraHandler {
private static final int SHADOWMAP_SIZE = 1024 * 8; private static final int SHADOWMAP_SIZE = 1024 * 8;
private Vector3f defaultCameraPosition; public CameraHandler(MdgaApp app, FilterPostProcessor fpp){
private Quaternion defaultCameraRotation;
FilterPostProcessor fpp;
DirectionalLightShadowFilter dlsf;
Spatial sky;
public CameraHandler(MdgaApp app, FilterPostProcessor fpp) {
this.app = app; this.app = app;
this.fpp = fpp;
// Save the default camera state
this.defaultCameraPosition = app.getCamera().getLocation().clone();
this.defaultCameraRotation = app.getCamera().getRotation().clone();
sun = new DirectionalLight(); sun = new DirectionalLight();
sun.setColor(ColorRGBA.White); sun.setColor(ColorRGBA.White);
@@ -45,34 +27,19 @@ public CameraHandler(MdgaApp app, FilterPostProcessor fpp) {
ambient = new AmbientLight(); ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1)); ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
dlsf = new DirectionalLightShadowFilter(app.getAssetManager(), SHADOWMAP_SIZE, 1); DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(app.getAssetManager(), SHADOWMAP_SIZE, 4);
dlsf.setLight(sun); dlsf.setLight(sun);
dlsf.setEnabled(true); fpp.addFilter(dlsf);
dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
dlsf.setShadowIntensity(0.7f);
sky = SkyFactory.createSky(app.getAssetManager(), "Images/sky/sky.dds", EnvMapType.EquirectMap).rotate(FastMath.HALF_PI*1,0,FastMath.HALF_PI*0.2f);
} }
public void init() { public void init() {
app.getRootNode().addLight(sun); app.getRootNode().addLight(sun);
app.getRootNode().addLight(ambient); app.getRootNode().addLight(ambient);
app.getRootNode().attachChild(sky);
fpp.addFilter(dlsf);
} }
public void shutdown() { public void shutdown() {
app.getRootNode().removeLight(sun); app.getRootNode().removeLight(sun);
app.getRootNode().removeLight(ambient); app.getRootNode().removeLight(ambient);
app.getRootNode().detachChild(sky);
// Reset the camera to its default state
app.getCamera().setLocation(defaultCameraPosition);
app.getCamera().setRotation(defaultCameraRotation);
fpp.removeFilter(dlsf);
} }
public void update(float scroll, float rotation) { public void update(float scroll, float rotation) {

View File

@@ -1,27 +1,22 @@
package pp.mdga.client.board; package pp.mdga.client.board;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.MdgaApp;
public class NodeControl extends OutlineControl { public class NodeControl extends AbstractControl {
private static final ColorRGBA OUTLINE_HIGHLIGHT_COLOR = ColorRGBA.White; @Override
private static final int OUTLINE_HIGHLIGHT_WIDTH = 6; protected void controlUpdate(float v) {
}
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
public NodeControl(MdgaApp app, FilterPostProcessor fpp) {
super(app, fpp);
} }
public Vector3f getLocation(){ public Vector3f getLocation(){
return this.getSpatial().getLocalTranslation(); return this.getSpatial().getLocalTranslation();
} }
public void highlight() {
super.outline(OUTLINE_HIGHLIGHT_COLOR, OUTLINE_HIGHLIGHT_WIDTH);
}
} }

View File

@@ -1,79 +0,0 @@
package pp.mdga.client.board.Outline;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.material.MaterialDef;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.post.Filter;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.texture.FrameBuffer;
public class OutlineProFilter extends Filter {
private OutlinePreFilter outlinePreFilter;
private ColorRGBA outlineColor = new ColorRGBA(0, 1, 0, 1);
private float outlineWidth = 1;
public OutlineProFilter(OutlinePreFilter outlinePreFilter) {
super("OutlineFilter");
this.outlinePreFilter = outlinePreFilter;
}
@Override
protected void initFilter(AssetManager assetManager, RenderManager renderManager, ViewPort vp, int w, int h) {
MaterialDef matDef = (MaterialDef) assetManager.loadAsset("MatDefs/SelectObjectOutliner/OutlinePro.j3md");
material = new Material(matDef);
material.setVector2("Resolution", new Vector2f(w, h));
material.setColor("OutlineColor", outlineColor);
material.setFloat("OutlineWidth", outlineWidth);
}
@Override
protected void preFrame(float tpf) {
super.preFrame(tpf);
material.setTexture("OutlineDepthTexture", outlinePreFilter.getOutlineTexture());
// System.out.println("OutlineFilter.preFrame()");
}
@Override
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
super.postFrame(renderManager, viewPort, prevFilterBuffer, sceneBuffer);
// material.setTexture("OutlineDepthTexture", outlinePreFilter.getDefaultPassDepthTexture());
// System.out.println("OutlineFilter.postFrame()");
}
@Override
protected Material getMaterial() {
return material;
}
public ColorRGBA getOutlineColor() {
return outlineColor;
}
public void setOutlineColor(ColorRGBA outlineColor) {
this.outlineColor = outlineColor;
if (material != null) {
material.setColor("OutlineColor", outlineColor);
}
}
public float getOutlineWidth() {
return outlineWidth;
}
public void setOutlineWidth(float outlineWidth) {
this.outlineWidth = outlineWidth;
if (material != null) {
material.setFloat("OutlineWidth", outlineWidth);
}
}
public OutlinePreFilter getOutlinePreFilter() {
return outlinePreFilter;
}
}

View File

@@ -7,7 +7,6 @@
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import pp.mdga.client.MdgaApp;
public class SelectObjectOutliner { public class SelectObjectOutliner {
@@ -18,18 +17,16 @@ public class SelectObjectOutliner {
private final int width; private final int width;
private boolean selected; private boolean selected;
private ViewPort outlineViewport = null; private ViewPort outlineViewport = null;
// private OutlineFilter outlineFilter = null; private OutlineFilter outlineFilter = null;
private OutlineProFilter outlineFilter = null;
private final MdgaApp app;
public SelectObjectOutliner(int width, FilterPostProcessor fpp, RenderManager renderManager, AssetManager assetManager, Camera cam, MdgaApp app) {
public SelectObjectOutliner(int width, FilterPostProcessor fpp, RenderManager renderManager, AssetManager assetManager, Camera cam) {
this.selected = false; this.selected = false;
this.fpp = fpp; this.fpp = fpp;
this.renderManager = renderManager; this.renderManager = renderManager;
this.assetManager = assetManager; this.assetManager = assetManager;
this.cam = cam; this.cam = cam;
this.width = width; this.width = width;
this.app = app;
} }
public void deselect(Spatial model) { public void deselect(Spatial model) {
@@ -46,43 +43,29 @@ public void select(Spatial model, ColorRGBA color) {
} }
} }
public void select(Spatial model, ColorRGBA color, int width) {
if(!selected){
selected = true;
showOutlineFilterEffect(model, width, color);
}
}
private void hideOutlineFilterEffect(Spatial model) { private void hideOutlineFilterEffect(Spatial model) {
// app.enqueue(() -> { outlineFilter.setEnabled(false);
outlineFilter.setEnabled(false); outlineFilter.getOutlinePreFilter().setEnabled(false);
outlineFilter.getOutlinePreFilter().setEnabled(false); fpp.removeFilter(outlineFilter);
fpp.removeFilter(outlineFilter); outlineViewport.detachScene(model);
outlineViewport.detachScene(model); renderManager.removePreView(outlineViewport);
outlineViewport.clearProcessors(); outlineViewport = null;
renderManager.removePreView(outlineViewport);
outlineViewport = null;
// return null;
// });
} }
private void showOutlineFilterEffect(Spatial model, int width, ColorRGBA color) { private void showOutlineFilterEffect(Spatial model, int width, ColorRGBA color) {
// app.enqueue(() -> { outlineViewport = renderManager.createPreView("outlineViewport", cam);
outlineViewport = renderManager.createPreView("outlineViewport", cam); FilterPostProcessor outlineFpp = new FilterPostProcessor(assetManager);
FilterPostProcessor outlineFpp = new FilterPostProcessor(assetManager);
OutlinePreFilter outlinePreFilter = new OutlinePreFilter(); OutlinePreFilter outlinePreFilter = new OutlinePreFilter();
outlineFpp.addFilter(outlinePreFilter); outlineFpp.addFilter(outlinePreFilter);
outlineViewport.attachScene(model); outlineViewport.attachScene(model);
outlineViewport.addProcessor(outlineFpp); outlineViewport.addProcessor(outlineFpp);
outlineFilter = new OutlineProFilter(outlinePreFilter); outlineFilter = new OutlineFilter(outlinePreFilter);
outlineFilter.setOutlineColor(color); outlineFilter.setOutlineColor(color);
outlineFilter.setOutlineWidth(width); outlineFilter.setOutlineWidth(width);
fpp.addFilter(outlineFilter); fpp.addFilter(outlineFilter);
// return null;
// });
} }
} }

View File

@@ -1,75 +0,0 @@
package pp.mdga.client.board;
import com.jme3.math.ColorRGBA;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.board.Outline.SelectObjectOutliner;
public class OutlineControl extends AbstractControl {
private static final int THICKNESS_DEFAULT = 6;
private final SelectObjectOutliner outlineOwn;
private MdgaApp app;
public OutlineControl(MdgaApp app, FilterPostProcessor fpp){
this.app = app;
outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), app.getCamera(), app);
}
public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam){
this.app = app;
outlineOwn = new SelectObjectOutliner(THICKNESS_DEFAULT, fpp, app.getRenderManager(), app.getAssetManager(), cam, app);
}
public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, int thickness){
this.app = app;
outlineOwn = new SelectObjectOutliner(thickness, fpp, app.getRenderManager(), app.getAssetManager(), cam, app);
}
public void outline(ColorRGBA color){
outlineOwn.select(spatial, color);
}
public void outline(ColorRGBA color, int width){
deOutline();
outlineOwn.select(spatial, color, width);
}
public void deOutline(){
outlineOwn.deselect(spatial);
}
@Override
protected void controlUpdate(float tpf) {
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public void initSpatial(){
}
@Override
public void setSpatial(Spatial spatial){
if(this.spatial == null && spatial != null){
super.setSpatial(spatial);
initSpatial();
}
else{
super.setSpatial(spatial);
}
}
public MdgaApp getApp() {
return app;
}
}

View File

@@ -7,14 +7,18 @@
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor; import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.Asset; import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.board.Outline.SelectObjectOutliner;
public class PieceControl extends OutlineControl { public class PieceControl extends AbstractControl {
private final float initRotation; private final float initRotation;
private final AssetManager assetManager; private final AssetManager assetManager;
private Spatial shieldRing; private Spatial shieldRing;
@@ -26,53 +30,40 @@ public class PieceControl extends OutlineControl {
private static final ColorRGBA SHIELD_SUPPRESSED_COLOR = new ColorRGBA(1f, 0.5f, 0, SHIELD_TRANSPARENCY); private static final ColorRGBA SHIELD_SUPPRESSED_COLOR = new ColorRGBA(1f, 0.5f, 0, SHIELD_TRANSPARENCY);
private static final float SHIELD_Z = 0f; private static final float SHIELD_Z = 0f;
SelectObjectOutliner outlineOwn;
private static final ColorRGBA OUTLINE_OWN_COLOR = ColorRGBA.White; private static final ColorRGBA OUTLINE_OWN_COLOR = ColorRGBA.White;
private static final ColorRGBA OUTLINE_ENEMY_COLOR = ColorRGBA.Red; private static final ColorRGBA OUTLINE_ENEMY_COLOR = ColorRGBA.Red;
private static final ColorRGBA OUTLINE_OWN_HOVER_COLOR = ColorRGBA.Yellow; private static final int OUTLINE_THICKNESS = 4;
private static final ColorRGBA OUTLINE_ENEMY_HOVER_COLOR = ColorRGBA.Green;
private static final ColorRGBA OUTLINE_OWN_SELECT_COLOR = ColorRGBA.Cyan;
private static final ColorRGBA OUTLINE_ENEMY_SELECT_COLOR = ColorRGBA.Orange;
private static final int OUTLINE_HIGHLIGHT_WIDTH = 8;
private static final int OUTLINE_HOVER_WIDTH = 8;
private static final int OUTLINE_SELECT_WIDTH = 10;
private final Node parentNode; private final Node parentNode;
private boolean enemy;
private boolean hoverable;
private boolean highlight;
private boolean selectable;
private boolean select;
public PieceControl(float initRotation, AssetManager assetManager, MdgaApp app, FilterPostProcessor fpp){ public PieceControl(float initRotation, AssetManager assetManager, MdgaApp app, FilterPostProcessor fpp){
super(app, fpp); super();
this.parentNode = new Node(); this.parentNode = new Node();
this.initRotation = initRotation; this.initRotation = initRotation;
this.assetManager = assetManager; this.assetManager = assetManager;
this.shieldRing = null; this.shieldRing = null;
this.shieldMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); this.shieldMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
this.shieldMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); this.shieldMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
enemy = false;
hoverable = false;
highlight = false; outlineOwn = new SelectObjectOutliner(OUTLINE_THICKNESS, fpp, app.getRenderManager(), app.getAssetManager(), app.getCamera());
selectable = false;
select = false;
} }
public float getRotation() { public float getRotation() {
return (float) Math.toDegrees(spatial.getLocalRotation().toAngleAxis(new Vector3f(0,0,1))); return (float) Math.toDegrees(this.spatial.getLocalRotation().toAngleAxis(new Vector3f(0,0,1)));
} }
public void setRotation(float rot){ public void setRotation(float rot){
if(rot < 0) rot =- 360;
Quaternion quaternion = new Quaternion(); Quaternion quaternion = new Quaternion();
quaternion.fromAngleAxis((float) Math.toRadians(rot), new Vector3f(0,0,1)); quaternion.fromAngleAxis((float) Math.toRadians(rot), new Vector3f(0,0,1));
spatial.setLocalRotation(quaternion); this.spatial.setLocalRotation(quaternion);
} }
public Vector3f getLocation(){ public Vector3f getLocation(){
return spatial.getLocalTranslation(); return this.getSpatial().getLocalTranslation();
} }
@Override @Override
@@ -82,16 +73,31 @@ protected void controlUpdate(float delta) {
} }
} }
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
}
public void setLocation(Vector3f loc){ public void setLocation(Vector3f loc){
this.spatial.setLocalTranslation(loc); this.getSpatial().setLocalTranslation(loc);
} }
@Override @Override
public void setSpatial(Spatial spatial){
if(this.getSpatial() == null && spatial != null){
super.setSpatial(spatial);
initSpatial();
}
else{
super.setSpatial(spatial);
}
}
public void initSpatial(){ public void initSpatial(){
setRotation(this.initRotation); setRotation(this.initRotation);
Node oldParent = spatial.getParent(); Node oldParent = this.spatial.getParent();
this.parentNode.setName(spatial.getName() + " Parent"); this.parentNode.setName(this.spatial.getName() + " Parent");
oldParent.detachChild(this.getSpatial()); oldParent.detachChild(this.getSpatial());
this.parentNode.attachChild(this.getSpatial()); this.parentNode.attachChild(this.getSpatial());
oldParent.attachChild(this.parentNode); oldParent.attachChild(this.parentNode);
@@ -126,60 +132,19 @@ public void suppressShield(){
} }
public void setMaterial(Material mat){ public void setMaterial(Material mat){
spatial.setMaterial(mat); this.spatial.setMaterial(mat);
} }
public Material getMaterial(){ public Material getMaterial(){
return ((Geometry) getSpatial()).getMaterial(); return ((Geometry) this.spatial).getMaterial();
} }
public void highlight(boolean enemy) { public void outline(boolean enemy) {
this.enemy = enemy; ColorRGBA color = enemy ? OUTLINE_ENEMY_COLOR : OUTLINE_OWN_COLOR;
highlight = true; outlineOwn.select(this.getSpatial(), color);
super.outline(enemy ? OUTLINE_ENEMY_COLOR : OUTLINE_OWN_COLOR, OUTLINE_HIGHLIGHT_WIDTH);
} }
public void unHighlight(){ public void deOutline() {
highlight = false; outlineOwn.deselect(this.getSpatial());
deOutline();
}
public void hover(){
if(!hoverable) return;
super.outline(enemy ? OUTLINE_ENEMY_HOVER_COLOR : OUTLINE_OWN_HOVER_COLOR, OUTLINE_HOVER_WIDTH);
}
public void hoverOff(){
if(!hoverable) return;
if(select) select();
else if(highlight) highlight(enemy);
else deOutline();
}
public void unSelect(){
select = false;
if(highlight) highlight(enemy);
else deOutline();
}
public void select(){
if(!selectable) return;
select = true;
super.outline(enemy ? OUTLINE_ENEMY_SELECT_COLOR : OUTLINE_OWN_SELECT_COLOR, OUTLINE_SELECT_WIDTH);
}
public void setSelectable(boolean selectable){
this.selectable = selectable;
}
public boolean isSelected() { return select; }
public boolean isSelectable() {
return selectable;
}
public void setHoverable(boolean hoverable) {
this.hoverable = hoverable;
} }
} }

View File

@@ -1,161 +0,0 @@
package pp.mdga.client.button;
import com.jme3.font.BitmapFont;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import com.jme3.ui.Picture;
import pp.mdga.client.MdgaApp;
/**
* Represents an abstract base class for creating customizable button components in a graphical user interface.
* This class provides the framework for rendering buttons with different visual states, such as normal and pressed,
* and supports position adjustments and font customization.
*
* <p>Subclasses must implement the {@link #show()} and {@link #hide()} methods to define how the button
* is displayed and hidden in the application.</p>
*/
public abstract class AbstractButton {
/**
* Color representing the normal state of the button.
*/
public static final ColorRGBA BUTTON_NORMAL = ColorRGBA.fromRGBA255(233, 236, 239, 255);
/**
* Color representing the pressed state of the button.
*/
public static final ColorRGBA BUTTON_PRESSED = ColorRGBA.fromRGBA255(105, 117, 89, 255);
/**
* Color representing the normal state of the button text.
*/
public static final ColorRGBA TEXT_NORMAL = ColorRGBA.Black;
/**
* Color representing the pressed state of the button text.
*/
public static final ColorRGBA TEXT_PRESSED = ColorRGBA.fromRGBA255(180, 195, 191, 255);
/**
* The image representing the normal state of the button.
*/
protected Picture pictureNormal = new Picture("normalButton");
/**
* The image representing the hover state of the button.
*/
protected Picture pictureHover = new Picture("normalButton");
/**
* The number of horizontal divisions for calculating relative sizes.
*/
public static final float HORIZONTAL = 16;
/**
* The number of vertical divisions for calculating relative sizes.
*/
public static final float VERTICAL = 9;
/**
* The font used for rendering text on the button.
*/
protected BitmapFont font;
/**
* Reference to the application instance for accessing assets and settings.
*/
protected final MdgaApp app;
/**
* Node in the scene graph to which the button belongs.
*/
protected final Node node;
/**
* The position of the button in 2D space.
*/
protected Vector2f pos;
/**
* Factor for scaling the font size.
*/
protected float fontSizeFactor = 1.0f;
/**
* Computed font size based on scaling factor and screen dimensions.
*/
protected float fontSize;
/**
* Computed horizontal step size based on screen dimensions.
*/
protected float horizontalStep;
/**
* Computed vertical step size based on screen dimensions.
*/
protected float verticalStep;
/**
* Computed height step size based on vertical steps.
*/
protected float heightStep;
/**
* Computed width step size based on horizontal steps.
*/
protected float widthStep;
/**
* Flag indicating whether adjustments are applied to the button.
*/
protected boolean adjust = false;
/**
* Constructs an AbstractButton instance with the specified application context and scene node.
* Initializes the button's visual elements and font.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button is attached
*/
public AbstractButton(MdgaApp app, Node node) {
this.app = app;
this.node = node;
pictureNormal.setImage(app.getAssetManager(), "Images/General_Button_normal.png", true);
pictureHover.setImage(app.getAssetManager(), "Images/General_Button_hover.png", true);
font = app.getAssetManager().loadFont("Fonts/Gunplay.fnt");
}
/**
* Displays the button. Implementation must define how the button is rendered on the screen.
*/
public abstract void show();
/**
* Hides the button. Implementation must define how the button is removed from the screen.
*/
public abstract void hide();
/**
* Sets the position of the button in 2D space.
*
* @param pos the position to set
*/
public void setPos(Vector2f pos) {
this.pos = pos;
}
/**
* Calculates relative sizes and dimensions for the button based on the screen resolution.
*/
protected void calculateRelative() {
fontSize = fontSizeFactor * 15 * (float) app.getCamera().getWidth() / 720;
horizontalStep = (float) app.getCamera().getWidth() / HORIZONTAL;
verticalStep = (float) app.getCamera().getHeight() / VERTICAL;
heightStep = verticalStep / 2;
widthStep = horizontalStep / 2;
}
}

View File

@@ -1,46 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import com.jme3.ui.Picture;
/**
* Represents a specific implementation of a clickable button positioned on the left side.
* This class extends {@link ClickButton} and provides a predefined position and size for the button.
* It also includes placeholder methods for handling hover events, which can be customized as needed.
*/
public class ButtonLeft extends ClickButton {
/**
* Constructs a ButtonLeft instance with the specified properties.
*
* @param app the application instance for accessing resources and settings
* @param node the node in the scene graph to which the button belongs
* @param action the action to execute when the button is clicked
* @param label the text label to display on the button
* @param narrowFactor a factor to adjust position of the button
*/
public ButtonLeft(MdgaApp app, Node node, Runnable action, String label, int narrowFactor) {
super(app, node, action, label, new Vector2f(5, 2), new Vector2f(0.5f * narrowFactor, 1.8f));
}
/**
* Called when the button is hovered over by the pointer.
* Subclasses can override this method to define specific hover behavior.
*/
@Override
public void onHover() {
// Placeholder for hover behavior
}
/**
* Called when the pointer stops hovering over the button.
* Subclasses can override this method to define specific unhover behavior.
*/
@Override
public void onUnHover() {
// Placeholder for unhover behavior
}
}

View File

@@ -1,48 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
/**
* Represents a specific implementation of a clickable button positioned on the right side.
* This class extends {@link ClickButton} and provides a predefined position and size for the button.
* It includes placeholder methods for handling hover events, which can be customized as needed.
*/
public class ButtonRight extends ClickButton {
/**
* Constructs a ButtonRight instance with the specified properties.
*
* @param app the application instance for accessing resources and settings
* @param node the node in the scene graph to which the button belongs
* @param action the action to execute when the button is clicked
* @param label the text label to display on the button
* @param narrowFactor a factor to adjust the position of the button
*/
public ButtonRight(MdgaApp app, Node node, Runnable action, String label, int narrowFactor) {
super(app, node, action, label, new Vector2f(5, 2), new Vector2f(HORIZONTAL - 0.5f * narrowFactor, 1.8f));
// Enable adjustments specific to this button
adjust = true;
}
/**
* Called when the button is hovered over by the pointer.
* Subclasses can override this method to define specific hover behavior.
*/
@Override
public void onHover() {
// Placeholder for hover behavior
}
/**
* Called when the pointer stops hovering over the button.
* Subclasses can override this method to define specific unhover behavior.
*/
@Override
public void onUnHover() {
// Placeholder for unhover behavior
}
}

View File

@@ -1,251 +0,0 @@
package pp.mdga.client.button;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color;
/**
* Represents a button used in a ceremony screen, with 3D model integration, customizable
* appearance based on type, and interactive behavior. The button can rotate and display
* different positions such as FIRST, SECOND, THIRD, and LOST.
*/
public class CeremonyButton extends ClickButton {
/**
* Enum representing the possible positions of the button in the ceremony screen.
*/
public enum Pos {
FIRST,
SECOND,
THIRD,
LOST,
}
/**
* Fixed width of the button in the UI layout.
*/
static final float WIDTH = 4.0f;
/**
* Node to which the 3D model associated with this button is attached.
*/
private final Node node3d;
/**
* Flag to determine if the button's 3D model should rotate.
*/
private boolean rotate = false;
/**
* The 3D model associated with the button.
*/
private Spatial model;
/**
* Current rotation angle of the button's 3D model.
*/
private float rot = 180;
/**
* The taken state of the button (default is NOT taken).
*/
private LobbyButton.Taken taken = LobbyButton.Taken.NOT;
/**
* A label associated with the button for displaying additional information.
*/
private LabelButton label;
/**
* Constructs a CeremonyButton with specified attributes such as type, position, and label.
* The button supports both 2D and 3D components for UI and visual effects.
*
* @param app the application instance for accessing resources and settings
* @param node the node in the scene graph to which the button belongs
* @param node3d the node for 3D scene components associated with this button
* @param tsk the type/color associated with the button
* @param pos the position of the button in the ceremony layout
* @param name the label or name displayed on the button
*/
public CeremonyButton(MdgaApp app, Node node, Node node3d, Color tsk, Pos pos, String name) {
super(app, node, () -> {}, "", new Vector2f(WIDTH, 7), new Vector2f(0, 0));
this.node3d = node3d;
label = new LabelButton(app, node, name, new Vector2f(WIDTH, 1), new Vector2f(0, 0), true);
final float mid = HORIZONTAL / 2;
final float uiSpacing = 1.4f;
final float figSpacingX = 0.9f;
final float figSpacingY = 0.25f;
float uiX = mid;
float uiY = 6;
float figX = 0;
float figY = -0.32f;
Asset asset = switch (tsk) {
case CYBER -> {
instance.setText("CIR");
yield Asset.cir;
}
case AIRFORCE -> {
instance.setText("Luftwaffe");
yield Asset.lw;
}
case ARMY -> {
instance.setText("Heer");
yield Asset.heer;
}
case NAVY -> {
instance.setText("Marine");
yield Asset.marine;
}
default -> throw new RuntimeException("None is not valid");
};
switch (pos) {
case FIRST:
rotate = true;
uiX = 0;
figY -= 1 * figSpacingY;
break;
case SECOND:
adjust = true;
label.adjust = true;
uiX -= uiSpacing;
uiY -= 1;
figX -= figSpacingX;
figY -= 2 * figSpacingY;
figY -= 0.1f;
break;
case THIRD:
uiX += uiSpacing;
uiY -= 1.5f;
figX += figSpacingX;
figY -= 3 * figSpacingY;
figY -= 0.07f;
break;
case LOST:
adjust = true;
label.adjust = true;
uiX -= 2 * uiSpacing + 0.4f;
uiX -= WIDTH / 2;
uiY -= 2.0f;
figX -= 2.5f * figSpacingX + 0.05f;
figY -= 4.5f * figSpacingY;
break;
}
setPos(new Vector2f(uiX, uiY));
label.setPos(new Vector2f(uiX, uiY + 1));
createModel(asset, new Vector3f(figX, figY, 6));
}
/**
* Handles hover behavior by changing the button's background appearance.
*/
@Override
public void onHover() {
ColorRGBA buttonNormal = BUTTON_NORMAL.clone();
buttonNormal.a = 0.1f;
QuadBackgroundComponent background = new QuadBackgroundComponent(buttonNormal);
instance.setBackground(background);
}
/**
* Handles unhover behavior by resetting the button's background appearance.
*/
@Override
public void onUnHover() {
ColorRGBA buttonNormal = BUTTON_NORMAL.clone();
buttonNormal.a = 0.1f;
QuadBackgroundComponent background = new QuadBackgroundComponent(buttonNormal);
instance.setBackground(background);
}
/**
* Displays the button along with its 3D model and associated label.
*/
@Override
public void show() {
release();
calculateRelative();
setRelative();
node.attachChild(instance);
node3d.attachChild(model);
label.show();
}
/**
* Hides the button along with its 3D model and associated label.
*/
@Override
public void hide() {
node.detachChild(instance);
node3d.detachChild(model);
label.hide();
}
/**
* Updates the rotation of the button's 3D model over time.
*
* @param tpf time per frame, used for smooth rotation calculations
*/
public void update(float tpf) {
if (rotate) {
rot += 140.0f * tpf;
rot %= 360;
} else {
rot = 180;
}
model.setLocalRotation(new Quaternion().fromAngles(
(float) Math.toRadians(90),
(float) Math.toRadians(rot),
(float) Math.toRadians(180)
));
}
/**
* Creates a 3D model associated with the button and applies its materials and position.
*
* @param asset the asset representing the 3D model and texture
* @param pos the initial position of the model in 3D space
*/
private void createModel(Asset asset, Vector3f pos) {
String modelName = asset.getModelPath();
String texName = asset.getDiffPath();
model = app.getAssetManager().loadModel(modelName);
model.scale(asset.getSize() / 2);
model.rotate(
(float) Math.toRadians(90),
(float) Math.toRadians(rot),
(float) Math.toRadians(180)
);
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
model.setLocalTranslation(pos);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat);
}
}

View File

@@ -1,212 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.ui.Picture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
/**
* Abstract base class for creating interactive buttons with click functionality.
* This class extends {@link AbstractButton} and provides additional behavior such as
* click handling, hover effects, and alignment management.
*/
public abstract class ClickButton extends AbstractButton {
/**
* The action to be executed when the button is clicked.
*/
protected final Runnable action;
/**
* The label or text displayed on the button.
*/
protected String label;
/**
* The size of the button in relative units.
*/
protected Vector2f size;
/**
* The instance of the button being managed.
*/
protected Button instance;
/**
* Constructs a ClickButton with the specified properties.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button belongs
* @param action the action to execute on button click
* @param label the text label displayed on the button
* @param size the size of the button
* @param pos the position of the button in relative units
*/
ClickButton(MdgaApp app, Node node, Runnable action, String label, Vector2f size, Vector2f pos) {
super(app, node);
this.action = action;
this.label = label;
this.pos = pos;
this.size = size;
instance = new Button(label);
// Add click behavior
instance.addClickCommands((button) -> {
app.getAcousticHandler().playSound(MdgaSound.BUTTON_PRESSED);
action.run();
});
// Set text alignment
instance.setTextHAlignment(HAlignment.Center);
instance.setTextVAlignment(VAlignment.Center);
// Add hover commands
instance.addCommands(Button.ButtonAction.HighlightOn, (button) -> click());
instance.addCommands(Button.ButtonAction.HighlightOff, (button) -> release());
// Set font and colors
instance.setFont(font);
instance.setFocusColor(TEXT_NORMAL);
calculateRelative();
setRelative();
}
/**
* Displays the button by attaching it and its background image to the node.
*/
@Override
public void show() {
node.attachChild(pictureNormal);
release();
calculateRelative();
setRelative();
setImageRelative(pictureNormal);
node.attachChild(instance);
}
/**
* Hides the button by detaching it and its background images from the node.
*/
@Override
public void hide() {
node.detachChild(instance);
if (node.hasChild(pictureNormal)) {
node.detachChild(pictureNormal);
}
if (node.hasChild(pictureHover)) {
node.detachChild(pictureHover);
}
}
/**
* Abstract method to define hover behavior. Must be implemented by subclasses.
*/
protected abstract void onHover();
/**
* Abstract method to define unhover behavior. Must be implemented by subclasses.
*/
protected abstract void onUnHover();
/**
* Handles the button click behavior, including visual feedback and sound effects.
*/
protected void click() {
instance.setColor(TEXT_PRESSED);
instance.setHighlightColor(TEXT_PRESSED);
QuadBackgroundComponent background = new QuadBackgroundComponent(BUTTON_PRESSED);
instance.setBackground(background);
app.getAcousticHandler().playSound(MdgaSound.UI_CLICK);
if (node.hasChild(pictureNormal)) {
node.detachChild(pictureNormal);
setImageRelative(pictureHover);
node.attachChild(pictureHover);
}
onHover();
}
/**
* Resets the button to its normal state after a click or hover event.
*/
protected void release() {
instance.setColor(TEXT_NORMAL);
instance.setHighlightColor(TEXT_NORMAL);
QuadBackgroundComponent background = new QuadBackgroundComponent(BUTTON_NORMAL);
instance.setBackground(background);
if (node.hasChild(pictureHover)) {
node.detachChild(pictureHover);
setImageRelative(pictureNormal);
node.attachChild(pictureNormal);
}
onUnHover();
}
/**
* Sets the relative size and position of the button based on screen dimensions.
*/
protected void setRelative() {
instance.setFontSize(fontSize);
instance.setPreferredSize(new Vector3f(size.x * widthStep, size.y * heightStep, 0));
float xAdjust = 0.0f;
if (adjust) {
xAdjust = instance.getPreferredSize().x;
}
instance.setLocalTranslation(pos.x * horizontalStep - xAdjust, pos.y * verticalStep, -1);
final float horizontalMid = ((float) app.getCamera().getWidth() / 2) - (instance.getPreferredSize().x / 2);
final float verticalMid = ((float) app.getCamera().getHeight() / 2) - instance.getPreferredSize().y / 2;
if (0 == pos.x) {
instance.setLocalTranslation(horizontalMid, instance.getLocalTranslation().y, instance.getLocalTranslation().z);
}
if (0 == pos.y) {
instance.setLocalTranslation(instance.getLocalTranslation().x, verticalMid, instance.getLocalTranslation().z);
}
}
/**
* Sets the relative size and position of the button's background image.
*
* @param picture the background image to set
*/
protected void setImageRelative(Picture picture) {
if (null == picture) {
return;
}
final float LARGER = 10;
picture.setWidth(instance.getPreferredSize().x + LARGER);
picture.setHeight(instance.getPreferredSize().y + LARGER);
picture.setLocalTranslation(
instance.getLocalTranslation().x - LARGER / 2,
(instance.getLocalTranslation().y - picture.getHeight()) + LARGER / 2,
instance.getLocalTranslation().z + 0.01f
);
}
}

View File

@@ -1,166 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
/**
* Represents an input button with a label and a text field, allowing users to input text.
* The button is designed for graphical user interfaces and supports configurable
* size, position, and character limit.
*/
public class InputButton extends AbstractButton {
/**
* The label associated with the input field, displayed above or beside the text field.
*/
private Label label;
/**
* The text field where users input their text.
*/
private TextField field;
/**
* A container to hold the label and the text field for layout management.
*/
private Container container = new Container();
/**
* The maximum allowed length of the input text.
*/
private final int maxLenght;
/**
* The size of the input button in relative units.
*/
protected Vector2f size;
/**
* Constructs an InputButton with the specified label, character limit, and other properties.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the input button belongs
* @param label the label displayed with the input field
* @param maxLenght the maximum number of characters allowed in the input field
*/
public InputButton(MdgaApp app, Node node, String label, int maxLenght) {
super(app, node);
this.label = new Label(label);
this.maxLenght = maxLenght;
// Configure label properties
this.label.setColor(TEXT_NORMAL);
// Configure text field properties
field = new TextField("");
field.setColor(TEXT_NORMAL);
field.setTextHAlignment(HAlignment.Left);
field.setTextVAlignment(VAlignment.Center);
// Set background for the text field
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(BUTTON_NORMAL);
field.setBackground(grayBackground);
// Set fonts for label and text field
this.label.setFont(font);
field.setFont(font);
// Default position and size
pos = new Vector2f(0, 0);
size = new Vector2f(5.5f, 1);
// Add components to the container
container.addChild(this.label);
container.addChild(field);
}
/**
* Displays the input button by attaching it to the scene graph node.
*/
@Override
public void show() {
calculateRelative();
setRelative();
node.attachChild(container);
}
/**
* Hides the input button by detaching it from the scene graph node.
*/
@Override
public void hide() {
node.detachChild(container);
}
/**
* Updates the input field, enforcing the character limit.
* Trims the text if it exceeds the maximum allowed length.
*/
public void update() {
String text = field.getText();
int length = text.length();
if (length > maxLenght) {
field.setText(text.substring(0, maxLenght));
}
}
/**
* Adjusts the relative size and position of the input button based on the screen resolution.
*/
protected void setRelative() {
this.label.setFontSize(fontSize);
field.setFontSize(fontSize);
field.setPreferredSize(new Vector3f(size.x * widthStep, size.y * heightStep, 0));
float xAdjust = 0.0f;
if (adjust) {
xAdjust = container.getPreferredSize().x;
}
container.setLocalTranslation(pos.x * horizontalStep - xAdjust, pos.y * verticalStep, -1);
final float horizontalMid = ((float) app.getCamera().getWidth() / 2) - (container.getPreferredSize().x / 2);
final float verticalMid = ((float) app.getCamera().getHeight() / 2) - container.getPreferredSize().y / 2;
if (0 == pos.x) {
container.setLocalTranslation(horizontalMid, container.getLocalTranslation().y, -1);
}
if (0 == pos.y) {
container.setLocalTranslation(container.getLocalTranslation().x, verticalMid, -1);
}
}
/**
* Retrieves the text currently entered in the input field.
*
* @return the current text in the input field
*/
public String getString() {
return field.getText();
}
/**
* Sets the text of the input field to the specified string.
*
* @param string the text to set in the input field
*/
public void setString(String string) {
field.setText(string);
}
/**
* Resets the input field by clearing its text.
*/
public void reset() {
field.setText("");
}
}

View File

@@ -1,131 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
/**
* A specialized button that can function as a label or a clickable button.
* It inherits from {@link ClickButton} and allows for flexible usage with or without button-like behavior.
*/
public class LabelButton extends ClickButton {
/**
* The color of the text displayed on the label or button.
*/
private ColorRGBA text = TEXT_NORMAL;
/**
* The color of the button's background.
*/
private ColorRGBA button = BUTTON_NORMAL;
/**
* Flag indicating whether this component functions as a button.
*/
private boolean isButton;
/**
* Constructs a LabelButton with specified properties.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button belongs
* @param label the text displayed on the label or button
* @param size the size of the label or button
* @param pos the position of the label or button in relative units
* @param isButton whether this component acts as a button or a simple label
*/
public LabelButton(MdgaApp app, Node node, String label, Vector2f size, Vector2f pos, boolean isButton) {
super(app, node, () -> {}, label, size, pos);
this.isButton = isButton;
// Use the same image for hover and normal states
pictureHover = pictureNormal;
}
/**
* Displays the label or button, attaching it to the scene graph.
* If the component is a button, it also attaches the background image.
*/
@Override
public void show() {
if (isButton) {
node.attachChild(pictureNormal);
}
release();
calculateRelative();
setRelative();
setImageRelative(pictureNormal);
instance.setFontSize(fontSize / 2);
node.attachChild(instance);
}
/**
* Hides the label or button, detaching it from the scene graph.
*/
@Override
public void hide() {
node.detachChild(instance);
if (node.hasChild(pictureNormal)) {
node.detachChild(pictureNormal);
}
if (node.hasChild(pictureHover)) {
node.detachChild(pictureHover);
}
}
/**
* Handles hover behavior, updating the colors of the text and background.
*/
@Override
public void onHover() {
instance.setColor(text);
instance.setHighlightColor(text);
QuadBackgroundComponent background = new QuadBackgroundComponent(button);
instance.setBackground(background);
}
/**
* Handles unhover behavior, restoring the colors of the text and background.
*/
@Override
public void onUnHover() {
instance.setColor(text);
instance.setHighlightColor(text);
QuadBackgroundComponent background = new QuadBackgroundComponent(button);
instance.setBackground(background);
}
/**
* Sets the text displayed on the label or button.
*
* @param text the text to display
*/
public void setText(String text) {
instance.setText(text);
}
/**
* Sets the colors of the text and background, and refreshes the label or button.
*
* @param text the color of the text
* @param button the color of the button's background
*/
public void setColor(ColorRGBA text, ColorRGBA button) {
this.text = text;
this.button = button;
hide();
show();
}
}

View File

@@ -1,334 +0,0 @@
package pp.mdga.client.button;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color;
/**
* Represents a button in a multiplayer lobby screen. The button supports multiple states
* (not taken, self, other) and displays a 3D model alongside its label. It can also indicate readiness
* and interactively respond to hover and click events.
*/
public class LobbyButton extends ClickButton {
/**
* Enum representing the possible ownership states of the lobby button.
*/
public enum Taken {
NOT, // The button is not taken
SELF, // The button is taken by the user
OTHER // The button is taken by another user
}
/**
* Color for a lobby button that is taken by another user.
*/
static final ColorRGBA LOBBY_TAKEN = ColorRGBA.fromRGBA255(193, 58, 59, 100);
/**
* Color for a lobby button that is ready but not hovered.
*/
static final ColorRGBA LOBBY_READY = ColorRGBA.fromRGBA255(55, 172, 190, 100);
/**
* Color for a lobby button that is ready and hovered.
*/
static final ColorRGBA LOBBY_READY_HOVER = ColorRGBA.fromRGBA255(17, 211, 218, 100);
/**
* Color for a lobby button owned by the user in normal state.
*/
static final ColorRGBA LOBBY_SELF_NORMAL = ColorRGBA.fromRGBA255(0, 151, 19, 100);
/**
* Color for a lobby button owned by the user when hovered.
*/
static final ColorRGBA LOBBY_SELF_HOVER = ColorRGBA.fromRGBA255(0, 230, 19, 100);
/**
* Fixed width for the lobby button.
*/
static final float WIDTH = 4.0f;
/**
* Node to which the 3D model associated with this button is attached.
*/
private final Node node3d;
/**
* Indicates whether the 3D model should rotate.
*/
private boolean rotate = false;
/**
* The 3D model displayed alongside the button.
*/
private Spatial model;
/**
* The rotation angle of the 3D model.
*/
private float rot = 180;
/**
* The current ownership state of the lobby button.
*/
private Taken taken = Taken.NOT;
/**
* Label displayed on the lobby button.
*/
private LabelButton label;
/**
* Indicates whether the button represents a ready state.
*/
private boolean isReady = false;
/**
* Constructs a LobbyButton with specified properties, including a 3D model and label.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button belongs
* @param node3d the node for 3D scene components associated with this button
* @param action the action to execute when the button is clicked
* @param tsk the type or category of the button (e.g., CYBER, AIRFORCE)
*/
public LobbyButton(MdgaApp app, Node node, Node node3d, Runnable action, Color tsk) {
super(app, node, action, "", new Vector2f(WIDTH, 7), new Vector2f(0, 0));
this.node3d = node3d;
label = new LabelButton(app, node, "- leer -", new Vector2f(WIDTH, 1), new Vector2f(0, 0), true);
final float mid = HORIZONTAL / 2;
final float uiSpacing = 0.4f;
final float figSpacing = 0.51f;
float uiX = mid;
float figX = 0;
Asset asset = null;
// Configure the button based on its type
switch (tsk) {
case CYBER:
adjust = true;
label.adjust = true;
uiX -= 3 * uiSpacing;
uiX -= WIDTH / 2;
asset = Asset.cir;
figX -= 3 * figSpacing;
instance.setText("CIR");
break;
case AIRFORCE:
adjust = true;
label.adjust = true;
uiX -= uiSpacing;
asset = Asset.lw;
figX -= figSpacing;
instance.setText("Luftwaffe");
break;
case ARMY:
uiX += uiSpacing;
asset = Asset.heer;
figX += figSpacing;
instance.setText("Heer");
break;
case NAVY:
uiX += 3 * uiSpacing;
uiX += WIDTH / 2;
asset = Asset.marine;
figX += 3 * figSpacing;
instance.setText("Marine");
break;
}
setPos(new Vector2f(uiX, 6));
label.setPos(new Vector2f(uiX, 7));
createModel(asset, new Vector3f(figX, -0.55f, 6));
}
/**
* Handles hover behavior, updating the button's color and enabling rotation.
*/
@Override
public void onHover() {
ColorRGBA buttonPressed = BUTTON_PRESSED.clone();
switch (taken) {
case NOT:
buttonPressed.a = 0.3f;
break;
case SELF:
buttonPressed = LOBBY_SELF_HOVER;
break;
case OTHER:
buttonPressed = LOBBY_TAKEN;
break;
}
if (isReady) {
buttonPressed = LOBBY_READY_HOVER;
}
QuadBackgroundComponent background = new QuadBackgroundComponent(buttonPressed);
instance.setBackground(background);
rotate = true;
}
/**
* Handles unhover behavior, restoring the button's color and disabling rotation.
*/
@Override
public void onUnHover() {
ColorRGBA buttonNormal = BUTTON_NORMAL.clone();
switch (taken) {
case NOT:
buttonNormal.a = 0.3f;
break;
case SELF:
buttonNormal = LOBBY_SELF_NORMAL;
break;
case OTHER:
buttonNormal = LOBBY_TAKEN;
break;
}
if (isReady) {
buttonNormal = LOBBY_READY;
}
QuadBackgroundComponent background = new QuadBackgroundComponent(buttonNormal);
instance.setBackground(background);
rotate = false;
}
/**
* Displays the lobby button and its associated components.
*/
@Override
public void show() {
release();
calculateRelative();
setRelative();
node.attachChild(instance);
node3d.attachChild(model);
label.show();
}
/**
* Hides the lobby button and its associated components.
*/
@Override
public void hide() {
node.detachChild(instance);
node3d.detachChild(model);
label.hide();
}
/**
* Updates the 3D model's rotation if the button is being hovered.
*
* @param tpf time per frame, used for smooth rotation calculations
*/
public void update(float tpf) {
if (rotate) {
rot += 140.0f * tpf;
rot %= 360;
} else {
rot = 180;
}
model.setLocalRotation(new Quaternion().fromAngles(
(float) Math.toRadians(90),
(float) Math.toRadians(rot),
(float) Math.toRadians(180)
));
}
/**
* Creates the 3D model associated with the lobby button and applies textures and positioning.
*
* @param asset the asset representing the 3D model
* @param pos the initial position of the 3D model
*/
private void createModel(Asset asset, Vector3f pos) {
String modelName = asset.getModelPath();
String texName = asset.getDiffPath();
model = app.getAssetManager().loadModel(modelName);
model.scale(asset.getSize() / 2);
model.rotate(
(float) Math.toRadians(90),
(float) Math.toRadians(rot),
(float) Math.toRadians(180)
);
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
model.setLocalTranslation(pos);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat);
}
/**
* Gets the current ownership state of the lobby button.
*
* @return the current state of the button
*/
public Taken getTaken() {
return taken;
}
/**
* Sets the ownership state of the lobby button and updates its label accordingly.
*
* @param taken the new ownership state
* @param name the name to display on the button
*/
public void setTaken(Taken taken, String name) {
this.taken = taken;
if (taken == Taken.NOT) {
label.setText("- leer -");
isReady = false;
} else {
label.setText(name);
}
onUnHover();
}
/**
* Sets the ready state of the lobby button and updates its appearance.
*
* @param isReady whether the button represents a ready state
*/
public void setReady(boolean isReady) {
this.isReady = isReady;
onUnHover();
}
}

View File

@@ -1,43 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
/**
* Represents a button used in menu screens for navigation or executing actions.
* Inherits from {@link ClickButton} and provides customizable text and actions.
*/
public class MenuButton extends ClickButton {
/**
* Constructs a MenuButton with specified properties.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button belongs
* @param action the action to execute when the button is clicked
* @param label the text label displayed on the button
*/
public MenuButton(MdgaApp app, Node node, Runnable action, String label) {
super(app, node, action, label, new Vector2f(5.5f, 2), new Vector2f(0, 0));
}
/**
* Called when the button is hovered over. Can be overridden to define hover-specific behavior.
* Currently, no additional behavior is implemented.
*/
@Override
public void onHover() {
// Placeholder for hover behavior
}
/**
* Called when the pointer stops hovering over the button. Can be overridden to define unhover-specific behavior.
* Currently, no additional behavior is implemented.
*/
@Override
public void onUnHover() {
// Placeholder for unhover behavior
}
}

View File

@@ -1,75 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.IconComponent;
import pp.mdga.client.MdgaApp;
/**
* Represents a button in the settings menu, designed to display an icon and handle hover effects.
* Inherits from {@link ClickButton} and customizes its behavior for settings functionality.
*/
public class SettingsButton extends ClickButton {
/**
* The icon displayed on the button, which changes based on hover state.
*/
private IconComponent icon;
/**
* Constructs a SettingsButton with a predefined size and position.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the button belongs
* @param action the action to execute when the button is clicked
*/
public SettingsButton(MdgaApp app, Node node, Runnable action) {
super(app, node, action, "", new Vector2f(2, 2), new Vector2f(HORIZONTAL - 0.5f, VERTICAL - 0.5f));
// Enable adjustment for positioning
adjust = true;
}
/**
* Displays the settings button by attaching it to the scene graph.
*/
@Override
public void show() {
release();
calculateRelative();
setRelative();
setImageRelative(pictureNormal);
node.attachChild(instance);
}
/**
* Handles hover behavior by changing the icon to the hover state.
*/
@Override
public void onHover() {
icon = new IconComponent("Images/Settings_Button_hover.png");
icon.setIconScale(0.02f * app.getImageScale());
icon.setHAlignment(HAlignment.Center);
icon.setVAlignment(VAlignment.Center);
instance.setIcon(icon);
}
/**
* Handles unhover behavior by restoring the icon to the normal state.
*/
@Override
public void onUnHover() {
icon = new IconComponent("Images/Settings_Button_normal.png");
icon.setIconScale(0.02f * app.getImageScale());
icon.setHAlignment(HAlignment.Center);
icon.setVAlignment(VAlignment.Center);
instance.setIcon(icon);
}
}

View File

@@ -1,163 +0,0 @@
package pp.mdga.client.button;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
/**
* Represents a slider button component with a label, providing functionality for
* adjusting values in a graphical user interface. It includes increment, decrement,
* and thumb buttons, allowing for interactive adjustments.
*/
public class SliderButton extends AbstractButton {
/**
* The label displayed next to the slider.
*/
private Label label;
/**
* The slider component for adjusting values.
*/
private Slider slider;
/**
* A container to hold the label and slider for layout management.
*/
private Container container = new Container();
/**
* The size of the slider button in relative units.
*/
protected Vector2f size;
/**
* Constructs a SliderButton with the specified label.
*
* @param app the application instance for accessing resources
* @param node the node in the scene graph to which the slider button belongs
* @param label the text label displayed alongside the slider
*/
public SliderButton(MdgaApp app, Node node, String label) {
super(app, node);
this.label = new Label(label);
this.label.setColor(TEXT_NORMAL);
// Configure the slider
slider = new Slider("slider");
// Configure decrement button
slider.getDecrementButton().setText(" - ");
slider.getDecrementButton().setFont(font);
slider.getDecrementButton().setFocusColor(TEXT_NORMAL);
slider.getDecrementButton().setTextVAlignment(VAlignment.Bottom);
slider.getDecrementButton().setColor(TEXT_NORMAL);
slider.getDecrementButton().setHighlightColor(TEXT_NORMAL);
// Configure increment button
slider.getIncrementButton().setText(" + ");
slider.getIncrementButton().setFont(font);
slider.getIncrementButton().setFocusColor(TEXT_NORMAL);
slider.getIncrementButton().setTextVAlignment(VAlignment.Bottom);
slider.getIncrementButton().setColor(TEXT_NORMAL);
slider.getIncrementButton().setHighlightColor(TEXT_NORMAL);
// Configure thumb button
slider.getThumbButton().setText("X");
slider.getThumbButton().setFont(font);
slider.getThumbButton().setFocusColor(TEXT_NORMAL);
slider.getThumbButton().setColor(TEXT_NORMAL);
slider.getThumbButton().setHighlightColor(TEXT_NORMAL);
// Set slider background
QuadBackgroundComponent background = new QuadBackgroundComponent(BUTTON_NORMAL);
slider.setBackground(background);
// Configure the label font
this.label.setFont(font);
// Default position and size
pos = new Vector2f(0, 0);
size = new Vector2f(5.5f, 1);
// Add label and slider to container
container.addChild(this.label);
container.addChild(slider);
}
/**
* Displays the slider button by attaching its container to the scene graph.
*/
@Override
public void show() {
calculateRelative();
setRelative();
node.attachChild(container);
}
/**
* Hides the slider button by detaching its container from the scene graph.
*/
@Override
public void hide() {
node.detachChild(container);
}
/**
* Sets the relative size and position of the slider button based on screen resolution.
*/
protected void setRelative() {
this.label.setFontSize(fontSize);
// Set font sizes for slider components
slider.getDecrementButton().setFontSize(fontSize);
slider.getIncrementButton().setFontSize(fontSize);
slider.getThumbButton().setFontSize(fontSize);
// Set slider size
slider.setPreferredSize(new Vector3f(size.x * widthStep, size.y * heightStep, 0));
float xAdjust = 0.0f;
if (adjust) {
xAdjust = container.getPreferredSize().x;
}
// Set container position
container.setLocalTranslation(pos.x * horizontalStep - xAdjust, pos.y * verticalStep, -1);
final float horizontalMid = ((float) app.getCamera().getWidth() / 2) - (container.getPreferredSize().x / 2);
final float verticalMid = ((float) app.getCamera().getHeight() / 2) - container.getPreferredSize().y / 2;
if (0 == pos.x) {
container.setLocalTranslation(horizontalMid, container.getLocalTranslation().y, -1);
}
if (0 == pos.y) {
container.setLocalTranslation(container.getLocalTranslation().x, verticalMid, -1);
}
}
/**
* Retrieves the current percentage value of the slider.
*
* @return the current percentage value as a float
*/
public float getPercent() {
return (float) slider.getModel().getPercent();
}
/**
* Sets the slider to the specified percentage value.
*
* @param percent the percentage value to set
*/
public void setPercent(float percent) {
slider.getModel().setPercent(percent);
}
}

View File

@@ -1,80 +0,0 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.button.SliderButton;
import pp.mdga.client.view.MdgaView;
public class AudioSettingsDialog extends Dialog {
private final MdgaView view;
private SliderButton mainVolume;
private SliderButton musicVolume;
private SliderButton soundVolume;
private MenuButton backButton;
private boolean active = false;
public AudioSettingsDialog(MdgaApp app, Node node, MdgaView view) {
super(app, node);
this.view = view;
mainVolume = new SliderButton(app, node, "Gesamt Lautstärke");
musicVolume = new SliderButton(app, node, "Musik Lautstärke");
soundVolume = new SliderButton(app, node, "Effekt Lautstärke");
backButton = new MenuButton(app, node, view::leaveAudioSettings, "Zurück");
float offset = 2.8f;
mainVolume.setPos(new Vector2f(0, MenuButton.VERTICAL - offset));
offset += 1.0f;
musicVolume.setPos(new Vector2f(0, MenuButton.VERTICAL - offset));
offset += 1.0f;
soundVolume.setPos(new Vector2f(0, MenuButton.VERTICAL - offset));
backButton.setPos(new Vector2f(0, 1.8f));
}
@Override
protected void onShow() {
active = true;
mainVolume.setPercent(app.getAcousticHandler().getMainVolume());
musicVolume.setPercent(app.getAcousticHandler().getMusicVolume());
soundVolume.setPercent(app.getAcousticHandler().getSoundVolume());
backButton.show();
mainVolume.show();
musicVolume.show();
soundVolume.show();
}
@Override
protected void onHide() {
active = false;
backButton.hide();
mainVolume.hide();
musicVolume.hide();
soundVolume.hide();
}
public void update() {
if(!active) {
return;
}
app.getAcousticHandler().setMainVolume(mainVolume.getPercent());
app.getAcousticHandler().setMusicVolume(musicVolume.getPercent());
app.getAcousticHandler().setSoundVolume(soundVolume.getPercent());
}
}

View File

@@ -1,105 +0,0 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.AbstractButton;
import pp.mdga.client.button.LabelButton;
import pp.mdga.client.button.MenuButton;
import java.util.ArrayList;
public class CeremonyDialog extends Dialog {
private ArrayList<ArrayList<LabelButton>> labels;
float offsetX;
public CeremonyDialog(MdgaApp app, Node node) {
super(app, node);
prepare();
}
@Override
protected void onShow() {
for (ArrayList<LabelButton> row : labels) {
for (LabelButton b : row) {
b.show();
}
}
}
@Override
protected void onHide() {
for (ArrayList<LabelButton> row : labels) {
for (LabelButton b : row) {
b.hide();
}
}
}
public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) {
float offsetYSmall = 0.5f;
ArrayList<LabelButton> row = new ArrayList<>();
Vector2f sizeSmall = new Vector2f(4, 1.2f);
row.add(new LabelButton(app, node, name, sizeSmall, new Vector2f(), true));
row.add(new LabelButton(app, node, "" + v1, sizeSmall, new Vector2f(), false));
row.add(new LabelButton(app, node, "" + v2, sizeSmall, new Vector2f(), false));
row.add(new LabelButton(app, node, "" + v3, sizeSmall, new Vector2f(), false));
row.add(new LabelButton(app, node, "" + v4, sizeSmall, new Vector2f(), false));
row.add(new LabelButton(app, node, "" + v5, sizeSmall, new Vector2f(), false));
row.add(new LabelButton(app, node, "" + v6, sizeSmall, new Vector2f(), false));
ColorRGBA colorText = AbstractButton.TEXT_NORMAL.clone();
colorText.a = 0.2f;
ColorRGBA colorButton = AbstractButton.BUTTON_NORMAL.clone();
colorButton.a = 0.2f;
int j = 0;
for (LabelButton b : row) {
if(j > 0) {
b.setColor(colorText, colorButton);
}
b.setPos(new Vector2f(offsetX, MenuButton.VERTICAL - offsetYSmall));
offsetYSmall += 0.8f;
j++;
}
offsetX += 2.3f;
labels.add(row);
}
public void prepare() {
offsetX = 0.5f;
labels = new ArrayList<>();
ArrayList<LabelButton> first = new ArrayList<>();
Vector2f size = new Vector2f(4, 1.2f);
first.add(new LabelButton(app, node, "", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Figuren geworfen", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Figuren verloren", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Gespielte Bonuskarten", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Gewürfelte 6en", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Gelaufene Felder", size, new Vector2f(), true));
first.add(new LabelButton(app, node, "Bonusfeldern erreicht", size, new Vector2f(), true));
float offsetY = 0.5f;
for (LabelButton b : first) {
b.setPos(new Vector2f(offsetX, MenuButton.VERTICAL - offsetY));
offsetY += 0.8f;
}
offsetX += 2.3f;
labels.add(first);
}
}

View File

@@ -1,32 +1,82 @@
package pp.mdga.client.dialog; package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import static com.jme3.math.FastMath.floor;
public abstract class Dialog { public abstract class Dialog {
protected final ColorRGBA COLOR_DEFAULT = ColorRGBA.Gray;
protected final ColorRGBA COLOR_HOVER = ColorRGBA.DarkGray;
protected Container container;
protected final MdgaApp app; protected final MdgaApp app;
protected final Node node = new Node(); private final Node node;
private final Node root; protected final float vertical_step;
protected final float horitontal_step;
Dialog(MdgaApp app, Node node) { protected float fontSize = 35;
public Dialog(MdgaApp app, Node node) {
this.app = app; this.app = app;
this.root = node; this.node = node;
this.container = new Container();
this.horitontal_step = app.getCamera().getWidth() / 16;
this.vertical_step = app.getCamera().getHeight() / 9;
int val = (int) (32 * Math.min(app.getResolutionFactor() * 0.9f, 1));
fontSize = val;
} }
public void show() { public void show() {
root.attachChild(node); node.attachChild(container);
onShow();
} }
public void hide() { public void hide () {
root.detachChild(node); node.detachChild(container);
onHide();
} }
protected abstract void onShow(); protected void createButton(String label, Runnable action, Vector3f size) {
protected abstract void onHide (); Button button = new Button(label);
button.addClickCommands(source -> action.run());
button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
container.addChild(button);
}
} }

View File

@@ -0,0 +1,15 @@
package pp.mdga.client.dialog;
import java.util.function.Supplier;
public class GetPercentRunnable {
private final Supplier<Float> action;
public GetPercentRunnable(Supplier<Float> action) {
this.action = action;
}
public float get() {
return action.get();
}
}

View File

@@ -1,68 +1,143 @@
package pp.mdga.client.dialog; package pp.mdga.client.dialog;
import com.jme3.math.Vector2f; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.InputButton;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MainView;
import java.util.prefs.Preferences; public class HostDialog extends Dialog {
private TextField portInput;
public class HostDialog extends Dialog { public HostDialog(MdgaApp app, Node node, Runnable backAction) {
private InputButton portInput;
private ButtonRight hostButton;
private ButtonLeft backButton;
private final MainView view;
private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
public HostDialog(MdgaApp app, Node node, MainView view) {
super(app, node); super(app, node);
this.view = view; QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
portInput = new InputButton(app, node, "Port: ", 5); Texture texture = app.getAssetManager().loadTexture("mdga_logo.png");
portInput.setString(prefs.get("hostPort", "11111"));
hostButton = new ButtonRight(app, node, view::forward, "Spiel hosten", 10); QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
backButton = new ButtonLeft(app, node, view::back, "Zurück", 10);
float offset = 2.8f; Panel imagePanel = new Panel();
imagePanel.setBackground(b);
portInput.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); container.addChild(imagePanel).setPreferredSize(new Vector3f(texture.getImage().getWidth() / 4 * app.getResolutionFactor(), texture.getImage().getHeight() / 4 * app.getResolutionFactor(), 0));
offset += 1.5f;
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
createTextField();
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
Container sub = new Container(new SpringGridLayout(Axis.X, Axis.Y));
createButton(sub, "Abbrechen", backAction, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
sub.addChild(new Panel(40 * app.getResolutionFactor(), 0 * app.getResolutionFactor(), ColorRGBA.Gray));
createButton(sub, "Starten", () -> tryStart(), new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
container.addChild(sub);
}
void tryStart() {
if (null == portInput.getText()) {
portInput.setText("");
return;
}
int port = 0;
try {
port = Integer.parseInt(portInput.getText());
} catch (NumberFormatException e) {
portInput.setText("");
return;
}
if(port >= 1 && port <= 65535) {
app.getModelSyncronizer().setHost(port);
}
portInput.setText("");
} }
@Override @Override
protected void onShow() { public void show() {
portInput.show(); super.show();
hostButton.show();
backButton.show(); container.setLocalTranslation(
app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
} }
@Override @Override
protected void onHide() { public void hide() {
portInput.hide(); super.hide();
hostButton.hide();
backButton.hide();
} }
public void update() { private void createTextField() {
portInput.update(); Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
Label nameLabel = new Label("Port:\t");
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
portInput = new TextField("");
portInput.setColor(ColorRGBA.Black);
portInput.setTextHAlignment(HAlignment.Left);
portInput.setFontSize(fontSize);
portInput.setSingleLine(true);
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(ColorRGBA.DarkGray);
portInput.setBackground(grayBackground);
subContainer.addChild(nameLabel);
subContainer.addChild(portInput);
container.addChild(subContainer);
} }
public String getPort() { protected void createButton(Container c, String label, Runnable action, Vector3f size) {
prefs.put("hostPort", portInput.getString()); Button button = new Button(label);
return portInput.getString(); button.addClickCommands(source -> action.run());
} button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
public void resetPort() { QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
portInput.reset(); background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
prefs.put("hostPort", "11111"); button.setBackground(background);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
c.addChild(button);
} }
} }

View File

@@ -1,4 +0,0 @@
package pp.mdga.client.dialog;
public class InterruptDialog {
}

View File

@@ -1,88 +1,192 @@
package pp.mdga.client.dialog; package pp.mdga.client.dialog;
import com.jme3.math.Vector2f; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.AcousticHandler;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.InputButton;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MainView;
import java.util.prefs.Preferences; import java.util.regex.Pattern;
public class JoinDialog extends Dialog { public class JoinDialog extends Dialog {
private InputButton ipInput; private TextField portInput;
private InputButton portInput; private TextField ipInput;
private ButtonRight joinButton; public JoinDialog(MdgaApp app, Node node, Runnable backAction) {
private ButtonLeft backButton;
private final MainView view;
private Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
public JoinDialog(MdgaApp app, Node node, MainView view) {
super(app, node); super(app, node);
this.view = view; QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
ipInput = new InputButton(app, node, "Ip: ", 15); Texture texture = app.getAssetManager().loadTexture("mdga_logo.png");
portInput = new InputButton(app, node, "Port: ", 5);
portInput.setString(prefs.get("joinPort", "11111"));
ipInput.setString(prefs.get("joinIp", ""));
joinButton = new ButtonRight(app, node, view::forward, "Spiel beitreten", 10); QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
backButton = new ButtonLeft(app, node, view::back, "Zurück", 10);
float offset = 2.8f; Panel imagePanel = new Panel();
imagePanel.setBackground(b);
ipInput.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); container.addChild(imagePanel).setPreferredSize(new Vector3f(texture.getImage().getWidth() / 4 * app.getResolutionFactor(), texture.getImage().getHeight() / 4 * app.getResolutionFactor(), 0));
offset += 1.5f;
portInput.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); //abstandshalter
offset += 1.5f; container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
createIpField();
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
createPortField();
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
Container sub = new Container(new SpringGridLayout(Axis.X, Axis.Y));
createButton(sub, "Abbrechen", backAction, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
sub.addChild(new Panel(40 * app.getResolutionFactor(), 0 * app.getResolutionFactor(), ColorRGBA.Gray));
createButton(sub, "Beitreten", () -> tryJoin(), new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
container.addChild(sub);
}
void tryJoin() {
if (null == portInput.getText()) {
portInput.setText("");
ipInput.setText("");
return;
}
int port = 0;
try {
port = Integer.parseInt(portInput.getText());
} catch (NumberFormatException e) {
portInput.setText("");
ipInput.setText("");
return;
}
if(!(port >= 1 && port <= 65535)) {
portInput.setText("");
ipInput.setText("");
return;
}
if (null == ipInput.getText()) {
portInput.setText("");
ipInput.setText("");
return;
}
String ipv4Pattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
if(!Pattern.matches(ipv4Pattern, ipInput.getText())) {
portInput.setText("");
ipInput.setText("");
return;
}
app.getModelSyncronizer().setJoin(ipInput.getText(), port);
} }
@Override @Override
protected void onShow() { public void show() {
ipInput.show(); super.show();
portInput.show();
joinButton.show(); container.setLocalTranslation(
backButton.show(); app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
} }
@Override @Override
protected void onHide() { public void hide() {
ipInput.hide(); super.hide();
portInput.hide();
joinButton.hide();
backButton.hide();
} }
public void update() { private void createPortField() {
ipInput.update(); Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
portInput.update();
Label nameLabel = new Label("Port:\t");
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
portInput = new TextField("");
portInput.setColor(ColorRGBA.Black);
portInput.setTextHAlignment(HAlignment.Left);
portInput.setFontSize(fontSize);
portInput.setSingleLine(true);
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(ColorRGBA.DarkGray);
portInput.setBackground(grayBackground);
subContainer.addChild(nameLabel);
subContainer.addChild(portInput);
container.addChild(subContainer);
} }
public String getIpt() { private void createIpField() {
prefs.put("joinIp", ipInput.getString()); Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
return ipInput.getString();
Label nameLabel = new Label("Ip:\t");
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
ipInput = new TextField("");
ipInput.setColor(ColorRGBA.Black);
ipInput.setTextHAlignment(HAlignment.Left);
ipInput.setFontSize(fontSize);
ipInput.setSingleLine(true);
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(ColorRGBA.DarkGray);
ipInput.setBackground(grayBackground);
subContainer.addChild(nameLabel);
subContainer.addChild(ipInput);
container.addChild(subContainer);
} }
public void resetIp() { protected void createButton(Container c, String label, Runnable action, Vector3f size) {
ipInput.reset(); Button button = new Button(label);
prefs.put("joinIp", ""); button.addClickCommands(source -> action.run());
} button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
public String getPort() { QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
prefs.put("joinPort", portInput.getString()); background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
return portInput.getString(); button.setBackground(background);
}
public void resetPort() { button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
portInput.reset(); QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
prefs.put("joinPort", "11111"); hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
c.addChild(button);
} }
} }

View File

@@ -0,0 +1,165 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Command;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color;
public class LobbyButtonDialog extends Dialog {
private final int pos;
private Button button;
private Command<Button> clickCommand;
private boolean taken = false;
private final String label;
private int val;
public LobbyButtonDialog(MdgaApp app, Node node, String label, int pos) {
super(app, node);
clickCommand = (Button source) -> {
toggleButton();
};
this.pos = pos;
this.label = label;
this.button = new Button(label);
this.button.setFontSize(fontSize);
val = pos;
createNotTakenButton(new Vector3f(170 * app.getResolutionFactor(), 250 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = ((2 + (4 * pos)) * horitontal_step) - ((0.33333333f * pos) * container.getPreferredSize().x);
float y = 6 * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
public void setTaken(boolean isTaken, boolean self, String name) {
taken = isTaken;
if(isTaken) {
createTakenButton(new Vector3f(170 * app.getResolutionFactor(), 250 * app.getResolutionFactor(), 0), self);
button.setText(label + "\n\n" + name);
} else {
createNotTakenButton(new Vector3f(170 * app.getResolutionFactor(), 250 * app.getResolutionFactor(), 0));
button.setText(label);
}
}
protected void createNotTakenButton(Vector3f size) {
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
if(button.getClickCommands() != null) {
button.removeClickCommands(clickCommand);
}
button.addClickCommands(clickCommand);
QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
container.addChild(button);
}
private void toggleButton() {
if(taken) {
app.getModelSyncronizer().unselectTsk();
}
else {
app.getModelSyncronizer().selectTsk(Color.values()[val]);
}
}
protected void createTakenButton(Vector3f size, boolean self) {
ColorRGBA color_a;
ColorRGBA color_b;
if(button.getClickCommands() != null) {
button.removeClickCommands(clickCommand);
}
if(!self) {
color_a = ColorRGBA.Red;
color_b = ColorRGBA.Red;
} else {
color_a = ColorRGBA.Green;
color_b = ColorRGBA.Yellow;
button.addClickCommands(clickCommand);
}
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
QuadBackgroundComponent background = new QuadBackgroundComponent(color_a);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(color_b);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(color_a);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
container.addChild(button);
}
}

View File

@@ -0,0 +1,15 @@
package pp.mdga.client.dialog;
import java.util.function.Consumer;
public class PercentRunnable {
private final Consumer<Float> action;
public PercentRunnable(Consumer<Float> action) {
this.action = action;
}
public void run(float percent) {
action.accept(percent);
}
}

View File

@@ -0,0 +1,78 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
public class SettingsButtonDialog extends Dialog {
private IconComponent icon;
public SettingsButtonDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
icon = new IconComponent("zahnrad.png");
icon.setIconScale(0.1f * app.getResolutionFactor());
createButton(label, action, new Vector3f(60 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = (15.5f * horitontal_step) - container.getPreferredSize().x;
float y = 8.5f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
@Override
protected void createButton(String label, Runnable action, Vector3f size) {
Button button = new Button(label);
button.addClickCommands(source -> action.run());
button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.setIcon(icon);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setIcon(icon);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setIcon(icon);
});
container.addChild(button);
}
}

View File

@@ -1,50 +1,112 @@
package pp.mdga.client.dialog; package pp.mdga.client.dialog;
import com.jme3.math.Vector2f; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.event.CursorListener;
import com.simsilica.lemur.event.CursorMotionEvent;
import com.simsilica.lemur.event.MouseEventControl;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.InputButton; import com.simsilica.lemur.*;
import pp.mdga.client.button.MenuButton; import com.simsilica.lemur.style.*;
import pp.mdga.client.view.MainView;
import pp.mdga.client.view.MdgaView; import java.util.HashMap;
public class SettingsDialog extends Dialog { public class SettingsDialog extends Dialog {
private MenuButton videoButton; private TextField nameInput;
private MenuButton audioButton;
private MenuButton backButton;
private final MdgaView view; private HashMap<Slider, PercentRunnable> map = new HashMap<Slider, PercentRunnable>();
private HashMap<Slider, GetPercentRunnable> map2 = new HashMap<Slider, GetPercentRunnable>();
public SettingsDialog(MdgaApp app, Node node, MdgaView view) { public SettingsDialog(MdgaApp app, Node node, String path) {
super(app, node); super(app, node);
this.view = view; QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
videoButton = new MenuButton(app, node, view::enterVideoSettings, "Video"); Texture texture = app.getAssetManager().loadTexture(path);
audioButton = new MenuButton(app, node, view::enterAudioSettings, "Audio");
backButton = new MenuButton(app, node, view::leaveSettings, "Zurück");
float offset = 2.8f; QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
videoButton.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); Panel imagePanel = new Panel();
offset += 1.25f; imagePanel.setBackground(b);
audioButton.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); container.addChild(imagePanel).setPreferredSize(new Vector3f((texture.getImage().getWidth() / 2) * app.getResolutionFactor(), (texture.getImage().getHeight() / 2) * app.getResolutionFactor(), 0));
backButton.setPos(new Vector2f(0, 1.8f)); //abstandshalter
container.addChild(new Panel(80 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
} }
@Override @Override
protected void onShow() { public void show() {
videoButton.show(); super.show();
audioButton.show();
backButton.show(); container.setLocalTranslation(
app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
} }
@Override @Override
protected void onHide() { public void hide() {
videoButton.hide(); super.hide();
audioButton.hide(); }
backButton.hide();
public void addButton(String label, Runnable action, Vector3f size) {
createButton(label, action, size);
}
public void addSlider(String label, PercentRunnable action, GetPercentRunnable action2, Vector3f size, int start) {
Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
Slider slider = new Slider("slider");
QuadBackgroundComponent background = new QuadBackgroundComponent(ColorRGBA.DarkGray);
slider.setBackground(background);
slider.setPreferredSize(size);
slider.setModel(new DefaultRangedValueModel(0, 100, start));
slider.setPreferredSize(new Vector3f(150 * app.getResolutionFactor(), 30 * app.getResolutionFactor(), 0));
slider.getDecrementButton().setText(" - ");
slider.getIncrementButton().setText(" + ");
slider.getDecrementButton().setFontSize(25 * app.getResolutionFactor());
slider.getIncrementButton().setFontSize(25 * app.getResolutionFactor());
Label nameLabel = new Label(label);
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
nameLabel.setPreferredSize(new Vector3f(150 * app.getResolutionFactor(), 10 * app.getResolutionFactor(), 0));
subContainer.addChild(nameLabel);
subContainer.addChild(slider);
container.addChild(subContainer);
map.put(slider, action);
map2.put(slider, action2);
//abstandshalter
container.addChild(new Panel(20 * app.getResolutionFactor(), 10 * app.getResolutionFactor(), ColorRGBA.Gray));
}
public void initVolume() {
map2.forEach((slider, runnable) -> {
double val = (double) runnable.get();
slider.getModel().setPercent(val);
});
}
public void update() {
map.forEach((slider, runnable) -> {
float val = (float) slider.getModel().getPercent();
runnable.run(val);
});
} }
} }

View File

@@ -0,0 +1,28 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
public class SingleButtonLeftDialog extends Dialog {
public SingleButtonLeftDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
createButton(label, action, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = 2 * horitontal_step;
float y = 1.8f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
}

View File

@@ -0,0 +1,28 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
public class SingleButtonRightDialog extends Dialog {
public SingleButtonRightDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
createButton(label, action, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = (14 * horitontal_step) - container.getPreferredSize().x;
float y = 1.8f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
}

View File

@@ -1,188 +1,86 @@
package pp.mdga.client.dialog; package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.simsilica.lemur.Container; import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.InputButton;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MainView;
import java.util.Random;
import java.util.random.RandomGenerator;
public class StartDialog extends Dialog { public class StartDialog extends Dialog {
private InputButton nameInput; private TextField nameInput;
private MenuButton hostButton; public StartDialog(MdgaApp app, Node node) {
private MenuButton joinButton;
private MenuButton endButton;
private final MainView view;
public StartDialog(MdgaApp app, Node node, MainView view) {
super(app, node); super(app, node);
this.view = view; QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
nameInput = new InputButton(app, node, "Name: ", 16); Texture texture = app.getAssetManager().loadTexture("mdga_logo.png");
hostButton = new MenuButton(app, node, () -> view.forward(true), "Spiel hosten"); QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
joinButton = new MenuButton(app, node, () -> view.forward(false), "Spiel beitreten");
endButton = new MenuButton(app, node, app::stop, "Spiel beenden");
float offset = 2.8f; Panel imagePanel = new Panel();
imagePanel.setBackground(b);
nameInput.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); container.addChild(imagePanel).setPreferredSize(new Vector3f(texture.getImage().getWidth() / 4, texture.getImage().getHeight() / 4, 0));
offset += 1.15f;
hostButton.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); //abstandshalter
offset += 1.25f; container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
joinButton.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); createTextField();
offset += 1.25f;
endButton.setPos(new Vector2f(0, 1.8f)); //abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
} }
@Override @Override
protected void onShow() { public void show() {
nameInput.show(); super.show();
hostButton.show(); container.setLocalTranslation(
joinButton.show(); app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
endButton.show(); app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
} }
@Override @Override
protected void onHide () public void hide() {
{ super.hide();
nameInput.hide();
hostButton.hide();
joinButton.hide();
endButton.hide();
} }
public void update() { public void addButton(String label, Runnable action, Vector3f size) {
nameInput.update(); createButton(label, action, size);
}
private void createTextField() {
Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
Label nameLabel = new Label("Name:\t");
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
nameInput = new TextField("");
nameInput.setColor(ColorRGBA.Black);
nameInput.setTextHAlignment(HAlignment.Left);
nameInput.setFontSize(fontSize);
nameInput.setSingleLine(true);
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(ColorRGBA.DarkGray);
nameInput.setBackground(grayBackground);
subContainer.addChild(nameLabel);
subContainer.addChild(nameInput);
container.addChild(subContainer);
} }
public String getName() { public String getName() {
String name = nameInput.getString(); return nameInput.getText();
if (name == null || name.trim().isEmpty()) {
String[] names = {
"PixelPirat",
"NoobJäger",
"LagMeister",
"KnopfDrücker",
"SpawnCamper",
"AFKHeld",
"RageQuitter",
"GameOverPro",
"Checkpoint",
"RespawnHeld",
"Teebeutel",
"GlitchHexer",
"QuickScope",
"LootSammler",
"EpicLauch",
"KartoffelPro",
"StilleKlinge",
"TastenHeld",
"PixelKrieger",
"HacknSlash",
"JoystickJoe",
"SpawnFalle",
"OneHitWanda",
"CamperKing",
"GameGenie",
"HighPing",
"CheesePro",
"Speedy",
"GigaGamer",
"LevelNoob",
"SkillTobi",
"HeadshotMax",
"PentaPaul",
"CritKarl",
"ManaLeerer",
"Nachlader",
"ClutchKönig",
"FriendlyFe",
"ZonenHeld",
"SchleichKatze",
"ShotgunPro",
"SniperUdo",
"BossHunter",
"HeldenNoob",
"KillFranz",
"FragKarl",
"TeamNiete",
"LootPaul",
"UltraNoob",
"ProfiScout",
"PunkteKlaus",
"KrüppelKill",
"PixelNinja",
"NoobCrusher",
"LagBoss",
"SpawnKing",
"AFKSlayer",
"RespawnPro",
"Killjoy",
"GameBreaker",
"FastFingers",
"LootKing",
"QuickFlick",
"SilentShot",
"HackGod",
"GlitchHero",
"SpeedyBot",
"AimWizard",
"FragMaster",
"OneTapPro",
"KnifeLord",
"MetaHunter",
"PingWarrior",
"KeyBash",
"ClutchPro",
"ScopeBot",
"TrollMage",
"PowerLooter",
"TankHero",
"CampLord",
"SmurfSlayer",
"SkillThief",
"SniperGod",
"LevelHack",
"GhostAim",
"BossTamer",
"ShotgunJoe",
"AimRider",
"KillCount",
"PixelManiac",
"TrollOver",
"SneakPro",
"ReloadKing",
"SpawnTrap",
"LagLover",
"MetaHater",
"BoomMaker",
"WipeLord",
"CarryPro",
"ProBaiter",
"GameWarden",
};
Random random = new Random();
name = names[random.nextInt(names.length)];
}
return name;
} }
} }

View File

@@ -1,47 +0,0 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MdgaView;
public class VideoSettingsDialog extends Dialog {
private MenuButton backButton;
private final MdgaView view;
private boolean active = false;
public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) {
super(app, node);
this.view = view;
backButton = new MenuButton(app, node, view::leaveVideoSettings, "Zurück");
float offset = 2.8f;
backButton.setPos(new Vector2f(0, 1.8f));
}
@Override
protected void onShow() {
active = true;
backButton.show();
}
@Override
protected void onHide() {
active = false;
backButton.hide();
}
public void update() {
if(!active) {
return;
}
}
}

View File

@@ -1,129 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.asset.AssetManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import pp.mdga.client.Asset;
import pp.mdga.game.Color;
public class ActionTextHandler {
private Node root;
private BitmapFont font;
private AppSettings appSettings;
public ActionTextHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){
root = new Node("actionTextRoot");
guiNode.attachChild(root);
root.setLocalTranslation(center(appSettings.getWidth(), appSettings.getHeight(), Vector3f.ZERO));
font = assetManager.loadFont("Fonts/Gunplay.fnt");
this.appSettings = appSettings;
}
private Node createTextWithSpacing(String[] textArr, float spacing, float size, ColorRGBA[] colorArr) {
if(textArr.length != colorArr.length) throw new RuntimeException("text and color are not the same length");
Node textNode = new Node("TextWithSpacing");
Node center = new Node();
float xOffset = 0;
for(int i = 0; i < textArr.length; i++){
String text = textArr[i];
ColorRGBA color = colorArr[i];
for (char c : text.toCharArray()) {
BitmapText letter = new BitmapText(font);
letter.setColor(color);
letter.setSize(size);
letter.setText(Character.toString(c));
letter.setLocalTranslation(xOffset, letter.getHeight()/2, 0);
center.attachChild(letter);
xOffset += letter.getLineWidth() + spacing;
}
}
center.setLocalTranslation(new Vector3f(-xOffset/2,0,0));
textNode.attachChild(center);
return textNode;
}
private Node createTextWithSpacing(String text, float spacing, float size, ColorRGBA color) {
return createTextWithSpacing(new String[]{text}, spacing, size, new ColorRGBA[]{color});
}
private Vector3f center(float width, float height, Vector3f pos){
return new Vector3f(pos.x+width/2, pos.y+height/2,0);
}
private Node createTopText(String name, float spacing, float size, ColorRGBA color, float top){
return createTopText(new String[]{name}, spacing, size, new ColorRGBA[]{color}, top);
}
private Node createTopText(String[] name, float spacing, float size, ColorRGBA color[], float top){
Node text = createTextWithSpacing(name, spacing, size, color);
text.setLocalTranslation(0, (appSettings.getHeight()/2f)*0.8f-top,0);
root.attachChild(text);
return text;
}
private Vector3f centerText(float width, float height, Vector3f pos){
return center(-width, height, pos);
}
public void activePlayer(String name, Color color){
createTopText(new String[]{name," ist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
}
public void ownActive(Color color){
createTopText(new String[]{"Du"," bist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
}
public void diceNum(int diceNum, String name, Color color){
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 100);
}
public void diceNumMult(int diceNum,int mult, String name, Color color){
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 100);
}
public void ownDice(int diceNum){
createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 0);
}
public void ownDiceMult(int diceNum, int mult){
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 0);
}
public void drawCard(String name, Color color){
createTopText(new String[]{name," erhält eine Bonuskarte"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
}
public void drawCardOwn(Color color){
createTopText(new String[]{"Du"," erhälst eine Bonuskarte"}, 5,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
}
private ColorRGBA playerColorToColorRGBA(Color color){
return switch (color){
case ARMY -> ColorRGBA.Green;
case NAVY -> ColorRGBA.Blue;
case CYBER -> ColorRGBA.Orange;
case AIRFORCE -> ColorRGBA.Black;
default -> throw new RuntimeException("None is not valid");
};
}
public void hide(){
root.detachAllChildren();
}
}

View File

@@ -1,150 +1,23 @@
package pp.mdga.client.gui; package pp.mdga.client.gui;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import com.jme3.scene.shape.Sphere;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.board.OutlineControl;
import java.awt.*; public class CardControl extends AbstractControl {
public class CardControl extends OutlineControl { public CardControl(){
private static final ColorRGBA OUTLINE_COLOR = ColorRGBA.Yellow;
private static final ColorRGBA HIGHLIGHT_COLOR = ColorRGBA.Yellow;
private static final int HIGHLIGHT_WIDTH = 9;
private static final ColorRGBA HOVER_COLOR = ColorRGBA.Green;
private static final int HOVER_WIDTH = 12;
private static final ColorRGBA SELECT_COLOR = ColorRGBA.Blue;
private static final int SELECT_WIDTH = 13;
private static final int OUTLINE_THICKNESS = 9;
private boolean hoverable;
private boolean highlight;
private boolean selectable;
private boolean select;
private Node root;
private BitmapText num;
public CardControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, Node root){
super(app, fpp, cam, OUTLINE_THICKNESS);
this.root = root;
Node rootNum = createNum();
rootNum.setLocalTranslation(new Vector3f(0.35f,0.8f,0));
root.attachChild(rootNum);
} }
private Node createNum(){
Node rootNum = new Node("root Num");
Geometry circle = new Geometry("circle", new Sphere(20,20,1));
circle.setLocalTranslation(new Vector3f(0.03f,0.01f,1));
circle.setLocalScale(0.2f);
Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Black);
circle.setMaterial(mat);
root.attachChild(circle);
BitmapFont guiFont = getApp().getAssetManager().loadFont("Fonts/Gunplay.fnt");
num = new BitmapText(guiFont);
num.setSize(0.3f);
num.setText("1");
num.setColor(ColorRGBA.White);
num.setLocalTranslation(-num.getLineWidth() / 2, num.getHeight() / 2, 2);
rootNum.attachChild(circle);
rootNum.attachChild(num);
return rootNum;
}
public void setNumCard(int num){ @Override
this.num.setText(String.valueOf(num)); protected void controlUpdate(float tpf) {
}
public Node getRoot() {
return root;
} }
@Override @Override
public void initSpatial(){ protected void controlRender(RenderManager rm, ViewPort vp) {
}
public void outline(){
super.outline(OUTLINE_COLOR);
}
private final static Vector3f HIGHLIGHT_Y = new Vector3f(0,0.4f,0);
public void setHighlight() {
this.highlight = true;
root.setLocalTranslation(root.getLocalTranslation().add(HIGHLIGHT_Y));
highlight();
}
public void highlight() {
super.outline(HIGHLIGHT_COLOR, HIGHLIGHT_WIDTH);
}
public void unHighlight(){
highlight = false;
root.setLocalTranslation(root.getLocalTranslation().subtract(HIGHLIGHT_Y));
deOutline();
}
public void hover(){
if(!hoverable) return;
super.outline(HOVER_COLOR, HOVER_WIDTH);
}
public void hoverOff(){
if(!hoverable) return;
if(select) select();
else if(highlight) highlight();
else deOutline();
}
public void select(){
if(!selectable) return;
select = true;
super.outline(SELECT_COLOR, SELECT_WIDTH);
}
public void unSelect(){
if(!selectable) return;
select = false;
if(highlight) highlight();
else deOutline();
}
public void setSelectable(boolean selectable){
this.selectable = selectable;
}
public boolean isSelected() {
return select;
}
public boolean isSelectable() {
return selectable;
}
public void setHoverable(boolean hoverable) {
this.hoverable = hoverable;
} }
} }

View File

@@ -3,22 +3,13 @@
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;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.ComposeFilter;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.shadow.DirectionalLightShadowFilter;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.texture.Image;
import com.jme3.texture.Texture2D;
import pp.mdga.client.Asset; import pp.mdga.client.Asset;
import java.util.*; import java.util.*;
@@ -30,16 +21,11 @@ public class CardLayer extends AbstractAppState {
private boolean init; private boolean init;
private List<Spatial> cardBuffer; private List<Spatial> cardBuffer;
private final FilterPostProcessor fpp;
private final Camera overlayCam;
Texture2D backTexture;
public CardLayer(FilterPostProcessor fpp, Camera overlayCam, Texture2D backTexture) {
this.overlayCam = overlayCam; public CardLayer() {
this.fpp = fpp;
this.cardBuffer = new ArrayList<>(); this.cardBuffer = new ArrayList<>();
init = false; init = false;
this.backTexture = backTexture;
} }
@Override @Override
@@ -47,36 +33,23 @@ public void initialize(AppStateManager stateManager, Application app ) {
this.app = app; this.app = app;
root = new Node("Under gui viewport Root"); root = new Node("Under gui viewport Root");
ViewPort view = app.getRenderManager().createMainView("Under gui ViewPort", overlayCam); Camera originalCam = app.getCamera();
Camera cam = new Camera(originalCam.getWidth(), originalCam.getHeight());
cam.setParallelProjection(false);
cam.setFrustum(originalCam.getFrustumNear(), originalCam.getFrustumFar(), originalCam.getFrustumLeft(), originalCam.getFrustumRight(),originalCam.getFrustumTop(), originalCam.getFrustumBottom());
cam.setFov(originalCam.getFov());
cam.setLocation(new Vector3f(0, 0, 10));
cam.lookAt(new Vector3f(0,0,0), Vector3f.UNIT_Y);
ViewPort view = app.getRenderManager().createMainView("Under gui ViewPort", cam);
view.setEnabled(true); view.setEnabled(true);
view.setClearFlags(true, true, true); view.setClearFlags(false, true, false);
view.attachScene(root); view.attachScene(root);
fpp.setFrameBufferFormat(Image.Format.RGBA8);
fpp.addFilter(new ComposeFilter(backTexture));
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(.5f,-.5f,-1));
root.addLight(sun);
final int SHADOWMAP_SIZE=1024*8;
DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(app.getAssetManager(), SHADOWMAP_SIZE, 3);
dlsf.setLight(sun);
dlsf.setEnabled(true);
dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
dlsf.setShadowIntensity(.5f);
fpp.addFilter(dlsf);
view.addProcessor(fpp);
if(!init) init = true; if(!init) init = true;
}
public void shutdown(){
cardBuffer.clear();
root.detachAllChildren();
} }
@@ -88,28 +61,17 @@ public void render(RenderManager rm) {
@Override @Override
public void update( float tpf ) { public void update( float tpf ) {
root.updateLogicalState(tpf);
if (init && !cardBuffer.isEmpty()) { if (init && !cardBuffer.isEmpty()) {
for(Spatial spatial : cardBuffer){ for(Spatial spatial : cardBuffer){
root.attachChild(spatial); root.attachChild(spatial);
} }
cardBuffer.clear(); cardBuffer.clear();
} }
root.updateLogicalState(tpf);
} }
public void addSpatial(Spatial card){ public void addCard(Spatial card){
cardBuffer.add(card); cardBuffer.add(card);
} }
}
public void deleteSpatial(Spatial spatial){
root.detachChild(spatial);
}
public Camera getOverlayCam(){
return overlayCam;
}
public Node getRootNode(){
return root;
}
}

View File

@@ -1,216 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture2D;
import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.BonusCard;
import java.util.*;
public class CardLayerHandler {
private static final Vector3f START = new Vector3f(-1.8f, -3.5f, 0);
private static final Vector3f MARGIN = new Vector3f(1.8f, 0, 0);
private static final float CARDLAYER_CAMERA_ZOOM = 4;
private final MdgaApp app;
private final FilterPostProcessor fpp;
private final Texture2D backTexture;
private Camera cardLayerCamera;
private CardLayer cardLayer;
private DiceControl diceControl;
private final Map<BonusCard, CardControl> bonusCardControlMap = new HashMap<>();
private final Map<BonusCard, Integer> bonusCardIntegerMap = new HashMap<>();
private final Set<CardControl> selectableCards = new HashSet<>();
private BonusCard cardSelect = null;
public CardLayerHandler(MdgaApp app, Texture2D backTexture) {
this.app = app;
this.fpp = new FilterPostProcessor(app.getAssetManager());
this.backTexture = backTexture;
}
public void init() {
cardLayerCamera = createOverlayCam();
cardLayer = new CardLayer(fpp, cardLayerCamera, backTexture);
app.getStateManager().attach(cardLayer);
diceControl = new DiceControl(app.getAssetManager());
diceControl.create(new Vector3f(0, 0, 0), 1f, false);
}
public void shutdown() {
if (cardLayer != null) {
cardLayer.shutdown();
clearSelectableCards();
}
cardLayer = null;
}
public void rollDice(int rollNum, Runnable actionAfter) {
if (!(1 <= rollNum && rollNum <= 6)) throw new RuntimeException("rollNum is not in the range [1,6]");
diceControl.rollDice(rollNum, actionAfter);
}
public void showDice() {
cardLayer.addSpatial(diceControl.getSpatial());
diceControl.spin();
}
public void hideDice() {
diceControl.hide();
}
public void addCard(BonusCard card) {
if (card == BonusCard.HIDDEN) throw new RuntimeException("Can't add hidden card to GUI");
if (!bonusCardControlMap.containsKey(card)) {
CardControl control = createCard(bonusToAsset(card), nextPos());
bonusCardControlMap.put(card, control);
cardLayer.addSpatial(control.getRoot());
}
int newNum = bonusCardIntegerMap.getOrDefault(card, 0) + 1;
bonusCardIntegerMap.put(card, newNum);
bonusCardControlMap.get(card).setNumCard(newNum);
}
public void clearSelectableCards() {
for (CardControl control : selectableCards) {
control.setSelectable(false);
control.setHoverable(false);
control.unHighlight();
control.unSelect();
}
selectableCards.clear();
cardSelect = null;
}
public void setSelectableCards(List<BonusCard> select) {
for (BonusCard card : select) {
selectableCards.add(bonusCardControlMap.get(card));
}
for (CardControl control : selectableCards) {
control.setSelectable(true);
control.setHoverable(true);
control.setHighlight();
}
}
public void selectCard(CardControl cardControl) {
if (cardControl.isSelected()) {
cardControl.unSelect();
cardSelect = null;
} else {
for (CardControl control : selectableCards) {
control.unSelect();
}
cardControl.select();
cardSelect = getKeyByValue(bonusCardControlMap, cardControl);
}
}
public Camera getCardLayerCamera() {
return cardLayerCamera;
}
public void shield(){
SymbolControl control = createSymbol(Asset.shieldSymbol);
cardLayer.addSpatial(control.getSpatial());
control.shield();
}
public void swap(){
SymbolControl control = createSymbol(Asset.swapSymbol);
cardLayer.addSpatial(control.getSpatial());
control.swap();
}
public void turbo(){
SymbolControl control = createSymbol(Asset.turboSymbol);
cardLayer.addSpatial(control.getSpatial());
control.turbo();
}
private Asset bonusToAsset(BonusCard card) {
return switch (card) {
case TURBO -> Asset.turboCard;
case SHIELD -> Asset.shieldCard;
case SWAP -> Asset.swapCard;
case HIDDEN -> throw new RuntimeException("HIDDEN is not allowed in GUI");
};
}
private Vector3f nextPos() {
return START.add(MARGIN.mult(bonusCardControlMap.size()));
}
private Camera createOverlayCam() {
Camera originalCam = app.getCamera();
Camera overlayCam = new Camera(originalCam.getWidth(), originalCam.getHeight());
overlayCam.setParallelProjection(true);
float aspect = (float) originalCam.getWidth() / originalCam.getHeight();
float size = CARDLAYER_CAMERA_ZOOM;
overlayCam.setFrustum(-1000, 1000, -aspect * size, aspect * size, size, -size);
overlayCam.setLocation(new Vector3f(0, 0, 10));
overlayCam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
return overlayCam;
}
private <K, V> K getKeyByValue(Map<K, V> map, V value) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return null;
}
public void test() {
addCard(BonusCard.SHIELD);
addCard(BonusCard.SHIELD);
addCard(BonusCard.TURBO);
addCard(BonusCard.SWAP);
}
private CardControl createCard(Asset card, Vector3f pos){
Node rootCard = new Node("Root Card");
Spatial spatial = app.getAssetManager().loadModel(card.getModelPath());
rootCard.attachChild(spatial);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(card.getDiffPath()));
spatial.setMaterial(mat);
spatial.setLocalScale(1f);
rootCard.setLocalTranslation(pos);
spatial.rotate((float)Math.toRadians(90), (float)Math.toRadians(180), (float)Math.toRadians(180));
spatial.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
CardControl control = new CardControl(app, fpp, cardLayer.getOverlayCam(), rootCard);
spatial.addControl(control);
return control;
}
private SymbolControl createSymbol(Asset asset){
Spatial spatial = app.getAssetManager().loadModel(asset.getModelPath());
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", app.getAssetManager().loadTexture(asset.getDiffPath()));
spatial.setMaterial(mat);
spatial.setLocalScale(1f);
spatial.rotate((float)Math.toRadians(90), (float)Math.toRadians(180), (float)Math.toRadians(180));
SymbolControl control = new SymbolControl();
spatial.addControl(control);
return control;
}
public CardLayer getCardLayer(){
return cardLayer;
}
}

View File

@@ -1,171 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.Asset;
import java.util.Random;
import static com.jme3.material.Materials.LIGHTING;
import static com.jme3.material.Materials.UNSHADED;
public class DiceControl extends AbstractControl {
private Quaternion targetRotation;
private final Vector3f angularVelocity = new Vector3f();
private float deceleration = 0.5f;
private float timeElapsed = 0.0f;
private float rollDuration = 1f;
private static final int ANGULAR_MIN = 5;
private static final int ANGULAR_MAX = 15;
private static final int ANGULAR_SPIN = 10;
private boolean isRolling = false;
private boolean slerp = false;
private boolean spin = false;
private final AssetManager assetManager;
private Runnable actionAfter;
public DiceControl(AssetManager assetManager){
this.assetManager = assetManager;
}
@Override
protected void controlUpdate(float tpf) {
if (isRolling) {
if(!slerp) {
// Apply rotational velocity to the dice
spinWithAngularVelocity(tpf);
// Gradually reduce rotational velocity (simulate deceleration)
angularVelocity.subtractLocal(
angularVelocity.mult(deceleration * tpf)
);
// Stop rolling when angular velocity is close to zero
if (angularVelocity.lengthSquared() < 3f) {
slerp = true;
}
}
else {
timeElapsed += tpf * rollDuration;
if (timeElapsed > 1.0f) timeElapsed = 1.0f;
Quaternion interpolated = spatial.getLocalRotation().clone();
interpolated.slerp(targetRotation, timeElapsed);
spatial.setLocalRotation(interpolated);
// Stop rolling once duration is complete
if (timeElapsed >= 1.0f) {
isRolling = false;
slerp = false;
actionAfter.run();
}
}
}else if(spin){
spinWithAngularVelocity(tpf);
}
}
private void spinWithAngularVelocity(float tpf){
Quaternion currentRotation = spatial.getLocalRotation();
Quaternion deltaRotation = new Quaternion();
deltaRotation.fromAngles(
angularVelocity.x * tpf,
angularVelocity.y * tpf,
angularVelocity.z * tpf
);
spatial.setLocalRotation(currentRotation.mult(deltaRotation));
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public void rollDice(int diceNum, Runnable actionAfter) {
if (isRolling) return;
spin = false;
slerp = false;
this.actionAfter = actionAfter;
angularVelocity.set(
FastMath.nextRandomInt(ANGULAR_MIN,ANGULAR_MAX),
FastMath.nextRandomInt(ANGULAR_MIN,ANGULAR_MAX),
FastMath.nextRandomInt(ANGULAR_MIN,ANGULAR_MAX)
);
targetRotation = getRotationForDiceNum(diceNum);
isRolling = true;
}
private Quaternion getRotationForDiceNum(int diceNum) {
return switch (diceNum) {
case 1 -> new Quaternion().fromAngleAxis((float) (1 * (Math.PI / 2)), Vector3f.UNIT_X);
case 2 -> new Quaternion().fromAngleAxis((float) (1 * (Math.PI / 2)), Vector3f.UNIT_Y);
case 3 -> new Quaternion().fromAngleAxis((float) (0 * (Math.PI / 2)), Vector3f.UNIT_X);
case 4 -> new Quaternion().fromAngleAxis((float) (2 * (Math.PI / 2)), Vector3f.UNIT_Y);
case 5 -> new Quaternion().fromAngleAxis((float) (3 * (Math.PI / 2)), Vector3f.UNIT_Y);
case 6 -> new Quaternion().fromAngleAxis((float) (3 * (Math.PI / 2)), Vector3f.UNIT_X);
default -> throw new IllegalArgumentException("Invalid dice number: " + diceNum);
};
}
public static float lerp(float t) {
return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
}
public void randomRotation() {
Quaternion randomRotation = new Quaternion();
randomRotation.fromAngles(
FastMath.nextRandomFloat() * FastMath.TWO_PI, // Random X rotation
FastMath.nextRandomFloat() * FastMath.TWO_PI, // Random Y rotation
FastMath.nextRandomFloat() * FastMath.TWO_PI // Random Z rotation
);
spatial.setLocalRotation(randomRotation);
}
public void spin(){
angularVelocity.set(ANGULAR_SPIN,ANGULAR_SPIN,ANGULAR_SPIN);
spin = true;
}
public void hide(){
spatial.removeFromParent();
spin = false;
isRolling = false;
slerp = false;
}
public void create(Vector3f pos, float scale, boolean shadow){
Spatial spatial = assetManager.loadModel(Asset.dice.getModelPath());
Material mat;
if(shadow){
mat = new Material(assetManager, LIGHTING);
mat.setTexture("DiffuseMap", assetManager.loadTexture(Asset.dice.getDiffPath()));
spatial.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
}
else{
mat = new Material(assetManager, UNSHADED);
mat.setTexture("ColorMap", assetManager.loadTexture(Asset.dice.getDiffPath()));
}
spatial.setMaterial(mat);
spatial.setLocalScale(scale);
spatial.setLocalTranslation(pos);
spatial.rotate((float)Math.toRadians(90), (float)Math.toRadians(180), (float)Math.toRadians(180));
spatial.addControl(this);
}
public void setPos(Vector3f pos){
spatial.setLocalTranslation(pos);
}
}

View File

@@ -1,132 +1,70 @@
package pp.mdga.client.gui; package pp.mdga.client.gui;
import com.jme3.renderer.Camera; import com.jme3.material.Material;
import com.jme3.scene.Node; import com.jme3.math.Vector3f;
import com.jme3.texture.FrameBuffer; import com.jme3.scene.Spatial;
import com.jme3.texture.Image; import pp.mdga.client.Asset;
import com.jme3.texture.Texture2D;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color; import pp.mdga.game.BonusCard;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.List;
public class GuiHandler { public class GuiHandler {
private final MdgaApp app;
private final CardLayerHandler cardLayerHandler;
private final PlayerNameHandler playerNameHandler;
private final ActionTextHandler actionTextHandler;
private Color ownColor;
private FrameBuffer backFrameBuffer; private MdgaApp app;
private CardLayer cardLayer;
private Map<UUID, CardControl> ownCardsMap;
public GuiHandler(MdgaApp app, Node guiNode) { private static final Vector3f START = new Vector3f(-3,-3,0);
private static final Vector3f MARGIN = new Vector3f(2.5f,0,0);
public GuiHandler(MdgaApp app) {
this.app = app; this.app = app;
this.ownColor = ownColor;
backFrameBuffer = new FrameBuffer(app.getCamera().getWidth(), app.getCamera().getHeight(), 1);
Texture2D backTexture = new Texture2D(app.getCamera().getWidth(), app.getCamera().getHeight(), Image.Format.RGBA8);
backFrameBuffer.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.Depth));
backFrameBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(backTexture));
cardLayerHandler = new CardLayerHandler(app, backTexture);
playerNameHandler = new PlayerNameHandler(guiNode, app.getAssetManager(), app.getContext().getSettings());
actionTextHandler = new ActionTextHandler(guiNode, app.getAssetManager(), app.getContext().getSettings());
} }
public void init(Color ownColor) { public void init(){
cardLayerHandler.init(); cardLayer = new CardLayer();
playerNameHandler.show(); app.getStateManager().attach(cardLayer);
this.ownColor = ownColor; ownCardsMap = new HashMap<>();
app.getViewPort().setOutputFrameBuffer(backFrameBuffer);
addCard(BonusCard.SHIELD, UUID.randomUUID());
addCard(BonusCard.TURBO, UUID.randomUUID());
addCard(BonusCard.SWAP, UUID.randomUUID());
} }
public void shutdown() { private Asset bonusToAsset(BonusCard card){
cardLayerHandler.shutdown(); return switch (card){
app.getViewPort().setOutputFrameBuffer(null); case TURBO -> Asset.turboCard;
case SHIELD -> Asset.shieldCard;
case SWAP -> Asset.swapCard;
case HIDDEN -> throw new RuntimeException("HIDDEN is not allowed in GUI");
};
} }
public void rollDice(int rollNum, int mult) { public void addCard(BonusCard card, UUID uuid) {
cardLayerHandler.rollDice(rollNum, ()->{ CardControl control = createCard(bonusToAsset(card), nextPos());
if(mult == -1) actionTextHandler.ownDice(rollNum); ownCardsMap.put(uuid, control);
else actionTextHandler.ownDiceMult(rollNum, mult); cardLayer.addCard(control.getSpatial());
hideDice();
//TODO send Model finished
});
} }
public void showRolledDiceMult(int rollNum, int mult, Color color) { private Vector3f nextPos() {
String name = playerNameHandler.getName(color); return START.add(MARGIN.mult(ownCardsMap.size()));
if(mult == -1) actionTextHandler.diceNum(rollNum, name, color);
else actionTextHandler.diceNumMult(rollNum, mult, name, color);
} }
public void showRolledDice(int rollNum, Color color) { private CardControl createCard(Asset card, Vector3f pos){
actionTextHandler.diceNum(rollNum, playerNameHandler.getName(color), color); Spatial spatial = app.getAssetManager().loadModel(card.getModelPath());
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", app.getAssetManager().loadTexture(card.getDiffPath()));
spatial.setMaterial(mat);
spatial.setLocalScale(1f);
spatial.setLocalTranslation(pos);
spatial.rotate((float)Math.toRadians(90), (float)Math.toRadians(180), (float)Math.toRadians(180));
CardControl control = new CardControl();
spatial.addControl(control);
return control;
} }
public void showDice() {
cardLayerHandler.showDice();
}
public void hideDice() {
cardLayerHandler.hideDice();
}
public void addCard(pp.mdga.game.BonusCard card) {
cardLayerHandler.addCard(card);
}
public void clearSelectableCards() {
cardLayerHandler.clearSelectableCards();
}
public void setSelectableCards(List<pp.mdga.game.BonusCard> select) {
cardLayerHandler.setSelectableCards(select);
}
public void selectCard(CardControl cardControl) {
cardLayerHandler.selectCard(cardControl);
}
public Camera getCardLayerCamera() {
return cardLayerHandler.getCardLayerCamera();
}
public Node getCardLayerRootNode(){
return cardLayerHandler.getCardLayer().getRootNode();
}
public void addPlayer(Color color, String name) {
playerNameHandler.addPlayer(color, name, color == ownColor);
}
public void setActivePlayer(Color color) {
playerNameHandler.setActivePlayer(color);
if (ownColor == color) actionTextHandler.ownActive(color);
else actionTextHandler.activePlayer(playerNameHandler.getName(color), color);
}
public void shield(){
cardLayerHandler.shield();
}
public void swap(){
cardLayerHandler.swap();
}
public void turbo(){
cardLayerHandler.turbo();
}
public void hideText(){
actionTextHandler.hide();
}
public void drawCard(Color color) {
if (ownColor == color) actionTextHandler.drawCardOwn(color);
else actionTextHandler.drawCard(playerNameHandler.getName(color), color);
}
} }

View File

@@ -1,127 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.asset.AssetManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.system.AppSettings;
import com.jme3.ui.Picture;
import pp.mdga.game.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PlayerNameHandler {
private final BitmapFont playerFont;
private final Node playerNameNode;
private final List<Color> playerOrder;
private final Map<Color, String> colorNameMap;
private final AppSettings appSettings;
private final AssetManager assetManager;
private Color ownColor;
private static final float PADDING_TOP = 35;
private static final float PADDING_LEFT = 50;
private static final float MARGIN_NAMES = 50;
private static final float IMAGE_SIZE = 50;
private static final float TEXT_SIZE = 28;
private static final ColorRGBA NORMAL_COLOR = ColorRGBA.White;
private static final ColorRGBA ACTIVE_COLOR = ColorRGBA.Blue;
private static final ColorRGBA OWN_COLOR = ColorRGBA.Cyan;
private final Node guiNode;
public PlayerNameHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){
this.guiNode = guiNode;
playerFont = assetManager.loadFont("Fonts/Gunplay.fnt");
playerNameNode = new Node("player name node");
playerOrder = new ArrayList<>();
colorNameMap = new HashMap<>();
this.appSettings = appSettings;
this.assetManager = assetManager;
}
public void show() {
guiNode.attachChild(playerNameNode);
}
public void hide() {
guiNode.detachChild(playerNameNode);
}
private void drawPlayers(){
playerNameNode.detachAllChildren();
for(int i = 0; i < playerOrder.size(); i++) {
Color color = playerOrder.get(i);
if(!colorNameMap.containsKey(color)) throw new RuntimeException(color + " isn't mapped to a name");
Node nameParent = new Node("nameParent");
nameParent.attachChild(createName(colorNameMap.get(color), i == 0, color == ownColor));
nameParent.attachChild(createColor(color));
nameParent.setLocalTranslation(50,appSettings.getWindowHeight()-PADDING_TOP- MARGIN_NAMES *i,0);
playerNameNode.attachChild(nameParent);
}
}
private String imagePath(Color color){
String root = "./Images/name_pictures/";
return switch(color){
case ARMY -> root+"HEER_IMAGE.png";
case NAVY -> root+"MARINE_IMAGE.png";
case CYBER -> root+"CIR_IMAGE.png";
case AIRFORCE -> root+"LW_IMAGE.png";
default -> throw new RuntimeException("None is not valid");
};
}
private Spatial createColor(Color color) {
Picture pic = new Picture("HUD Picture");
pic.setImage(assetManager, imagePath(color), true);
pic.setWidth(IMAGE_SIZE);
pic.setHeight(IMAGE_SIZE);
pic.setPosition(-pic.getWidth()/2,-pic.getHeight()/2);
return pic;
}
private Spatial createName(String name, boolean first, boolean own){
BitmapText hudText = new BitmapText(playerFont);
//renderedSize = 45
hudText.setSize(TEXT_SIZE);
hudText.setColor(first ? ACTIVE_COLOR : own ? OWN_COLOR : NORMAL_COLOR);
hudText.setText(name);
hudText.setLocalTranslation(PADDING_LEFT,hudText.getHeight()/2, 0);
return hudText;
}
public void addPlayer(Color color, String name, boolean own){
if(own) ownColor = color;
colorNameMap.put(color, name);
playerOrder.add(color);
drawPlayers();
}
public void setActivePlayer(Color color) {
Color lastFirst = playerOrder.remove(0);
playerOrder.remove(color);
playerOrder.add(0, color);
playerOrder.add(lastFirst);
drawPlayers();
}
public String getName(Color color){
return colorNameMap.get(color);
}
}

View File

@@ -1,147 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.game.BonusCard;
public class SymbolControl extends AbstractControl {
private boolean zoomingIn = false;
private boolean zoomingOut = false;
private float zoomSpeed = 1f;
private float zoomFactor = 3f;
private float progress = 0;
private BonusCard state;
private float rotationSpeed = 0.8f;
private Quaternion initialRotation = null;
private float Y = 5;
@Override
protected void controlUpdate(float tpf) {
if(state == null) return;
switch (state){
case SHIELD -> shieldUpdate(tpf);
case SWAP -> swapUpdate(tpf);
case TURBO -> turboUpdate(tpf);
case HIDDEN -> throw new RuntimeException("forbidden state");
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
private void shieldUpdate(float tpf){
if (zoomingIn) {
progress += tpf * zoomSpeed;
if (progress > 1) progress = 1;
spatial.setLocalScale(lerp(0, zoomFactor, easeOut(progress)));
if (progress >= 1) {
zoomingIn = false;
zoomingOut = true;
progress = 0;
}
} else if (zoomingOut) {
progress += tpf * zoomSpeed;
spatial.setLocalScale(lerp(zoomFactor, 0, easeIn(progress)));
if (progress > 1) {
zoomingIn = false;
spatial.removeFromParent();
state = null;
progress = 0;
}
}
}
private void swapUpdate(float tpf){
if (initialRotation == null) {
initialRotation = spatial.getLocalRotation().clone();
}
progress += tpf*rotationSpeed;
if(progress < 0) return;
float angle = lerp(0, 360, easeInOut(progress));
Quaternion newRotation = new Quaternion();
newRotation.fromAngleAxis((float) Math.toRadians(angle), new Vector3f(0, 1, 0));
spatial.setLocalRotation(initialRotation.mult(newRotation));
if (progress >= 1.2f) {
state = null;
initialRotation = null;
progress = 0;
spatial.removeFromParent();
}
}
private void turboUpdate(float tpf){
if (zoomingIn) {
progress += tpf * zoomSpeed;
if (progress > 1) progress = 1;
float y = lerp(-Y,0, easeOut(progress));
spatial.setLocalTranslation(0,y,0);
if (progress >= 1) {
zoomingIn = false;
zoomingOut = true;
progress = 0;
}
} else if (zoomingOut) {
progress += tpf * zoomSpeed;
float y = lerp(0,Y, easeIn(progress));
spatial.setLocalTranslation(0,y,0);
if (progress > 1) {
zoomingIn = false;
spatial.removeFromParent();
state = null;
}
}
}
public void shield(){
if(state != null) throw new RuntimeException("another state is avtive");
state = BonusCard.SHIELD;
zoomingIn = true;
zoomingOut = false;
progress = 0;
spatial.setLocalScale(1f);
}
public void swap(){
if(state != null) throw new RuntimeException("another state is avtive");
spatial.setLocalScale(3);
state = BonusCard.SWAP;
progress = -0.2f;
}
public void turbo(){
if(state != null) throw new RuntimeException("another state is avtive");
spatial.setLocalScale(2);
state = BonusCard.TURBO;
zoomingIn = true;
zoomingOut = false;
progress = 0;
}
private static float lerp(float start, float end, float t) {
return (1 - t) * start + t * end;
}
private static float easeOut(float t) {
return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
}
private float easeInOut(float t) {
if(t>1) t=1;
return (float) -(Math.cos(Math.PI * t) - 1) / 2;
}
private float easeIn(float t) {
return t * t * t * t;
}
}

View File

@@ -1,82 +0,0 @@
package pp.mdga.client.gui;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
public class ZoomControl extends AbstractControl {
private boolean zoomingIn = false;
private boolean zoomingOut = false;
private float progress = 0;
private float zoomSpeed = 1f;
private float zoomFactor = 1f;
public ZoomControl(){}
public ZoomControl(float speed) {
zoomSpeed = speed;
}
@Override
public void setSpatial(Spatial spatial){
if(this.spatial == null && spatial != null){
super.setSpatial(spatial);
initSpatial();
}
}
private void initSpatial() {
zoomingIn = true;
}
@Override
protected void controlUpdate(float tpf) {
if (zoomingIn) {
progress += tpf * zoomSpeed;
if (progress > 1) progress = 1;
spatial.setLocalScale(lerp(0, zoomFactor, easeOut(progress)));
if (progress >= 1) {
zoomingIn = false;
zoomingOut = true;
progress = 0;
}
} else if (zoomingOut) {
progress += tpf * zoomSpeed;
spatial.setLocalScale(lerp(zoomFactor, 0, easeIn(progress)));
if (progress > 1) {
zoomingOut = false;
end();
}
}
}
private void end(){
spatial.removeFromParent();
spatial.removeControl(this);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
private static float lerp(float start, float end, float t) {
return (1 - t) * start + t * end;
}
// private static float easeOut(float t) {
// return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
// }
private float easeOut(float x) {
return x == 1 ? 1 : (float) (1 - Math.pow(2, -10 * x));
}
// private float easeIn(float t) {
// return t * t * t * t;
// }
private float easeIn(float x) {
return x == 0 ? 0 : (float) Math.pow(2, 10 * x - 10);
}
}

View File

@@ -13,7 +13,6 @@
import java.io.IOException; import java.io.IOException;
import java.lang.System.Logger; import java.lang.System.Logger;
import java.lang.System.Logger.Level; import java.lang.System.Logger.Level;
import java.sql.Connection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@@ -26,7 +25,6 @@ public class MdgaServer implements MessageListener<HostedConnection>, Connection
private static final Logger LOGGER = System.getLogger(MdgaServer.class.getName()); private static final Logger LOGGER = System.getLogger(MdgaServer.class.getName());
private Server myServer; private Server myServer;
private static int port;
private final ServerGameLogic logic; private final ServerGameLogic logic;
private final BlockingQueue<ReceivedMessage> pendingMessages = new LinkedBlockingQueue<>(); private final BlockingQueue<ReceivedMessage> pendingMessages = new LinkedBlockingQueue<>();
@@ -42,38 +40,37 @@ public class MdgaServer implements MessageListener<HostedConnection>, Connection
} }
/** /**
* Constructor. * Starts the Battleships server.
*
* @param port as the port for this server
*/ */
public MdgaServer(int port) { public static void main(String[] args) {
MdgaServer.port = port; new MdgaServer().run();
}
/**
* Creates a new MdgaServer.
*/
public MdgaServer() {
LOGGER.log(Level.INFO, "Creating MdgaServer"); //NON-NLS LOGGER.log(Level.INFO, "Creating MdgaServer"); //NON-NLS
logic = new ServerGameLogic(this, new Game()); logic = new ServerGameLogic(this, new Game());
} }
/**
*
*/
public void run() { public void run() {
startServer(); startServer();
this.connectionAdded(myServer, myServer.getConnection(0));
while (true) while (true)
processNextMessage(); processNextMessage();
} }
/**
*
*/
private void startServer() { private void startServer() {
try { try {
LOGGER.log(Level.INFO, "Starting server..."); //NON-NLS LOGGER.log(Level.INFO, "Starting server..."); //NON-NLS
myServer = Network.createServer(port); myServer = Network.createServer(1234);
initializeSerializables(); initializeSerializables();
myServer.start(); myServer.start();
registerListeners(); registerListeners();
LOGGER.log(Level.INFO, "Server started: {0}", myServer.isRunning()); //NON-NLS LOGGER.log(Level.INFO, "Server started: {0}", myServer.isRunning()); //NON-NLS
} } catch (IOException e) {
catch (IOException e) {
LOGGER.log(Level.ERROR, "Couldn't start server: {0}", e.getMessage()); //NON-NLS LOGGER.log(Level.ERROR, "Couldn't start server: {0}", e.getMessage()); //NON-NLS
exit(1); exit(1);
} }
@@ -89,98 +86,76 @@ private void processNextMessage() {
} }
private void initializeSerializables() { private void initializeSerializables() {
Serializer.registerClass(AnimationEndMessage.class); Serializer.registerClass(AnimationEnd.class);
Serializer.registerClass(ClientStartGameMessage.class); Serializer.registerClass(ClientStartGame.class);
Serializer.registerClass(DeselectTSKMessage.class); Serializer.registerClass(DeselectTSK.class);
Serializer.registerClass(ForceContinueGameMessage.class); Serializer.registerClass(ForceContinueGame.class);
Serializer.registerClass(StartGameMessage.class); Serializer.registerClass(StartGame.class);
Serializer.registerClass(JoinedLobbyMessage.class); Serializer.registerClass(JoinServer.class);
Serializer.registerClass(LeaveGameMessage.class); Serializer.registerClass(LeaveGame.class);
Serializer.registerClass(LobbyNotReadyMessage.class); Serializer.registerClass(LobbyNotReady.class);
Serializer.registerClass(LobbyReadyMessage.class); Serializer.registerClass(LobbyReady.class);
Serializer.registerClass(NoPowerCardMessage.class); Serializer.registerClass(NoPowerCard.class);
Serializer.registerClass(RequestBriefingMessage.class); Serializer.registerClass(RequestBriefing.class);
Serializer.registerClass(RequestDieMessage.class); Serializer.registerClass(RequestDie.class);
Serializer.registerClass(RequestMoveMessage.class); Serializer.registerClass(RequestMove.class);
Serializer.registerClass(RequestPlayCardMessage.class); Serializer.registerClass(RequestPlayCard.class);
Serializer.registerClass(SelectCardMessage.class); Serializer.registerClass(SelectCard.class);
Serializer.registerClass(SelectedPiecesMessage.class); Serializer.registerClass(SelectedPieces.class);
Serializer.registerClass(SelectTSKMessage.class); Serializer.registerClass(SelectTSK.class);
Serializer.registerClass(ActivePlayerMessage.class); Serializer.registerClass(ActivePlayer.class);
Serializer.registerClass(AnyPieceMessage.class); Serializer.registerClass(AnyPiece.class);
Serializer.registerClass(BriefingMessage.class); Serializer.registerClass(Briefing.class);
Serializer.registerClass(CeremonyMessage.class); Serializer.registerClass(CeremonyMessage.class);
Serializer.registerClass(DieMessage.class); Serializer.registerClass(Die.class);
Serializer.registerClass(DiceAgainMessage.class); Serializer.registerClass(DiceAgain.class);
Serializer.registerClass(DiceNowMessage.class); Serializer.registerClass(DiceNow.class);
Serializer.registerClass(EndOfTurnMessage.class); Serializer.registerClass(EndOfTurn.class);
Serializer.registerClass(LobbyAcceptMessage.class); Serializer.registerClass(LobbyAccept.class);
Serializer.registerClass(LobbyDenyMessage.class); Serializer.registerClass(LobbyDeny.class);
Serializer.registerClass(LobbyPlayerJoinedMessage.class); Serializer.registerClass(LobbyPlayerJoin.class);
Serializer.registerClass(LobbyPlayerLeaveMessage.class); Serializer.registerClass(LobbyPlayerLeave.class);
Serializer.registerClass(MoveMessage.class); Serializer.registerClass(MoveMessage.class);
Serializer.registerClass(NoTurnMessage.class); Serializer.registerClass(NoTurn.class);
Serializer.registerClass(PauseGameMessage.class); Serializer.registerClass(PauseGame.class);
Serializer.registerClass(PlayCardMessage.class); Serializer.registerClass(PlayCard.class);
Serializer.registerClass(PossibleCardMessage.class); Serializer.registerClass(PossibleCard.class);
Serializer.registerClass(PossiblePieceMessage.class); Serializer.registerClass(PossiblePiece.class);
Serializer.registerClass(RankingResponseMessage.class); Serializer.registerClass(RankingResponse.class);
Serializer.registerClass(RankingRollAgainMessage.class); Serializer.registerClass(RankingRollAgain.class);
Serializer.registerClass(ReconnectBriefingMessage.class); Serializer.registerClass(ReconnectBriefing.class);
Serializer.registerClass(ResumeGameMessage.class); Serializer.registerClass(ResumeGame.class);
Serializer.registerClass(ServerStartGameMessage.class); Serializer.registerClass(ServerStartGame.class);
Serializer.registerClass(StartPieceMessage.class); Serializer.registerClass(StartPiece.class);
Serializer.registerClass(UpdateReadyMessage.class); Serializer.registerClass(UpdateReady.class);
Serializer.registerClass(UpdateTSKMessage.class); Serializer.registerClass(UpdateTSK.class);
Serializer.registerClass(WaitPieceMessage.class); Serializer.registerClass(WaitPiece.class);
} }
private void registerListeners() { private void registerListeners() {
myServer.addMessageListener(this, AnimationEndMessage.class); myServer.addMessageListener(this, AnimationEnd.class);
myServer.addMessageListener(this, ClientStartGameMessage.class); myServer.addMessageListener(this, ClientStartGame.class);
myServer.addMessageListener(this, DeselectTSKMessage.class); myServer.addMessageListener(this, DeselectTSK.class);
myServer.addMessageListener(this, ForceContinueGameMessage.class); myServer.addMessageListener(this, ForceContinueGame.class);
myServer.addMessageListener(this, StartGameMessage.class); myServer.addMessageListener(this, StartGame.class);
myServer.addMessageListener(this, JoinedLobbyMessage.class); myServer.addMessageListener(this, JoinServer.class);
myServer.addMessageListener(this, LeaveGameMessage.class); myServer.addMessageListener(this, LeaveGame.class);
myServer.addMessageListener(this, LobbyNotReadyMessage.class); myServer.addMessageListener(this, LobbyNotReady.class);
myServer.addMessageListener(this, LobbyReadyMessage.class); myServer.addMessageListener(this, LobbyReady.class);
myServer.addMessageListener(this, NoPowerCardMessage.class); myServer.addMessageListener(this, NoPowerCard.class);
myServer.addMessageListener(this, RequestBriefingMessage.class); myServer.addMessageListener(this, RequestBriefing.class);
myServer.addMessageListener(this, RequestDieMessage.class); myServer.addMessageListener(this, RequestDie.class);
myServer.addMessageListener(this, RequestMoveMessage.class); myServer.addMessageListener(this, RequestMove.class);
myServer.addMessageListener(this, RequestPlayCardMessage.class); myServer.addMessageListener(this, RequestPlayCard.class);
myServer.addMessageListener(this, SelectCardMessage.class); myServer.addMessageListener(this, SelectCard.class);
myServer.addMessageListener(this, SelectedPiecesMessage.class); myServer.addMessageListener(this, SelectedPieces.class);
myServer.addMessageListener(this, SelectTSKMessage.class); myServer.addMessageListener(this, SelectTSK.class);
myServer.addConnectionListener(this); myServer.addConnectionListener(this);
} }
/**
* This method will be used to receive network messages from the given source parameter.
* It will check if the given message parameter is a ClientMessage object. If yes it will call the messageReceived
* method with the casted ClientMessage object.
*
* @param source as the connection which sends the message as a HostedConnection object.
* @param message as the received message as a Message object.
*/
@Override
public void messageReceived(HostedConnection source, Message message) {
if (message instanceof ClientMessage) {
this.messageReceived(source, (ClientMessage) message);
}
}
/** public void messageReceived(HostedConnection source, ClientMessage message) {
* This method will be used to received network messages from the given source parameter.
* It will add the given message parameter to the pendingMessage attribute of MdgaServer after creating
* a ReceivedMessage object with it and its id.
*
* @param source as the connection which sends the message as a HostedConnection object.
* @param message as the received message as a Message object.
*/
private void messageReceived(HostedConnection source, ClientMessage message) {
LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS
pendingMessages.add(new ReceivedMessage(message, source.getId())); pendingMessages.add(new ReceivedMessage(message, source.getId()));
} }
@@ -188,6 +163,8 @@ private void messageReceived(HostedConnection source, ClientMessage message) {
@Override @Override
public void connectionAdded(Server server, HostedConnection hostedConnection) { public void connectionAdded(Server server, HostedConnection hostedConnection) {
LOGGER.log(Level.INFO, "new connection {0}", hostedConnection); //NON-NLS LOGGER.log(Level.INFO, "new connection {0}", hostedConnection); //NON-NLS
// ToDo: Synchronize data between server and client.
logic.getGame().addPlayer(hostedConnection.getId(), new Player());
} }
@Override @Override
@@ -209,7 +186,7 @@ public void connectionRemoved(Server server, HostedConnection hostedConnection)
* @param id as the id of the disconnected player. * @param id as the id of the disconnected player.
*/ */
public void handleDisconnect(int id) { public void handleDisconnect(int id) {
this.logic.received(new DisconnectedMessage(), id); this.logic.received(new Disconnected(), id);
} }
public void exit(int exitValue) { //NON-NLS public void exit(int exitValue) { //NON-NLS
@@ -226,7 +203,6 @@ public void exit(int exitValue) { //NON-NLS
* @param id the connection id * @param id the connection id
* @param message the message * @param message the message
*/ */
@Override
public void send(int id, ServerMessage message) { public void send(int id, ServerMessage message) {
if (myServer == null || !myServer.isRunning()) { if (myServer == null || !myServer.isRunning()) {
LOGGER.log(Level.ERROR, "no server running when trying to send {0}", message); //NON-NLS LOGGER.log(Level.ERROR, "no server running when trying to send {0}", message); //NON-NLS
@@ -245,20 +221,15 @@ public void send(int id, ServerMessage message) {
* *
* @param message as the message which will be sent to all players as a ServerMessage. * @param message as the message which will be sent to all players as a ServerMessage.
*/ */
@Override
public void broadcast(ServerMessage message) { public void broadcast(ServerMessage message) {
for (Map.Entry<Integer, Player> entry: this.logic.getGame().getPlayers().entrySet()) { for (Map.Entry<Integer, Player> entry: this.logic.getGame().getPlayers().entrySet()) {
this.send(entry.getKey(), message); this.send(entry.getKey(), message);
} }
} }
/** //TODO:
* This method will be used to diconenect the client depending on the given id parameter.
*
* @param id as the connection id of the client as an Integer.
*/
@Override @Override
public void disconnectClient(int id) { public void messageReceived(HostedConnection source, Message m) {
this.myServer.getConnection(id).close("");
} }
} }

View File

@@ -1,25 +1,13 @@
package pp.mdga.client.view; package pp.mdga.client.view;
import com.jme3.asset.TextureKey;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import pp.mdga.client.dialog.SingleButtonLeftDialog;
import com.jme3.texture.Texture; import pp.mdga.client.dialog.SingleButtonRightDialog;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState; import pp.mdga.client.MdgaState;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.CeremonyButton;
import pp.mdga.client.dialog.CeremonyDialog;
import pp.mdga.game.Color;
import java.util.ArrayList;
public class CeremonyView extends MdgaView { public class CeremonyView extends MdgaView {
private enum SubState { private enum SubState {
AWARD_CEREMONY, AWARD_CEREMONY,
STATISTICS, STATISTICS,
@@ -27,146 +15,54 @@ private enum SubState {
private SubState state; private SubState state;
private SingleButtonRightDialog continueButton;
private SingleButtonLeftDialog backButton;
private Geometry background; private Geometry background;
private Geometry podest;
private ButtonLeft backButton;
private ButtonRight continueButton;
private ArrayList<CeremonyButton> ceremonyButtons;
private CeremonyDialog ceremonyDialog;
private AmbientLight ambient = new AmbientLight();
public CeremonyView(MdgaApp app) { public CeremonyView(MdgaApp app) {
super(app); super(app);
backButton = new ButtonLeft(app, guiNode, this::back, "Zurück", 1); continueButton = new SingleButtonRightDialog(app, node, "Weiter", () -> forward());
continueButton = new ButtonRight(app, guiNode, this::forward, "Weiter", 1); backButton = new SingleButtonLeftDialog(app, node, "Zurück", () -> back());
ceremonyButtons = new ArrayList<>(4);
ceremonyDialog = new CeremonyDialog(app, guiNode);
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
} }
@Override @Override
public void onEnter() { public void onEnter() {
rootNode.addLight(ambient);
app.getAcousticHandler().playSound(MdgaSound.VICTORY);
float screenWidth = app.getCamera().getWidth();
float screenHeight = app.getCamera().getHeight();
float aspectRatio = screenWidth / screenHeight;
float scale = 3.5f;
float distanceFromCamera = 5f;
float verticalSize = (float) (2 * Math.tan(Math.toRadians(app.getCamera().getFov() / 2)) * distanceFromCamera * scale);
float horizontalSize = verticalSize * aspectRatio;
Quad backgroundQuad = new Quad(horizontalSize, verticalSize);
background = new Geometry("LobbyBackground", backgroundQuad);
TextureKey backgroundKey = new TextureKey("Images/lobby.png", true);
Texture backgroundTexture = app.getAssetManager().loadTexture(backgroundKey);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundTexture);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(-horizontalSize / 2, -verticalSize / 2, -distanceFromCamera);
rootNode.attachChild(background);
verticalSize *= 0.99f;
Quad overlayQuad = new Quad(horizontalSize, verticalSize * 0.8f);
podest = new Geometry("TransparentOverlay", overlayQuad);
TextureKey overlayKey = new TextureKey("Images/Ceremony.png", true);
Texture overlayTexture = app.getAssetManager().loadTexture(overlayKey);
Material overlayMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
overlayMaterial.setTexture("ColorMap", overlayTexture);
overlayMaterial.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
podest.setMaterial(overlayMaterial);
float overlayDistance = distanceFromCamera - 0.1f;
podest.setLocalTranslation(-horizontalSize / 2, -verticalSize * 0.415f, -overlayDistance);
enterSub(SubState.AWARD_CEREMONY); enterSub(SubState.AWARD_CEREMONY);
} }
@Override @Override
public void onLeave() { public void onLeave() {
backButton.hide();
continueButton.hide(); continueButton.hide();
backButton.hide();
if(null != background) {
guiNode.detachChild(background);
}
ceremonyButtons.clear();
rootNode.removeLight(ambient);
ceremonyDialog.prepare();
rootNode.detachChild(background);
}
@Override
protected void onEnterOverlay(Overlay overlay) {
if(rootNode.hasChild(podest)) {
rootNode.detachChild(podest);
}
}
@Override
protected void onLeaveOverlay(Overlay overlay) {
enterSub(state);
}
@Override
protected void onUpdate(float tpf) {
for (CeremonyButton c : ceremonyButtons) {
c.update(tpf);
}
} }
private void awardCeremony() { private void awardCeremony() {
background = createBackground("b1.png");
node.attachChild(background);
continueButton.show(); continueButton.show();
backButton.hide();
rootNode.attachChild(podest);
for (CeremonyButton c : ceremonyButtons) {
c.show();
}
} }
private void statistics() { private void statistics() {
//background = createBackground("Images/b2.png"); background = createBackground("b2.png");
//guiNode.attachChild(background); node.attachChild(background);
backButton.show();
continueButton.show(); continueButton.show();
ceremonyDialog.show(); backButton.show();
} }
private void enterSub(SubState state) { private void enterSub(SubState state) {
this.state = state; this.state = state;
if(rootNode.hasChild(podest)) { if(null != background) {
rootNode.detachChild(podest); node.detachChild(background);
} }
backButton.hide(); backButton.hide();
continueButton.hide(); continueButton.hide();
for (CeremonyButton c : ceremonyButtons) {
c.hide();
}
ceremonyDialog.hide();
switch (state) { switch (state) {
case AWARD_CEREMONY: case AWARD_CEREMONY:
@@ -178,13 +74,13 @@ private void enterSub(SubState state) {
} }
} }
public void forward() { private void forward() {
switch (state) { switch (state) {
case AWARD_CEREMONY: case AWARD_CEREMONY:
enterSub(SubState.STATISTICS); enterSub(SubState.STATISTICS);
break; break;
case STATISTICS: case STATISTICS:
app.getModelSynchronize().enter(MdgaState.MAIN); app.getModelSyncronizer().enter(MdgaState.MAIN);
break; break;
} }
} }
@@ -199,18 +95,4 @@ private void back() {
break; break;
} }
} }
public void addCeremonyParticipant(Color color, int pos, String name) {
CeremonyButton button = new CeremonyButton(app, guiNode, rootNode, color, CeremonyButton.Pos.values()[pos - 1], name);
ceremonyButtons.add(button);
if(state.equals(SubState.AWARD_CEREMONY)) {
button.show();
}
}
public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) {
ceremonyDialog.addStatisticsRow(name, v1, v2, v3, v4, v5, v6);
}
} }

View File

@@ -1,169 +1,79 @@
package pp.mdga.client.view; package pp.mdga.client.view;
import com.jme3.post.FilterPostProcessor; import com.jme3.post.FilterPostProcessor;
import pp.mdga.client.MdgaState;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.board.BoardHandler; import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.board.CameraHandler; import pp.mdga.client.board.CameraHandler;
import pp.mdga.client.dialog.SingleButtonLeftDialog;
import pp.mdga.client.dialog.SingleButtonRightDialog;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.ButtonLeft; import pp.mdga.client.MdgaState;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.gui.GuiHandler; import pp.mdga.client.gui.GuiHandler;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import pp.mdga.notification.AcquireCardNotification;
import pp.mdga.notification.ActivePlayerNotification;
import pp.mdga.notification.DiceNowNotification;
import pp.mdga.notification.GameNotification;
import pp.mdga.notification.MovePieceNotification;
import pp.mdga.notification.PlayerInGameNotification;
import pp.mdga.notification.RollDiceNotification;
import pp.mdga.notification.SelectableCardsNotification;
import pp.mdga.notification.SelectableMoveNotification;
import pp.mdga.notification.ShieldActiveNotification;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class GameView extends MdgaView { public class GameView extends MdgaView {
private BoardHandler boardHandler; private BoardHandler boardHandler;
private CameraHandler camera; private CameraHandler camera;
private GuiHandler guiHandler; private GuiHandler guiHandler;
private ButtonRight cheatButton; //TODO private SingleButtonLeftDialog leaveButton;
private SingleButtonRightDialog continueButton;
private ButtonLeft leaveButton;
private ButtonRight confirmButton;
private Color ownColor = null;
private FilterPostProcessor fpp;
public GameView(MdgaApp app) { public GameView(MdgaApp app) {
super(app); super(app);
cheatButton = new ButtonRight(app, overlayNode, () -> app.getModelSynchronize().enter(MdgaState.CEREMONY), "CHEAT", 1); //Filter für Outline: Reihenfolge CameraHandler(dlsf) -> BoardHandler -> viewPort.addProcessor einhalten!
leaveButton = new ButtonLeft(app, overlayNode, () -> app.getModelSynchronize().leave(), "Spiel verlassen", 1); FilterPostProcessor fpp = new FilterPostProcessor(app.getAssetManager());
confirmButton = new ButtonRight(app, guiNode, () -> app.getModelSynchronize().confirm(), "Bestätigen", 1);
fpp = new FilterPostProcessor(app.getAssetManager());
this.camera = new CameraHandler(app, fpp); this.camera = new CameraHandler(app, fpp);
this.boardHandler = new BoardHandler(app, rootNode, fpp); this.boardHandler = new BoardHandler(app, fpp);
app.getViewPort().addProcessor(fpp);
guiHandler = new GuiHandler(app, guiNode); this.guiHandler = new GuiHandler(app);
leaveButton = new SingleButtonLeftDialog(app, settingsNode, "Verlassen", () -> leaveGame());
continueButton = new SingleButtonRightDialog(app, node, "Weiter", () -> app.getModelSyncronizer().enter(MdgaState.CEREMONY));
} }
@Override @Override
public void onEnter() { public void onEnter() {
camera.init(); camera.init();
boardHandler.init(); boardHandler.init();
setOwnColor(Color.AIRFORCE); guiHandler.init();
guiHandler.init(ownColor); continueButton.show();
app.getViewPort().addProcessor(fpp);
app.getAcousticHandler().playSound(MdgaSound.START);
//Test
List<UUID> uuid1 = new ArrayList<>();
UUID p1 = UUID.randomUUID();
UUID p2 = UUID.randomUUID();
uuid1.add(p1);
uuid1.add(p2);
uuid1.add(UUID.randomUUID());
uuid1.add(UUID.randomUUID());
List<UUID> uuid2 = new ArrayList<>();
UUID p1_2 = UUID.randomUUID();
UUID p2_2 = UUID.randomUUID();
uuid2.add(p1_2);
uuid2.add(p2_2);
uuid2.add(UUID.randomUUID());
uuid2.add(UUID.randomUUID());
app.getNotificationSynchronizer().addTestNotification(new PlayerInGameNotification(Color.AIRFORCE, uuid1, "Cedric"));
app.getNotificationSynchronizer().addTestNotification(new PlayerInGameNotification(Color.NAVY, uuid2, "Test"));
app.getNotificationSynchronizer().addTestNotification(new MovePieceNotification(p1, 0, true));
app.getNotificationSynchronizer().addTestNotification(new MovePieceNotification(p1_2, 30, true));
// app.getNotificationSynchronizer().addTestNotification(new SelectableMoveNotification(List.of(p1), List.of(4), List.of(false)));
app.getNotificationSynchronizer().addTestNotification(new AcquireCardNotification(BonusCard.SHIELD));
// app.getNotificationSynchronizer().addTestNotification(new SelectableCardsNotification(List.of(BonusCard.SHIELD)));
// app.getNotificationSynchronizer().addTestNotification(new ShieldActiveNotification(p1));
// app.getNotificationSynchronizer().addTestNotification(new ActivePlayerNotification(Color.NAVY));
// app.getNotificationSynchronizer().addTestNotification(new DiceNowNotification());
// app.getNotificationSynchronizer().addTestNotification(new RollDiceNotification(Color.AIRFORCE, 5, true, 2));
p1 = p1;
} }
@Override @Override
public void onLeave() { public void onLeave() {
boardHandler.shutdown(); continueButton.hide();
guiHandler.shutdown();
camera.shutdown(); camera.shutdown();
boardHandler.shutdown();
confirmButton.hide();
app.getViewPort().removeProcessor(fpp);
} }
@Override @Override
public void onUpdate(float tpf) { public void onUpdate() {
camera.update(app.getInputSynchronize().getScroll(), app.getInputSynchronize().getRotation()); camera.update(app.getInputSyncronizer().getScroll(), app.getInputSyncronizer().getRotation());
} }
@Override @Override
protected void onEnterOverlay(Overlay overlay) { protected void enterExtendedSettings() {
if(overlay == Overlay.SETTINGS) { leaveButton.show();
leaveButton.show();
cheatButton.show();
}
} }
@Override @Override
protected void onLeaveOverlay(Overlay overlay) { protected void leaveExtendedSettings() {
if(overlay == Overlay.SETTINGS) { leaveButton.hide();
leaveButton.hide();
cheatButton.hide();
}
} }
private void leaveGame() { private void leaveGame() {
app.getModelSynchronize().leave(); leaveSettings(false);
app.getModelSyncronizer().leave();
app.afteGameCleanup();
} }
public BoardHandler getBoardHandler() { public BoardHandler getBoardHandler() {
return boardHandler; return boardHandler;
} }
public GuiHandler getGuiHandler() {
return guiHandler;
}
public void setOwnColor(Color ownColor) {
this.ownColor = ownColor;
}
public Color getOwnColor() {
return ownColor;
}
public void needConfirm() {
confirmButton.show();
}
public void noConfirm() {
confirmButton.hide();
}
} }

View File

@@ -1,255 +1,58 @@
package pp.mdga.client.view; package pp.mdga.client.view;
import com.jme3.asset.TextureKey;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial; import pp.mdga.client.dialog.LobbyButtonDialog;
import com.jme3.scene.shape.Quad; import pp.mdga.client.dialog.SingleButtonLeftDialog;
import com.jme3.texture.Texture; import pp.mdga.client.dialog.SingleButtonRightDialog;
import com.jme3.util.SkyFactory;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.LobbyButton;
import pp.mdga.client.button.SettingsButton;
import pp.mdga.game.Color; import pp.mdga.game.Color;
import pp.mdga.notification.GameNotification;
import java.util.ArrayList;
public class LobbyView extends MdgaView { public class LobbyView extends MdgaView {
private Geometry background; private Geometry background;
private ButtonLeft leaveButton; private SingleButtonRightDialog readyButton;
private ButtonRight readyButton; private SingleButtonLeftDialog leaveButton;
private LobbyButton cyberButton; private ArrayList<LobbyButtonDialog> lobbyButtons = new ArrayList<>();
private LobbyButton airforceButton;
private LobbyButton armyButton;
private LobbyButton navyButton;
private AmbientLight ambient = new AmbientLight();
private boolean isReady = false;
private Color own = null;
public LobbyView(MdgaApp app) { public LobbyView(MdgaApp app) {
super(app); super(app);
leaveButton = new ButtonLeft(app, guiNode, this::leaveLobby, "Verlassen", 1); background = createBackground("lobby.png");
readyButton = new ButtonRight(app, guiNode, this::ready, "Bereit", 1); node.attachChild(background);
cyberButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.CYBER), Color.CYBER); readyButton = new SingleButtonRightDialog(app, node, "Fertig", () -> app.getModelSyncronizer().setReady());
airforceButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.AIRFORCE), Color.AIRFORCE); leaveButton = new SingleButtonLeftDialog(app, node, "Verlassen", () -> app.getModelSyncronizer().leave());
armyButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.ARMY), Color.ARMY);
navyButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.NAVY), Color.NAVY);
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1)); lobbyButtons.add(new LobbyButtonDialog(app, node, "HEER", 0));
lobbyButtons.add(new LobbyButtonDialog(app, node, "MARINE", 1));
lobbyButtons.add(new LobbyButtonDialog(app, node, "CIR", 2));
lobbyButtons.add(new LobbyButtonDialog(app, node, "LUFTWAFFE", 3));
} }
@Override @Override
public void onEnter() { public void onEnter() {
app.getCamera().setParallelProjection(true);
float aspect = (float) app.getCamera().getWidth() / app.getCamera().getHeight();
float size = 1.65f;
app.getCamera().setFrustum(-1000, 1000, -aspect * size, aspect * size, size, -size);
leaveButton.show();
readyButton.show(); readyButton.show();
leaveButton.show();
cyberButton.show(); for (LobbyButtonDialog b : lobbyButtons) {
airforceButton.show(); b.show();
armyButton.show(); }
navyButton.show();
rootNode.addLight(ambient);
float screenWidth = app.getCamera().getWidth();
float screenHeight = app.getCamera().getHeight();
float aspectRatio = screenWidth / screenHeight;
float scale = 3.5f;
float quadWidth = scale * aspectRatio;
float quadHeight = scale;
Quad quad = new Quad(quadWidth, quadHeight);
background = new Geometry("LobbyBackground", quad);
TextureKey key = new TextureKey("Images/lobby.png", true);
Texture texture = app.getAssetManager().loadTexture(key);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setTexture("ColorMap", texture);
background.setMaterial(material);
background.setLocalTranslation(-quadWidth / 2, -quadHeight / 2, -5);
rootNode.attachChild(background);
} }
@Override @Override
public void onLeave() { public void onLeave() {
leaveButton.hide(); for (LobbyButtonDialog b : lobbyButtons) {
b.hide();
}
readyButton.hide(); readyButton.hide();
leaveButton.hide();
airforceButton.hide();
armyButton.hide();
navyButton.hide();
cyberButton.hide();
rootNode.removeLight(ambient);
app.getCamera().setParallelProjection(false);
app.getCamera().setFrustumPerspective(
45.0f,
(float) app.getCamera().getWidth() / app.getCamera().getHeight(),
0.1f,
1000.0f
);
app.getCamera().setLocation(new Vector3f(0, 0, 10));
app.getCamera().lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
airforceButton.setReady(false);
armyButton.setReady(false);
navyButton.setReady(false);
cyberButton.setReady(false);
airforceButton.setTaken(LobbyButton.Taken.NOT, null);
armyButton.setTaken(LobbyButton.Taken.NOT, null);
navyButton.setTaken(LobbyButton.Taken.NOT, null);
cyberButton.setTaken(LobbyButton.Taken.NOT, null);
rootNode.detachChild(background);
}
@Override
protected void onUpdate(float tpf) {
airforceButton.update(tpf);
armyButton.update(tpf);
navyButton.update(tpf);
cyberButton.update(tpf);
}
@Override
protected void onEnterOverlay(Overlay overlay) {
}
@Override
protected void onLeaveOverlay(Overlay overlay)
{
} }
public void setTaken(Color color, boolean isTaken, boolean isSelf, String name) { public void setTaken(Color color, boolean isTaken, boolean isSelf, String name) {
LobbyButton.Taken taken; lobbyButtons.get(color.ordinal()).setTaken(isTaken, isSelf, name);
if(isTaken) {
if(isSelf) {
own = color;
taken = LobbyButton.Taken.SELF;
} else {
taken = LobbyButton.Taken.OTHER;
}
} else {
if(isSelf) {
own = null;
}
taken = LobbyButton.Taken.NOT;
}
switch (color) {
case CYBER:
cyberButton.setTaken(taken, name);
break;
case AIRFORCE:
airforceButton.setTaken(taken, name);
break;
case ARMY:
armyButton.setTaken(taken, name);
break;
case NAVY:
navyButton.setTaken(taken, name);
break;
}
}
public void setReady(Color color, boolean isReady) {
LobbyButton button = switch (color) {
case CYBER -> cyberButton;
case AIRFORCE -> airforceButton;
case ARMY -> armyButton;
case NAVY -> navyButton;
default -> throw new RuntimeException("None is not valid");
};
button.setReady(isReady);
if (button.getTaken() == LobbyButton.Taken.SELF) {
this.isReady = isReady;
}
if(!isReady) {
app.getAcousticHandler().playSound(MdgaSound.NOT_READY);
} else {
if(button.getTaken() != LobbyButton.Taken.SELF) {
app.getAcousticHandler().playSound(MdgaSound.OTHER_READY);
}
}
}
private void toggleTsk(Color color) {
LobbyButton.Taken taken = LobbyButton.Taken.NOT;
switch (color) {
case CYBER:
taken = cyberButton.getTaken();
break;
case AIRFORCE:
taken = airforceButton.getTaken();
break;
case ARMY:
taken = armyButton.getTaken();
break;
case NAVY:
taken = navyButton.getTaken();
break;
}
switch (taken) {
case NOT:
app.getModelSynchronize().selectTsk(color);
break;
case SELF:
app.getModelSynchronize().unselectTsk();
break;
case OTHER:
//nothing
break;
}
}
public void ready() {
if(own == null) {
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
return;
}
if(!isReady) {
app.getAcousticHandler().playSound(MdgaSound.SELF_READY);
}
app.getModelSynchronize().setReady(!isReady);
}
private void leaveLobby() {
app.getModelSynchronize().leave();
} }
} }

View File

@@ -1,220 +1,79 @@
package pp.mdga.client.view; package pp.mdga.client.view;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import pp.mdga.client.MdgaApp; import pp.mdga.client.dialog.Dialog;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.dialog.HostDialog; import pp.mdga.client.dialog.HostDialog;
import pp.mdga.client.dialog.JoinDialog; import pp.mdga.client.dialog.JoinDialog;
import pp.mdga.client.dialog.StartDialog; import pp.mdga.client.dialog.StartDialog;
import pp.mdga.client.MdgaApp;
import com.jme3.math.Vector3f;
public class MainView extends MdgaView { public class MainView extends MdgaView {
private enum SubState {
HOST,
JOIN,
MAIN,
}
private SubState state;
private Geometry background; private Geometry background;
private StartDialog startDialog; private StartDialog dialog;
private JoinDialog joinDialog; private Dialog subDialog;
private HostDialog hostDialog;
public MainView(MdgaApp app) { public MainView(MdgaApp app) {
super(app); super(app);
startDialog = new StartDialog(app, guiNode, this); background = createBackground("powercards.png");
joinDialog = new JoinDialog(app, guiNode, this); node.attachChild(background);
hostDialog = new HostDialog(app, guiNode, this);
background = createBackground("Images/startmenu.png"); Vector3f size = new Vector3f(280, 60, 0);
dialog = new StartDialog(app, node);
dialog.addButton("Spiel beitreten", () -> enterJoin(), size);
dialog.addButton("Spiel hosten", () -> enterHost(), size);
dialog.addButton("Einstellungen", () -> enterSettings(false), size);
dialog.addButton("Spiel beenden", () -> app.stop(), size);
} }
@Override @Override
public void onEnter() { public void onEnter() {
app.setup(); dialog.show();
guiNode.attachChild(background);
enterSub(SubState.MAIN);
} }
@Override @Override
public void onLeave() { public void onLeave() {
startDialog.hide(); dialog.hide();
joinDialog.hide();
hostDialog.hide();
guiNode.detachChild(background); if(subDialog != null) {
} subDialog.hide();
subDialog = null;
@Override
public void onUpdate(float tpf) {
startDialog.update();
joinDialog.update();
hostDialog.update();
}
@Override
protected void onEnterOverlay(Overlay overlay) {
guiNode.detachChild(background);
overlayNode.attachChild(background);
}
@Override
protected void onLeaveOverlay(Overlay overlay) {
overlayNode.detachChild(background);
guiNode.attachChild(background);
}
private void joinMenu() {
startDialog.hide();
hostDialog.hide();
joinDialog.show();
}
private void hostMenu() {
startDialog.hide();
joinDialog.hide();
hostDialog.show();
}
private void mainMenu() {
joinDialog.hide();
hostDialog.hide();
startDialog.show();
}
private void tryHost() {
int port = 0;
String text = hostDialog.getPort();
try {
port = Integer.parseInt(text);
if(port >= 1 && port <= 65535) {
app.getModelSynchronize().setName(startDialog.getName());
app.getModelSynchronize().setHost(port);
//app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
return;
}
} catch (NumberFormatException e) {
//nothing
}
hostDialog.resetPort();
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
}
private void tryJoin() {
int port = 0;
String ip = joinDialog.getIpt();
String portText = hostDialog.getPort();
try {
// Validate the port
port = Integer.parseInt(portText);
if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Invalid port");
}
// Validate the IP address
if (isValidIpAddress(ip)) {
app.getModelSynchronize().setName(startDialog.getName());
app.getModelSynchronize().setJoin(ip, port);
return;
}
} catch (IllegalArgumentException e) {
// Invalid input, fall through to reset
}
hostDialog.resetPort();
joinDialog.resetIp();
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
}
private boolean isValidIpAddress(String ip) {
String ipRegex =
"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)$";
return ip != null && ip.matches(ipRegex);
}
private void enterSub(SubState state) {
this.state = state;
if(null != background) {
rootNode.detachChild(background);
}
switch (state) {
case HOST:
hostMenu();
break;
case JOIN:
joinMenu();
break;
case MAIN:
mainMenu();
break;
} }
} }
public void forward() { private void enterJoin() {
switch (state) { app.getModelSyncronizer().setName(dialog.getName());
case HOST:
tryHost(); subDialog = new JoinDialog(app, node, () -> leaveJoin());
break;
case JOIN: dialog.hide();
tryJoin(); subDialog.show();
break;
case MAIN:
throw new RuntimeException("call forward(boolean host) insted of forward()");
}
} }
public void forward(boolean host) { private void leaveJoin() {
switch (state) { subDialog.hide();
case HOST: dialog.show();
tryHost();
break; subDialog = null;
case JOIN:
tryJoin();
break;
case MAIN:
if(host) {
enterSub(SubState.HOST);
//TODO playSound
} else {
enterSub(SubState.JOIN);
//TODO: playSound
}
break;
}
} }
public void back() { private void enterHost() {
switch (state) { app.getModelSyncronizer().setName(dialog.getName());
case HOST:
enterSub(SubState.MAIN); subDialog = new HostDialog(app, node, () -> leaveHost());
//TODO: playSound
break; dialog.hide();
case JOIN: subDialog.show();
enterSub(SubState.MAIN); }
//TODO: playSound
break; private void leaveHost() {
case MAIN: subDialog.hide();
//nothing dialog.show();
break;
} subDialog = null;
} }
} }

View File

@@ -2,48 +2,81 @@
import com.jme3.asset.TextureKey; import com.jme3.asset.TextureKey;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import pp.mdga.client.dialog.GetPercentRunnable;
import pp.mdga.client.dialog.PercentRunnable;
import pp.mdga.client.dialog.SettingsButtonDialog;
import pp.mdga.client.MdgaApp; import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.button.*;
import pp.mdga.client.dialog.AudioSettingsDialog;
import pp.mdga.client.dialog.SettingsDialog; import pp.mdga.client.dialog.SettingsDialog;
import pp.mdga.client.dialog.VideoSettingsDialog;
public abstract class MdgaView { public abstract class MdgaView {
public enum Overlay {
INTERRUPT,
SETTINGS,
}
protected MdgaApp app; protected MdgaApp app;
protected Node rootNode = new Node("View Root"); protected Node node;
protected Node guiNode = new Node("View Root GUI");
protected Node overlayNode = new Node("View Root Overlay");
private SettingsButton settingsButton; protected int depth = 0;
private boolean isVideo = false;
private boolean isAudio = false;
private SettingsDialog settingsDialog; protected Node settingsNode;
private VideoSettingsDialog videoSettingsDialog; protected Node audioSettingsNode;
private AudioSettingsDialog audioSettingsDialog; protected Node videoSettingsNode;
private int settingsDepth = 0; private SettingsButtonDialog settingsButton;
private Geometry settingsBackground;
private Geometry audioBackground;
private Geometry videoBackground;
private SettingsDialog settings;
private SettingsDialog audio;
private SettingsDialog video;
public MdgaView(MdgaApp app) { public MdgaView(MdgaApp app) {
this.app = app; this.app = app;
settingsButton = new SettingsButton(app, guiNode, this::enterSettings); this.node = new Node();
settingsDialog = new SettingsDialog(app, overlayNode, this); this.settingsNode = new Node();
videoSettingsDialog = new VideoSettingsDialog(app, overlayNode, this); this.audioSettingsNode = new Node();
audioSettingsDialog = new AudioSettingsDialog(app, overlayNode, this); this.videoSettingsNode = new Node();
this.settingsButton = new SettingsButtonDialog(app, node, "", () -> enterSettings(false));
this.settingsBackground = createBackground("background/zahnräder.png");
settingsNode.attachChild(settingsBackground);
this.audioBackground = createBackground("background/lautsprecher.png");
audioSettingsNode.attachChild(audioBackground);
this.videoBackground = createBackground("background/monitors.png");
videoSettingsNode.attachChild(videoBackground);
Vector3f size = new Vector3f(280, 60, 0);
this.settings = new SettingsDialog(app, settingsNode, "zahnrad.png");
this.settings.addButton("Video", () -> enterVideo(), size);
this.settings.addButton("Audio", () -> enterAudio(), size);
this.settings.addButton("Zurück", () -> leaveSettings(false), size);
this.audio = new SettingsDialog(app, audioSettingsNode, "audio_icon.png");
this.audio.addSlider("Lautstärke", new PercentRunnable(app.getAcousticHandler()::setMainVolume), new GetPercentRunnable(app.getAcousticHandler()::getMainVolume), size, (int) app.getAcousticHandler().getMainVolume() * 100);
this.audio.addSlider("Musik", new PercentRunnable(app.getAcousticHandler()::setMusicVolume), new GetPercentRunnable(app.getAcousticHandler()::getMusicVolume), size, (int) app.getAcousticHandler().getMusicVolume() * 100);
this.audio.addSlider("Sound", new PercentRunnable(app.getAcousticHandler()::setSoundVolume), new GetPercentRunnable(app.getAcousticHandler()::getSoundVolume), size, (int) app.getAcousticHandler().getSoundVolume() * 100);
this.audio.addButton("Zurück", () -> leaveAudio(), size);
this.video = new SettingsDialog(app, videoSettingsNode, "monitor.png");
this.video.addButton("A", () -> System.out.println("A"), size);
this.video.addButton("B", () -> System.out.println("B"), size);
this.video.addButton("Zurück", () -> leaveVideo(), size);
} }
public void enter() { public void enter() {
app.getRootNode().attachChild(rootNode); app.getGuiNode().attachChild(node);
app.getGuiNode().attachChild(guiNode);
audio.initVolume();
settingsButton.show(); settingsButton.show();
@@ -53,140 +86,121 @@ public void enter() {
public void leave() { public void leave() {
onLeave(); onLeave();
settingsButton.hide(); settingsButton.hide();
while (settingsDepth > 0) { app.getGuiNode().detachChild(node);
pressEscape();
}
app.getRootNode().detachChild(rootNode);
app.getGuiNode().detachChild(guiNode);
} }
public void enterOverlay(Overlay overlay) { public void update() {
app.getGuiNode().detachChild(guiNode); audio.update();
onUpdate();
onEnterOverlay(overlay);
}
public void leaveOverlay(Overlay overlay) {
app.getGuiNode().attachChild(guiNode);
onLeaveOverlay(overlay);
}
public void update(float tpf) {
videoSettingsDialog.update();
audioSettingsDialog.update();
onUpdate(tpf);
} }
protected abstract void onEnter(); protected abstract void onEnter();
protected abstract void onLeave(); protected abstract void onLeave();
protected void onUpdate(float tpf) {} protected void onUpdate() {}
protected abstract void onEnterOverlay(Overlay overlay);
protected abstract void onLeaveOverlay(Overlay overlay);
protected Geometry createBackground(String texturePath) { protected Geometry createBackground(String texturePath) {
TextureKey key = new TextureKey(texturePath, true); TextureKey key = new TextureKey(texturePath, true);
Texture backgroundTexture = app.getAssetManager().loadTexture(key); Texture backgroundTexture = app.getAssetManager().loadTexture(key);
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry background = new Geometry("Background", quad);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", backgroundTexture); mat.setTexture("ColorMap", backgroundTexture);
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry background = new Geometry("Background", quad);
background.setMaterial(mat); background.setMaterial(mat);
background.setLocalTranslation(0, 0, -2); background.setLocalTranslation(0, 0, -1);
return background; return background;
} }
public void enterSettings() { protected void enterExtendedSettings() {}
enterOverlay(Overlay.SETTINGS); protected void leaveExtendedSettings() {}
app.getGuiNode().attachChild(overlayNode); protected void enterSettings(boolean soft) {
leave();
settingsDialog.show(); app.getGuiNode().attachChild(settingsNode);
settingsDepth++; if(!soft) {
depth++;
enterExtendedSettings();
}
settings.show();
} }
public void leaveSettings() { protected void leaveSettings(boolean soft) {
leaveOverlay(Overlay.SETTINGS); settings.hide();
app.getGuiNode().detachChild(overlayNode); app.getGuiNode().detachChild(settingsNode);
settingsDialog.hide(); if(!soft) {
leaveExtendedSettings();
settingsDepth--; enter();
depth--;
}
} }
public void enterVideoSettings() { protected void enterAudio() {
settingsDialog.hide(); leaveSettings(true);
videoSettingsDialog.show();
settingsDepth++; depth++;
isAudio = true;
app.getGuiNode().attachChild(audioSettingsNode);
audio.show();
} }
public void leaveVideoSettings() { protected void leaveAudio() {
settingsDialog.show(); audio.hide();
videoSettingsDialog.hide();
settingsDepth--; app.getGuiNode().detachChild(audioSettingsNode);
isAudio = false;
depth--;
enterSettings(true);
} }
public void enterAudioSettings() { protected void enterVideo() {
settingsDialog.hide(); leaveSettings(true);
audioSettingsDialog.show();
settingsDepth++; app.getGuiNode().attachChild(videoSettingsNode);
depth++;
isVideo = true;
video.show();
} }
public void leaveAudioSettings() { protected void leaveVideo() {
settingsDialog.show(); video.hide();
audioSettingsDialog.hide();
settingsDepth--; app.getGuiNode().detachChild(videoSettingsNode);
}
private void leaveAdvanced() { depth--;
settingsDialog.show(); isVideo = false;
audioSettingsDialog.hide();
videoSettingsDialog.hide(); enterSettings(true);
settingsDepth--;
} }
public void pressEscape() { public void pressEscape() {
if(settingsDepth == 0) { if(depth == 0) {
enterSettings(); enterSettings(false);
} else if(settingsDepth == 1) { } else if(depth == 1) {
leaveSettings(); leaveSettings(false);
}
else if (depth == 2){
if(isVideo) {
leaveVideo();
}
if(isAudio) {
leaveAudio();
}
} else { } else {
leaveAdvanced(); throw new RuntimeException();
}
}
public void pressForward() {
if(this instanceof MainView mainView) {
mainView.forward(false);
app.getAcousticHandler().playSound(MdgaSound.BUTTON_PRESSED);
}
if(this instanceof LobbyView lobbyView) {
lobbyView.ready();
}
if(this instanceof GameView gameView) {
app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
}
if(this instanceof CeremonyView ceremonyView) {
ceremonyView.forward();
} }
} }
} }

View File

@@ -1,195 +0,0 @@
info face=null size=178 bold=0 italic=0 charset=ASCII unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
common lineHeight=214 base=26 scaleW=2048 scaleH=2048 pages=1 packed=0
page id=0 file="Gunplay.png"
chars count=255
char id=9 x=0 y=46 width=6 height=220 xoffset=0 yoffset=0 xadvance=-1 page=0 chnl=0
char id=10 x=6 y=46 width=6 height=220 xoffset=0 yoffset=0 xadvance=-1 page=0 chnl=0
char id=13 x=12 y=46 width=6 height=220 xoffset=0 yoffset=0 xadvance=-1 page=0 chnl=0
char id=32 x=18 y=46 width=6 height=220 xoffset=0 yoffset=0 xadvance=59 page=0 chnl=0
char id=33 x=24 y=46 width=40 height=220 xoffset=8 yoffset=0 xadvance=49 page=0 chnl=0
char id=34 x=64 y=46 width=62 height=220 xoffset=8 yoffset=0 xadvance=71 page=0 chnl=0
char id=35 x=126 y=46 width=95 height=220 xoffset=3 yoffset=0 xadvance=95 page=0 chnl=0
char id=36 x=221 y=46 width=84 height=220 xoffset=4 yoffset=0 xadvance=86 page=0 chnl=0
char id=37 x=305 y=46 width=148 height=220 xoffset=6 yoffset=0 xadvance=153 page=0 chnl=0
char id=38 x=453 y=46 width=127 height=220 xoffset=6 yoffset=0 xadvance=131 page=0 chnl=0
char id=39 x=580 y=46 width=31 height=220 xoffset=8 yoffset=0 xadvance=39 page=0 chnl=0
char id=40 x=611 y=46 width=44 height=220 xoffset=4 yoffset=0 xadvance=44 page=0 chnl=0
char id=41 x=655 y=46 width=44 height=220 xoffset=4 yoffset=0 xadvance=44 page=0 chnl=0
char id=42 x=699 y=46 width=71 height=220 xoffset=4 yoffset=0 xadvance=71 page=0 chnl=0
char id=43 x=770 y=46 width=86 height=220 xoffset=3 yoffset=0 xadvance=85 page=0 chnl=0
char id=44 x=856 y=46 width=38 height=220 xoffset=7 yoffset=0 xadvance=43 page=0 chnl=0
char id=45 x=894 y=46 width=65 height=220 xoffset=8 yoffset=0 xadvance=75 page=0 chnl=0
char id=46 x=959 y=46 width=39 height=220 xoffset=8 yoffset=0 xadvance=48 page=0 chnl=0
char id=47 x=998 y=46 width=102 height=220 xoffset=1 yoffset=0 xadvance=97 page=0 chnl=0
char id=48 x=1100 y=46 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=49 x=1207 y=46 width=61 height=220 xoffset=2 yoffset=0 xadvance=64 page=0 chnl=0
char id=50 x=1268 y=46 width=104 height=220 xoffset=6 yoffset=0 xadvance=111 page=0 chnl=0
char id=51 x=1372 y=46 width=100 height=220 xoffset=6 yoffset=0 xadvance=106 page=0 chnl=0
char id=52 x=1472 y=46 width=111 height=220 xoffset=3 yoffset=0 xadvance=109 page=0 chnl=0
char id=53 x=1583 y=46 width=98 height=220 xoffset=7 yoffset=0 xadvance=105 page=0 chnl=0
char id=54 x=1681 y=46 width=104 height=220 xoffset=8 yoffset=0 xadvance=112 page=0 chnl=0
char id=55 x=1785 y=46 width=92 height=220 xoffset=6 yoffset=0 xadvance=93 page=0 chnl=0
char id=56 x=1877 y=46 width=100 height=220 xoffset=7 yoffset=0 xadvance=107 page=0 chnl=0
char id=57 x=0 y=266 width=105 height=220 xoffset=7 yoffset=0 xadvance=112 page=0 chnl=0
char id=58 x=105 y=266 width=36 height=220 xoffset=8 yoffset=0 xadvance=43 page=0 chnl=0
char id=59 x=141 y=266 width=37 height=220 xoffset=7 yoffset=0 xadvance=43 page=0 chnl=0
char id=60 x=178 y=266 width=59 height=220 xoffset=1 yoffset=0 xadvance=58 page=0 chnl=0
char id=61 x=237 y=266 width=92 height=220 xoffset=8 yoffset=0 xadvance=97 page=0 chnl=0
char id=62 x=329 y=266 width=59 height=220 xoffset=8 yoffset=0 xadvance=61 page=0 chnl=0
char id=63 x=388 y=266 width=96 height=220 xoffset=4 yoffset=0 xadvance=98 page=0 chnl=0
char id=64 x=484 y=266 width=132 height=220 xoffset=4 yoffset=0 xadvance=136 page=0 chnl=0
char id=65 x=616 y=266 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=66 x=736 y=266 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=67 x=843 y=266 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=68 x=950 y=266 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=69 x=1057 y=266 width=87 height=220 xoffset=8 yoffset=0 xadvance=93 page=0 chnl=0
char id=70 x=1144 y=266 width=87 height=220 xoffset=8 yoffset=0 xadvance=91 page=0 chnl=0
char id=71 x=1231 y=266 width=105 height=220 xoffset=8 yoffset=0 xadvance=114 page=0 chnl=0
char id=72 x=1336 y=266 width=105 height=220 xoffset=8 yoffset=0 xadvance=114 page=0 chnl=0
char id=73 x=1441 y=266 width=41 height=220 xoffset=8 yoffset=0 xadvance=50 page=0 chnl=0
char id=74 x=1482 y=266 width=63 height=220 xoffset=3 yoffset=0 xadvance=67 page=0 chnl=0
char id=75 x=1545 y=266 width=114 height=220 xoffset=8 yoffset=0 xadvance=118 page=0 chnl=0
char id=76 x=1659 y=266 width=83 height=220 xoffset=8 yoffset=0 xadvance=87 page=0 chnl=0
char id=77 x=1742 y=266 width=142 height=220 xoffset=8 yoffset=0 xadvance=151 page=0 chnl=0
char id=78 x=1884 y=266 width=111 height=220 xoffset=8 yoffset=0 xadvance=121 page=0 chnl=0
char id=79 x=0 y=486 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=80 x=107 y=486 width=105 height=220 xoffset=8 yoffset=0 xadvance=108 page=0 chnl=0
char id=81 x=212 y=486 width=107 height=220 xoffset=6 yoffset=0 xadvance=113 page=0 chnl=0
char id=82 x=319 y=486 width=107 height=220 xoffset=8 yoffset=0 xadvance=113 page=0 chnl=0
char id=83 x=426 y=486 width=112 height=220 xoffset=6 yoffset=0 xadvance=117 page=0 chnl=0
char id=84 x=538 y=486 width=107 height=220 xoffset=3 yoffset=0 xadvance=105 page=0 chnl=0
char id=85 x=645 y=486 width=107 height=220 xoffset=8 yoffset=0 xadvance=116 page=0 chnl=0
char id=86 x=752 y=486 width=117 height=220 xoffset=1 yoffset=0 xadvance=111 page=0 chnl=0
char id=87 x=869 y=486 width=169 height=220 xoffset=1 yoffset=0 xadvance=165 page=0 chnl=0
char id=88 x=1038 y=486 width=123 height=220 xoffset=3 yoffset=0 xadvance=124 page=0 chnl=0
char id=89 x=1161 y=486 width=119 height=220 xoffset=2 yoffset=0 xadvance=115 page=0 chnl=0
char id=90 x=1280 y=486 width=101 height=220 xoffset=5 yoffset=0 xadvance=104 page=0 chnl=0
char id=91 x=1381 y=486 width=37 height=220 xoffset=8 yoffset=0 xadvance=44 page=0 chnl=0
char id=92 x=1418 y=486 width=102 height=220 xoffset=1 yoffset=0 xadvance=97 page=0 chnl=0
char id=93 x=1520 y=486 width=37 height=220 xoffset=8 yoffset=0 xadvance=44 page=0 chnl=0
char id=94 x=1557 y=486 width=95 height=220 xoffset=4 yoffset=0 xadvance=96 page=0 chnl=0
char id=95 x=1652 y=486 width=125 height=220 xoffset=-1 yoffset=0 xadvance=115 page=0 chnl=0
char id=96 x=1777 y=486 width=57 height=220 xoffset=-2 yoffset=0 xadvance=56 page=0 chnl=0
char id=97 x=1834 y=486 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=98 x=1932 y=486 width=91 height=220 xoffset=8 yoffset=0 xadvance=96 page=0 chnl=0
char id=99 x=0 y=706 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=100 x=91 y=706 width=90 height=220 xoffset=4 yoffset=0 xadvance=96 page=0 chnl=0
char id=101 x=181 y=706 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=102 x=272 y=706 width=70 height=220 xoffset=1 yoffset=0 xadvance=66 page=0 chnl=0
char id=103 x=342 y=706 width=89 height=220 xoffset=6 yoffset=0 xadvance=96 page=0 chnl=0
char id=104 x=431 y=706 width=91 height=220 xoffset=8 yoffset=0 xadvance=96 page=0 chnl=0
char id=105 x=522 y=706 width=37 height=220 xoffset=8 yoffset=0 xadvance=46 page=0 chnl=0
char id=106 x=559 y=706 width=57 height=220 xoffset=-14 yoffset=0 xadvance=44 page=0 chnl=0
char id=107 x=616 y=706 width=98 height=220 xoffset=8 yoffset=0 xadvance=101 page=0 chnl=0
char id=108 x=714 y=706 width=37 height=220 xoffset=8 yoffset=0 xadvance=46 page=0 chnl=0
char id=109 x=751 y=706 width=138 height=220 xoffset=8 yoffset=0 xadvance=147 page=0 chnl=0
char id=110 x=889 y=706 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=111 x=980 y=706 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=112 x=1071 y=706 width=91 height=220 xoffset=8 yoffset=0 xadvance=96 page=0 chnl=0
char id=113 x=1162 y=706 width=90 height=220 xoffset=5 yoffset=0 xadvance=96 page=0 chnl=0
char id=114 x=1252 y=706 width=65 height=220 xoffset=8 yoffset=0 xadvance=69 page=0 chnl=0
char id=115 x=1317 y=706 width=91 height=220 xoffset=6 yoffset=0 xadvance=96 page=0 chnl=0
char id=116 x=1408 y=706 width=73 height=220 xoffset=1 yoffset=0 xadvance=68 page=0 chnl=0
char id=117 x=1481 y=706 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=118 x=1572 y=706 width=99 height=220 xoffset=1 yoffset=0 xadvance=95 page=0 chnl=0
char id=119 x=1671 y=706 width=146 height=220 xoffset=3 yoffset=0 xadvance=144 page=0 chnl=0
char id=120 x=1817 y=706 width=102 height=220 xoffset=4 yoffset=0 xadvance=103 page=0 chnl=0
char id=121 x=1919 y=706 width=99 height=220 xoffset=2 yoffset=0 xadvance=96 page=0 chnl=0
char id=122 x=0 y=926 width=84 height=220 xoffset=5 yoffset=0 xadvance=86 page=0 chnl=0
char id=123 x=84 y=926 width=67 height=220 xoffset=3 yoffset=0 xadvance=68 page=0 chnl=0
char id=124 x=151 y=926 width=27 height=220 xoffset=8 yoffset=0 xadvance=36 page=0 chnl=0
char id=125 x=178 y=926 width=67 height=220 xoffset=6 yoffset=0 xadvance=68 page=0 chnl=0
char id=126 x=245 y=926 width=93 height=220 xoffset=12 yoffset=0 xadvance=110 page=0 chnl=0
char id=161 x=338 y=926 width=40 height=220 xoffset=8 yoffset=0 xadvance=49 page=0 chnl=0
char id=162 x=378 y=926 width=82 height=220 xoffset=8 yoffset=0 xadvance=90 page=0 chnl=0
char id=163 x=460 y=926 width=93 height=220 xoffset=5 yoffset=0 xadvance=95 page=0 chnl=0
char id=164 x=553 y=926 width=80 height=220 xoffset=12 yoffset=0 xadvance=97 page=0 chnl=0
char id=165 x=633 y=926 width=119 height=220 xoffset=4 yoffset=0 xadvance=120 page=0 chnl=0
char id=166 x=752 y=926 width=27 height=220 xoffset=8 yoffset=0 xadvance=35 page=0 chnl=0
char id=167 x=779 y=926 width=95 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=168 x=874 y=926 width=68 height=220 xoffset=8 yoffset=0 xadvance=78 page=0 chnl=0
char id=169 x=942 y=926 width=153 height=220 xoffset=7 yoffset=0 xadvance=157 page=0 chnl=0
char id=170 x=1095 y=926 width=68 height=220 xoffset=7 yoffset=0 xadvance=75 page=0 chnl=0
char id=171 x=1163 y=926 width=77 height=220 xoffset=8 yoffset=0 xadvance=88 page=0 chnl=0
char id=172 x=1240 y=926 width=102 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=174 x=1342 y=926 width=93 height=220 xoffset=5 yoffset=0 xadvance=95 page=0 chnl=0
char id=175 x=1435 y=926 width=65 height=220 xoffset=8 yoffset=0 xadvance=75 page=0 chnl=0
char id=176 x=1500 y=926 width=70 height=220 xoffset=6 yoffset=0 xadvance=73 page=0 chnl=0
char id=177 x=1570 y=926 width=93 height=220 xoffset=12 yoffset=0 xadvance=110 page=0 chnl=0
char id=178 x=1663 y=926 width=55 height=220 xoffset=8 yoffset=0 xadvance=63 page=0 chnl=0
char id=179 x=1718 y=926 width=53 height=220 xoffset=8 yoffset=0 xadvance=60 page=0 chnl=0
char id=180 x=1771 y=926 width=60 height=220 xoffset=9 yoffset=0 xadvance=61 page=0 chnl=0
char id=182 x=1831 y=926 width=73 height=220 xoffset=14 yoffset=0 xadvance=92 page=0 chnl=0
char id=183 x=1904 y=926 width=39 height=220 xoffset=8 yoffset=0 xadvance=48 page=0 chnl=0
char id=184 x=1943 y=926 width=44 height=220 xoffset=8 yoffset=0 xadvance=48 page=0 chnl=0
char id=185 x=1987 y=926 width=33 height=220 xoffset=9 yoffset=0 xadvance=46 page=0 chnl=0
char id=186 x=0 y=1146 width=69 height=220 xoffset=7 yoffset=0 xadvance=78 page=0 chnl=0
char id=187 x=69 y=1146 width=77 height=220 xoffset=8 yoffset=0 xadvance=88 page=0 chnl=0
char id=188 x=146 y=1146 width=128 height=220 xoffset=10 yoffset=0 xadvance=139 page=0 chnl=0
char id=189 x=274 y=1146 width=126 height=220 xoffset=9 yoffset=0 xadvance=140 page=0 chnl=0
char id=190 x=400 y=1146 width=135 height=220 xoffset=3 yoffset=0 xadvance=138 page=0 chnl=0
char id=191 x=535 y=1146 width=97 height=220 xoffset=4 yoffset=0 xadvance=98 page=0 chnl=0
char id=192 x=632 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=193 x=752 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=194 x=872 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=195 x=992 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=196 x=1112 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=197 x=1232 y=1146 width=120 height=220 xoffset=1 yoffset=0 xadvance=114 page=0 chnl=0
char id=198 x=1352 y=1146 width=131 height=220 xoffset=1 yoffset=0 xadvance=133 page=0 chnl=0
char id=199 x=1483 y=1146 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=200 x=1590 y=1146 width=87 height=220 xoffset=8 yoffset=0 xadvance=93 page=0 chnl=0
char id=201 x=1677 y=1146 width=87 height=220 xoffset=8 yoffset=0 xadvance=93 page=0 chnl=0
char id=202 x=1764 y=1146 width=87 height=220 xoffset=8 yoffset=0 xadvance=93 page=0 chnl=0
char id=203 x=1851 y=1146 width=87 height=220 xoffset=8 yoffset=0 xadvance=93 page=0 chnl=0
char id=204 x=1938 y=1146 width=56 height=220 xoffset=-3 yoffset=0 xadvance=50 page=0 chnl=0
char id=205 x=0 y=1366 width=60 height=220 xoffset=2 yoffset=0 xadvance=50 page=0 chnl=0
char id=206 x=60 y=1366 width=69 height=220 xoffset=-6 yoffset=0 xadvance=50 page=0 chnl=0
char id=207 x=129 y=1366 width=68 height=220 xoffset=-5 yoffset=0 xadvance=50 page=0 chnl=0
char id=208 x=197 y=1366 width=117 height=220 xoffset=5 yoffset=0 xadvance=123 page=0 chnl=0
char id=209 x=314 y=1366 width=111 height=220 xoffset=8 yoffset=0 xadvance=121 page=0 chnl=0
char id=210 x=425 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=211 x=532 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=212 x=639 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=213 x=746 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=214 x=853 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=215 x=960 y=1366 width=77 height=220 xoffset=8 yoffset=0 xadvance=85 page=0 chnl=0
char id=216 x=1037 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=115 page=0 chnl=0
char id=217 x=1144 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=116 page=0 chnl=0
char id=218 x=1251 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=116 page=0 chnl=0
char id=219 x=1358 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=116 page=0 chnl=0
char id=220 x=1465 y=1366 width=107 height=220 xoffset=8 yoffset=0 xadvance=116 page=0 chnl=0
char id=221 x=1572 y=1366 width=119 height=220 xoffset=2 yoffset=0 xadvance=115 page=0 chnl=0
char id=222 x=1691 y=1366 width=84 height=220 xoffset=8 yoffset=0 xadvance=92 page=0 chnl=0
char id=223 x=1775 y=1366 width=99 height=220 xoffset=7 yoffset=0 xadvance=106 page=0 chnl=0
char id=224 x=1874 y=1366 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=225 x=0 y=1586 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=226 x=98 y=1586 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=227 x=196 y=1586 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=228 x=294 y=1586 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=229 x=392 y=1586 width=98 height=220 xoffset=7 yoffset=0 xadvance=103 page=0 chnl=0
char id=230 x=490 y=1586 width=148 height=220 xoffset=7 yoffset=0 xadvance=155 page=0 chnl=0
char id=231 x=638 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=232 x=729 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=233 x=820 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=234 x=911 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=235 x=1002 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=98 page=0 chnl=0
char id=236 x=1093 y=1586 width=56 height=220 xoffset=-5 yoffset=0 xadvance=46 page=0 chnl=0
char id=237 x=1149 y=1586 width=61 height=220 xoffset=8 yoffset=0 xadvance=46 page=0 chnl=0
char id=238 x=1210 y=1586 width=69 height=220 xoffset=-8 yoffset=0 xadvance=46 page=0 chnl=0
char id=239 x=1279 y=1586 width=67 height=220 xoffset=-7 yoffset=0 xadvance=46 page=0 chnl=0
char id=240 x=1346 y=1586 width=105 height=220 xoffset=8 yoffset=0 xadvance=112 page=0 chnl=0
char id=241 x=1451 y=1586 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=242 x=1542 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=243 x=1633 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=244 x=1724 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=245 x=1815 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=246 x=1906 y=1586 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=247 x=0 y=1806 width=65 height=220 xoffset=8 yoffset=0 xadvance=75 page=0 chnl=0
char id=248 x=65 y=1806 width=91 height=220 xoffset=7 yoffset=0 xadvance=99 page=0 chnl=0
char id=249 x=156 y=1806 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=250 x=247 y=1806 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=251 x=338 y=1806 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=252 x=429 y=1806 width=91 height=220 xoffset=8 yoffset=0 xadvance=100 page=0 chnl=0
char id=253 x=520 y=1806 width=99 height=220 xoffset=2 yoffset=0 xadvance=96 page=0 chnl=0
char id=254 x=619 y=1806 width=91 height=220 xoffset=8 yoffset=0 xadvance=96 page=0 chnl=0
char id=255 x=710 y=1806 width=99 height=220 xoffset=2 yoffset=0 xadvance=96 page=0 chnl=0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 866 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

View File

@@ -1,40 +1,29 @@
// Samplers for textures
uniform sampler2D m_Texture; uniform sampler2D m_Texture;
uniform sampler2D m_OutlineDepthTexture; uniform sampler2D m_OutlineDepthTexture;
uniform sampler2D m_DepthTexture; uniform sampler2D m_DepthTexture;
varying vec2 texCoord;
// Input texture coordinates from the vertex shader
in vec2 texCoord;
// Resolution of the screen and outline settings
uniform vec2 m_Resolution; uniform vec2 m_Resolution;
uniform vec4 m_OutlineColor; uniform vec4 m_OutlineColor;
uniform float m_OutlineWidth; uniform float m_OutlineWidth;
// Output color of the fragment
out vec4 fragColor;
void main() { void main() {
// Sample depth textures vec4 depth = texture2D(m_OutlineDepthTexture, texCoord);
vec4 depth = texture(m_OutlineDepthTexture, texCoord); vec4 depth1 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,m_OutlineWidth))/m_Resolution);
vec4 depth1 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(m_OutlineWidth, m_OutlineWidth)) / m_Resolution); vec4 depth2 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,-m_OutlineWidth))/m_Resolution);
vec4 depth2 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(m_OutlineWidth, -m_OutlineWidth)) / m_Resolution); vec4 depth3 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,m_OutlineWidth))/m_Resolution);
vec4 depth3 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(-m_OutlineWidth, m_OutlineWidth)) / m_Resolution); vec4 depth4 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,-m_OutlineWidth))/m_Resolution);
vec4 depth4 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(-m_OutlineWidth, -m_OutlineWidth)) / m_Resolution); vec4 depth5 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,m_OutlineWidth))/m_Resolution);
vec4 depth5 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(0.0, m_OutlineWidth)) / m_Resolution); vec4 depth6 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,-m_OutlineWidth))/m_Resolution);
vec4 depth6 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(0.0, -m_OutlineWidth)) / m_Resolution); vec4 depth7 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,0.))/m_Resolution);
vec4 depth7 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(m_OutlineWidth, 0.0)) / m_Resolution); vec4 depth8 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,0.))/m_Resolution);
vec4 depth8 = texture(m_OutlineDepthTexture, ((texCoord * m_Resolution) + vec2(-m_OutlineWidth, 0.0)) / m_Resolution); vec4 color = texture2D(m_Texture, texCoord);
//如果是背景
// Sample the main texture if(depth==vec4(0.) && (depth1 != depth || depth2 != depth || depth3 != depth || depth4 != depth||depth5 != depth || depth6 != depth || depth7 != depth || depth8 != depth)){
vec4 color = texture(m_Texture, texCoord); gl_FragColor = m_OutlineColor;
}else{
// Determine whether to apply the outline color gl_FragColor = color;
if (depth == vec4(0.0) && }
(depth1 != depth || depth2 != depth || depth3 != depth || depth4 != depth || //debug
depth5 != depth || depth6 != depth || depth7 != depth || depth8 != depth)) { //gl_FragColor = vec4(0.,(1.-ratio),0.,1.);
fragColor = m_OutlineColor; // Apply outline color }
} else {
fragColor = color; // Use the original texture color
}
}

View File

@@ -1,18 +1,10 @@
varying vec2 texCoord;
// Use 'in' instead of 'varying' for inputs from the vertex shader
in vec2 texCoord;
// Declare a custom output variable for the fragment color
out vec4 fragColor;
// Uniform samplers
uniform sampler2D m_Texture; uniform sampler2D m_Texture;
uniform sampler2D m_NormalsTexture; uniform sampler2D m_NormalsTexture;
uniform sampler2D m_DepthTexture; uniform sampler2D m_DepthTexture;
void main() { void main(){
// Sample the texture at the given texture coordinates vec4 color = texture2D(m_Texture, texCoord);
vec4 color = texture(m_Texture, texCoord); gl_FragColor=color;
// Assign the color to the output variable }
fragColor = color;
}

View File

@@ -1,109 +0,0 @@
uniform sampler2D m_Texture;
uniform sampler2D m_OutlineDepthTexture;
uniform sampler2D m_DepthTexture;
varying vec2 texCoord;
uniform vec2 m_Resolution;
uniform vec4 m_OutlineColor;
uniform float m_OutlineWidth;
void main() {
vec4 depth = texture2D(m_OutlineDepthTexture, texCoord);
vec4 depth1 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,m_OutlineWidth))/m_Resolution);
vec4 depth2 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,-m_OutlineWidth))/m_Resolution);
vec4 depth3 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,m_OutlineWidth))/m_Resolution);
vec4 depth4 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,-m_OutlineWidth))/m_Resolution);
vec4 depth5 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,m_OutlineWidth))/m_Resolution);
vec4 depth6 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,-m_OutlineWidth))/m_Resolution);
vec4 depth7 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(m_OutlineWidth,0.))/m_Resolution);
vec4 depth8 = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-m_OutlineWidth,0.))/m_Resolution);
vec4 color = texture2D(m_Texture, texCoord);
//如果是背景
float ratio=0.;
if(depth==vec4(0.) && (depth1 != depth || depth2 != depth || depth3 != depth || depth4 != depth||depth5 != depth || depth6 != depth || depth7 != depth || depth8 != depth)){
float dist=m_OutlineWidth;
//距离边的像素
vec4 nearDepth;
if(depth1 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(i,i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth2 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(i,-i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth3 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-i,i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth4 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-i,-i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth5 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth6 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(0.,-i))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth7 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(i,0.))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}else
if(depth8 != depth){
for(float i=0.;i<m_OutlineWidth;i++){
nearDepth = texture2D(m_OutlineDepthTexture, ((texCoord*m_Resolution)+vec2(-i,0.))/m_Resolution);
if(nearDepth != depth){
dist = i;
break;
}
}
}
//0:场景颜色 1:outline颜色
ratio = clamp(1.- dist/m_OutlineWidth,0.,1.);
//float off = (1.-ratio*ratio)*(1.-ratio*ratio);
gl_FragColor = color*(1.-ratio) +m_OutlineColor*ratio;
//gl_FragColor = m_OutlineColor;
}else{
gl_FragColor = color;
}
//debug
//gl_FragColor = vec4(0.,(1.-ratio),0.,1.);
}

View File

@@ -1,21 +0,0 @@
MaterialDef Cartoon Edge {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D Texture
Texture2D OutlineDepthTexture
Texture2D DepthTexture
Vector2 Resolution
Color OutlineColor
Float OutlineWidth
}
Technique {
VertexShader GLSL150: MatDefs/SelectObjectOutliner/Post15.vert
FragmentShader GLSL150: MatDefs/SelectObjectOutliner/OutlinePro.frag
WorldParameters {
}
}
}

View File

@@ -1,15 +1,10 @@
// Use 'in' for vertex attributes
in vec4 inPosition; in vec4 inPosition;
in vec2 inTexCoord; in vec2 inTexCoord;
// Use 'out' for passing data to the fragment shader
out vec2 texCoord; out vec2 texCoord;
void main() { void main() {
// Transform position to clip space
vec2 pos = inPosition.xy * 2.0 - 1.0; vec2 pos = inPosition.xy * 2.0 - 1.0;
gl_Position = vec4(pos, 0.0, 1.0); gl_Position = vec4(pos, 0.0, 1.0);
// Pass texture coordinates to the fragment shader
texCoord = inTexCoord; texCoord = inTexCoord;
} }

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

View File

@@ -1,582 +0,0 @@
# Blender 3.6.5
# www.blender.org
o Shield.001
v 0.331177 0.029684 0.498915
v 0.331177 0.029684 -0.019826
v 0.324814 0.029684 -0.113625
v 0.305971 0.029684 -0.203821
v 0.275372 0.029684 -0.286945
v 0.234192 0.029684 -0.359804
v 0.184014 0.029684 -0.419598
v 0.126767 0.029684 -0.464029
v 0.064650 0.029684 -0.491389
v 0.000000 0.029684 -0.500628
v 0.000000 0.029684 0.498915
v 0.318062 -0.020828 0.485801
v 0.318062 -0.020828 -0.019381
v 0.311791 -0.020828 -0.111832
v 0.293331 -0.020828 -0.200195
v 0.263432 -0.020828 -0.281417
v 0.223370 -0.020828 -0.352299
v 0.174868 -0.020828 -0.410095
v 0.120002 -0.020828 -0.452678
v 0.061012 -0.020828 -0.478662
v 0.000000 -0.020828 0.498915
v 0.331177 -0.020828 0.498915
v 0.000000 -0.020828 -0.500628
v 0.331177 -0.020828 -0.019826
v 0.324814 -0.020828 -0.113625
v 0.305971 -0.020828 -0.203821
v 0.275372 -0.020828 -0.286945
v 0.234192 -0.020828 -0.359804
v 0.184014 -0.020828 -0.419598
v 0.126767 -0.020828 -0.464029
v 0.064650 -0.020828 -0.491389
v 0.000000 -0.020828 -0.485507
v 0.000000 -0.020828 0.485800
v 0.000000 -0.020828 0.000147
v 0.318062 -0.030185 0.485801
v 0.318062 -0.030185 -0.019381
v 0.311791 -0.030185 -0.111832
v 0.293331 -0.030185 -0.200195
v 0.263432 -0.030185 -0.281417
v 0.223370 -0.030185 -0.352299
v 0.174868 -0.030185 -0.410095
v 0.120002 -0.030185 -0.452678
v 0.061012 -0.030185 -0.478662
v 0.000000 -0.030185 0.498915
v 0.331177 -0.030185 0.498915
v 0.000000 -0.030185 -0.500628
v 0.331177 -0.030185 -0.019826
v 0.324814 -0.030185 -0.113625
v 0.305971 -0.030185 -0.203821
v 0.275372 -0.030185 -0.286945
v 0.234192 -0.030185 -0.359804
v 0.184014 -0.030185 -0.419598
v 0.126767 -0.030185 -0.464029
v 0.064650 -0.030185 -0.491389
v 0.000000 -0.030185 -0.485507
v 0.000000 -0.030185 0.485800
v -0.331177 0.029684 0.498915
v -0.331177 0.029684 -0.019826
v -0.324814 0.029684 -0.113625
v -0.305971 0.029684 -0.203821
v -0.275372 0.029684 -0.286945
v -0.234192 0.029684 -0.359804
v -0.184014 0.029684 -0.419598
v -0.126767 0.029684 -0.464029
v -0.064650 0.029684 -0.491389
v -0.318062 -0.020828 0.485801
v -0.318062 -0.020828 -0.019381
v -0.311791 -0.020828 -0.111832
v -0.293331 -0.020828 -0.200195
v -0.263432 -0.020828 -0.281417
v -0.223370 -0.020828 -0.352299
v -0.174868 -0.020828 -0.410095
v -0.120002 -0.020828 -0.452678
v -0.061012 -0.020828 -0.478662
v -0.331177 -0.020828 0.498915
v -0.331177 -0.020828 -0.019826
v -0.324814 -0.020828 -0.113625
v -0.305971 -0.020828 -0.203821
v -0.275372 -0.020828 -0.286945
v -0.234192 -0.020828 -0.359804
v -0.184014 -0.020828 -0.419598
v -0.126767 -0.020828 -0.464029
v -0.064650 -0.020828 -0.491389
v -0.318062 -0.030185 0.485801
v -0.318062 -0.030185 -0.019381
v -0.311791 -0.030185 -0.111832
v -0.293331 -0.030185 -0.200195
v -0.263432 -0.030185 -0.281417
v -0.223370 -0.030185 -0.352299
v -0.174868 -0.030185 -0.410095
v -0.120002 -0.030185 -0.452678
v -0.061012 -0.030185 -0.478662
v -0.331177 -0.030185 0.498915
v -0.331177 -0.030185 -0.019826
v -0.324814 -0.030185 -0.113625
v -0.305971 -0.030185 -0.203821
v -0.275372 -0.030185 -0.286945
v -0.234192 -0.030185 -0.359804
v -0.184014 -0.030185 -0.419598
v -0.126767 -0.030185 -0.464029
v -0.064650 -0.030185 -0.491389
vn 0.6574 0.6894 -0.3043
vn 0.8218 -0.0000 -0.5698
vn 0.5971 0.6870 -0.4141
vn -0.5120 -0.0000 0.8590
vn -0.6935 -0.0000 0.7205
vn 0.7153 0.6919 -0.0985
vn 0.9994 -0.0000 -0.0339
vn 0.9907 -0.0000 -0.1364
vn 1.0000 -0.0000 -0.0000
vn 0.2021 0.6777 -0.7070
vn 0.1415 -0.0000 -0.9899
vn 0.1046 0.6729 -0.7323
vn 0.6935 -0.0000 -0.7205
vn 0.5059 0.6840 -0.5256
vn 0.9612 -0.0000 -0.2757
vn 0.6949 0.6910 -0.1993
vn 0.0437 0.7064 0.7064
vn 0.7142 0.6996 -0.0242
vn -0.0000 0.7071 0.7071
vn -0.0000 -0.0000 1.0000
vn 0.5120 -0.0000 -0.8590
vn 0.3751 0.6806 -0.6294
vn 0.9075 -0.0000 -0.4201
vn 0.2748 -0.0000 -0.9615
vn -0.0000 -1.0000 -0.0000
vn -0.8218 -0.0000 0.5698
vn -0.9075 -0.0000 0.4201
vn -0.1115 -0.0000 0.9938
vn -0.2603 -0.0000 0.9655
vn -0.9612 -0.0000 0.2757
vn -0.9994 -0.0000 0.0339
vn -1.0000 -0.0000 -0.0000
vn -0.9907 -0.0000 0.1364
vn -0.0000 -0.0000 -1.0000
vn -0.8218 -0.0000 -0.5698
vn -0.9075 -0.0000 -0.4201
vn 0.6935 -0.0000 0.7205
vn 0.5120 -0.0000 0.8590
vn -0.9907 -0.0000 -0.1364
vn -0.9994 -0.0000 -0.0339
vn -0.1415 -0.0000 -0.9899
vn -0.2748 -0.0000 -0.9615
vn -0.6935 -0.0000 -0.7205
vn -0.9612 -0.0000 -0.2757
vn -0.5120 -0.0000 -0.8590
vn 0.8218 -0.0000 0.5698
vn 0.9075 -0.0000 0.4201
vn 0.2603 -0.0000 0.9655
vn 0.1115 -0.0000 0.9938
vn 0.9612 -0.0000 0.2757
vn 0.9994 -0.0000 0.0339
vn 0.9907 -0.0000 0.1364
vn -0.0000 1.0000 -0.0000
vt 0.852452 0.926767
vt 0.863932 0.943326
vt 0.852452 0.943326
vt 0.416217 0.784524
vt 0.414091 0.772054
vt 0.416217 0.772054
vt 0.852452 0.887374
vt 0.863932 0.866055
vt 0.863932 0.887374
vt 0.550685 0.744478
vt 0.539205 0.630661
vt 0.539205 0.741041
vt 0.348119 0.828570
vt 0.336639 0.813877
vt 0.348119 0.813877
vt 0.863932 0.956916
vt 0.852452 0.956916
vt 0.863932 0.907874
vt 0.852452 0.907874
vt 0.852452 0.748155
vt 0.852452 0.866055
vt 0.643871 0.823767
vt 0.632391 0.748497
vt 0.643871 0.748497
vt 0.348119 0.855700
vt 0.336639 0.842689
vt 0.348119 0.842689
vt 0.863932 0.926767
vt 0.336639 0.828570
vt 0.980591 0.564665
vt 0.984787 0.584748
vt 0.913922 0.610199
vt 0.866059 0.956916
vt 0.537078 0.741041
vt 0.537078 0.744478
vt 0.630264 0.517300
vt 0.632391 0.530436
vt 0.630264 0.530436
vt 0.866059 0.943326
vt 0.632391 0.546546
vt 0.630264 0.546546
vt 0.416217 0.811798
vt 0.414091 0.797931
vt 0.416217 0.797931
vt 0.866059 0.926767
vt 0.632391 0.565007
vt 0.630264 0.565007
vt 0.334512 0.813877
vt 0.434232 0.744478
vt 0.506522 0.741497
vt 0.509502 0.744478
vt 0.505096 0.605666
vt 0.509502 0.626577
vt 0.506522 0.626678
vt 0.500901 0.585583
vt 0.508056 0.605259
vt 0.494105 0.567123
vt 0.503773 0.584759
vt 0.485000 0.551012
vt 0.496819 0.565866
vt 0.473976 0.537876
vt 0.487459 0.549307
vt 0.461506 0.528198
vt 0.476055 0.535717
vt 0.448099 0.522293
vt 0.463044 0.525618
vt 0.434232 0.517300
vt 0.434232 0.520737
vt 0.336639 0.855700
vt 0.334512 0.842689
vt 0.632391 0.823767
vt 0.630264 0.748497
vt 0.414091 0.784524
vt 0.334512 0.828570
vt 0.539205 0.520281
vt 0.539205 0.517300
vt 0.537078 0.517300
vt 0.630264 0.606102
vt 0.632391 0.720921
vt 0.630264 0.720921
vt 0.863932 0.748155
vt 0.866059 0.866055
vt 0.630264 0.585090
vt 0.632391 0.606102
vt 0.866059 0.887374
vt 0.182971 0.916633
vt 0.180845 0.844343
vt 0.182971 0.844343
vt 0.632391 0.585090
vt 0.866059 0.907874
vt 0.600561 0.530890
vt 0.589081 0.547450
vt 0.589081 0.530890
vt 0.414091 0.851542
vt 0.416217 0.839072
vt 0.416217 0.851542
vt 0.600561 0.586842
vt 0.589081 0.608161
vt 0.589081 0.586842
vt 0.348119 0.799183
vt 0.600561 0.517300
vt 0.589081 0.517300
vt 0.600561 0.566342
vt 0.589081 0.566342
vt 0.600561 0.608161
vt 0.589081 0.726061
vt 0.643871 0.899038
vt 0.336639 0.785065
vt 0.348119 0.772054
vt 0.348119 0.785065
vt 0.600561 0.547450
vt 0.336639 0.799183
vt 0.913922 0.720579
vt 0.841633 0.720579
vt 0.602688 0.517300
vt 0.893635 0.938640
vt 0.895762 0.951776
vt 0.893635 0.951776
vt 0.602688 0.530890
vt 0.895762 0.922530
vt 0.893635 0.922530
vt 0.414091 0.825665
vt 0.416217 0.825665
vt 0.602688 0.547450
vt 0.895762 0.904069
vt 0.893635 0.904069
vt 0.361942 0.741497
vt 0.434232 0.741497
vt 0.358961 0.626577
vt 0.363367 0.605666
vt 0.361942 0.626678
vt 0.360408 0.605259
vt 0.367563 0.585583
vt 0.364690 0.584759
vt 0.374359 0.567123
vt 0.371645 0.565866
vt 0.383464 0.551012
vt 0.381004 0.549307
vt 0.394488 0.537876
vt 0.392409 0.535717
vt 0.406958 0.528198
vt 0.405420 0.525618
vt 0.420365 0.522293
vt 0.419538 0.519400
vt 0.334512 0.785065
vt 0.336639 0.772054
vt 0.630264 0.899038
vt 0.632391 0.899038
vt 0.334512 0.799183
vt 0.895762 0.748155
vt 0.893635 0.862974
vt 0.893635 0.748155
vt 0.602688 0.608161
vt 0.600561 0.726061
vt 0.895762 0.862974
vt 0.893635 0.883986
vt 0.602688 0.586842
vt 0.182971 0.772054
vt 0.602688 0.566342
vt 0.550685 0.517300
vt 0.539205 0.744478
vt 0.986212 0.605761
vt 0.986212 0.720579
vt 0.913922 0.499819
vt 0.941197 0.507280
vt 0.927789 0.501375
vt 0.953667 0.516959
vt 0.964690 0.530095
vt 0.973795 0.546205
vt 0.632391 0.517300
vt 0.414091 0.811798
vt 0.448925 0.519400
vt 0.334512 0.855700
vt 0.630264 0.823767
vt 0.537078 0.520281
vt 0.866059 0.748155
vt 0.180845 0.916633
vt 0.414091 0.839072
vt 0.841633 0.605761
vt 0.843058 0.584748
vt 0.847254 0.564665
vt 0.854049 0.546205
vt 0.863155 0.530095
vt 0.874178 0.516959
vt 0.886648 0.507280
vt 0.900055 0.501375
vt 0.895762 0.938640
vt 0.358961 0.744478
vt 0.334512 0.772054
vt 0.602688 0.726061
vt 0.895762 0.883986
vt 0.180845 0.772054
vt 0.591727 0.581771
vt 0.592669 0.565234
vt 0.601155 0.522724
vt 0.866647 0.820446
vt 0.866647 0.893741
vt 0.855496 0.893741
vt 0.593938 0.550739
vt 0.595485 0.538844
vt 0.597249 0.530005
vt 0.599163 0.524562
vt 0.601155 0.721574
vt 0.590950 0.618375
vt 0.591146 0.599714
vt 0.590950 0.721574
vt 0.855496 0.752511
vt 0.857673 0.753816
vt 0.859764 0.757682
vt 0.864768 0.782703
vt 0.863381 0.772408
vt 0.861692 0.763960
vt 0.865798 0.794448
vt 0.866433 0.807192
s 1
f 5/1/1 28/2/2 6/3/3
f 19/4/4 41/5/5 18/6/5
f 3/7/6 24/8/7 25/9/8
f 10/10/9 34/11/9 32/12/9
f 9/13/10 23/14/11 10/15/12
f 6/3/3 29/16/13 7/17/14
f 3/7/6 26/18/15 4/19/16
f 1/20/17 24/8/7 2/21/18
f 11/22/19 22/23/20 1/24/17
f 7/25/14 30/26/21 8/27/22
f 4/19/16 27/28/23 5/1/1
f 8/27/22 31/29/24 9/13/10
f 15/30/25 14/31/25 34/32/25
f 28/2/2 52/33/13 29/16/13
f 32/12/9 55/34/9 46/35/9
f 18/36/5 40/37/26 17/38/26
f 27/28/23 51/39/2 28/2/2
f 17/38/26 39/40/27 16/41/27
f 32/42/28 43/43/29 20/44/29
f 26/18/15 50/45/23 27/28/23
f 16/41/27 38/46/30 15/47/30
f 31/29/24 46/48/11 23/14/11
f 44/49/25 35/50/25 45/51/25
f 37/52/25 47/53/25 36/54/25
f 38/55/25 48/56/25 37/52/25
f 39/57/25 49/58/25 38/55/25
f 40/59/25 50/60/25 39/57/25
f 41/61/25 51/62/25 40/59/25
f 42/63/25 52/64/25 41/61/25
f 43/65/25 53/66/25 42/63/25
f 35/50/25 47/53/25 45/51/25
f 46/67/25 43/65/25 55/68/25
f 29/69/13 53/70/21 30/26/21
f 21/71/20 45/72/20 22/23/20
f 19/4/4 43/43/29 42/73/4
f 30/26/21 54/74/24 31/29/24
f 33/75/9 21/76/9 44/77/9
f 13/78/31 35/79/32 12/80/32
f 22/81/9 47/82/7 24/8/7
f 14/83/33 36/84/31 13/78/31
f 24/8/7 48/85/8 25/9/8
f 12/86/34 56/87/34 33/88/34
f 15/47/30 37/89/33 14/83/33
f 25/9/8 49/90/15 26/18/15
f 80/91/35 61/92/36 62/93/35
f 90/94/37 73/95/38 72/96/37
f 77/97/39 58/98/40 59/99/39
f 23/14/41 65/100/42 10/15/41
f 81/101/43 62/93/35 63/102/43
f 78/103/44 59/99/39 60/104/44
f 76/105/40 57/106/32 58/98/40
f 57/107/20 21/71/20 11/22/20
f 82/108/45 63/109/43 64/110/45
f 79/111/36 60/104/44 61/92/36
f 83/112/42 64/110/45 65/100/42
f 34/32/25 33/113/25 66/114/25
f 99/115/43 80/91/35 81/101/43
f 71/116/46 90/117/37 72/118/37
f 98/119/35 79/111/36 80/91/35
f 88/120/47 71/116/46 70/121/47
f 92/122/48 32/42/49 74/123/48
f 97/124/36 78/103/44 79/111/36
f 87/125/50 70/121/47 69/126/50
f 46/48/41 83/112/42 23/14/41
f 44/49/25 84/127/25 56/128/25
f 94/129/25 86/130/25 85/131/25
f 95/132/25 87/133/25 86/130/25
f 96/134/25 88/135/25 87/133/25
f 97/136/25 89/137/25 88/135/25
f 98/138/25 90/139/25 89/137/25
f 99/140/25 91/141/25 90/139/25
f 100/142/25 92/143/25 91/141/25
f 84/127/25 94/129/25 85/131/25
f 46/67/25 92/143/25 101/144/25
f 100/145/45 81/146/43 82/108/45
f 93/147/20 21/71/20 75/148/20
f 73/95/38 92/122/48 74/123/48
f 101/149/42 82/108/45 83/112/42
f 84/150/9 67/151/51 66/152/9
f 94/153/40 75/154/32 76/105/40
f 85/155/51 68/156/52 67/151/51
f 95/157/39 76/105/40 77/97/39
f 56/87/34 66/158/34 33/88/34
f 68/156/52 87/125/50 69/126/50
f 96/159/44 77/97/39 78/103/44
f 5/1/1 27/28/23 28/2/2
f 19/4/4 42/73/4 41/5/5
f 3/7/6 2/21/18 24/8/7
f 21/76/9 33/75/9 11/160/9
f 11/160/9 34/11/9 10/10/9
f 10/10/9 32/12/9 23/161/9
f 34/11/9 11/160/9 33/75/9
f 9/13/10 31/29/24 23/14/11
f 6/3/3 28/2/2 29/16/13
f 3/7/6 25/9/8 26/18/15
f 1/20/9 22/81/9 24/8/7
f 11/22/19 21/71/20 22/23/20
f 7/25/14 29/69/13 30/26/21
f 4/19/16 26/18/15 27/28/23
f 8/27/22 30/26/21 31/29/24
f 14/31/25 13/162/25 34/32/25
f 13/162/25 12/163/25 34/32/25
f 12/163/25 33/113/25 34/32/25
f 34/32/25 32/164/25 19/165/25
f 32/164/25 20/166/25 19/165/25
f 34/32/25 19/165/25 18/167/25
f 18/167/25 17/168/25 34/32/25
f 17/168/25 16/169/25 34/32/25
f 16/169/25 15/30/25 34/32/25
f 28/2/2 51/39/2 52/33/13
f 32/12/9 46/35/9 23/161/9
f 18/36/5 41/170/5 40/37/26
f 27/28/23 50/45/23 51/39/2
f 17/38/26 40/37/26 39/40/27
f 32/42/28 55/171/28 43/43/29
f 26/18/15 49/90/15 50/45/23
f 16/41/27 39/40/27 38/46/30
f 31/29/24 54/74/24 46/48/11
f 44/49/25 56/128/25 35/50/25
f 37/52/25 48/56/25 47/53/25
f 38/55/25 49/58/25 48/56/25
f 39/57/25 50/60/25 49/58/25
f 40/59/25 51/62/25 50/60/25
f 41/61/25 52/64/25 51/62/25
f 42/63/25 53/66/25 52/64/25
f 43/65/25 54/172/25 53/66/25
f 35/50/25 36/54/25 47/53/25
f 46/67/25 54/172/25 43/65/25
f 29/69/13 52/173/13 53/70/21
f 21/71/20 44/174/20 45/72/20
f 19/4/4 20/44/29 43/43/29
f 30/26/21 53/70/21 54/74/24
f 33/75/9 44/77/9 56/175/9
f 13/78/31 36/84/31 35/79/32
f 22/81/9 45/176/9 47/82/7
f 14/83/33 37/89/33 36/84/31
f 24/8/7 47/82/7 48/85/8
f 12/86/34 35/177/34 56/87/34
f 15/47/30 38/46/30 37/89/33
f 25/9/8 48/85/8 49/90/15
f 80/91/35 79/111/36 61/92/36
f 90/94/37 91/178/38 73/95/38
f 77/97/39 76/105/40 58/98/40
f 23/14/41 83/112/42 65/100/42
f 81/101/43 80/91/35 62/93/35
f 78/103/44 77/97/39 59/99/39
f 76/105/40 75/154/32 57/106/32
f 57/107/20 75/148/20 21/71/20
f 82/108/45 81/146/43 63/109/43
f 79/111/36 78/103/44 60/104/44
f 83/112/42 82/108/45 64/110/45
f 66/114/25 67/179/25 34/32/25
f 67/179/25 68/180/25 34/32/25
f 68/180/25 69/181/25 34/32/25
f 69/181/25 70/182/25 34/32/25
f 70/182/25 71/183/25 34/32/25
f 71/183/25 72/184/25 34/32/25
f 72/184/25 73/185/25 34/32/25
f 73/185/25 74/186/25 32/164/25
f 32/164/25 34/32/25 73/185/25
f 99/115/43 98/119/35 80/91/35
f 71/116/46 89/187/46 90/117/37
f 98/119/35 97/124/36 79/111/36
f 88/120/47 89/187/46 71/116/46
f 92/122/48 55/171/49 32/42/49
f 97/124/36 96/159/44 78/103/44
f 87/125/50 88/120/47 70/121/47
f 46/48/41 101/149/42 83/112/42
f 44/49/25 93/188/25 84/127/25
f 94/129/25 95/132/25 86/130/25
f 95/132/25 96/134/25 87/133/25
f 96/134/25 97/136/25 88/135/25
f 97/136/25 98/138/25 89/137/25
f 98/138/25 99/140/25 90/139/25
f 99/140/25 100/142/25 91/141/25
f 100/142/25 101/144/25 92/143/25
f 84/127/25 93/188/25 94/129/25
f 46/67/25 55/68/25 92/143/25
f 100/145/45 99/189/43 81/146/43
f 93/147/20 44/174/20 21/71/20
f 73/95/38 91/178/38 92/122/48
f 101/149/42 100/145/45 82/108/45
f 84/150/9 85/155/51 67/151/51
f 94/153/40 93/190/32 75/154/32
f 85/155/51 86/191/52 68/156/52
f 95/157/39 94/153/40 76/105/40
f 56/87/34 84/192/34 66/158/34
f 68/156/52 86/191/52 87/125/50
f 96/159/44 95/157/39 77/97/39
f 4/193/16 5/194/1 10/195/12
s 0
f 58/196/53 57/197/53 11/198/53
s 1
f 5/194/1 6/199/3 10/195/12
f 6/199/3 7/200/14 10/195/12
f 7/200/14 8/201/22 10/195/12
f 8/201/22 9/202/10 10/195/12
f 10/195/12 11/203/19 2/204/18
f 4/193/16 10/195/12 3/205/6
f 11/203/19 1/206/17 2/204/18
f 2/204/18 3/205/6 10/195/12
s 0
f 11/198/53 10/207/53 58/196/53
f 10/207/53 65/208/53 64/209/53
f 61/210/53 10/207/53 62/211/53
f 64/209/53 63/212/53 10/207/53
f 63/212/53 62/211/53 10/207/53
f 61/210/53 60/213/53 10/207/53
f 60/213/53 59/214/53 10/207/53
f 59/214/53 58/196/53 10/207/53

View File

@@ -1,275 +0,0 @@
# Blender 3.6.5
# www.blender.org
o turbo.001
v 0.479911 0.031444 0.058178
v 0.008582 0.031444 0.530813
v 0.469532 0.031444 0.039992
v 0.309421 0.031444 0.039992
v 0.001804 0.031444 0.348364
v -0.304681 0.031444 0.041125
v -0.474757 0.031444 0.041125
v -0.474757 0.031444 0.059620
v -0.006999 0.031444 0.530813
v 0.479911 0.031444 -0.248942
v 0.008582 0.031444 0.223694
v 0.469532 0.031444 -0.267127
v 0.309421 0.031444 -0.267127
v 0.001804 0.031444 0.041245
v -0.304681 0.031444 -0.265994
v -0.474757 0.031444 -0.265994
v -0.474757 0.031444 -0.247499
v -0.006999 0.031444 0.223694
v 0.479911 0.031444 -0.561796
v 0.008582 0.031444 -0.092817
v 0.469532 0.031444 -0.579981
v 0.309421 0.031444 -0.579981
v 0.001804 0.031444 -0.275266
v -0.304681 0.031444 -0.578848
v -0.474757 0.031444 -0.578848
v -0.474757 0.031444 -0.560354
v -0.006999 0.031444 -0.092817
v 0.479911 -0.029054 0.058178
v 0.008582 -0.029055 0.530813
v 0.469532 -0.029054 0.039992
v 0.309421 -0.029054 0.039992
v 0.001804 -0.029055 0.348364
v -0.304681 -0.029054 0.041125
v -0.474757 -0.029055 0.041125
v -0.474757 -0.029055 0.059620
v -0.006999 -0.029055 0.530813
v 0.479911 -0.029054 -0.248942
v 0.008582 -0.029055 0.223694
v 0.469532 -0.029054 -0.267127
v 0.309421 -0.029054 -0.267127
v 0.001804 -0.029055 0.041245
v -0.304681 -0.029054 -0.265994
v -0.474757 -0.029055 -0.265994
v -0.474757 -0.029055 -0.247499
v -0.006999 -0.029055 0.223694
v 0.479911 -0.029054 -0.561796
v 0.008582 -0.029055 -0.092817
v 0.469532 -0.029054 -0.579981
v 0.309421 -0.029054 -0.579981
v 0.001804 -0.029055 -0.275266
v -0.304681 -0.029054 -0.578848
v -0.474757 -0.029055 -0.578848
v -0.474757 -0.029055 -0.560354
v -0.006999 -0.029055 -0.092817
vn 0.8685 -0.0000 -0.4957
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -0.0000 -1.0000
vn -0.7080 -0.0000 -0.7062
vn -0.7097 -0.0000 0.7045
vn 0.7081 -0.0000 0.7061
vn -0.7069 -0.0000 0.7073
vn 0.7080 -0.0000 -0.7062
vn -0.7037 -0.0000 -0.7104
vn 0.7053 -0.0000 0.7089
vn 0.7037 -0.0000 -0.7105
vn -0.0000 -1.0000 -0.0000
vt 0.588715 0.839843
vt 0.583870 0.825758
vt 0.588715 0.825758
vt 0.452602 0.883467
vt 0.448296 0.897552
vt 0.448296 0.883467
vt 0.203212 0.786027
vt 0.189127 0.782563
vt 0.203212 0.782563
vt 0.077824 0.851102
vt 0.063739 0.811505
vt 0.077824 0.811505
vt 0.419186 0.782563
vt 0.405101 0.854358
vt 0.405101 0.782563
vt 0.246407 0.922613
vt 0.232322 0.786027
vt 0.246407 0.786027
vt 0.588715 0.883038
vt 0.583869 0.868953
vt 0.588715 0.868953
vt 0.409407 0.883467
vt 0.405101 0.897552
vt 0.405101 0.883467
vt 0.619270 0.531191
vt 0.633355 0.686593
vt 0.619270 0.686593
vt 0.232322 0.782563
vt 0.246407 0.782563
vt 0.462381 0.782563
vt 0.448296 0.854357
vt 0.448296 0.782563
vt 0.881817 0.837845
vt 0.867732 0.701259
vt 0.881817 0.701259
vt 0.881817 0.866955
vt 0.867732 0.904232
vt 0.867732 0.866955
vt 0.588715 0.796648
vt 0.583869 0.782563
vt 0.588715 0.782563
vt 0.619270 0.715702
vt 0.633355 0.871104
vt 0.619270 0.871104
vt 0.867732 0.697796
vt 0.881817 0.697796
vt 0.318711 0.782563
vt 0.332797 0.876581
vt 0.318711 0.876581
vt 0.505575 0.782563
vt 0.491490 0.854357
vt 0.491490 0.782563
vt 0.548770 0.876182
vt 0.534685 0.913458
vt 0.534685 0.876182
vt 0.121019 0.851102
vt 0.106934 0.811505
vt 0.121019 0.811505
vt 0.867732 0.513285
vt 0.881817 0.668686
vt 0.867732 0.668686
vt 0.361906 0.782563
vt 0.375991 0.876581
vt 0.361906 0.876581
vt 0.106934 0.880211
vt 0.111240 0.894296
vt 0.106934 0.894296
vt 0.077824 0.917488
vt 0.063739 0.880211
vt 0.077824 0.880211
vt 0.028640 0.858942
vt 0.014555 0.819345
vt 0.028640 0.819345
vt 0.203212 0.922613
vt 0.189127 0.786027
vt 0.275517 0.782563
vt 0.289602 0.876581
vt 0.275517 0.876581
vt 0.231604 0.642143
vt 0.303398 0.713761
vt 0.299165 0.753454
vt 0.374985 0.642143
vt 0.446779 0.713761
vt 0.442546 0.753454
vt 0.518366 0.642143
vt 0.590160 0.713761
vt 0.585927 0.753454
vt 0.583870 0.839843
vt 0.452602 0.897552
vt 0.063739 0.851102
vt 0.419186 0.854358
vt 0.232322 0.922613
vt 0.583869 0.883038
vt 0.409407 0.897552
vt 0.633355 0.531191
vt 0.462381 0.854357
vt 0.867732 0.837845
vt 0.881817 0.904232
vt 0.583869 0.796649
vt 0.633355 0.715702
vt 0.332797 0.782563
vt 0.505575 0.854357
vt 0.548770 0.913458
vt 0.106934 0.851102
vt 0.881817 0.513285
vt 0.375991 0.782563
vt 0.111240 0.880211
vt 0.063739 0.917488
vt 0.014555 0.858942
vt 0.189127 0.922613
vt 0.289602 0.782563
vt 0.303399 0.751038
vt 0.189127 0.643721
vt 0.189127 0.640093
vt 0.298829 0.531191
vt 0.303135 0.531191
vt 0.303135 0.570788
vt 0.446779 0.751038
vt 0.332508 0.643721
vt 0.332508 0.640093
vt 0.442210 0.531191
vt 0.446516 0.531191
vt 0.446516 0.570788
vt 0.590160 0.751038
vt 0.475889 0.643721
vt 0.475889 0.640093
vt 0.585591 0.531191
vt 0.589897 0.531191
vt 0.589897 0.570788
s 0
f 3/1/1 28/2/1 30/3/1
f 16/4/2 44/5/2 17/6/2
f 9/7/3 29/8/3 2/9/3
f 24/10/4 52/11/4 25/12/4
f 5/13/5 31/14/5 32/15/5
f 17/16/6 45/17/6 18/18/6
f 12/19/1 37/20/1 39/21/1
f 25/22/2 53/23/2 26/24/2
f 2/25/7 28/26/7 1/27/7
f 18/18/3 38/28/3 11/29/3
f 14/30/5 40/31/5 41/32/5
f 26/33/8 54/34/8 27/35/8
f 4/36/4 30/37/4 31/38/4
f 21/39/1 46/40/1 48/41/1
f 11/42/7 37/43/7 10/44/7
f 27/35/3 47/45/3 20/46/3
f 5/47/9 33/48/9 6/49/9
f 23/50/10 49/51/10 50/52/10
f 13/53/4 39/54/4 40/55/4
f 6/56/4 34/57/4 7/58/4
f 20/59/11 46/60/11 19/61/11
f 14/62/9 42/63/9 15/64/9
f 8/65/2 34/66/2 35/67/2
f 21/68/4 49/69/4 22/70/4
f 15/71/4 43/72/4 16/73/4
f 8/74/6 36/75/6 9/7/6
f 23/76/12 51/77/12 24/78/12
f 32/79/13 31/80/13 28/81/13
f 41/82/13 40/83/13 37/84/13
f 50/85/13 49/86/13 46/87/13
f 3/1/1 1/88/1 28/2/1
f 16/4/2 43/89/2 44/5/2
f 9/7/3 36/75/3 29/8/3
f 24/10/4 51/90/4 52/11/4
f 5/13/5 4/91/5 31/14/5
f 17/16/6 44/92/6 45/17/6
f 12/19/1 10/93/1 37/20/1
f 25/22/2 52/94/2 53/23/2
f 2/25/7 29/95/7 28/26/7
f 18/18/3 45/17/3 38/28/3
f 14/30/5 13/96/5 40/31/5
f 26/33/8 53/97/8 54/34/8
f 4/36/4 3/98/4 30/37/4
f 21/39/1 19/99/1 46/40/1
f 11/42/7 38/100/7 37/43/7
f 27/35/3 54/34/3 47/45/3
f 5/47/9 32/101/9 33/48/9
f 23/50/10 22/102/10 49/51/10
f 13/53/4 12/103/4 39/54/4
f 6/56/4 33/104/4 34/57/4
f 20/59/11 47/105/11 46/60/11
f 14/62/9 41/106/9 42/63/9
f 8/65/2 7/107/2 34/66/2
f 21/68/4 48/108/4 49/69/4
f 15/71/4 42/109/4 43/72/4
f 8/74/6 35/110/6 36/75/6
f 23/76/12 50/111/12 51/77/12
f 31/80/13 30/112/13 28/81/13
f 28/81/13 29/113/13 32/79/13
f 29/113/13 36/114/13 32/79/13
f 36/114/13 35/115/13 32/79/13
f 35/115/13 34/116/13 33/117/13
f 32/79/13 35/115/13 33/117/13
f 40/83/13 39/118/13 37/84/13
f 37/84/13 38/119/13 41/82/13
f 38/119/13 45/120/13 41/82/13
f 45/120/13 44/121/13 41/82/13
f 44/121/13 43/122/13 42/123/13
f 41/82/13 44/121/13 42/123/13
f 49/86/13 48/124/13 46/87/13
f 46/87/13 47/125/13 50/85/13
f 47/125/13 54/126/13 50/85/13
f 54/126/13 53/127/13 50/85/13
f 53/127/13 52/128/13 51/129/13
f 50/85/13 53/127/13 51/129/13

Some files were not shown because too many files have changed in this diff Show More