24 Commits

Author SHA1 Message Date
Simon Wilkening
1f4ebdb630 fixed incorrect splash effect 2024-10-18 17:15:57 +02:00
Simon Wilkening
1f5c8ba4a6 fixed bug of chrashing servers when shell hits a target 2024-10-18 17:09:50 +02:00
Simon Wilkening
0cdd345ab5 corrected minor error 2024-10-18 13:54:04 +02:00
Simon Wilkening
ba837d4016 shell sound 2024-10-18 13:21:29 +02:00
Simon Wilkening
28d9cb10e5 shell animation 2024-10-18 13:20:23 +02:00
Simon Wilkening
21553ec52e ships are finally sinking 2024-10-14 04:40:37 +02:00
Simon Wilkening
5f79e8e00c Added effect for not hitting ships 2024-10-14 04:25:55 +02:00
Simon Wilkening
03adf45167 Adjusted effects 2024-10-14 04:06:27 +02:00
Simon Wilkening
17c4fca078 Added effects for hits 2024-10-13 18:54:36 +02:00
Simon Wilkening
16620a0a3b Added map 7 and map 8 to compare 3D ship models 2024-10-13 14:18:25 +02:00
Simon Wilkening
2028d936e3 Server can now be started from client menu 2024-10-13 14:16:28 +02:00
Simon Wilkening
21fc46f9c5 Added background music for everything 2024-10-13 04:32:33 +02:00
Simon Wilkening
dc52cf4f32 Added boat model for 3x1 boats 2024-10-12 21:35:55 +02:00
Simon Wilkening
c339f3fc9d Added boat model for 2x1 boats 2024-10-12 21:16:13 +02:00
Simon Wilkening
de0b2a4054 Added boat model for 1x1 boats 2024-10-12 20:41:35 +02:00
Simon Wilkening
67e4c1e805 Added map6 with missing ship 2024-10-12 16:54:39 +02:00
Simon Wilkening
0a66d3cbfd Added map5 ignoring zoc 2024-10-12 16:50:25 +02:00
Simon Wilkening
30d129735c Added map3 with ship out of map
Added map4 with ship colliding each other
2024-10-12 16:31:15 +02:00
Simon Wilkening
5f91ce0947 Server site map loading validation 2024-10-12 16:27:38 +02:00
Simon Wilkening
fae747e504 Server site map loading validation 2024-10-12 15:55:30 +02:00
Simon Wilkening
64834e8bf1 Map generation fixed 2024-10-07 12:26:14 +02:00
Simon Wilkening
8f08e83358 Map generation fixed 2024-10-07 12:25:17 +02:00
Johannes Schmelz
f47cda7dc4 Merge branch 'b_schmelz_johannes' into 'main'
Revert "branched"

See merge request progproj/gruppen-ht24/Gruppe-02!1
2024-10-03 14:03:23 +00:00
Mark Minas
71a4ac8d12 added contents 2024-09-18 17:04:31 +02:00
166 changed files with 408341 additions and 565119 deletions

View File

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

View File

@@ -9,7 +9,7 @@
# #
# Specifies the map used by the opponent in single mode. # Specifies the map used by the opponent in single mode.
# Single mode is activated if this property is set. # 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. # Specifies the map used by the player in single mode.
# The player must define their own map if this property is not set. # The player must define their own map if this property is not set.

View File

