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