15 Commits

Author SHA1 Message Date
Tamino Mueller
e0bea47583 task 13 2024-10-14 08:39:59 +02:00
Tamino Mueller
38979bdf86 effect when opponent miss the ship 2024-10-14 08:15:02 +02:00
Tamino Mueller
68beedcf29 effect when opponent miss the ship 2024-10-14 08:12:56 +02:00
Tamino Mueller
7d70e8bd13 effect when opponent miss the ship 2024-10-14 08:12:37 +02:00
Tamino Mueller
0fd0555dea add effects when ships are hit 2024-10-14 08:07:57 +02:00
Tamino Mueller
b962444506 task 11 2024-10-13 20:58:18 +02:00
Tamino Mueller
c0a3e8b37a task 10 2024-10-13 20:34:01 +02:00
Tamino Mueller
c8621e02c6 insert music 2024-10-13 19:56:12 +02:00
Tamino Mueller
25d7884cad fixed sizes of the boats 2024-10-13 17:34:43 +02:00
Tamino Mueller
2192f6dbc3 fixed sizes of the boats 2024-10-11 10:22:17 +02:00
Tamino Mueller
2b8bfb82ba added last boat und finished task 9 2024-10-11 02:47:38 +02:00
Tamino Mueller
70ed981ea2 added boat with length 1 and 3 2024-10-11 02:23:59 +02:00
Tamino Mueller
d5450df77c added alienboat 2024-10-11 01:39:25 +02:00
Tamino Mueller
1f75f7bf30 Task 8 2024-10-08 20:49:19 +02:00
Tamino Mueller
1ac55a9570 Aufgabe 7 2024-10-07 00:57:00 +02:00
122 changed files with 147397 additions and 1087219 deletions

BIN
Projekte/Alienship.j3o Normal file

Binary file not shown.

BIN
Projekte/Boje.j3o Normal file

Binary file not shown.

BIN
Projekte/KingGeorgeV.j3o Normal file

Binary file not shown.

BIN
Projekte/Marlow66.j3o Normal file

Binary file not shown.

Binary file not shown.

BIN
Projekte/UX23.j3o Normal file

Binary file not shown.

View File

@@ -9,6 +9,9 @@ dependencies {
implementation project(":battleship:model")
implementation libs.jme3.desktop
implementation libs.jme3.effects
implementation project(path: ':battleship:server')
implementation project(path: ':battleship:server')
runtimeOnly libs.jme3.awt.dialogs
runtimeOnly libs.jme3.plugins

View File

@@ -9,7 +9,7 @@
#
# Specifies the map used by the opponent in single mode.
# Single mode is activated if this property is set.
map.opponent=maps/map2.json
#map.opponent=maps/map2.json
#
# Specifies the map used by the player in single mode.
# The player must define their own map if this property is not set.

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 15,
"y": 5,
"rot": "DOWN"
},
{
"length": 3,
"x": 0,
"y": 9,
"rot": "DOWN"
},
{
"length": 3,
"x": 2,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 4,
"rot": "DOWN"
},
{
"length": 2,
"x": 2,
"y": 1,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 0,
"y": 5,
"rot": "DOWN"
},
{
"length": 3,
"x": 0,
"y": 9,
"rot": "DOWN"
},
{
"length": 3,
"x": 2,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 0,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 4,
"rot": "DOWN"
},
{
"length": 2,
"x": 2,
"y": 1,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 0,
"y": 5,
"rot": "DOWN"
},
{
"length": 3,
"x": 0,
"y": 9,
"rot": "DOWN"
},
{
"length": 3,
"x": 0,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 4,
"rot": "DOWN"
},
{
"length": 2,
"x": 2,
"y": 1,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,60 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 3,
"x": 0,
"y": 9,
"rot": "DOWN"
},
{
"length": 3,
"x": 2,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 4,
"rot": "DOWN"
},
{
"length": 2,
"x": 2,
"y": 1,
"rot": "DOWN"
},
{
"length": 1,
"x": 6,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 0,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 0,
"y": 9,
"rot": "RIGHT"
},
{
"length": 3,
"x": 4,
"y": 9,
"rot": "RIGHT"
},
{
"length": 3,
"x": 7,
"y": 9,
"rot": "RIGHT"
},
{
"length": 2,
"x": 0,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 2,
"y": 8,
"rot": "RIGHT"
},
{
"length": 2,
"x": 4,
"y": 8,
"rot": "RIGHT"
},
{
"length": 1,
"x": 6,
"y": 8,
"rot": "RIGHT"
},
{
"length": 1,
"x": 7,
"y": 8,
"rot": "RIGHT"
},
{
"length": 1,
"x": 8,
"y": 8,
"rot": "RIGHT"
},
{
"length": 1,
"x": 9,
"y": 8,
"rot": "RIGHT"
}
]
}

View File

@@ -1,66 +0,0 @@
{
"width": 10,
"height": 10,
"ships": [
{
"length": 4,
"x": 0,
"y": 9,
"rot": "RIGHT"
},
{
"length": 3,
"x": 0,
"y": 8,
"rot": "RIGHT"
},
{
"length": 3,
"x": 0,
"y": 7,
"rot": "RIGHT"
},
{
"length": 2,
"x": 0,
"y": 6,
"rot": "RIGHT"
},
{
"length": 2,
"x": 0,
"y": 5,
"rot": "RIGHT"
},
{
"length": 2,
"x": 0,
"y": 4,
"rot": "RIGHT"
},
{
"length": 1,
"x": 0,
"y": 3,
"rot": "RIGHT"
},
{
"length": 1,
"x": 0,
"y": 2,
"rot": "RIGHT"
},
{
"length": 1,
"x": 0,
"y": 1,
"rot": "RIGHT"
},
{
"length": 1,
"x": 0,
"y": 0,
"rot": "RIGHT"
}
]
}

