Home | History | Annotate | Download | only in events
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.cinematic.events;
     33 
     34 import com.jme3.animation.LoopMode;
     35 import com.jme3.app.Application;
     36 import com.jme3.cinematic.Cinematic;
     37 import com.jme3.cinematic.MotionPath;
     38 import com.jme3.cinematic.PlayState;
     39 import com.jme3.export.InputCapsule;
     40 import com.jme3.export.JmeExporter;
     41 import com.jme3.export.JmeImporter;
     42 import com.jme3.export.OutputCapsule;
     43 import com.jme3.math.Quaternion;
     44 import com.jme3.math.Vector2f;
     45 import com.jme3.math.Vector3f;
     46 import com.jme3.renderer.RenderManager;
     47 import com.jme3.renderer.ViewPort;
     48 import com.jme3.scene.Spatial;
     49 import com.jme3.scene.control.Control;
     50 import com.jme3.util.TempVars;
     51 import java.io.IOException;
     52 
     53 /**
     54  * A MotionTrack is a control over the spatial that manage the position and direction of the spatial while following a motion Path
     55  *
     56  * You must first create a MotionPath and then create a MotionTrack to associate a spatial and the path.
     57  *
     58  * @author Nehon
     59  */
     60 public class MotionTrack extends AbstractCinematicEvent implements Control {
     61 
     62     protected Spatial spatial;
     63     protected int currentWayPoint;
     64     protected float currentValue;
     65     protected Vector3f direction = new Vector3f();
     66     protected Vector3f lookAt;
     67     protected Vector3f upVector;
     68     protected Quaternion rotation;
     69     protected Direction directionType = Direction.None;
     70     protected MotionPath path;
     71     private boolean isControl = true;
     72     /**
     73      * the distance traveled by the spatial on the path
     74      */
     75     protected float traveledDistance = 0;
     76 
     77     /**
     78      * Enum for the different type of target direction behavior
     79      */
     80     public enum Direction {
     81 
     82         /**
     83          * the target stay in the starting direction
     84          */
     85         None,
     86         /**
     87          * The target rotates with the direction of the path
     88          */
     89         Path,
     90         /**
     91          * The target rotates with the direction of the path but with the additon of a rtotation
     92          * you need to use the setRotation mathod when using this Direction
     93          */
     94         PathAndRotation,
     95         /**
     96          * The target rotates with the given rotation
     97          */
     98         Rotation,
     99         /**
    100          * The target looks at a point
    101          * You need to use the setLookAt method when using this direction
    102          */
    103         LookAt
    104     }
    105 
    106     /**
    107      * Create MotionTrack,
    108      * when using this constructor don't forget to assign spatial and path
    109      */
    110     public MotionTrack() {
    111         super();
    112     }
    113 
    114     /**
    115      * Creates a MotionPath for the given spatial on the given motion path
    116      * @param spatial
    117      * @param path
    118      */
    119     public MotionTrack(Spatial spatial, MotionPath path) {
    120         super();
    121         this.spatial = spatial;
    122         spatial.addControl(this);
    123         this.path = path;
    124     }
    125 
    126     /**
    127      * Creates a MotionPath for the given spatial on the given motion path
    128      * @param spatial
    129      * @param path
    130      */
    131     public MotionTrack(Spatial spatial, MotionPath path, float initialDuration) {
    132         super(initialDuration);
    133         this.spatial = spatial;
    134         spatial.addControl(this);
    135         this.path = path;
    136     }
    137 
    138     /**
    139      * Creates a MotionPath for the given spatial on the given motion path
    140      * @param spatial
    141      * @param path
    142      */
    143     public MotionTrack(Spatial spatial, MotionPath path, LoopMode loopMode) {
    144         super();
    145         this.spatial = spatial;
    146         spatial.addControl(this);
    147         this.path = path;
    148         this.loopMode = loopMode;
    149     }
    150 
    151     /**
    152      * Creates a MotionPath for the given spatial on the given motion path
    153      * @param spatial
    154      * @param path
    155      */
    156     public MotionTrack(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
    157         super(initialDuration);
    158         this.spatial = spatial;
    159         spatial.addControl(this);
    160         this.path = path;
    161         this.loopMode = loopMode;
    162     }
    163 
    164     public void update(float tpf) {
    165         if (isControl) {
    166 
    167             if (playState == PlayState.Playing) {
    168                 time = time + (tpf * speed);
    169 
    170                 if (time >= initialDuration && loopMode == loopMode.DontLoop) {
    171                     stop();
    172                 } else {
    173                     onUpdate(tpf);
    174                 }
    175             }
    176         }
    177     }
    178 
    179     @Override
    180     public void initEvent(Application app, Cinematic cinematic) {
    181         super.initEvent(app, cinematic);
    182         isControl = false;
    183     }
    184 
    185     @Override
    186     public void setTime(float time) {
    187         super.setTime(time);
    188         onUpdate(0);
    189     }
    190 
    191     public void onUpdate(float tpf) {
    192         traveledDistance = path.interpolatePath(time, this);
    193         computeTargetDirection();
    194     }
    195 
    196     @Override
    197     public void write(JmeExporter ex) throws IOException {
    198         super.write(ex);
    199         OutputCapsule oc = ex.getCapsule(this);
    200         oc.write(lookAt, "lookAt", Vector3f.ZERO);
    201         oc.write(upVector, "upVector", Vector3f.UNIT_Y);
    202         oc.write(rotation, "rotation", Quaternion.IDENTITY);
    203         oc.write(directionType, "directionType", Direction.None);
    204         oc.write(path, "path", null);
    205     }
    206 
    207     @Override
    208     public void read(JmeImporter im) throws IOException {
    209         super.read(im);
    210         InputCapsule in = im.getCapsule(this);
    211         lookAt = (Vector3f) in.readSavable("lookAt", Vector3f.ZERO);
    212         upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
    213         rotation = (Quaternion) in.readSavable("rotation", Quaternion.IDENTITY);
    214         directionType = in.readEnum("directionType", Direction.class, Direction.None);
    215         path = (MotionPath) in.readSavable("path", null);
    216     }
    217 
    218     /**
    219      * this method is meant to be called by the motion path only
    220      * @return
    221      */
    222     public boolean needsDirection() {
    223         return directionType == Direction.Path || directionType == Direction.PathAndRotation;
    224     }
    225 
    226     private void computeTargetDirection() {
    227         switch (directionType) {
    228             case Path:
    229                 Quaternion q = new Quaternion();
    230                 q.lookAt(direction, Vector3f.UNIT_Y);
    231                 spatial.setLocalRotation(q);
    232                 break;
    233             case LookAt:
    234                 if (lookAt != null) {
    235                     spatial.lookAt(lookAt, upVector);
    236                 }
    237                 break;
    238             case PathAndRotation:
    239                 if (rotation != null) {
    240                     Quaternion q2 = new Quaternion();
    241                     q2.lookAt(direction, Vector3f.UNIT_Y);
    242                     q2.multLocal(rotation);
    243                     spatial.setLocalRotation(q2);
    244                 }
    245                 break;
    246             case Rotation:
    247                 if (rotation != null) {
    248                     spatial.setLocalRotation(rotation);
    249                 }
    250                 break;
    251             case None:
    252                 break;
    253             default:
    254                 break;
    255         }
    256     }
    257 
    258     /**
    259      * Clone this control for the given spatial
    260      * @param spatial
    261      * @return
    262      */
    263     public Control cloneForSpatial(Spatial spatial) {
    264         MotionTrack control = new MotionTrack(spatial, path);
    265         control.playState = playState;
    266         control.currentWayPoint = currentWayPoint;
    267         control.currentValue = currentValue;
    268         control.direction = direction.clone();
    269         control.lookAt = lookAt.clone();
    270         control.upVector = upVector.clone();
    271         control.rotation = rotation.clone();
    272         control.initialDuration = initialDuration;
    273         control.speed = speed;
    274         control.loopMode = loopMode;
    275         control.directionType = directionType;
    276 
    277         return control;
    278     }
    279 
    280     @Override
    281     public void onPlay() {
    282         traveledDistance = 0;
    283     }
    284 
    285     @Override
    286     public void onStop() {
    287         currentWayPoint = 0;
    288     }
    289 
    290     @Override
    291     public void onPause() {
    292     }
    293 
    294     /**
    295      * this method is meant to be called by the motion path only
    296      * @return
    297      */
    298     public float getCurrentValue() {
    299         return currentValue;
    300     }
    301 
    302     /**
    303      * this method is meant to be called by the motion path only
    304      *
    305      */
    306     public void setCurrentValue(float currentValue) {
    307         this.currentValue = currentValue;
    308     }
    309 
    310     /**
    311      * this method is meant to be called by the motion path only
    312      * @return
    313      */
    314     public int getCurrentWayPoint() {
    315         return currentWayPoint;
    316     }
    317 
    318     /**
    319      * this method is meant to be called by the motion path only
    320      *
    321      */
    322     public void setCurrentWayPoint(int currentWayPoint) {
    323         if (this.currentWayPoint != currentWayPoint) {
    324             this.currentWayPoint = currentWayPoint;
    325             path.triggerWayPointReach(currentWayPoint, this);
    326         }
    327     }
    328 
    329     /**
    330      * returns the direction the spatial is moving
    331      * @return
    332      */
    333     public Vector3f getDirection() {
    334         return direction;
    335     }
    336 
    337     /**
    338      * Sets the direction of the spatial
    339      * This method is used by the motion path.
    340      * @param direction
    341      */
    342     public void setDirection(Vector3f direction) {
    343         this.direction.set(direction);
    344     }
    345 
    346     /**
    347      * returns the direction type of the target
    348      * @return the direction type
    349      */
    350     public Direction getDirectionType() {
    351         return directionType;
    352     }
    353 
    354     /**
    355      * Sets the direction type of the target
    356      * On each update the direction given to the target can have different behavior
    357      * See the Direction Enum for explanations
    358      * @param directionType the direction type
    359      */
    360     public void setDirectionType(Direction directionType) {
    361         this.directionType = directionType;
    362     }
    363 
    364     /**
    365      * Set the lookAt for the target
    366      * This can be used only if direction Type is Direction.LookAt
    367      * @param lookAt the position to look at
    368      * @param upVector the up vector
    369      */
    370     public void setLookAt(Vector3f lookAt, Vector3f upVector) {
    371         this.lookAt = lookAt;
    372         this.upVector = upVector;
    373     }
    374 
    375     /**
    376      * returns the rotation of the target
    377      * @return the rotation quaternion
    378      */
    379     public Quaternion getRotation() {
    380         return rotation;
    381     }
    382 
    383     /**
    384      * sets the rotation of the target
    385      * This can be used only if direction Type is Direction.PathAndRotation or Direction.Rotation
    386      * With PathAndRotation the target will face the direction of the path multiplied by the given Quaternion.
    387      * With Rotation the rotation of the target will be set with the given Quaternion.
    388      * @param rotation the rotation quaternion
    389      */
    390     public void setRotation(Quaternion rotation) {
    391         this.rotation = rotation;
    392     }
    393 
    394     /**
    395      * retun the motion path this control follows
    396      * @return
    397      */
    398     public MotionPath getPath() {
    399         return path;
    400     }
    401 
    402     /**
    403      * Sets the motion path to follow
    404      * @param path
    405      */
    406     public void setPath(MotionPath path) {
    407         this.path = path;
    408     }
    409 
    410     public void setEnabled(boolean enabled) {
    411         if (enabled) {
    412             play();
    413         } else {
    414             pause();
    415         }
    416     }
    417 
    418     public boolean isEnabled() {
    419         return playState != PlayState.Stopped;
    420     }
    421 
    422     public void render(RenderManager rm, ViewPort vp) {
    423     }
    424 
    425     public void setSpatial(Spatial spatial) {
    426         this.spatial = spatial;
    427     }
    428 
    429     public Spatial getSpatial() {
    430         return spatial;
    431     }
    432 
    433     /**
    434      * return the distance traveled by the spatial on the path
    435      * @return
    436      */
    437     public float getTraveledDistance() {
    438         return traveledDistance;
    439     }
    440 }
    441