mirror of
https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
synced 2024-11-24 23:59:44 +01:00
Figure Syncronizer now added
This commit is contained in:
parent
8e3cb43244
commit
0e580a3180
@ -17,7 +17,7 @@ import pp.view.ModelViewSynchronizer;
|
|||||||
* are accurately reflected in the view.
|
* are accurately reflected in the view.
|
||||||
*/
|
*/
|
||||||
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
|
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
|
||||||
private final Board board;
|
protected final Board board;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new BoardSynchronizer.
|
* Constructs a new BoardSynchronizer.
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
////////////////////////////////////////
|
||||||
|
// Programming project code
|
||||||
|
// UniBw M, 2022, 2023, 2024
|
||||||
|
// www.unibw.de/inf2
|
||||||
|
// (c) Mark Minas (mark.minas@unibw.de)
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
package pp.monopoly.client.gui;
|
||||||
|
|
||||||
|
import com.jme3.effect.ParticleEmitter;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.RenderState.BlendMode;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.shape.Box;
|
||||||
|
import com.jme3.scene.shape.Cylinder;
|
||||||
|
|
||||||
|
import groovyjarjarantlr4.v4.parse.ANTLRParser.finallyClause_return;
|
||||||
|
import pp.monopoly.client.MonopolyApp;
|
||||||
|
import pp.monopoly.game.server.PlayerColor;
|
||||||
|
import pp.monopoly.model.Board;
|
||||||
|
import pp.monopoly.model.Figure;
|
||||||
|
import pp.monopoly.model.Item;
|
||||||
|
import pp.monopoly.model.Rotation;
|
||||||
|
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static pp.util.FloatMath.HALF_PI;
|
||||||
|
import static pp.util.FloatMath.PI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical
|
||||||
|
* representation of the ships and shots on the sea map with the underlying data model.
|
||||||
|
* It extends the {@link BoardSynchronizer} to provide specific synchronization
|
||||||
|
* logic for the sea map.
|
||||||
|
*/
|
||||||
|
class GameBoardSynchronizer extends BoardSynchronizer {
|
||||||
|
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
|
||||||
|
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
|
||||||
|
private static final String COLOR = "Color"; //NON-NLS
|
||||||
|
private static final String FIGURE = "figure"; //NON-NLS
|
||||||
|
|
||||||
|
private final MonopolyApp app;
|
||||||
|
private final ParticleEffectFactory particleFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map.
|
||||||
|
*
|
||||||
|
* @param app the Battleship application
|
||||||
|
* @param root the root node to which graphical elements will be attached
|
||||||
|
* @param map the ship map containing the ships and shots
|
||||||
|
*/
|
||||||
|
public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) {
|
||||||
|
super(board, root);
|
||||||
|
this.app = app;
|
||||||
|
this.particleFactory = new ParticleEffectFactory(app);
|
||||||
|
addExisting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a {@link Battleship} and creates a graphical representation of it.
|
||||||
|
* The representation is either a 3D model or a simple box depending on the
|
||||||
|
* type of battleship.
|
||||||
|
*
|
||||||
|
* @param ship the battleship to be represented
|
||||||
|
* @return the node containing the graphical representation of the battleship
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Spatial visit(Figure figure) {
|
||||||
|
final Node node = new Node(FIGURE);
|
||||||
|
node.attachChild(createBox(figure));
|
||||||
|
// compute the center of the ship in world coordinates
|
||||||
|
final float x = 1;
|
||||||
|
final float z = 1;
|
||||||
|
node.setLocalTranslation(x, 0f, z);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a simple box to represent a battleship that is not of the "King George V" type.
|
||||||
|
*
|
||||||
|
* @param ship the battleship to be represented
|
||||||
|
* @return the geometry representing the battleship as a box
|
||||||
|
*/
|
||||||
|
private Spatial createBox(Figure figure) {
|
||||||
|
final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f,
|
||||||
|
0.3f,
|
||||||
|
0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f);
|
||||||
|
final Geometry geometry = new Geometry(FIGURE, box);
|
||||||
|
geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor()));
|
||||||
|
geometry.setShadowMode(ShadowMode.CastAndReceive);
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Material} with the specified color.
|
||||||
|
* If the color includes transparency (i.e., alpha value less than 1),
|
||||||
|
* the material's render state is set to use alpha blending, allowing for
|
||||||
|
* semi-transparent rendering.
|
||||||
|
*
|
||||||
|
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
|
||||||
|
* of the color is less than 1, the material will support transparency.
|
||||||
|
* @return a {@link Material} instance configured with the specified color and,
|
||||||
|
* if necessary, alpha blending enabled.
|
||||||
|
*/
|
||||||
|
private Material createColoredMaterial(ColorRGBA color) {
|
||||||
|
final Material material = new Material(app.getAssetManager(), UNSHADED);
|
||||||
|
if (color.getAlpha() < 1f)
|
||||||
|
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||||
|
material.setColor(COLOR, color);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rotation angle for the specified rotation.
|
||||||
|
*
|
||||||
|
* @param rot the rotation of the battleship
|
||||||
|
* @return the rotation angle in radians
|
||||||
|
*/
|
||||||
|
private static float calculateRotationAngle(Rotation rot) {
|
||||||
|
return switch (rot) {
|
||||||
|
case RIGHT -> HALF_PI;
|
||||||
|
case DOWN -> 0f;
|
||||||
|
case LEFT -> -HALF_PI;
|
||||||
|
case UP -> PI;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package pp.monopoly.client.gui;
|
||||||
|
|
||||||
|
import com.jme3.effect.ParticleEmitter;
|
||||||
|
import com.jme3.effect.ParticleMesh.Type;
|
||||||
|
import com.jme3.effect.shapes.EmitterSphereShape;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import pp.monopoly.client.MonopolyApp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class responsible for creating particle effects used in the game.
|
||||||
|
* This centralizes the creation of various types of particle emitters.
|
||||||
|
*/
|
||||||
|
public class ParticleEffectFactory {
|
||||||
|
private static final int COUNT_FACTOR = 1;
|
||||||
|
private static final float COUNT_FACTOR_F = 1f;
|
||||||
|
private static final boolean POINT_SPRITE = true;
|
||||||
|
private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
|
||||||
|
|
||||||
|
private final MonopolyApp app;
|
||||||
|
|
||||||
|
ParticleEffectFactory(MonopolyApp app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,309 @@
|
|||||||
package pp.monopoly.model;
|
package pp.monopoly.model;
|
||||||
|
|
||||||
public class Figure implements Item{
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Override
|
import static java.lang.Math.max;
|
||||||
public <T> T accept(Visitor<T> visitor) {
|
import static java.lang.Math.min;
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'accept'");
|
public class Figure implements Item{
|
||||||
|
/**
|
||||||
|
* Enumeration representing the different statuses a Figure can have during the game.
|
||||||
|
*/
|
||||||
|
public enum Status {
|
||||||
|
/**
|
||||||
|
* The ship is in its normal state, not being previewed for placement.
|
||||||
|
*/
|
||||||
|
NORMAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ship is being previewed in a valid position for placement.
|
||||||
|
*/
|
||||||
|
VALID_PREVIEW,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ship is being previewed in an invalid position for placement.
|
||||||
|
*/
|
||||||
|
INVALID_PREVIEW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final int length; // The length of the Figure
|
||||||
|
private int x; // The x-coordinate of the Figure's position
|
||||||
|
private int y; // The y-coordinate of the Figure's position
|
||||||
|
private Rotation rot; // The rotation of the Figure
|
||||||
|
private Status status; // The current status of the Figure
|
||||||
|
private final Set<IntPoint> damaged = new HashSet<>(); // The set of positions that have been hit on this ship
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor for serialization. Initializes a Figure with length 0,
|
||||||
|
* at position (0, 0), with a default rotation of RIGHT.
|
||||||
|
*/
|
||||||
|
private Figure() {
|
||||||
|
this(0, 0, 0, Rotation.RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Figure with the specified length, position, and rotation.
|
||||||
|
*
|
||||||
|
* @param length the length of the Figure
|
||||||
|
* @param x the x-coordinate of the Figure's initial position
|
||||||
|
* @param y the y-coordinate of the Figure's initial position
|
||||||
|
* @param rot the rotation of the Figure
|
||||||
|
*/
|
||||||
|
public Figure(int length, int x, int y, Rotation rot) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.rot = rot;
|
||||||
|
this.length = length;
|
||||||
|
this.status = Status.NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current x-coordinate of the Figure's position.
|
||||||
|
*
|
||||||
|
* @return the x-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current y-coordinate of the Figure's position.
|
||||||
|
*
|
||||||
|
* @return the y-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the Figure to the specified coordinates.
|
||||||
|
*
|
||||||
|
* @param x the new x-coordinate of the Figure's position
|
||||||
|
* @param y the new y-coordinate of the Figure's position
|
||||||
|
*/
|
||||||
|
public void moveTo(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the Figure to the specified position.
|
||||||
|
*
|
||||||
|
* @param pos the new position of the Figure
|
||||||
|
*/
|
||||||
|
public void moveTo(IntPosition pos) {
|
||||||
|
moveTo(pos.getX(), pos.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current status of the Figure.
|
||||||
|
*
|
||||||
|
* @return the status of the Figure
|
||||||
|
*/
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of the Figure.
|
||||||
|
*
|
||||||
|
* @param status the new status to be set for the Figure
|
||||||
|
*/
|
||||||
|
public void setStatus(Status status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the Figure.
|
||||||
|
*
|
||||||
|
* @return the length of the Figure
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum x-coordinate that the Figure occupies based on its current position and rotation.
|
||||||
|
*
|
||||||
|
* @return the minimum x-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getMinX() {
|
||||||
|
return x + min(0, (length - 1) * rot.dx());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum x-coordinate that the Figure occupies based on its current position and rotation.
|
||||||
|
*
|
||||||
|
* @return the maximum x-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getMaxX() {
|
||||||
|
return x + max(0, (length - 1) * rot.dx());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum y-coordinate that the Figure occupies based on its current position and rotation.
|
||||||
|
*
|
||||||
|
* @return the minimum y-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getMinY() {
|
||||||
|
return y + min(0, (length - 1) * rot.dy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum y-coordinate that the Figure occupies based on its current position and rotation.
|
||||||
|
*
|
||||||
|
* @return the maximum y-coordinate of the Figure
|
||||||
|
*/
|
||||||
|
public int getMaxY() {
|
||||||
|
return y + max(0, (length - 1) * rot.dy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current rotation of the Figure.
|
||||||
|
*
|
||||||
|
* @return the rotation of the Figure
|
||||||
|
*/
|
||||||
|
public Rotation getRot() {
|
||||||
|
return rot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rotation of the Figure.
|
||||||
|
*
|
||||||
|
* @param rot the new rotation to be set for the Figure
|
||||||
|
*/
|
||||||
|
public void setRotation(Rotation rot) {
|
||||||
|
this.rot = rot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates the Figure by 90 degrees clockwise.
|
||||||
|
*/
|
||||||
|
public void rotated() {
|
||||||
|
setRotation(rot.rotate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to hit the Figure at the specified position.
|
||||||
|
* If the position is part of the Figure, the hit is recorded.
|
||||||
|
*
|
||||||
|
* @param x the x-coordinate of the position to hit
|
||||||
|
* @param y the y-coordinate of the position to hit
|
||||||
|
* @return true if the position is part of the Figure, false otherwise
|
||||||
|
* @see #contains(int, int)
|
||||||
|
*/
|
||||||
|
public boolean hit(int x, int y) {
|
||||||
|
if (!contains(x, y))
|
||||||
|
return false;
|
||||||
|
damaged.add(new IntPoint(x, y));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to hit the Figure at the specified position.
|
||||||
|
* If the position is part of the Figure, the hit is recorded.
|
||||||
|
* This is a convenience method for {@linkplain #hit(int, int)}.
|
||||||
|
*
|
||||||
|
* @param position the position to hit
|
||||||
|
* @return true if the position is part of the Figure, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hit(IntPosition position) {
|
||||||
|
return hit(position.getX(), position.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the positions of this Figure that have been hit.
|
||||||
|
*
|
||||||
|
* @return a set of positions that have been hit
|
||||||
|
* @see #hit(int, int)
|
||||||
|
*/
|
||||||
|
public Set<IntPoint> getDamaged() {
|
||||||
|
return Collections.unmodifiableSet(damaged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the specified position is covered by the Figure. This method does
|
||||||
|
* not record a hit, only checks coverage.
|
||||||
|
* This is a convenience method for {@linkplain #contains(int, int)}.
|
||||||
|
*
|
||||||
|
* @param pos the position to check
|
||||||
|
* @return true if the position is covered by the Figure, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean contains(IntPosition pos) {
|
||||||
|
return contains(pos.getX(), pos.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the specified position is covered by the Figure. This method does
|
||||||
|
* not record a hit, only checks coverage.
|
||||||
|
*
|
||||||
|
* @param x the x-coordinate of the position to check
|
||||||
|
* @param y the y-coordinate of the position to check
|
||||||
|
* @return true if the position is covered by the Figure, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean contains(int x, int y) {
|
||||||
|
return getMinX() <= x && x <= getMaxX() &&
|
||||||
|
getMinY() <= y && y <= getMaxY();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the Figure has been completely destroyed. A Figure is considered
|
||||||
|
* destroyed if all of its positions have been hit.
|
||||||
|
*
|
||||||
|
* @return true if the Figure is destroyed, false otherwise
|
||||||
|
* @see #hit(int, int)
|
||||||
|
*/
|
||||||
|
public boolean isDestroyed() {
|
||||||
|
return damaged.size() == length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this Figure collides with another Figure. Two Figures collide
|
||||||
|
* if any of their occupied positions overlap.
|
||||||
|
*
|
||||||
|
* @param other the other Figure to check collision with
|
||||||
|
* @return true if the Figures collide, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean collidesWith(Figure other) {
|
||||||
|
return other.getMaxX() >= getMinX() && getMaxX() >= other.getMinX() &&
|
||||||
|
other.getMaxY() >= getMinY() && getMaxY() >= other.getMinY();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the Figure, including its length, position,
|
||||||
|
* and rotation.
|
||||||
|
*
|
||||||
|
* @return a string representation of the Figure
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Ship{length=" + length + ", x=" + x + ", y=" + y + ", rot=" + rot + '}'; //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a visitor that returns a value of type {@code T}. This method is part of the
|
||||||
|
* Visitor design pattern.
|
||||||
|
*
|
||||||
|
* @param visitor the visitor to accept
|
||||||
|
* @param <T> the type of the value returned by the visitor
|
||||||
|
* @return the value returned by the visitor
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T accept(Visitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a visitor that does not return a value. This method is part of the
|
||||||
|
* Visitor design pattern.
|
||||||
|
*
|
||||||
|
* @param visitor the visitor to accept
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void accept(VoidVisitor visitor) {
|
public void accept(VoidVisitor visitor) {
|
||||||
// TODO Auto-generated method stub
|
visitor.visit(this);
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'accept'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,12 @@ package pp.monopoly.model;
|
|||||||
*/
|
*/
|
||||||
public interface Visitor<T> {
|
public interface Visitor<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a Figure element.
|
||||||
|
*
|
||||||
|
* @param figure the figure element to visit
|
||||||
|
* @return the result of visiting the figure element
|
||||||
|
*/
|
||||||
|
T visit(Figure figure);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,11 @@ package pp.monopoly.model;
|
|||||||
* without returning any result.
|
* without returning any result.
|
||||||
*/
|
*/
|
||||||
public interface VoidVisitor {
|
public interface VoidVisitor {
|
||||||
|
/**
|
||||||
|
* Visits a Figure element.
|
||||||
|
*
|
||||||
|
* @param figure the Figure element to visit
|
||||||
|
*/
|
||||||
|
void visit(Figure figure);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user