View File

@@ -25,6 +25,7 @@ import pp.battleship.client.gui.EditorAppState;
import pp.battleship.client.gui.SeaAppState;
import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ClientGameLogic;
import pp.battleship.game.client.GameMusic;
import pp.battleship.game.client.ServerConnection;
import pp.battleship.game.singlemode.BattleshipClientConfig;
import pp.battleship.game.singlemode.ServerConnectionMockup;
@@ -265,14 +266,24 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
flyCam.setEnabled(false);
stateManager.detach(stateManager.getState(StatsAppState.class));
stateManager.detach(stateManager.getState(DebugKeysAppState.class));
atttachGameMusic();
attachGameSound();
attachGameMusic();
stateManager.attachAll(new EditorAppState(), new BattleAppState(), new SeaAppState());
}
private void atttachGameMusic() {
final GameMusic gameSound = new GameMusic();
gameSound.setEnabled(GameMusic.enabledInPreferences());
stateManager.attach(gameSound);
}
/**
* Attaches the game sound state and sets its initial enabled state.
*
*/
private void attachGameSound() {
final GameSound gameSound = new GameSound();
@@ -281,16 +292,6 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
stateManager.attach(gameSound);
}
/**
* Attaches the music state and sets its initial enabled state.
*/
private void attachGameMusic() {
final GameMusic gameMusic = new GameMusic();
gameMusic.setEnabled(GameMusic.enabledInPreferences());
stateManager.attach(gameMusic);
}
/**
* Updates the application state every frame.
* This method is called once per frame during the game loop.

View File

@@ -12,6 +12,8 @@ import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import pp.battleship.game.client.ClientGameLogic;
/**
* Abstract class representing a state in the Battleship game.
* Extends the AbstractAppState from jMonkeyEngine to manage state behavior.

View File

@@ -34,7 +34,6 @@ public class GameSound extends AbstractAppState implements GameEventListener {
private AudioNode splashSound;
private AudioNode shipDestroyedSound;
private AudioNode explosionSound;
private AudioNode shellFlyingSound;
/**
* Checks if sound is enabled in the preferences.
@@ -79,8 +78,6 @@ public class GameSound extends AbstractAppState implements GameEventListener {
shipDestroyedSound = loadSound(app, "Sound/Effects/sunken.wav"); //NON-NLS
splashSound = loadSound(app, "Sound/Effects/splash.wav"); //NON-NLS
explosionSound = loadSound(app, "Sound/Effects/explosion.wav"); //NON-NLS
shellFlyingSound = loadSound(app, "Sound/Effects/shell_flying.wav");
}
/**
@@ -90,7 +87,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
* @param name The name of the sound file.
* @return The loaded AudioNode.
*/
private AudioNode loadSound(Application app, String name) {
public AudioNode loadSound(Application app, String name) {
try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false);
@@ -127,28 +124,12 @@ public class GameSound extends AbstractAppState implements GameEventListener {
shipDestroyedSound.playInstance();
}
/**
* Plays the shell flying sound effect.
*/
public void shellFly() {
if (isEnabled() && shellFlyingSound != null) {
shellFlyingSound.playInstance();
}
}
/**
* Handles a recieved {@code SoundEvent} and plays the according sound.
*
* @param event the Sound event to be processed
*/
@Override
public void receivedEvent(SoundEvent event) {
switch (event.sound()) {
case EXPLOSION -> explosion();
case SPLASH -> splash();
case DESTROYED_SHIP -> shipDestroyed();
case SHELL_FLYING -> shellFly();
}
}
}

View File

@@ -11,13 +11,11 @@ import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId;
import pp.battleship.game.client.GameMusic;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog;
import pp.battleship.client.GameMusic;
import pp.battleship.client.VolumeSlider;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;
@@ -33,27 +31,25 @@ import static pp.util.PreferencesUtils.getPreferences;
class Menu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(Menu.class);
private static final String LAST_PATH = "last.file.path";
// private final VolumeSlider slider;
private final BattleshipApp app;
private final Button loadButton = new Button(lookup("menu.map.load"));
private final Button saveButton = new Button(lookup("menu.map.save"));
private final VolumeSlider slider;
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the BattleshipApp instance
*/
public Menu(BattleshipApp app) {
super(app.getDialogManager());
this.app = app;
slider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
addChild(new Label(lookup("battleship.name"), new ElementId("header"))); //NON-NLS
addChild(new Checkbox(lookup("menu.sound-enabled"), new StateCheckboxModel(app, GameSound.class)));
addChild(new Checkbox(lookup("menu.background-sound-enabled"), new StateCheckboxModel(app, GameMusic.class)));
addChild(slider);
addChild(new Checkbox(lookup("menu.sound-enabled"),
new StateCheckboxModel(app, GameSound.class)));
// slider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
addChild(loadButton)
.addClickCommands(s -> ifTopDialog(this::loadDialog));
addChild(saveButton)
@@ -63,6 +59,11 @@ class Menu extends Dialog {
addChild(new Button(lookup("menu.quit")))
.addClickCommands(s -> ifTopDialog(app::closeApp));
update();
addChild(new Checkbox(lookup("menu.sound-enabled"), new StateCheckboxModel(app, GameSound.class)));
addChild(new Checkbox(lookup("menu.background-sound-enabled"), new StateCheckboxModel(app, GameMusic.class)));
// addChild(slider);
}
/**
@@ -74,6 +75,14 @@ class Menu extends Dialog {
saveButton.setEnabled(app.getGameLogic().maySaveMap());
}
/* @Override
public void update(float delta) {
slider.update();
}
*/
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@@ -149,13 +158,4 @@ class Menu extends Dialog {
private void saveDialog() {
fileDialog(app.getGameLogic()::saveMap, lookup("menu.map.save"));
}
/**
* Updates the position of the volume control slider.
*/
@Override
public void update(float delta) {
slider.update();
}
}

View File

@@ -35,10 +35,9 @@ class NetworkDialog extends SimpleDialog {
private final NetworkSupport network;
private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
// private final Button serverButton = new Button(lookup("client.server-star"));
private final Button serverButton = new Button(lookup("client.server-start"));
private String hostname;
private int portNumber;
private final Button serverButton = new Button(lookup("client.server-start"));
private Future<Object> connectionFuture;
private Dialog progressDialog;
@@ -69,10 +68,11 @@ class NetworkDialog extends SimpleDialog {
.setOkClose(false)
.setNoClose(false)
.build(this);
//Add the button to start the sever
addChild(serverButton).addClickCommands(s -> ifTopDialog(this::startServerInThread));
}
//Add the button to start the sever
/**
* Handles the action for the connect button in the connection dialog.
@@ -157,7 +157,6 @@ class NetworkDialog extends SimpleDialog {
network.getApp().errorDialog(lookup("server.connection.failed"));
network.getApp().setInfoText(e.getLocalizedMessage());
}
/**
* Starts the server in a separate thread.
*/
@@ -174,4 +173,5 @@ class NetworkDialog extends SimpleDialog {
});
serverThread.start();
}
}

