finished 12
@@ -26,7 +26,10 @@ map.own=maps/map1.json
|
|||||||
robot.targets=2, 0,\
|
robot.targets=2, 0,\
|
||||||
2, 1,\
|
2, 1,\
|
||||||
2, 2,\
|
2, 2,\
|
||||||
2, 3
|
2, 3,\
|
||||||
|
2, 4,\
|
||||||
|
2, 5,\
|
||||||
|
2, 6
|
||||||
#
|
#
|
||||||
# Delay in milliseconds between each shot fired by the RobotClient.
|
# Delay in milliseconds between each shot fired by the RobotClient.
|
||||||
robot.delay=500
|
robot.delay=500
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.System.Logger;
|
import java.lang.System.Logger;
|
||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.LogManager;
|
import java.util.logging.LogManager;
|
||||||
@@ -122,6 +125,8 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
|
|||||||
*/
|
*/
|
||||||
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
|
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
|
||||||
|
|
||||||
|
private EffectHandler effectHandler;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Configure logging
|
// Configure logging
|
||||||
LogManager manager = LogManager.getLogManager();
|
LogManager manager = LogManager.getLogManager();
|
||||||
@@ -155,6 +160,7 @@ private BattleshipApp() {
|
|||||||
logic.addListener(this);
|
logic.addListener(this);
|
||||||
setShowSettings(config.getShowSettings());
|
setShowSettings(config.getShowSettings());
|
||||||
setSettings(makeSettings());
|
setSettings(makeSettings());
|
||||||
|
effectHandler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,6 +230,7 @@ public void simpleInitApp() {
|
|||||||
setupInput();
|
setupInput();
|
||||||
setupStates();
|
setupStates();
|
||||||
setupGui();
|
setupGui();
|
||||||
|
effectHandler = new EffectHandler(this);
|
||||||
serverConnection.connect();
|
serverConnection.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,6 +309,19 @@ public void simpleUpdate(float tpf) {
|
|||||||
super.simpleUpdate(tpf);
|
super.simpleUpdate(tpf);
|
||||||
dialogManager.update(tpf);
|
dialogManager.update(tpf);
|
||||||
logic.update(tpf);
|
logic.update(tpf);
|
||||||
|
handleTimers(tpf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleTimers(float tpf) {
|
||||||
|
Iterator<Timer> iter = timerList.iterator();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Timer next = iter.next();
|
||||||
|
next.update(tpf);
|
||||||
|
if (next.isFinished()){
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,4 +457,14 @@ void errorDialog(String errorMessage) {
|
|||||||
.build()
|
.build()
|
||||||
.open();
|
.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EffectHandler getEffectHandler(){
|
||||||
|
return effectHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Timer> timerList = new ArrayList<>();
|
||||||
|
|
||||||
|
public void setTimer(float time, Runnable runnable){
|
||||||
|
timerList.add(new Timer(time, runnable));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package pp.battleship.client;
|
||||||
|
|
||||||
|
import com.jme3.app.Application;
|
||||||
|
import com.jme3.effect.ParticleEmitter;
|
||||||
|
import com.jme3.effect.ParticleMesh;
|
||||||
|
import com.jme3.effect.influencers.RadialParticleInfluencer;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
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 pp.battleship.model.Battleship;
|
||||||
|
import pp.battleship.model.IntPoint;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class EffectHandler {
|
||||||
|
private BattleshipApp app;
|
||||||
|
private Map<Battleship, List<ParticleEmitter>> effects;
|
||||||
|
|
||||||
|
|
||||||
|
public EffectHandler(BattleshipApp app){
|
||||||
|
this.app = app;
|
||||||
|
effects = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node createFire(Vector3f point, Battleship ship){
|
||||||
|
Node parent = new Node();
|
||||||
|
parent.setLocalTranslation(point);
|
||||||
|
|
||||||
|
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 50);
|
||||||
|
Material matRed = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
|
||||||
|
matRed.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/flame.png"));
|
||||||
|
fire.setMaterial(matRed);
|
||||||
|
fire.setImagesX(2);
|
||||||
|
fire.setImagesY(2);
|
||||||
|
fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f));
|
||||||
|
fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f));
|
||||||
|
fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 1.5f, 0));
|
||||||
|
fire.setStartSize(.4f);
|
||||||
|
fire.setEndSize(0.05f);
|
||||||
|
fire.setGravity(0, 0, 0);
|
||||||
|
fire.setLowLife(1f);
|
||||||
|
fire.setHighLife(2f);
|
||||||
|
fire.getParticleInfluencer().setVelocityVariation(0.2f);
|
||||||
|
parent.attachChild(fire);
|
||||||
|
|
||||||
|
ParticleEmitter smoke = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 600);
|
||||||
|
Material matBlack = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
|
||||||
|
matBlack.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Smoke/Smoke.png"));
|
||||||
|
smoke.setMaterial(matBlack);
|
||||||
|
smoke.setImagesX(15);
|
||||||
|
smoke.setImagesY(1);
|
||||||
|
smoke.setEndColor(new ColorRGBA(1f,1f,1f,0f));
|
||||||
|
smoke.setStartColor(new ColorRGBA(0.5f,0.5f,0.5f,0.5f));
|
||||||
|
smoke.getParticleInfluencer().setInitialVelocity(new Vector3f(0,1f, 0));
|
||||||
|
smoke.setStartSize(.2f);
|
||||||
|
smoke.setEndSize(0.1f);
|
||||||
|
smoke.setGravity(0, 0, 0);
|
||||||
|
smoke.setLowLife(1f);
|
||||||
|
smoke.setHighLife(5f);
|
||||||
|
smoke.getParticleInfluencer().setVelocityVariation(0.25f);
|
||||||
|
parent.attachChild(smoke);
|
||||||
|
|
||||||
|
|
||||||
|
List<ParticleEmitter> oldEffects = new ArrayList<>(effects.getOrDefault(ship,new ArrayList<>()));
|
||||||
|
oldEffects.add(fire);
|
||||||
|
oldEffects.add(smoke);
|
||||||
|
effects.put(ship,oldEffects);
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroyShip(Battleship ship){
|
||||||
|
for (ParticleEmitter emitter: effects.get(ship)){
|
||||||
|
emitter.setParticlesPerSec(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Geometry waterSplash(Vector3f pos){
|
||||||
|
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 100);
|
||||||
|
Material matRed = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
|
||||||
|
matRed.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/flash.png"));
|
||||||
|
fire.setMaterial(matRed);
|
||||||
|
fire.setImagesX(2);
|
||||||
|
fire.setImagesY(2); // 2x2 texture animation
|
||||||
|
fire.setEndColor(new ColorRGBA(0.3f, 0.8f, 1f, 0f));
|
||||||
|
fire.setStartColor(new ColorRGBA(0f, 0f, 1f, 1f));
|
||||||
|
RadialParticleInfluencer inf = new RadialParticleInfluencer();
|
||||||
|
inf.setRadialVelocity(5);
|
||||||
|
inf.setVelocityVariation(0.3f);
|
||||||
|
inf.setInitialVelocity(new Vector3f(0,3,0));
|
||||||
|
fire.setParticleInfluencer(inf);
|
||||||
|
fire.setStartSize(.6f);
|
||||||
|
fire.setEndSize(0.05f);
|
||||||
|
fire.setGravity(0, 4f, 0);
|
||||||
|
fire.setLowLife(1f);
|
||||||
|
fire.setHighLife(1.5f);
|
||||||
|
fire.setLocalTranslation(pos);
|
||||||
|
fire.emitAllParticles();
|
||||||
|
fire.setParticlesPerSec(0);
|
||||||
|
app.setTimer(2,()->deleteSplash(fire));
|
||||||
|
return fire;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteSplash(Geometry splash){
|
||||||
|
splash.getParent().detachChild(splash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Geometry debrisSplash(Vector3f pos){
|
||||||
|
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 50);
|
||||||
|
Material matRed = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
|
||||||
|
matRed.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/Debris.png"));
|
||||||
|
fire.setMaterial(matRed);
|
||||||
|
fire.setImagesX(3);
|
||||||
|
fire.setImagesY(3); // 2x2 texture animation
|
||||||
|
fire.setEndColor(new ColorRGBA(0.1f, 0.1f, 0.1f, 0f));
|
||||||
|
fire.setStartColor(new ColorRGBA(0.5f, 0.5f, 0.5f, .8f));
|
||||||
|
fire.setStartSize(0.1f);
|
||||||
|
fire.setEndSize(0.5f);
|
||||||
|
fire.setGravity(0, 2f, 0);
|
||||||
|
fire.setLowLife(1f);
|
||||||
|
fire.setHighLife(1.5f);
|
||||||
|
fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0,2f,0));
|
||||||
|
fire.getParticleInfluencer().setVelocityVariation(.5f);
|
||||||
|
|
||||||
|
|
||||||
|
fire.setLocalTranslation(pos);
|
||||||
|
|
||||||
|
fire.emitAllParticles();
|
||||||
|
fire.setParticlesPerSec(0);
|
||||||
|
|
||||||
|
return fire;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,18 +3,13 @@
|
|||||||
import com.jme3.app.Application;
|
import com.jme3.app.Application;
|
||||||
import com.jme3.app.state.AbstractAppState;
|
import com.jme3.app.state.AbstractAppState;
|
||||||
import com.jme3.app.state.AppStateManager;
|
import com.jme3.app.state.AppStateManager;
|
||||||
import com.jme3.asset.AssetLoadException;
|
|
||||||
import com.jme3.asset.AssetNotFoundException;
|
|
||||||
import com.jme3.audio.AudioData;
|
|
||||||
import com.jme3.audio.AudioNode;
|
import com.jme3.audio.AudioNode;
|
||||||
import pp.battleship.notification.GameEventListener;
|
import pp.battleship.notification.GameEventListener;
|
||||||
|
|
||||||
import java.lang.System.Logger;
|
|
||||||
import java.lang.System.Logger.Level;
|
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
import static pp.JmeUtil.loadSound;
|
||||||
import static pp.util.PreferencesUtils.getPreferences;
|
import static pp.util.PreferencesUtils.getPreferences;
|
||||||
import static pp.util.Util.loadSound;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An application state that plays sounds.
|
* An application state that plays sounds.
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
import static pp.JmeUtil.loadSound;
|
||||||
import static pp.util.PreferencesUtils.getPreferences;
|
import static pp.util.PreferencesUtils.getPreferences;
|
||||||
import static pp.util.Util.loadSound;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An application state that plays sounds.
|
* An application state that plays sounds.
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package pp.battleship.client;
|
||||||
|
|
||||||
|
public class Timer {
|
||||||
|
private float time;
|
||||||
|
private final Runnable runnable;
|
||||||
|
private boolean finished;
|
||||||
|
|
||||||
|
public Timer(float time, Runnable runnable){
|
||||||
|
this.time = time;
|
||||||
|
this.runnable = runnable;
|
||||||
|
this.finished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(float delta){
|
||||||
|
if(!finished){
|
||||||
|
time -= delta;
|
||||||
|
if(time < 0){
|
||||||
|
finished = true;
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished(){
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,17 +7,13 @@
|
|||||||
|
|
||||||
package pp.battleship.client.gui;
|
package pp.battleship.client.gui;
|
||||||
|
|
||||||
import com.jme3.bounding.BoundingVolume;
|
|
||||||
import com.jme3.collision.Collidable;
|
|
||||||
import com.jme3.collision.CollisionResults;
|
|
||||||
import com.jme3.collision.UnsupportedCollisionException;
|
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.material.RenderState.BlendMode;
|
import com.jme3.material.RenderState.BlendMode;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.SceneGraphVisitor;
|
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.shape.Box;
|
import com.jme3.scene.shape.Box;
|
||||||
import com.jme3.scene.shape.Cylinder;
|
import com.jme3.scene.shape.Cylinder;
|
||||||
@@ -27,8 +23,6 @@
|
|||||||
import pp.battleship.model.ShipMap;
|
import pp.battleship.model.ShipMap;
|
||||||
import pp.battleship.model.Shot;
|
import pp.battleship.model.Shot;
|
||||||
|
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static pp.util.FloatMath.HALF_PI;
|
import static pp.util.FloatMath.HALF_PI;
|
||||||
import static pp.util.FloatMath.PI;
|
import static pp.util.FloatMath.PI;
|
||||||
@@ -76,7 +70,11 @@ public SeaSynchronizer(BattleshipApp app, Node root, ShipMap map) {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Spatial visit(Shot shot) {
|
public Spatial visit(Shot shot) {
|
||||||
return shot.isHit() ? handleHit(shot) : createCylinder(shot);
|
return shot.isHit() ? handleHit(shot) : handleMiss(shot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Spatial handleMiss(Shot shot) {
|
||||||
|
return app.getEffectHandler().waterSplash(mapToWorldCord(shot.getX(), shot.getY()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,13 +89,24 @@ 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");
|
||||||
|
|
||||||
final Geometry representation = createCylinder(shot);
|
shipNode.getControl(ShipEffectControl.class).hit(shot);
|
||||||
representation.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
|
if(ship.isDestroyed()){
|
||||||
shipNode.attachChild(representation);
|
shipNode.getControl(ShipEffectControl.class).destroyed();
|
||||||
|
shipNode.getControl(ShipMovementControl.class).destroyed();
|
||||||
|
app.setTimer(9,()->handleShipDestroy(shipNode));
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleShipDestroy(Node shipNode) {
|
||||||
|
shipNode.getParent().detachChild(shipNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f mapToWorldCord(int x, int y){
|
||||||
|
return new Vector3f(y+0.5f, 0, x+0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a cylinder geometry representing the specified shot.
|
* Creates a cylinder geometry representing the specified shot.
|
||||||
* The appearance of the cylinder depends on whether the shot is a hit or a miss.
|
* The appearance of the cylinder depends on whether the shot is a hit or a miss.
|
||||||
@@ -136,7 +145,8 @@ public Spatial visit(Battleship ship) {
|
|||||||
final float x = 0.5f * (ship.getMinY() + ship.getMaxY() + 1f);
|
final float x = 0.5f * (ship.getMinY() + ship.getMaxY() + 1f);
|
||||||
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
|
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
|
||||||
node.setLocalTranslation(x, 0f, z);
|
node.setLocalTranslation(x, 0f, z);
|
||||||
node.addControl(new ShipControl(ship));
|
node.addControl(new ShipMovementControl(ship));
|
||||||
|
node.addControl(new ShipEffectControl(node, ship, app));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package pp.battleship.client.gui;
|
||||||
|
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.control.AbstractControl;
|
||||||
|
import pp.battleship.client.BattleshipApp;
|
||||||
|
import pp.battleship.client.EffectHandler;
|
||||||
|
import pp.battleship.model.Battleship;
|
||||||
|
import pp.battleship.model.Shot;
|
||||||
|
|
||||||
|
public class ShipEffectControl extends AbstractControl {
|
||||||
|
private final Node shipNode;
|
||||||
|
private final Battleship battleship;
|
||||||
|
private final BattleshipApp app;
|
||||||
|
|
||||||
|
public ShipEffectControl(Node node, Battleship battleship, BattleshipApp app){
|
||||||
|
this.shipNode = node;
|
||||||
|
this.battleship = battleship;
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlUpdate(float tpf) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hit(Shot shot){
|
||||||
|
Vector3f shipNodePos = shipNode.getLocalTranslation();
|
||||||
|
Vector3f shotWorld = mapToWorldCord(shot.getX(),shot.getY());
|
||||||
|
Vector3f firePos = shotWorld.subtract(shipNodePos);
|
||||||
|
shipNode.attachChild(app.getEffectHandler().createFire(firePos, battleship));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f mapToWorldCord(int x, int y){
|
||||||
|
return new Vector3f(y+0.5f, 0, x+0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroyed() {
|
||||||
|
shipNode.attachChild(app.getEffectHandler().debrisSplash(shipNode.getLocalTranslation()));
|
||||||
|
app.setTimer(4,this::stopEffects);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopEffects(){
|
||||||
|
app.getEffectHandler().destroyShip(battleship);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,10 @@
|
|||||||
* Controls the oscillating pitch motion of a battleship model in the game.
|
* Controls the oscillating pitch motion of a battleship model in the game.
|
||||||
* The ship oscillates to simulate a realistic movement on water, based on its orientation and length.
|
* The ship oscillates to simulate a realistic movement on water, based on its orientation and length.
|
||||||
*/
|
*/
|
||||||
class ShipControl extends AbstractControl {
|
class ShipMovementControl extends AbstractControl {
|
||||||
|
private final float sinkingSpeed = 0.04f;
|
||||||
|
private final float sinkRotSpeed = 0.1f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The axis of rotation for the ship's pitch (tilting forward and backward).
|
* The axis of rotation for the ship's pitch (tilting forward and backward).
|
||||||
*/
|
*/
|
||||||
@@ -48,14 +51,17 @@ class ShipControl extends AbstractControl {
|
|||||||
*/
|
*/
|
||||||
private float time;
|
private float time;
|
||||||
|
|
||||||
|
private boolean sinking;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new ShipControl instance for the specified Battleship.
|
* Constructs a new ShipMovementControl instance for the specified Battleship.
|
||||||
* The ship's orientation determines the axis of rotation, while its length influences
|
* The ship's orientation determines the axis of rotation, while its length influences
|
||||||
* the cycle duration and amplitude of the oscillation.
|
* the cycle duration and amplitude of the oscillation.
|
||||||
*
|
*
|
||||||
* @param ship the Battleship object to control
|
* @param ship the Battleship object to control
|
||||||
*/
|
*/
|
||||||
public ShipControl(Battleship ship) {
|
public ShipMovementControl(Battleship ship) {
|
||||||
|
sinking = false;
|
||||||
// Determine the axis of rotation based on the ship's orientation
|
// Determine the axis of rotation based on the ship's orientation
|
||||||
axis = switch (ship.getRot()) {
|
axis = switch (ship.getRot()) {
|
||||||
case LEFT, RIGHT -> Vector3f.UNIT_X;
|
case LEFT, RIGHT -> Vector3f.UNIT_X;
|
||||||
@@ -75,6 +81,18 @@ public ShipControl(Battleship ship) {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
|
if(sinking) handleSinking(tpf);
|
||||||
|
else handlePitch(tpf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSinking(float tpf) {
|
||||||
|
if (spatial == null) return;
|
||||||
|
|
||||||
|
spatial.setLocalTranslation(spatial.getLocalTranslation().add(new Vector3f(0,-1,0).mult(tpf * sinkingSpeed)));
|
||||||
|
spatial.rotate(tpf * sinkRotSpeed, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePitch(float tpf){
|
||||||
// If spatial is null, do nothing
|
// If spatial is null, do nothing
|
||||||
if (spatial == null) return;
|
if (spatial == null) return;
|
||||||
|
|
||||||
@@ -103,4 +121,8 @@ protected void controlUpdate(float tpf) {
|
|||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
// No rendering logic is needed for this control
|
// No rendering logic is needed for this control
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void destroyed() {
|
||||||
|
sinking = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
package pp.util;
|
package pp.util;
|
||||||
|
|
||||||
import com.jme3.app.Application;
|
//import com.jme3.app.Application;
|
||||||
import com.jme3.asset.AssetLoadException;
|
//import com.jme3.asset.AssetLoadException;
|
||||||
import com.jme3.asset.AssetNotFoundException;
|
//import com.jme3.asset.AssetNotFoundException;
|
||||||
import com.jme3.audio.AudioData;
|
//import com.jme3.audio.AudioData;
|
||||||
import com.jme3.audio.AudioNode;
|
//import com.jme3.audio.AudioNode;
|
||||||
|
|
||||||
import java.lang.System.Logger;
|
import java.lang.System.Logger;
|
||||||
import java.lang.System.Logger.Level;
|
//import java.lang.System.Logger.Level;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -25,8 +25,6 @@
|
|||||||
* A class with auxiliary functions.
|
* A class with auxiliary functions.
|
||||||
*/
|
*/
|
||||||
public class Util {
|
public class Util {
|
||||||
private static final Logger LOGGER = System.getLogger(Util.class.getName());
|
|
||||||
|
|
||||||
private Util() { /* do not instantiate */ }
|
private Util() { /* do not instantiate */ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,24 +95,4 @@ public static <T, E extends T> Set<T> add(Set<T> set, E element) {
|
|||||||
newSet.add(element);
|
newSet.add(element);
|
||||||
return newSet;
|
return newSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a sound from the specified file.
|
|
||||||
*
|
|
||||||
* @param app The application
|
|
||||||
* @param name The name of the sound file.
|
|
||||||
* @return The loaded AudioNode.
|
|
||||||
*/
|
|
||||||
public static AudioNode loadSound(Application app, String name) {
|
|
||||||
try {
|
|
||||||
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
|
||||||
sound.setLooping(false);
|
|
||||||
sound.setPositional(false);
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
catch (AssetLoadException | AssetNotFoundException ex) {
|
|
||||||
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
37
Projekte/jme-common/src/main/java/pp/JmeUtil.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package pp;
|
||||||
|
|
||||||
|
import com.jme3.app.Application;
|
||||||
|
import com.jme3.asset.AssetLoadException;
|
||||||
|
import com.jme3.asset.AssetNotFoundException;
|
||||||
|
import com.jme3.audio.AudioData;
|
||||||
|
import com.jme3.audio.AudioNode;
|
||||||
|
import pp.util.Util;
|
||||||
|
|
||||||
|
import java.lang.System.Logger;
|
||||||
|
import java.lang.System.Logger.Level;
|
||||||
|
|
||||||
|
public class JmeUtil {
|
||||||
|
private JmeUtil(){ /* Do not initialize */ }
|
||||||
|
|
||||||
|
private static final Logger LOGGER = System.getLogger(Util.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a sound from the specified file.
|
||||||
|
*
|
||||||
|
* @param app The application
|
||||||
|
* @param name The name of the sound file.
|
||||||
|
* @return The loaded AudioNode.
|
||||||
|
*/
|
||||||
|
public static AudioNode loadSound(Application app, String name) {
|
||||||
|
try {
|
||||||
|
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
||||||
|
sound.setLooping(false);
|
||||||
|
sound.setPositional(false);
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
catch (AssetLoadException | AssetNotFoundException ex) {
|
||||||
|
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||