소스 검색

add a CinematicEvent for the new animation system (#1508)

* jme3-core: first cut at a CinematicEvent for the new animation system

* TestCinematic: use AnimEvent

* AnimationEvent: add deprecation advice to the javadoc
Stephen Gold 4 년 전
부모
커밋
65d809fbd3

+ 256 - 0
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);
+    }
+}

+ 1 - 0
jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java

@@ -51,6 +51,7 @@ import java.util.logging.Logger;
  *
  *
  * @author Nehon
+ * @deprecated use {@link AnimEvent}
  */
 @Deprecated
 public class AnimationEvent extends AbstractCinematicEvent {

+ 8 - 4
jme3-examples/src/main/java/jme3test/animation/TestCinematic.java

@@ -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.*;
@@ -53,7 +56,6 @@ import com.jme3.scene.shape.Box;
 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;
@@ -117,7 +119,9 @@ public class TestCinematic extends SimpleApplication {
         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");
 
@@ -196,7 +200,7 @@ public class TestCinematic extends SimpleApplication {
 
     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);