View File

@@ -28,7 +28,7 @@ import pp.util.Position;
* and interaction between the model and the view.
*/
class MapView {
public static final float FIELD_SIZE = 40f;
private static final float FIELD_SIZE = 40f;
private static final float GRID_LINE_WIDTH = 2f;
private static final float BACKGROUND_DEPTH = -4f;
private static final float GRID_DEPTH = -1f;

View File

@@ -7,20 +7,15 @@
package pp.battleship.client.gui;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import pp.battleship.model.Battleship;
import pp.battleship.model.Shell;
import pp.battleship.model.Shot;
import pp.util.Position;
import static com.jme3.material.Materials.UNSHADED;
/**
* Synchronizes the visual representation of the ship map with the game model.
@@ -43,6 +38,7 @@ class MapViewSynchronizer extends ShipMapSynchronizer {
// The MapView associated with this synchronizer
private final MapView view;
private Shell shell;
/**
* Constructs a new MapViewSynchronizer for the given MapView.
@@ -129,25 +125,16 @@ class MapViewSynchronizer extends ShipMapSynchronizer {
private Geometry shipLine(float x1, float y1, float x2, float y2, ColorRGBA color) {
return view.getApp().getDraw().makeFatLine(x1, y1, x2, y2, SHIP_DEPTH, color, SHIP_LINE_WIDTH);
}
/**
* Creates and returns a Spatial representation of the given {@code Shell} object
* for 2D visualization in the game. The shell is represented as a circle.
*
* @param shell The {@code Shell} object to be visualized.
* @return A {@code Spatial} object representing the shell on the map.
*/
@Override
public Spatial visit(Shell shell) {
final ColorRGBA color = ColorRGBA.Black;
Geometry ellipse = new Geometry("ellipse", new Sphere(50, 50, MapView.FIELD_SIZE / 2 * 0.8f));
Material mat = new Material(view.getApp().getAssetManager(), UNSHADED); //NON-NLS
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
mat.setColor("Color", color);
ellipse.setMaterial(mat);
ellipse.addControl(new Shell2DControl(view, shell));
return ellipse;
public void update(float deltaTime) {
if (shell != null) {
shell.updatePosition(deltaTime);
drawShell(shell.getCurrentPosition());
}
}
private void drawShell(Vector3f position){
//TODO implement
}
}

View File

@@ -7,10 +7,13 @@ import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import pp.battleship.client.BattleshipApp;
public class ParticleCreator {
/**
* 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;
@@ -18,7 +21,7 @@ public class ParticleCreator {
private final BattleshipApp app;
ParticleCreator(BattleshipApp app) {
ParticleEffectFactory(BattleshipApp app) {
this.app = app;
}
@@ -27,8 +30,7 @@ public class ParticleCreator {
*
* @return a configured flame particle emitter
*/
ParticleEmitter createFlame(){
ParticleEmitter createFlame() {
ParticleEmitter flame = new ParticleEmitter("Flame", EMITTER_TYPE, 32 * COUNT_FACTOR);
flame.setSelectRandomImage(true);
flame.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (1f / COUNT_FACTOR_F)));
@@ -123,9 +125,9 @@ public class ParticleCreator {
spark.setFacingVelocity(true);
spark.setParticlesPerSec(0);
spark.setGravity(0, 5, 0);
spark.setLowLife(0.5f);
spark.setLowLife(1.1f);
spark.setHighLife(1.5f);
spark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 8, 0)); // y20
spark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 20, 0));
spark.getParticleInfluencer().setVelocityVariation(1);
spark.setImagesX(1);
spark.setImagesY(1);
@@ -238,7 +240,6 @@ public class ParticleCreator {
return smokeEmitter;
}
/**
* Creates a one-time water splash particle emitter.
*

View File

@@ -20,10 +20,8 @@ import com.jme3.scene.shape.Cylinder;
import pp.battleship.client.BattleshipApp;
import pp.battleship.model.Battleship;
import pp.battleship.model.Rotation;
import pp.battleship.model.Shell;
import pp.battleship.model.ShipMap;
import pp.battleship.model.Shot;
import static java.util.Objects.requireNonNull;
import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI;
@@ -36,11 +34,13 @@ import static pp.util.FloatMath.PI;
*/
class SeaSynchronizer extends ShipMapSynchronizer {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
private static final String KING_GEORGE_V_MODEL = "Models/KingGeorgeV/KingGeorgeV.j3o"; //NON-NLS
private static final String SMALL_SHIP_MODEL = "Models/SmallShip/SmallShip.j3o"; //NON-NLS
private static final String U_BOAT_MODEL = "Models/WWII_ship_German_Type_II_U-boat_v2/WW2Uboat.j3o"; //NON-NLS
private static final String TUG_BOAT_MODEL = "Models/TugBoat/TugBoat.j3o"; //NON-NLS
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
private static final String UX23 = "Models/UX23/UX23.j3o";
private static final String BOJE = "Models/Boje/Boje.j3o";
private static final String ALIENSHIP = "Models/Alienship/Alienship.j3o";
private static final String MARLOW66 = "Models/Marlow66/Marlow66.j3o";
private static final String KING_GEORGE_V_MODEL = "Models/KingGeorgeV/KingGeorgeV.j3o";
private static final String COLOR = "Color"; //NON-NLS
private static final String SHIP = "ship"; //NON-NLS
private static final String SHOT = "shot"; //NON-NLS
@@ -50,8 +50,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
private final ShipMap map;
private final BattleshipApp app;
private final ParticleCreator particlecreator;
private final ParticleEffectFactory particleFactory;
/**
* Constructs a {@code SeaSynchronizer} object with the specified application, root node, and ship map.
@@ -64,7 +63,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
super(app.getGameLogic().getOwnMap(), root);
this.app = app;
this.map = map;
this.particlecreator = new ParticleCreator(app);
this.particleFactory = new ParticleEffectFactory(app);
addExisting();
}
@@ -81,46 +80,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
return shot.isHit() ? handleHit(shot) : handleMiss(shot);
}
/**
* Handles a miss by representing it with a blue cylinder
* and attaching a water splash effect to it.
* @param shot the shot to be processed
* @return a Spatial simulating a miss with water splash effect
*/
private Spatial handleMiss(Shot shot) {
Node shotNode = new Node("ShotNode");
Geometry shotCylinder = createCylinder(shot);
shotNode.attachChild(shotCylinder);
ParticleEmitter waterSplash = particlecreator.createWaterSplash();
waterSplash.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
shotNode.attachChild(waterSplash);
waterSplash.emitAllParticles();
return shotNode;
}
/**
* Handles the sinking animation and removal of ship if destroyed
* @param ship the ship to be sunk
*/
private void sinkAndRemoveShip(Battleship ship) {
Battleship dasIstGelebteTeamarbeit = ship;
final Node shipNode = (Node) getSpatial(dasIstGelebteTeamarbeit);
if (shipNode == null) return;
// Add sinking control to animate the sinking
shipNode.addControl(new SinkControl(shipNode));
// Add particle effects
ParticleEmitter bubbles = particlecreator.createWaterSplash();
bubbles.setLocalTranslation(shipNode.getLocalTranslation());
shipNode.attachChild(bubbles);
bubbles.emitAllParticles();
}
/**
/**
* Handles a hit by attaching its representation to the node that
* contains the ship model as a child so that it moves with the ship.
*
@@ -132,18 +92,20 @@ class SeaSynchronizer extends ShipMapSynchronizer {
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
// Create a new node specifically for the hit effects
Node hitEffectNode = new Node("HitEffectNode");
// Create particle effects
ParticleEmitter flame = particlecreator.createFlame();
ParticleEmitter flash = particlecreator.createFlash();
ParticleEmitter spark = particlecreator.createSpark();
ParticleEmitter roundSpark = particlecreator.createRoundSpark();
ParticleEmitter smokeTrail = particlecreator.createSmokeTrail();
ParticleEmitter debris = particlecreator.createDebris();
ParticleEmitter shockwave = particlecreator.createShockwave();
ParticleEmitter movingSmoke = particlecreator.createMovingSmokeEmitter();
ParticleEmitter flame = particleFactory.createFlame();
ParticleEmitter flash = particleFactory.createFlash();
ParticleEmitter spark = particleFactory.createSpark();
ParticleEmitter roundSpark = particleFactory.createRoundSpark();
ParticleEmitter smokeTrail = particleFactory.createSmokeTrail();
ParticleEmitter debris = particleFactory.createDebris();
ParticleEmitter shockwave = particleFactory.createShockwave();
ParticleEmitter movingSmoke = particleFactory.createMovingSmokeEmitter();
// Attach all effects to the hitEffectNode
hitEffectNode.attachChild(flame);
@@ -157,8 +119,8 @@ class SeaSynchronizer extends ShipMapSynchronizer {
// Set the local translation for the hit effect to the point of impact
hitEffectNode.setLocalTranslation(shot.getY() + 0.5f - shipNode.getLocalTranslation().x,
0.5f, // Adjust as needed for height above the ship
shot.getX() + 0.5f - shipNode.getLocalTranslation().z);
0.5f, // Adjust as needed for height above the ship
shot.getX() + 0.5f - shipNode.getLocalTranslation().z);
// Attach the hitEffectNode to the shipNode so it moves with the ship
shipNode.attachChild(hitEffectNode);
@@ -172,13 +134,20 @@ class SeaSynchronizer extends ShipMapSynchronizer {
flame.emitAllParticles();
roundSpark.emitAllParticles();
//Checks if ship is destroyed and triggers animation accordingly
if (ship.isDestroyed()) {
sinkAndRemoveShip(ship);
}
return null;
}
private Spatial handleMiss(Shot shot) {
Node shotNode = new Node("ShotNode");
Geometry shotCylinder = createCylinder(shot);
shotNode.attachChild(shotCylinder);
ParticleEmitter waterSplash = particleFactory.createWaterSplash();
waterSplash.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
shotNode.attachChild(waterSplash);
waterSplash.emitAllParticles();
return shotNode;
}
/**
* Creates a cylinder geometry representing the specified shot.
@@ -231,18 +200,12 @@ class SeaSynchronizer extends ShipMapSynchronizer {
*/
private Spatial createShip(Battleship ship) {
switch (ship.getLength()) {
case 4:
return createBattleship(ship);
case 3:
return createLargeship(ship);
case 2:
return createMediumship(ship);
case 1:
return createSmallship(ship);
default:
return createBox(ship);
case 4: return createBattleship(ship);
case 3: return createMarlow66(ship);
case 2: return createUX23(ship);
case 1: return createAllienship(ship);
default: return createBox(ship);
}
}
/**
@@ -292,36 +255,42 @@ class SeaSynchronizer extends ShipMapSynchronizer {
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(1.48f);
// model.scale(0.0007f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
private Spatial createSmallship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(SMALL_SHIP_MODEL);
private Spatial createAllienship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(ALIENSHIP);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(0.0005f);
model.scale(0.10f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;}
private Spatial createUX23(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(UX23);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
// model.move(0f, -0.05f, 0f);
model.scale(0.89f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
private Spatial createMediumship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(U_BOAT_MODEL);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(0.27f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
private Spatial createLargeship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(TUG_BOAT_MODEL);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(0.0004f);
private Spatial createMarlow66(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(MARLOW66);
model.rotate(0f, calculateRotationAngle(ship.getRot()), 0f);
model.move(0f, 0.25f, 0f);
model.scale(0.135f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
@@ -341,25 +310,4 @@ class SeaSynchronizer extends ShipMapSynchronizer {
case UP -> PI;
};
}
/**
* Creates and returns a 3D model representation of the given {@code Shell} object
* for visualization in the game.
*
* @param shell The {@code Shell} object to be visualized.
* @return A {@code Spatial} object representing the 3D model of the shell.
*/
@Override
public Spatial visit(Shell shell) {
final Spatial model = app.getAssetManager().loadModel("Models/Shell/shell.j3o");
model.setLocalScale(.05f);
model.setShadowMode(ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), LIGHTING);
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture("Models/Shell/shell_color.png"));
mat.setReceivesShadows(true);
model.setMaterial(mat);
model.addControl(new ShellControl(shell));
return model;
}
}

