added part solution for exercise 12
added the Effecthandler class to handle the effects for a shot hit or missed added jme3-effects libary and used it to display the effects for the shots minor tweaks the the gui and backgroundmuisc
This commit is contained in:
parent
dca0875ad5
commit
44a25a2e1f
@@ -9,6 +9,7 @@ implementation project(":jme-common")
|
||||
implementation project(":battleship:model")
|
||||
|
||||
implementation libs.jme3.desktop
|
||||
implementation libs.jme3.effects
|
||||
|
||||
runtimeOnly libs.jme3.awt.dialogs
|
||||
runtimeOnly libs.jme3.plugins
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -174,28 +174,28 @@ public boolean isMusicEnabled() {
|
||||
*/
|
||||
public void changeMusic(Music music) {
|
||||
if(music == Music.MENU_THEME && !lastNodePlayed.equals(MENU_MUSIC)) {
|
||||
LOGGER.log(Level.DEBUG, "Received Music change Event {0}", music.toString());
|
||||
LOGGER.log(Level.INFO, "Received Music change Event {0}", music.toString());
|
||||
stop(battleMusic);
|
||||
stop(gameOverMusicL);
|
||||
stop(gameOverMusicV);
|
||||
play(menuMusic);
|
||||
lastNodePlayed = menuMusic.getName();
|
||||
} else if (music == Music.BATTLE_THEME && !lastNodePlayed.equals(BATTLE_MUSIC)) {
|
||||
LOGGER.log(Level.DEBUG, "Received Music change Event {0}", music.toString());
|
||||
LOGGER.log(Level.INFO, "Received Music change Event {0}", music.toString());
|
||||
stop(menuMusic);
|
||||
stop(gameOverMusicL);
|
||||
stop(gameOverMusicV);
|
||||
play(battleMusic);
|
||||
lastNodePlayed = battleMusic.getName();
|
||||
} else if (music == Music.GAME_OVER_THEME_L && !lastNodePlayed.equals(GAME_OVER_MUSIC_L)) {
|
||||
LOGGER.log(Level.DEBUG, "Received Music change Event {0}", music.toString());
|
||||
LOGGER.log(Level.INFO, "Received Music change Event {0}", music.toString());
|
||||
stop(menuMusic);
|
||||
stop(battleMusic);
|
||||
stop(gameOverMusicV);
|
||||
play(gameOverMusicL);
|
||||
lastNodePlayed = gameOverMusicL.getName();
|
||||
} else if (music == Music.GAME_OVER_THEME_V && !lastNodePlayed.equals(GAME_OVER_MUSIC_V)){
|
||||
LOGGER.log(Level.DEBUG, "Received Music change Event {0}", music.toString());
|
||||
LOGGER.log(Level.INFO, "Received Music change Event {0}", music.toString());
|
||||
stop(menuMusic);
|
||||
stop(battleMusic);
|
||||
stop(gameOverMusicL);
|
||||
@@ -211,7 +211,7 @@ public void changeMusic(Music music) {
|
||||
*/
|
||||
@Override
|
||||
public void receivedEvent (MusicEvent music){
|
||||
LOGGER.log(Level.DEBUG, "Received Music change Event {0}", music.toString());
|
||||
LOGGER.log(Level.INFO, "Received Music change Event {0}", music.toString());
|
||||
switch (music.music()){
|
||||
case MENU_THEME:
|
||||
changeMusic(Music.MENU_THEME);
|
||||
|
||||
@@ -115,7 +115,7 @@ private void connect() {
|
||||
private void startServer() {
|
||||
new Thread(() -> {
|
||||
try{
|
||||
BattleshipServer battleshipServer = new BattleshipServer();
|
||||
BattleshipServer battleshipServer = new BattleshipServer(Integer.parseInt(port.getText()));
|
||||
battleshipServer.run();
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.ERROR, e.getMessage(), e);
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package pp.battleship.client.gui;
|
||||
|
||||
import com.jme3.app.Application;
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.effect.ParticleEmitter;
|
||||
import com.jme3.effect.ParticleMesh;
|
||||
import com.jme3.effect.ParticleMesh.Type;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.battleship.model.Shot;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
|
||||
/**
|
||||
* This class is used to handle the effects for impacts
|
||||
*/
|
||||
public class EffectHandler {
|
||||
|
||||
private final AssetManager assetManager;
|
||||
static final Logger LOGGER = System.getLogger(EffectHandler.class.getName());
|
||||
|
||||
private Material particleMat;
|
||||
|
||||
/**
|
||||
* the constructor is used to get the asset manager from the app
|
||||
*
|
||||
* @param app the main application
|
||||
*/
|
||||
public EffectHandler(Application app) {
|
||||
assetManager = app.getAssetManager();
|
||||
particleMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
|
||||
}
|
||||
|
||||
/**
|
||||
* this method is used to create a hit effect at a position
|
||||
*
|
||||
* @param battleshipNode the node of the battleship where the effect should be attached to
|
||||
*/
|
||||
public void createHitEffect(Node battleshipNode, Shot shot) {
|
||||
ParticleEmitter hitEffect = new ParticleEmitter("HitEffect", Type.Triangle,30);
|
||||
hitEffect.setMaterial(particleMat);
|
||||
hitEffect.setImagesX(2);
|
||||
hitEffect.setImagesY(2);
|
||||
hitEffect.setStartColor(ColorRGBA.Orange);
|
||||
hitEffect.setEndColor(ColorRGBA.Red);
|
||||
hitEffect.getParticleInfluencer().setInitialVelocity(new Vector3f(0,1,0));
|
||||
hitEffect.setStartSize(0.45f);
|
||||
hitEffect.setEndSize(0.1f);
|
||||
hitEffect.setGravity(0, -0.5f, 0);
|
||||
hitEffect.setLowLife(1f);
|
||||
hitEffect.setHighLife(2f);
|
||||
hitEffect.setParticlesPerSec(0);
|
||||
hitEffect.setLocalTranslation(shot.getY() + 0.5f, 0 , shot.getX() + 0.5f);
|
||||
LOGGER.log(Level.DEBUG, "Created HitEffect at {0}", hitEffect.getLocalTranslation().toString());
|
||||
LOGGER.log(Level.DEBUG, "Created HitEffect at {0}", hitEffect.getLocalTranslation().toString());
|
||||
|
||||
hitEffect.emitAllParticles();
|
||||
|
||||
battleshipNode.attachChild(hitEffect);
|
||||
|
||||
hitEffect.addControl(new EffectControl(hitEffect, battleshipNode));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to create a miss effect at a certain location
|
||||
*/
|
||||
public ParticleEmitter createMissEffect(Shot shot) {
|
||||
ParticleEmitter missEffect = new ParticleEmitter("MissEffect", Type.Triangle, 15);
|
||||
missEffect.setMaterial(particleMat);
|
||||
missEffect.setImagesX(2);
|
||||
missEffect.setImagesY(2);
|
||||
missEffect.setStartColor(ColorRGBA.Blue); // Water color
|
||||
missEffect.setEndColor(ColorRGBA.Cyan);
|
||||
missEffect.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 1, 0));
|
||||
missEffect.setStartSize(0.3f);
|
||||
missEffect.setEndSize(0.05f);
|
||||
missEffect.setGravity(0, -0.1f, 0);
|
||||
missEffect.setLowLife(0.5f);
|
||||
missEffect.setHighLife(1.5f);
|
||||
missEffect.setParticlesPerSec(0);
|
||||
missEffect.setLocalTranslation(shot.getY() + 0.5f, 0 , shot.getX() + 0.5f);
|
||||
missEffect.emitAllParticles();
|
||||
|
||||
missEffect.addControl(new EffectControl(missEffect));
|
||||
|
||||
return missEffect;
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class is used to control the effects
|
||||
*/
|
||||
private static class EffectControl extends AbstractControl {
|
||||
private final ParticleEmitter emitter;
|
||||
private final Node parentNode;
|
||||
|
||||
/**
|
||||
* this constructor is used to when the effect should be attached to a specific node
|
||||
*
|
||||
* @param emitter the Particle emitter to be controlled
|
||||
* @param parentNode the node to be attached
|
||||
*/
|
||||
public EffectControl(ParticleEmitter emitter, Node parentNode) {
|
||||
this.emitter = emitter;
|
||||
this.parentNode = parentNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor is used when the effect shouldn't be attached to
|
||||
* a specific node
|
||||
*
|
||||
* @param emitter the Particle emitter to be controlled
|
||||
*/
|
||||
public EffectControl(ParticleEmitter emitter){
|
||||
this.emitter = emitter;
|
||||
this.parentNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method which checks if the Effect is not rendered anymore so it can be removed
|
||||
*
|
||||
* @param tpf time per frame (in seconds)
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (emitter.getParticlesPerSec() == 0 && emitter.getNumVisibleParticles() == 0) {
|
||||
if (parentNode != null)
|
||||
parentNode.detachChild(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rm the RenderManager rendering the controlled Spatial (not null)
|
||||
* @param vp the ViewPort being rendered (not null)
|
||||
*/
|
||||
@Override
|
||||
protected void controlRender(com.jme3.renderer.RenderManager rm, com.jme3.renderer.ViewPort vp) {}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package pp.battleship.client.gui;
|
||||
|
||||
import com.jme3.effect.ParticleEmitter;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
@@ -45,6 +46,8 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
private static final ColorRGBA SPLASH_COLOR = new ColorRGBA(0f, 0f, 1f, 0.4f);
|
||||
private static final ColorRGBA HIT_COLOR = new ColorRGBA(1f, 0f, 0f, 0.4f);
|
||||
|
||||
private EffectHandler effectHandler;
|
||||
|
||||
private final ShipMap map;
|
||||
private final BattleshipApp app;
|
||||
|
||||
@@ -59,6 +62,7 @@ public SeaSynchronizer(BattleshipApp app, Node root, ShipMap map) {
|
||||
super(app.getGameLogic().getOwnMap(), root);
|
||||
this.app = app;
|
||||
this.map = map;
|
||||
effectHandler = new EffectHandler(app);
|
||||
addExisting();
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ public SeaSynchronizer(BattleshipApp app, Node root, ShipMap map) {
|
||||
*/
|
||||
@Override
|
||||
public Spatial visit(Shot shot) {
|
||||
return shot.isHit() ? handleHit(shot) : createCylinder(shot);
|
||||
return shot.isHit() ? handleHit(shot) : effectHandler.createMissEffect(shot);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,9 +91,7 @@ private Spatial handleHit(Shot shot) {
|
||||
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
|
||||
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
|
||||
|
||||
final Geometry representation = createCylinder(shot);
|
||||
representation.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
|
||||
shipNode.attachChild(representation);
|
||||
effectHandler.createHitEffect(shipNode, shot);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class BattleshipServer implements MessageListener<HostedConnection>, Conn
|
||||
private static final Logger LOGGER = System.getLogger(BattleshipServer.class.getName());
|
||||
private static final File CONFIG_FILE = new File("server.properties");
|
||||
|
||||
private static int PORT;
|
||||
|
||||
private final BattleshipConfig config = new BattleshipConfig();
|
||||
private Server myServer;
|
||||
private final ServerGameLogic logic;
|
||||
@@ -65,8 +67,9 @@ public class BattleshipServer implements MessageListener<HostedConnection>, Conn
|
||||
/**
|
||||
* Creates the server.
|
||||
*/
|
||||
public BattleshipServer() {
|
||||
public BattleshipServer(int port) {
|
||||
config.readFromIfExists(CONFIG_FILE);
|
||||
PORT = port;
|
||||
LOGGER.log(Level.INFO, "Configuration: {0}", config); //NON-NLS
|
||||
logic = new ServerGameLogic(this, config);
|
||||
}
|
||||
@@ -80,7 +83,7 @@ public void run() {
|
||||
private void startServer() {
|
||||
try {
|
||||
LOGGER.log(Level.INFO, "Starting server..."); //NON-NLS
|
||||
myServer = Network.createServer(config.getPort());
|
||||
myServer = Network.createServer(PORT);
|
||||
initializeSerializables();
|
||||
myServer.start();
|
||||
registerListeners();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
library('jme3-testdata', 'org.jmonkeyengine', 'jme3-testdata').versionRef('jme')
|
||||
library('jme3-lwjgl', 'org.jmonkeyengine', 'jme3-lwjgl').versionRef('jme')
|
||||
library('jme3-lwjgl3', 'org.jmonkeyengine', 'jme3-lwjgl3').versionRef('jme')
|
||||
library('jme3-effects', 'org.jmonkeyengine', 'jme3-effects').versionRef('jme')
|
||||
|
||||
library('lemur', 'com.simsilica:lemur:1.16.0')
|
||||
library('lemur-proto', 'com.simsilica:lemur-proto:1.13.0')
|
||||
|
||||
Reference in New Issue
Block a user