@@ -0,0 +1,66 @@
{
"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

@@ -0,0 +1,66 @@
{
"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

@@ -0,0 +1,66 @@
{
"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

@@ -0,0 +1,60 @@
{
"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

@@ -0,0 +1,66 @@
{
"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

@@ -0,0 +1,66 @@
{
"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

@@ -22,7 +22,6 @@ import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles; import com.simsilica.lemur.style.BaseStyles;
import pp.battleship.client.gui.BattleAppState; import pp.battleship.client.gui.BattleAppState;
import pp.battleship.client.gui.EditorAppState; import pp.battleship.client.gui.EditorAppState;
import pp.battleship.client.gui.GameMusic;
import pp.battleship.client.gui.SeaAppState; import pp.battleship.client.gui.SeaAppState;
import pp.battleship.game.client.BattleshipClient; import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ClientGameLogic; import pp.battleship.game.client.ClientGameLogic;
@@ -283,14 +282,15 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
} }
/** /**
* Attaches the background music state and sets its initial enabled state. * Attaches the music state and sets its initial enabled state.
*/ */
private void attachGameMusic() { private void attachGameMusic() {
final GameMusic gameSound = new GameMusic(); final GameMusic gameMusic = new GameMusic();
gameSound.setEnabled(GameMusic.enabledInPreferences()); gameMusic.setEnabled(GameMusic.enabledInPreferences());
stateManager.attach(gameSound); stateManager.attach(gameMusic);
} }
/** /**
* Updates the application state every frame. * Updates the application state every frame.
* This method is called once per frame during the game loop. * This method is called once per frame during the game loop.

View File

@@ -1,4 +1,4 @@
package pp.battleship.client.gui; package pp.battleship.client;
import static pp.util.PreferencesUtils.getPreferences; import static pp.util.PreferencesUtils.getPreferences;
@@ -34,7 +34,7 @@ public class GameMusic extends AbstractAppState{
/** /**
* Checks if sound is enabled in the preferences. * Checks if sound is enabled in the preferences.
* *
* @return float to which the volume is set *
*/ */
public static float volumeInPreferences() { public static float volumeInPreferences() {
return PREFERENCES.getFloat(VOLUME_PREF, 0.5f); return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
@@ -50,7 +50,7 @@ public class GameMusic extends AbstractAppState{
@Override @Override
public void initialize(AppStateManager stateManager, Application app) { public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app); super.initialize(stateManager, app);
music = loadSound(app, "Sound/background.ogg"); music = loadSound(app, "Sound/DasBootMenu.ogg");
setVolume(volumeInPreferences()); setVolume(volumeInPreferences());
music.setLooping(true); music.setLooping(true);
if (isEnabled() && music != null) { if (isEnabled() && music != null) {
@@ -87,15 +87,11 @@ public class GameMusic extends AbstractAppState{
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return; if (isEnabled() == enabled) return;
else if(!isEnabled() && enabled) {
if (music != null) { if (music != null) music.play();
if (enabled) { } else if (isEnabled() && !enabled) {
music.play(); if (music != null) music.stop();
} else {
music.stop();
} }
}
super.setEnabled(enabled); super.setEnabled(enabled);
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
PREFERENCES.putBoolean(ENABLED_PREF, enabled); PREFERENCES.putBoolean(ENABLED_PREF, enabled);
@@ -108,10 +104,6 @@ public class GameMusic extends AbstractAppState{
setEnabled(!isEnabled()); setEnabled(!isEnabled());
} }
/**
* Sets the volume of music
* @param vol the volume to which the music should be set
*/
public void setVolume(float vol){ public void setVolume(float vol){
music.setVolume(vol); music.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol); PREFERENCES.putFloat(VOLUME_PREF, vol);

View File

@@ -34,6 +34,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
private AudioNode splashSound; private AudioNode splashSound;
private AudioNode shipDestroyedSound; private AudioNode shipDestroyedSound;
private AudioNode explosionSound; private AudioNode explosionSound;
private AudioNode shellFlyingSound;
/** /**
* Checks if sound is enabled in the preferences. * Checks if sound is enabled in the preferences.
@@ -78,6 +79,8 @@ public class GameSound extends AbstractAppState implements GameEventListener {
shipDestroyedSound = loadSound(app, "Sound/Effects/sunken.wav"); //NON-NLS shipDestroyedSound = loadSound(app, "Sound/Effects/sunken.wav"); //NON-NLS
splashSound = loadSound(app, "Sound/Effects/splash.wav"); //NON-NLS splashSound = loadSound(app, "Sound/Effects/splash.wav"); //NON-NLS
explosionSound = loadSound(app, "Sound/Effects/explosion.wav"); //NON-NLS explosionSound = loadSound(app, "Sound/Effects/explosion.wav"); //NON-NLS
shellFlyingSound = loadSound(app, "Sound/Effects/shell_flying.wav");
} }
/** /**
@@ -124,12 +127,28 @@ public class GameSound extends AbstractAppState implements GameEventListener {
shipDestroyedSound.playInstance(); 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 @Override
public void receivedEvent(SoundEvent event) { public void receivedEvent(SoundEvent event) {
switch (event.sound()) { switch (event.sound()) {
case EXPLOSION -> explosion(); case EXPLOSION -> explosion();
case SPLASH -> splash(); case SPLASH -> splash();
case DESTROYED_SHIP -> shipDestroyed(); case DESTROYED_SHIP -> shipDestroyed();
case SHELL_FLYING -> shellFly();
} }
} }
} }

View File

@@ -11,13 +11,13 @@ import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox; import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.battleship.client.gui.GameMusic;
import pp.battleship.client.gui.VolumeSlider;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel; import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog; import pp.dialog.TextInputDialog;
import pp.battleship.client.GameMusic;
import pp.battleship.client.VolumeSlider;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
@@ -54,11 +54,14 @@ class Menu extends Dialog {
addChild(slider); addChild(slider);
addChild(loadButton).addClickCommands(s -> ifTopDialog(this::loadDialog)); addChild(loadButton)
addChild(saveButton).addClickCommands(s -> ifTopDialog(this::saveDialog)); .addClickCommands(s -> ifTopDialog(this::loadDialog));
addChild(new Button(lookup("menu.return-to-game"))).addClickCommands(s -> ifTopDialog(this::close)); addChild(saveButton)
addChild(new Button(lookup("menu.quit"))).addClickCommands(s -> ifTopDialog(app::closeApp)); .addClickCommands(s -> ifTopDialog(this::saveDialog));
addChild(new Button(lookup("menu.return-to-game")))
.addClickCommands(s -> ifTopDialog(this::close));
addChild(new Button(lookup("menu.quit")))
.addClickCommands(s -> ifTopDialog(app::closeApp));
update(); update();
} }
@@ -71,11 +74,6 @@ class Menu extends Dialog {
saveButton.setEnabled(app.getGameLogic().maySaveMap()); 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. * As an escape action, this method closes the menu if it is the top dialog.
*/ */
@@ -151,4 +149,13 @@ class Menu extends Dialog {
private void saveDialog() { private void saveDialog() {
fileDialog(app.getGameLogic()::saveMap, lookup("menu.map.save")); 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

@@ -12,7 +12,6 @@ import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField; import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import pp.battleship.server.BattleshipServer; import pp.battleship.server.BattleshipServer;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.DialogBuilder; import pp.dialog.DialogBuilder;

View File

@@ -1,20 +1,13 @@
package pp.battleship.client.gui; package pp.battleship.client;
import com.simsilica.lemur.Slider; import com.simsilica.lemur.Slider;
/**
* The VolumeSlider class represents the Volume Slider in the Menu.
* It extends the Slider class and provides functionalities for setting the music volume,
* with the help of the Slider in the GUI
*/
public class VolumeSlider extends Slider { public class VolumeSlider extends Slider {
private final GameMusic music; private final GameMusic music;
private double vol; private double vol;
/**
* Constructs the Volume Slider for the Menu dialog
* @param music the music instance
*/
public VolumeSlider(GameMusic music) { public VolumeSlider(GameMusic music) {
super(); super();
this.music = music; this.music = music;
@@ -22,14 +15,10 @@ public class VolumeSlider extends Slider {
getModel().setPercent(vol); getModel().setPercent(vol);
} }
/**
* when triggered it updates the volume to the value set with the slider
*/
public void update() { public void update() {
if (vol != getModel().getPercent()) { if (vol != getModel().getPercent()) {
vol = getModel().getPercent(); vol = getModel().getPercent();
music.setVolume( (float) vol); music.setVolume( (float) vol);
} }
} }
} }

View File

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

View File

@@ -7,13 +7,20 @@
package pp.battleship.client.gui; 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.ColorRGBA;
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.shape.Sphere;
import pp.battleship.model.Battleship; import pp.battleship.model.Battleship;
import pp.battleship.model.Shell;
import pp.battleship.model.Shot; import pp.battleship.model.Shot;
import pp.util.Position; import pp.util.Position;
import static com.jme3.material.Materials.UNSHADED;
/** /**
* Synchronizes the visual representation of the ship map with the game model. * Synchronizes the visual representation of the ship map with the game model.
@@ -122,4 +129,25 @@ class MapViewSynchronizer extends ShipMapSynchronizer {
private Geometry shipLine(float x1, float y1, float x2, float y2, ColorRGBA color) { 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); 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;
}
} }

View File

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

View File

@@ -20,6 +20,7 @@ import com.jme3.scene.shape.Cylinder;
import pp.battleship.client.BattleshipApp; import pp.battleship.client.BattleshipApp;
import pp.battleship.model.Battleship; import pp.battleship.model.Battleship;
import pp.battleship.model.Rotation; import pp.battleship.model.Rotation;
import pp.battleship.model.Shell;
import pp.battleship.model.ShipMap; import pp.battleship.model.ShipMap;
import pp.battleship.model.Shot; import pp.battleship.model.Shot;
@@ -36,9 +37,10 @@ import static pp.util.FloatMath.PI;
class SeaSynchronizer extends ShipMapSynchronizer { class SeaSynchronizer extends ShipMapSynchronizer {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS 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 KING_GEORGE_V_MODEL = "Models/KingGeorgeV/KingGeorgeV.j3o"; //NON-NLS
private static final String BOAT_SMALL_MODEL = "Models/BoatSmall/12219_boat_v2_L2.j3o"; //NON-NLS private static final String SMALL_SHIP_MODEL = "Models/SmallShip/SmallShip.j3o"; //NON-NLS
private static final String CV_MODEL = "Models/CV/CV.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 BATTLE_MODEL = "Models/Battle/Battle.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 COLOR = "Color"; //NON-NLS private static final String COLOR = "Color"; //NON-NLS
private static final String SHIP = "ship"; //NON-NLS private static final String SHIP = "ship"; //NON-NLS
private static final String SHOT = "shot"; //NON-NLS private static final String SHOT = "shot"; //NON-NLS
@@ -48,7 +50,8 @@ class SeaSynchronizer extends ShipMapSynchronizer {
private final ShipMap map; private final ShipMap map;
private final BattleshipApp app; private final BattleshipApp app;
private final ParticleEffectFactory particleFactory; private final ParticleCreator particlecreator;
/** /**
* Constructs a {@code SeaSynchronizer} object with the specified application, root node, and ship map. * Constructs a {@code SeaSynchronizer} object with the specified application, root node, and ship map.
@@ -61,7 +64,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
super(app.getGameLogic().getOwnMap(), root); super(app.getGameLogic().getOwnMap(), root);
this.app = app; this.app = app;
this.map = map; this.map = map;
this.particleFactory = new ParticleEffectFactory(app); this.particlecreator = new ParticleCreator(app);
addExisting(); addExisting();
} }
@@ -88,7 +91,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
Node shotNode = new Node("ShotNode"); Node shotNode = new Node("ShotNode");
Geometry shotCylinder = createCylinder(shot); Geometry shotCylinder = createCylinder(shot);
shotNode.attachChild(shotCylinder); shotNode.attachChild(shotCylinder);
ParticleEmitter waterSplash = particleFactory.createWaterSplash(); ParticleEmitter waterSplash = particlecreator.createWaterSplash();
waterSplash.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f); waterSplash.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
shotNode.attachChild(waterSplash); shotNode.attachChild(waterSplash);
waterSplash.emitAllParticles(); waterSplash.emitAllParticles();
@@ -101,45 +104,46 @@ class SeaSynchronizer extends ShipMapSynchronizer {
* @param ship the ship to be sunk * @param ship the ship to be sunk
*/ */
private void sinkAndRemoveShip(Battleship ship) { private void sinkAndRemoveShip(Battleship ship) {
Battleship wilkeningklaunichtmeinencode = ship; Battleship dasIstGelebteTeamarbeit = ship;
final Node shipNode = (Node) getSpatial(wilkeningklaunichtmeinencode); final Node shipNode = (Node) getSpatial(dasIstGelebteTeamarbeit);
if (shipNode == null) return; if (shipNode == null) return;
// Add sinking control to animate the sinking // Add sinking control to animate the sinking
shipNode.addControl(new SinkingControl(shipNode)); shipNode.addControl(new SinkControl(shipNode));
// Add particle effects // Add particle effects
ParticleEmitter bubbles = particleFactory.createWaterSplash(); ParticleEmitter bubbles = particlecreator.createWaterSplash();
bubbles.setLocalTranslation(shipNode.getLocalTranslation()); bubbles.setLocalTranslation(shipNode.getLocalTranslation());
shipNode.attachChild(bubbles); shipNode.attachChild(bubbles);
bubbles.emitAllParticles(); bubbles.emitAllParticles();
} }
/** /**
* Handles a hit by attaching its representation to the node that * 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. * contains the ship model as a child so that it moves with the ship.
* *
* @param shot a hit * @param shot a hit
* @return always null to prevent the representation from being attached to the items node as well * @return always null to prevent the representation from being attached
* to the items node as well
*/ */
private Spatial handleHit(Shot shot) { private Spatial handleHit(Shot shot) {
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship"); final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node"); final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
// Create a new node specifically for the hit effects // Create a new node specifically for the hit effects
Node hitEffectNode = new Node("HitEffectNode"); Node hitEffectNode = new Node("HitEffectNode");
// Create particle effects // Create particle effects
ParticleEmitter flame = particleFactory.createFlame(); ParticleEmitter flame = particlecreator.createFlame();
ParticleEmitter flash = particleFactory.createFlash(); ParticleEmitter flash = particlecreator.createFlash();
ParticleEmitter spark = particleFactory.createSpark(); ParticleEmitter spark = particlecreator.createSpark();
ParticleEmitter roundSpark = particleFactory.createRoundSpark(); ParticleEmitter roundSpark = particlecreator.createRoundSpark();
ParticleEmitter smokeTrail = particleFactory.createSmokeTrail(); ParticleEmitter smokeTrail = particlecreator.createSmokeTrail();
ParticleEmitter debris = particleFactory.createDebris(); ParticleEmitter debris = particlecreator.createDebris();
ParticleEmitter shockwave = particleFactory.createShockwave(); ParticleEmitter shockwave = particlecreator.createShockwave();
ParticleEmitter movingSmoke = particleFactory.createMovingSmokeEmitter(); ParticleEmitter movingSmoke = particlecreator.createMovingSmokeEmitter();
// Attach all effects to the hitEffectNode // Attach all effects to the hitEffectNode
hitEffectNode.attachChild(flame); hitEffectNode.attachChild(flame);
@@ -227,12 +231,18 @@ class SeaSynchronizer extends ShipMapSynchronizer {
*/ */
private Spatial createShip(Battleship ship) { private Spatial createShip(Battleship ship) {
switch (ship.getLength()) { switch (ship.getLength()) {
case 4: return createBattleship(ship); case 4:
case 3: return createCV(ship); return createBattleship(ship);
case 2: return createBattle(ship); case 3:
case 1: return createSmallship(ship); return createLargeship(ship);
default: return createBox(ship); case 2:
return createMediumship(ship);
case 1:
return createSmallship(ship);
default:
return createBox(ship);
} }
} }
/** /**
@@ -282,20 +292,13 @@ class SeaSynchronizer extends ShipMapSynchronizer {
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f); model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(1.48f); model.scale(1.48f);
// model.scale(0.0007f);
model.setShadowMode(ShadowMode.CastAndReceive); model.setShadowMode(ShadowMode.CastAndReceive);
return model; return model;
} }
/**
* Creates a detailed 3D model to represent a small tug boat.
*
* @param ship the battleship to be represented
* @return the spatial representing a small tug boat
*/
private Spatial createSmallship(Battleship ship) { private Spatial createSmallship(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(BOAT_SMALL_MODEL); final Spatial model = app.getAssetManager().loadModel(SMALL_SHIP_MODEL);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f); model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(0.0005f); model.scale(0.0005f);
@@ -304,35 +307,21 @@ class SeaSynchronizer extends ShipMapSynchronizer {
return model; return model;
} }
/** private Spatial createMediumship(Battleship ship) {
* Creates a detailed 3D model to represent a "German WWII UBoat". final Spatial model = app.getAssetManager().loadModel(U_BOAT_MODEL);
*
* @param ship the battleship to be represented
* @return the spatial representing the "German WWII UBoat"
*/
private Spatial createCV(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(CV_MODEL);
model.rotate(0f, calculateRotationAngle(ship.getRot()), 0f); model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.move(0f, 0.25f, 0f); model.scale(0.27f);
model.scale(0.85f);
model.setShadowMode(ShadowMode.CastAndReceive); model.setShadowMode(ShadowMode.CastAndReceive);
return model; return model;
} }
/** private Spatial createLargeship(Battleship ship) {
* Creates a detailed 3D model to represent a battleship. final Spatial model = app.getAssetManager().loadModel(TUG_BOAT_MODEL);
*
* @param ship the battleship to be represented
* @return the spatial representing a battleship
*/
private Spatial createBattle(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(BATTLE_MODEL);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f); model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.move(0f, -0.06f, 0f); model.scale(0.0004f);
model.scale(0.27f);
model.setShadowMode(ShadowMode.CastAndReceive); model.setShadowMode(ShadowMode.CastAndReceive);
return model; return model;
@@ -352,4 +341,25 @@ class SeaSynchronizer extends ShipMapSynchronizer {
case UP -> PI; 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

@@ -0,0 +1,49 @@
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

@@ -0,0 +1,50 @@
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

@@ -10,7 +10,7 @@ import com.jme3.scene.Node;
* Control that handles the sinking effect for destroyed ships. * Control that handles the sinking effect for destroyed ships.
* It will gradually move the ship downwards and then remove it from the scene. * It will gradually move the ship downwards and then remove it from the scene.
*/ */
class SinkingControl extends AbstractControl { class SinkControl extends AbstractControl {
private static final float SINK_DURATION = 5f; // Duration of the sinking animation 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 static final float SINK_SPEED = 0.1f; // Speed at which the ship sinks
private float elapsedTime = 0; private float elapsedTime = 0;
@@ -21,7 +21,7 @@ class SinkingControl extends AbstractControl {
* Constructs a {@code SinkingControl} object with the shipNode to be to be sunk * Constructs a {@code SinkingControl} object with the shipNode to be to be sunk
* @param shipNode the node to handeld * @param shipNode the node to handeld
*/ */
public SinkingControl(Node shipNode) { public SinkControl(Node shipNode) {
this.shipNode = shipNode; this.shipNode = shipNode;
} }
@@ -51,3 +51,4 @@ class SinkingControl extends AbstractControl {
// No rendering-related code needed // No rendering-related code needed
} }
} }

View File

@@ -19,6 +19,7 @@ import pp.battleship.game.server.Player;
import pp.battleship.game.server.ServerGameLogic; import pp.battleship.game.server.ServerGameLogic;
import pp.battleship.game.server.ServerSender; import pp.battleship.game.server.ServerSender;
import pp.battleship.message.client.ClientMessage; import pp.battleship.message.client.ClientMessage;
import pp.battleship.message.client.AnimationFinishedMessage;
import pp.battleship.message.client.MapMessage; import pp.battleship.message.client.MapMessage;
import pp.battleship.message.client.ShootMessage; import pp.battleship.message.client.ShootMessage;
import pp.battleship.message.server.EffectMessage; import pp.battleship.message.server.EffectMessage;
@@ -115,6 +116,7 @@ public class BattleshipServer implements MessageListener<HostedConnection>, Conn
Serializer.registerClass(MapMessage.class); Serializer.registerClass(MapMessage.class);
Serializer.registerClass(ShootMessage.class); Serializer.registerClass(ShootMessage.class);
Serializer.registerClass(EffectMessage.class); Serializer.registerClass(EffectMessage.class);
Serializer.registerClass(AnimationFinishedMessage.class);
Serializer.registerClass(Battleship.class); Serializer.registerClass(Battleship.class);
Serializer.registerClass(IntPoint.class); Serializer.registerClass(IntPoint.class);
Serializer.registerClass(Shot.class); Serializer.registerClass(Shot.class);
@@ -123,6 +125,7 @@ public class BattleshipServer implements MessageListener<HostedConnection>, Conn
private void registerListeners() { private void registerListeners() {
myServer.addMessageListener(this, MapMessage.class); myServer.addMessageListener(this, MapMessage.class);
myServer.addMessageListener(this, ShootMessage.class); myServer.addMessageListener(this, ShootMessage.class);
myServer.addMessageListener(this, AnimationFinishedMessage.class);
myServer.addConnectionListener(this); myServer.addConnectionListener(this);
} }
@@ -177,3 +180,4 @@ public class BattleshipServer implements MessageListener<HostedConnection>, Conn
LOGGER.log(Level.ERROR, "there is no connection with id={0}", id); //NON-NLS LOGGER.log(Level.ERROR, "there is no connection with id={0}", id); //NON-NLS
} }
} }

View File

@@ -15,3 +15,4 @@ record ReceivedMessage(ClientMessage message, int from) {
message.accept(interpreter, from); message.accept(interpreter, from);
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -42,10 +42,9 @@ public class ModelExporter extends SimpleApplication {
@Override @Override
public void simpleInitApp() { public void simpleInitApp() {
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS
export("Models/BoatSmall/12219_boat_v2_L2.obj", "BoatSmall.j3o"); //NON-NLS export("Models/SmallShip/12219_boat_v2_L2.obj", "SmallShip.j3o"); //NON-NLS
export("Models/Battle/14084_WWII_Ship_German_Type_II_U-boat_v2_L1.obj", "Battle.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/CV/essex_scb-125_generic.obj", "CV.j3o"); //NON-NLS export("Models/TugBoat/12218_tugboat_v1_L2.obj", "TugBoat.j3o"); //NON-NLS
stop(); stop();
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

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