View File

@@ -1,49 +0,0 @@
package pp.battleship.client.gui;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.battleship.model.Shell;
import pp.util.Position;
/**
* Controls the 2D representation of a {@code Shell} in the game, updating its position
* based on the shell's current state in the game model. The {@code Shell2DControl} class
* is responsible for translating the shell's 3D position to a 2D view position within
* the game's map view.
*/
public class Shell2DControl extends AbstractControl {
private final Shell shell;
private final MapView view;
/**
* Constructs a new {@code Shell2DControl} to manage the 2D visualization of the given {@code Shell}.
*
* @param view The {@code MapView} used to get information about the map to display.
* @param shell The {@code Shell} being visualized.
*/
public Shell2DControl(MapView view, Shell shell){
this.shell = shell;
this.view = view;
}
/**
* Updates the position of the shell's 2D representation based on the shell's current
* 3D position in the game model. The position is mapped from model space to view space
* coordinates and translated to the appropriate location within the {@code MapView}.
*
* @param tpf Time per frame, representing the time elapsed since the last frame.
*/
@Override
protected void controlUpdate(float tpf) {
Vector3f shellPos = shell.getPosition();
Position viewPos = view.modelToView(shellPos.x, shellPos.z);
spatial.setLocalTranslation(viewPos.getX() + MapView.FIELD_SIZE / 2, viewPos.getY() + MapView.FIELD_SIZE / 2, 0);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// No rendering-specific behavior required for this control
}
}

