diff --git a/jme3-core/src/main/java/com/jme3/cinematic/events/AnimEvent.java b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimEvent.java new file mode 100644 index 0000000000..e871804368 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimEvent.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2009-2021 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.cinematic.events; + +import com.jme3.anim.AnimComposer; +import com.jme3.anim.tween.action.Action; +import com.jme3.animation.LoopMode; +import com.jme3.app.Application; +import com.jme3.cinematic.Cinematic; +import com.jme3.cinematic.PlayState; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An CinematicEvent that plays a canned animation action in an + * {@link com.jme3.anim.AnimComposer}. + * + * Inspired by Nehon's {@link AnimationEvent}. + */ +public class AnimEvent extends AbstractCinematicEvent { + + final public static Logger logger + = Logger.getLogger(AnimEvent.class.getName()); + + /* + * Control that will play the animation + */ + private AnimComposer composer; + /* + * Cinematic that contains this event + */ + private Cinematic cinematic; + /* + * name of the animation action to be played + */ + private String actionName; + /* + * name of the animation layer on which the action will be played + */ + private String layerName; + + /** + * Instantiate an event. + * + * @param composer the Control that will play the animation (not null) + * @param actionName the name of the animation action to be played + * @param layerName the name of the animation layer on which the action will + * be played + */ + public AnimEvent(AnimComposer composer, String actionName, + String layerName) { + this.composer = composer; + this.actionName = actionName; + this.layerName = layerName; + } + + /** + * No-argument constructor needed by SavableClassUtil. + */ + protected AnimEvent() { + super(); + } + + /** + * Initialize this event. (for internal use) + * + * @param app the Application that contains this event + * @param cinematic the Cinematic that contains this event + */ + @Override + public void initEvent(Application app, Cinematic cinematic) { + super.initEvent(app, cinematic); + this.cinematic = cinematic; + } + + /** + * Callback when the event is paused. + */ + @Override + public void onPause() { + logger.log(Level.SEVERE, ""); + + Action eventAction = composer.action(actionName); + eventAction.setSpeed(0f); + } + + /** + * Callback when the event is started. + */ + @Override + public void onPlay() { + logger.log(Level.INFO, ""); + + Action currentAction = composer.getCurrentAction(layerName); + Action eventAction = composer.action(actionName); + if (eventAction == null) { + throw new IllegalStateException("No action named: " + actionName); + } + + if (currentAction != eventAction) { + composer.setCurrentAction(actionName); + assert composer.getCurrentAction(layerName) == eventAction; + } + + if (playState == PlayState.Stopped) { + composer.setTime(layerName, 0.0); + } + eventAction.setSpeed(speed); + } + + /** + * Callback when the event is stopped. + */ + @Override + public void onStop() { + logger.log(Level.INFO, ""); + composer.removeCurrentAction(layerName); + } + + /** + * Callback on each render pass while the event is playing. + * + * @param tpf time per frame (in seconds) + */ + @Override + public void onUpdate(float tpf) { + // do nothing + } + + /** + * De-serialize this event from the specified importer, for example when + * loading from a J3O file. + * + * @param importer (not null) + * @throws IOException from the importer + */ + @Override + public void read(JmeImporter importer) throws IOException { + super.read(importer); + InputCapsule capsule = importer.getCapsule(this); + + actionName = capsule.readString("actionName", ""); + cinematic = (Cinematic) capsule.readSavable("cinematic", null); + composer = (AnimComposer) capsule.readSavable("composer", null); + layerName = capsule.readString("layerName", AnimComposer.DEFAULT_LAYER); + } + + /** + * Alter the speed of the animation. + * + * @param speed the relative speed (default=1) + */ + @Override + public void setSpeed(float speed) { + logger.log(Level.INFO, "speed = {0}", speed); + super.setSpeed(speed); + + if (playState != PlayState.Stopped) { + Action eventAction = composer.action(actionName); + eventAction.setSpeed(speed); + } + } + + /** + * Jump to the specified time. + * + * @param time the desired time (in seconds, time=0 is the start of the + * event) + */ + @Override + public void setTime(float time) { + logger.log(Level.INFO, "time = {0}", time); + super.setTime(time); + + Action currentAction = composer.getCurrentAction(layerName); + Action eventAction = composer.action(actionName); + if (currentAction != eventAction) { + composer.setCurrentAction(actionName); + assert composer.getCurrentAction(layerName) == eventAction; + } + + float t = time; + float duration = (float) eventAction.getLength(); + if (loopMode == LoopMode.Loop) { + t %= duration; + } else if (loopMode == LoopMode.Cycle) { + float direction = (float) Math.ceil(time / duration); + if (direction > 0f && direction % 2f == 0f) { + t = duration - t % duration; + } else { + t %= duration; + } + } + + if (t < 0f) { + composer.setTime(layerName, 0.0); + } else if (t > duration) { + composer.setTime(layerName, t); + stop(); + } else { + composer.setTime(layerName, t); + } + } + + /** + * Serialize this event to the specified exporter, for example when saving + * to a J3O file. + * + * @param exporter (not null) + * @throws IOException from the exporter + */ + @Override + public void write(JmeExporter exporter) throws IOException { + super.write(exporter); + OutputCapsule capsule = exporter.getCapsule(this); + + capsule.write(actionName, "actionName", ""); + capsule.write(cinematic, "cinematic", null); + capsule.write(composer, "composer", null); + capsule.write(layerName, "layerName", AnimComposer.DEFAULT_LAYER); + } +} diff --git a/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java index b561368934..d8955bb0e2 100644 --- a/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java +++ b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 jMonkeyEngine + * Copyright (c) 2009-2021 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,7 @@ * * * @author Nehon + * @deprecated use {@link AnimEvent} */ @Deprecated public class AnimationEvent extends AbstractCinematicEvent { diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java index ab4bd3bd77..9b66d3e47d 100644 --- a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java +++ b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2020 jMonkeyEngine + * Copyright (c) 2009-2021 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,10 @@ */ package jme3test.animation; -import com.jme3.animation.*; +import com.jme3.anim.AnimComposer; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimationFactory; +import com.jme3.animation.LoopMode; import com.jme3.app.SimpleApplication; import com.jme3.cinematic.*; import com.jme3.cinematic.events.*; @@ -52,7 +55,6 @@ import com.jme3.shadow.DirectionalLightShadowRenderer; import de.lessvoid.nifty.Nifty; -//TODO rework this Test when the new animation system is done. public class TestCinematic extends SimpleApplication { private Spatial model; @@ -118,7 +120,9 @@ public void simpleInitApp() { cinematic.addCinematicEvent(3f, new SoundEvent("Sound/Effects/kick.wav")); cinematic.addCinematicEvent(3, new SubtitleTrack(nifty, "start", 3, "jMonkey engine really kicks A...")); cinematic.addCinematicEvent(5.1f, new SoundEvent("Sound/Effects/Beep.ogg", 1)); - cinematic.addCinematicEvent(2, new AnimationEvent(model, "Walk", LoopMode.Loop)); + AnimComposer composer = model.getControl(AnimComposer.class); + cinematic.addCinematicEvent(2f, + new AnimEvent(composer, "Walk", AnimComposer.DEFAULT_LAYER)); cinematic.activateCamera(0, "topView"); // cinematic.activateCamera(10, "aroundCam"); @@ -197,7 +201,7 @@ private void createCameraMotion() { private void createScene() { - model = assetManager.loadModel("Models/Oto/OtoOldAnim.j3o"); + model = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); model.center(); model.setShadowMode(ShadowMode.CastAndReceive); rootNode.attachChild(model);