View File

@@ -1,50 +0,0 @@
package pp.battleship.client.gui;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.battleship.model.Shell;
import static pp.util.FloatMath.PI;
/**
* Controls the 3D representation of a {@code Shell} in the game, updating its position
* and rotation based on the shell's current state in the game model. The {@code ShellControl}
* class ensures that the spatial associated with the shell is positioned and oriented correctly
* within the world.
*/
public class ShellControl extends AbstractControl {
private final Shell shell;
/**
* Constructs a new {@code ShellControl} to manage the 3D visualization of the given {@code Shell}.
*
* @param shell The {@code Shell} being visualized and controlled.
*/
public ShellControl(Shell shell){
super();
this.shell = shell;
}
/**
* Updates the 3D position and rotation of the shell based on its current state.
* Converts map coordinates to world coordinates and applies the shell's orientation.
*
* @param tpf Time per frame, representing the elapsed time since the last update.
*/
@Override
protected void controlUpdate(float tpf) {
Vector3f pos = shell.getPosition();
Vector3f fixed = new Vector3f(pos.z + 0.5f, pos.y, pos.x + 0.5f);
fixed.setY(pos.y);
spatial.setLocalTranslation(fixed);
spatial.setLocalRotation(shell.getRotation());
spatial.rotate(PI/2,0,0);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// No rendering-specific behavior required for this control
}
}

View File

@@ -1,54 +0,0 @@
package pp.battleship.client.gui;
import com.jme3.scene.control.AbstractControl;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
/**
* Control that handles the sinking effect for destroyed ships.
* It will gradually move the ship downwards and then remove it from the scene.
*/
class SinkControl extends AbstractControl {
private static final float SINK_DURATION = 5f; // Duration of the sinking animation
private static final float SINK_SPEED = 0.1f; // Speed at which the ship sinks
private float elapsedTime = 0;
private final Node shipNode;
/**
* Constructs a {@code SinkingControl} object with the shipNode to be to be sunk
* @param shipNode the node to handeld
*/
public SinkControl(Node shipNode) {
this.shipNode = shipNode;
}
/**
* Updated the Map to sink the ship
*
* @param tpf time per frame
*/
@Override
protected void controlUpdate(float tpf) {
// Update the sinking effect
elapsedTime += tpf;
// Move the ship down over time
Vector3f currentPos = shipNode.getLocalTranslation();
shipNode.setLocalTranslation(currentPos.x, currentPos.y - SINK_SPEED * tpf, currentPos.z);
// Check if sinking duration has passed
if (elapsedTime >= SINK_DURATION) {
// Remove the ship from the scene
shipNode.removeFromParent();
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// No rendering-related code needed
}
}

View File

@@ -1,183 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.server;
import com.jme3.network.ConnectionListener;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;
import pp.battleship.BattleshipConfig;
import pp.battleship.game.server.Player;
import pp.battleship.game.server.ServerGameLogic;
import pp.battleship.game.server.ServerSender;
import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.client.AnimationFinishedMessage;
import pp.battleship.message.client.MapMessage;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerMessage;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.Battleship;
import pp.battleship.model.IntPoint;
import pp.battleship.model.Shot;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.LogManager;
/**
* Server implementing the visitor pattern as MessageReceiver for ClientMessages
*/
public class BattleshipServer implements MessageListener<HostedConnection>, ConnectionListener, ServerSender {
private static final Logger LOGGER = System.getLogger(BattleshipServer.class.getName());
private static final File CONFIG_FILE = new File("server.properties");
private final BattleshipConfig config = new BattleshipConfig();
private Server myServer;
private final ServerGameLogic logic;
private final BlockingQueue<ReceivedMessage> pendingMessages = new LinkedBlockingQueue<>();
static {
// Configure logging
LogManager manager = LogManager.getLogManager();
try {
manager.readConfiguration(new FileInputStream("logging.properties"));
LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.INFO, e.getMessage());
}
}
/**
* Starts the Battleships server.
*/
public static void main(String[] args) {
new BattleshipServer().run();
}
/**
* Creates the server.
*/
BattleshipServer() {
config.readFromIfExists(CONFIG_FILE);
LOGGER.log(Level.INFO, "Configuration: {0}", config); //NON-NLS
logic = new ServerGameLogic(this, config);
}
public void run() {
startServer();
while (true)
processNextMessage();
}
private void startServer() {
try {
LOGGER.log(Level.INFO, "Starting server..."); //NON-NLS
myServer = Network.createServer(config.getPort());
initializeSerializables();
myServer.start();
registerListeners();
LOGGER.log(Level.INFO, "Server started: {0}", myServer.isRunning()); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.ERROR, "Couldn't start server: {0}", e.getMessage()); //NON-NLS
exit(1);
}
}
private void processNextMessage() {
try {
pendingMessages.take().process(logic);
}
catch (InterruptedException ex) {
LOGGER.log(Level.INFO, "Interrupted while waiting for messages"); //NON-NLS
Thread.currentThread().interrupt();
}
}
private void initializeSerializables() {
Serializer.registerClass(GameDetails.class);
Serializer.registerClass(StartBattleMessage.class);
Serializer.registerClass(MapMessage.class);
Serializer.registerClass(ShootMessage.class);
Serializer.registerClass(EffectMessage.class);
Serializer.registerClass(AnimationFinishedMessage.class);
Serializer.registerClass(Battleship.class);
Serializer.registerClass(IntPoint.class);
Serializer.registerClass(Shot.class);
}
private void registerListeners() {
myServer.addMessageListener(this, MapMessage.class);
myServer.addMessageListener(this, ShootMessage.class);
myServer.addMessageListener(this, AnimationFinishedMessage.class);
myServer.addConnectionListener(this);
}
@Override
public void messageReceived(HostedConnection source, Message message) {
LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS
if (message instanceof ClientMessage clientMessage)
pendingMessages.add(new ReceivedMessage(clientMessage, source.getId()));
}
@Override
public void connectionAdded(Server server, HostedConnection hostedConnection) {
LOGGER.log(Level.INFO, "new connection {0}", hostedConnection); //NON-NLS
logic.addPlayer(hostedConnection.getId());
}
@Override
public void connectionRemoved(Server server, HostedConnection hostedConnection) {
LOGGER.log(Level.INFO, "connection closed: {0}", hostedConnection); //NON-NLS
final Player player = logic.getPlayerById(hostedConnection.getId());
if (player == null)
LOGGER.log(Level.INFO, "closed connection does not belong to an active player"); //NON-NLS
else { //NON-NLS
LOGGER.log(Level.INFO, "closed connection belongs to {0}", player); //NON-NLS
exit(0);
}
}
private void exit(int exitValue) { //NON-NLS
LOGGER.log(Level.INFO, "close request"); //NON-NLS
if (myServer != null)
for (HostedConnection client : myServer.getConnections()) //NON-NLS
if (client != null) client.close("Game over"); //NON-NLS
System.exit(exitValue);
}
/**
* Send the specified message to the specified connection.
*
* @param id the connection id
* @param message the message
*/
public void send(int id, ServerMessage message) {
if (myServer == null || !myServer.isRunning()) {
LOGGER.log(Level.ERROR, "no server running when trying to send {0}", message); //NON-NLS
return;
}
final HostedConnection connection = myServer.getConnection(id);
if (connection != null)
connection.send(message);
else
LOGGER.log(Level.ERROR, "there is no connection with id={0}", id); //NON-NLS
}
}

View File

@@ -1,18 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.battleship.server;
import pp.battleship.message.client.ClientInterpreter;
import pp.battleship.message.client.ClientMessage;
record ReceivedMessage(ClientMessage message, int from) {
void process(ClientInterpreter interpreter) {
message.accept(interpreter, from);
}
}

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -41,10 +41,12 @@ public class ModelExporter extends SimpleApplication {
*/
@Override
public void simpleInitApp() {
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS
export("Models/SmallShip/12219_boat_v2_L2.obj", "SmallShip.j3o"); //NON-NLS
export("Models/WWII_ship_German_Type_II_U-boat_v2/14084_WWII_Ship_German_Type_II_U-boat_v2_L1.obj", "WW2Uboat.j3o"); //NON-NLS
export("Models/TugBoat/12218_tugboat_v1_L2.obj", "TugBoat.j3o"); //NON-NLS
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o");//NON-NLS
export("Models/Alienship/Alienship.obj", "Alienship.j3o");//NON-NLS
export("Models/Marlow66/Marlow66.obj", "Marlow66.j3o");//NON-NLS
export("Models/UX23/UX23.obj", "UX23.j3o");//NON-NLS
export("Models/Boje/Boje.obj", "Boje.j3o");//NON-NLS
stop();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -0,0 +1,11 @@
# Blender MTL File: 'water ship.blend'
# Material Count: 1
newmtl Material
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ni 1.000000
d 1.000000
illum 2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -0,0 +1,90 @@
# Blender MTL File: 'Marlow66.blend'
# Material Count: 6
# DISCLOSURE:
# This model obj or mtl files are NOT intended for commercial purposes.
# Do not copy or sell in part or in full without explicit permission from original author
# including accompanying textures, jpgs etc...
# One or more textures bundled with this project have been created with images from Textures.com.
# These images may not be redistributed by default. Please visit www.textures.com for more information.
#
# AUTHOR: PapaySailor Copyright 2020
# WEB SITE: www.archipelagosim.com
newmtl Aluminum
Ns 40.0
Ka 0.2 0.2 0.2
Kd 0.8 0.8 0.8
Ks 0.1 0.1 0.1
newmtl Black
Ns 517.690314
Ka 0.235955 0.235955 0.235955
Kd 0.000000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 3
newmtl Chrome
Ns 10
Ka 0.05 0.05 0.1
Kd 0.99 0.99 0.99
Ks 1.0 1.0 1.0
newmtl DarkWood
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.58 0.41 0.25
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd WoodPlanks.jpg
newmtl LightBlue
Ns 440.461707
Ka 0.3 0.3 0.3
Kd 0.25 1.0 1.0
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 3
map_Kd HullTexture.png
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2
newmtl White
Ka 0.38 0.39 0.38
Kd 0.9 0.9 0.9
Ks 0.57 0.49 0.37
Ke 0.0 0.0 0.0
Ns 579.0
newmtl WindowShaded
Ka 0.184744 0.184744 0.184744
Kd 0.166368 0.218014 0.259048
Ks 0.6283 0.5559 0.3661
Ke 0.0 0.0 0.0
Ns 427.451019
Tr 0.2
newmtl Wood
Ns 50
Ka 0.2 0.2 0.2
Kd 0.93 0.82 0.63
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd FineWood.jpg

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

@@ -1,104 +0,0 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 16.12.2011 14:18:52
newmtl white
Ns 53.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.6667 0.6667 0.6667
Kd 0.6667 0.6667 0.6667
Ks 0.1800 0.1800 0.1800
Ke 0.0000 0.0000 0.0000
newmtl boat_elements_black
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.0000 0.0000 0.0000
Ks 0.3600 0.3600 0.3600
Ke 0.0000 0.0000 0.0000
newmtl boat_glass
Ns 60.0000
Ni 7.0000
d 0.4000
Tr 0.6000
Tf 0.4000 0.4000 0.4000
illum 2
Ka 0.1059 0.1569 0.1451
Kd 0.1059 0.1569 0.1451
Ks 0.6750 0.6750 0.6750
Ke 0.0000 0.0000 0.0000
newmtl boat_screw_hooks_bronze
Ns 80.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.2941 0.2157 0.0510
Kd 0.2941 0.2157 0.0510
Ks 0.7200 0.7200 0.7200
Ke 0.0000 0.0000 0.0000
newmtl boat_silver
Ns 80.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.3333 0.3333 0.3333
Kd 0.3333 0.3333 0.3333
Ks 0.7200 0.7200 0.7200
Ke 0.0000 0.0000 0.0000
newmtl boat_buffer
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.2700 0.2700 0.2700
Ke 0.0000 0.0000 0.0000
map_Ka boat_buffer_diffuse.jpg
map_Kd boat_buffer_diffuse.jpg
newmtl boat_roof_accessory
Ns 15.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.3600 0.3600 0.3600
Ke 0.0000 0.0000 0.0000
map_Ka boat_roof_accessory_diffuse.jpg
map_Kd boat_roof_accessory_diffuse.jpg
newmtl boat_body
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.3600 0.3600 0.3600
Ke 0.0000 0.0000 0.0000
map_Ka boat_body_diffuse.jpg
map_Kd boat_body_diffuse.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -1,154 +0,0 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 21.12.2011 10:51:13
newmtl 12218_tugboat_tube
Ns 40.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.1800 0.1800 0.1800
Ke 0.0000 0.0000 0.0000
map_Ka 12218_tugboat_tube_diffuse.jpg
map_Kd 12218_tugboat_tube_diffuse.jpg
newmtl 12218_tugboat_cabine
Ns 40.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.1800 0.1800 0.1800
Ke 0.0000 0.0000 0.0000
map_Ka 12218_tugboat_cabine_diffuse.jpg
map_Kd 12218_tugboat_cabine_diffuse.jpg
newmtl 12218_tugboat_boat
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.5400 0.5400 0.5400
Ke 0.0000 0.0000 0.0000
map_Ka 12218_tugboat_boat_diffuse.jpg
map_Kd 12218_tugboat_boat_diffuse.jpg
newmtl 12218_tugboat_blackpaint
Ns 40.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.1333 0.1333 0.1333
Kd 0.1333 0.1333 0.1333
Ks 0.1725 0.1725 0.1725
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_yellowpaint
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.8196 0.6588 0.1725
Kd 0.8196 0.6588 0.1725
Ks 0.6471 0.6471 0.6471
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_crane
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.6314 0.0588 0.0588
Kd 0.6314 0.0588 0.0588
Ks 0.6471 0.6471 0.6471
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_orangepaint
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.8627 0.2549 0.1137
Kd 0.8627 0.2549 0.1137
Ks 0.6471 0.6471 0.6471
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_whitepaint
Ns 60.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.8667 0.8667 0.8667
Kd 0.8667 0.8667 0.8667
Ks 0.7765 0.7765 0.7765
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_greypaint
Ns 55.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.3373 0.3412 0.3490
Kd 0.3373 0.3412 0.3490
Ks 0.6471 0.6471 0.6471
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_bronze
Ns 75.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.5529 0.4275 0.0000
Kd 0.5529 0.4275 0.0000
Ks 0.6471 0.6471 0.6471
Ke 0.0000 0.0000 0.0000
newmtl 12218_tugboat_saferound
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.2700 0.2700 0.2700
Ke 0.0000 0.0000 0.0000
map_Ka 12218_tugboat_saferound_diffuse.jpg
map_Kd 12218_tugboat_saferound_diffuse.jpg
newmtl 12218_tugboat_dirtdark
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.1216 0.1059 0.0863
Kd 0.1216 0.1059 0.0863
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000

View File

@@ -0,0 +1,55 @@
# Blender MTL File: 'None'
# Material Count: 5
newmtl mat_0_0
Ns 1.000002
Ka 1.000000 1.000000 1.000000
Kd 0.686275 0.686275 0.686275
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl mat_0_1
Ns 1.000002
Ka 1.000000 1.000000 1.000000
Kd 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd 001.JPG
newmtl mat_0_2
Ns 1.000002
Ka 1.000000 1.000000 1.000000
Kd 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd 001.JPG
newmtl mat_0_3
Ns 1.000002
Ka 1.000000 1.000000 1.000000
Kd 0.058824 0.058824 0.058824
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl mat_0_4
Ns 1.000002
Ka 1.000000 1.000000 1.000000
Kd 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd 001.JPG

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 29.03.2012 14:25:39
newmtl default
Ns 35.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.5400 0.5400 0.5400
Ke 0.0000 0.0000 0.0000
map_Ka 14084_WWII_ship_German_Type_II_U-boat_diff.jpg
map_Kd 14084_WWII_ship_German_Type_II_U-boat_diff.jpg

View File

@@ -10,7 +10,6 @@ package pp.battleship.game.client;
import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.model.IntPoint;
import pp.battleship.model.Shell;
import pp.battleship.model.ShipMap;
import pp.battleship.notification.Sound;
@@ -54,13 +53,16 @@ class BattleState extends ClientState {
@Override
public void receivedEffect(EffectMessage msg) {
ClientGameLogic.LOGGER.log(Level.INFO, "report effect: {0}", msg); //NON-NLS
playSound(msg);
myTurn = msg.isMyTurn();
logic.setInfoText(msg.getInfoTextKey());
Shell shell = new Shell(msg.getShot());
affectedMap(msg).add(shell);
logic.playSound(Sound.SHELL_FLYING);
logic.setState(new ShootingState(logic, shell, myTurn, msg));
affectedMap(msg).add(msg.getShot());
if (destroyedOpponentShip(msg))
logic.getOpponentMap().add(msg.getDestroyedShip());
if (msg.isGameOver()) {
msg.getRemainingOpponentShips().forEach(logic.getOpponentMap()::add);
logic.setState(new GameOverState(logic));
}
}
/**
@@ -72,4 +74,29 @@ class BattleState extends ClientState {
private ShipMap affectedMap(EffectMessage msg) {
return msg.isOwnShot() ? logic.getOpponentMap() : logic.getOwnMap();
}
/**
* Checks if the opponent's ship was destroyed by the player's shot.
*
* @param msg the effect message received from the server
* @return true if the shot destroyed an opponent's ship, false otherwise
*/
private boolean destroyedOpponentShip(EffectMessage msg) {
return msg.getDestroyedShip() != null && msg.isOwnShot();
}
/**
* Plays a sound based on the outcome of the shot. Different sounds are played for a miss, hit,
* or destruction of a ship.
*
* @param msg the effect message containing the result of the shot
*/
private void playSound(EffectMessage msg) {
if (!msg.getShot().isHit())
logic.playSound(Sound.SPLASH);
else if (msg.getDestroyedShip() == null)
logic.playSound(Sound.EXPLOSION);
else
logic.playSound(Sound.DESTROYED_SHIP);
}
}

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