# jME3 Cinematics

JME3 cinematics (com.jme.cinematic) allow you to remote control nodes and cameras in a 3D game. You use cinematics to script and record scenes. Use it for example to create cutscenes of your game.

Cinematics are implemented as AppStates. Attach the scene that you want to be visible in the cinematic to one Node. You create a Cinematic object, and add individual CinematicEvents to it.

## Overview

    Cinematic cinematic = new Cinematic(sceneNode, duration);
    cinematic.addCinematicEvent(triggerTime, cinematicEvent);

1. Create one Cinematic per scene.
   - sceneNode is the node containing the scene
   - duration is the duration of the cinematic scene in seconds
2. Create CinematicEvents to script your "movie". Each Cinematic is a set of CinematicEvents, that are triggered at a given time.
   - cinematicEvent is the cinematic event. More details below.
   - triggerTime is the time when this particular cinematic event starts. Specify the start time in seconds since the beginning of the scene.
3. Play and pause the Cinematic using `cinematic.pause()` and `cinematic.play();`

## CinematicEvents

There are several kinds of cinematic events:

CinematicEvent | Description
--- | ---
MotionTrack | Use this to move a Spatial non-linearly over time. A motionPath is a list of several waypoints added to a MotionPath. The path is interpolated using Catmull-Rom Splines between waypoints.
PositionTrack | Use this to move a Spatial linearly over time. It translates the Spatial to a destination in the given amount of time by linearly interpolating the positions.
RotationTrack | Use this to change the rotation of a Spatial over time. It rotates the Spatial in the given amount of time by linearly interpolating the rotation.
ScaleTrack | Use this to change the size of a Spatial over time. It scales the Spatial in the given amount of time by linearly interpolating the scale.
SoundTrack | Use this to play a sound at a given time for the given duration.
GuiTrack | Displays a Nifty GUI at a given time for the given duration. Use it to display subtitles or HUD elements. Bind the Nifty GUI XML to the cinematic using `cinematic.bindUi("path/to/nifty/file.xml");`
AnimationTrack | Use this to start playing a model animation at a given time (a character walking animation for example)

We will add more types of track implementions over time.

Each CinematicEvent supports the following methods to control the event.

CinematicEvent method | Usage
--- | ---
play() | Starts playing the cinematic.
stop() | Stops playing the cinematic.
pause() | Pauses the cinematic.

Those methods, must be called on the Cinematic and are propagated to the events. Don't use them directly on a sub cinematic event

### MotionTrack & MotionPath

A motion track is made up of MotionPaths.

    MotionPath path = new MotionPath();

MotionPath Method | Usage
--- | ---
setCycle(true) | Sets whether the motion along this path should be closed (true) or not (false).
addWayPoint(vector) | Adds individual waypoints to this path. The order is relevant.
removeWayPoint(vector) removeWayPoint(index) | Removes individual waypoints from this path. You can specify a vector or the integer index.
setCurveTension(0.83f) | Sets the tension of the curve (only for Catmull Rom Spline). A value of 0.0f will give a straight linear line, 1.0 a round curve.
enableDebugShape(assetManager,rootNode) | Shows a line to visualize the path. Used for debugging.
disableDebugShape() | Hides the line that visualizes the path. Used for debugging.
getNbWayPoints() | Returns the number of waypoints in this path.

    MotionTrack thingMotionControl = new MotionTrack(thingNode, path);

MotionTrack method | Usage
--- | ---
setLoopMode(LoopMode.Loop) | Sets whether the animation along this path should loop (true) or play only once (false).
setDirectionType(MotionTrack.Direction.None) | Sets the direction behavior type of the controled node. Direction.None deactivates this feature. See the following options:
setDirectionType(MotionTrack.Direction.LookAt) | Rotate to keep facing a point. Specify the point with setLookAt().
setDirectionType(MotionTrack.Direction.Path) | Face the direction of the path.
setDirectionType(MotionTrack.Direction.PathAndRotation) | Face the direction of the path, plus an added rotation. Use together with the setRotation() method.
setDirectionType(MotionTrack.Direction.Rotation) | Rotate while moving. Use together with the setRotation() method.
setLookAt(teapot.getWorldTranslation(), Vector3f.UNIT_Y) | Optional: Make the moving face towards a certain location. Use together with setDirectionType().
setRotation(quaternion) | Optional: Sets the rotation. Use together with MotionTrack.Direction.Rotation or MotionTrack.Direction.PathAndRotation.

### MotionPathListener

You can register a MotionPathListener to the MotionPath to track whether waypoints have been reached, and then trigger a custom action. In this example we just print the status. The onWayPointReach() method of the interface gives you access to the MotionTrack object `control`, and an integer value representing the current wayPointIndex.

    path.addListener( new MotionPathListener() {
      public void onWayPointReach(MotionTrack control, int wayPointIndex) {
        if (path.getNbWayPoints() == wayPointIndex + 1) {
          println(control.getSpatial().getName() + "Finished!!! ");
        } else {
          println(control.getSpatial().getName() + " Reached way point " + wayPointIndex);
        }
      }
    });

### PositionTrack

    PositionTrack thingPositionControl = new PositionTrack(
        thingNode, endPosition,  duration, loopMode);

Details of the constructor:

- thingNode is the Spatial to be moved.
- endPosition is the target location as Vector3f.
- duration is the time that it should take from start to end point.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

The start location is always the current location of the Spatial.

### RotationTrack

    RotationTrack thingRotationControl = new RotationTrack(
        thingNode, endRotation,  duration, loopMode);

Details of the constructor:

- thingNode is the Spatial to be rotated.
- endRotation is the target rotation in Quaternion format.
- duration is the time that it should take from start to target rotation.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

### ScaleTrack

    ScaleTrack thingScaleControl = new ScaleTrack(
        thingNode, endScale,  duration, loopMode);

Details of the constructor:

- thingNode is the Spatial to be resized.
- endScale is the target Scale in Vector3f format.
- duration is the time that it should take from start to target scale.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

### SoundTrack

    SoundTrack( audioPath, isStream, duration, loopMode )

Details of the constructor:

- audioPath is the path to an audio file as String, e.g. "Sounds/mySound.wav".
- isStream Set this to true to play a longer audio file as stream, or to false to play a short sound without streaming.
- duration is the time that it should take to play.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

### GuiTrack

    GuiTrack( screen, duration, loopMode )

You must use this together with bindUI() to specify the Nifty GUI XML file that you want to load:

    cinematic.bindUi("Interface/subtitle.xml");

Details of the constructor:

- screen is the name of the Nifty GUI screen to load, as String.
- duration is the time that it should take to play.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

### AnimationTrack

    AnimationTrack( thingNode, animationName, duration, loopMode )

Details of the constructor:

- thingNode is the Spatial whose animation you want to play.
- AnimationName the animation of the animated model that you want to trigger, as a String.
- duration is the time that it should take to play.
- loopMode can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.

### Customizations

You can extend individual CinematicEvents. The SubtitleTrack.java example shows how to extend a GuiTrack to script subtitles. See how the subtitles are used in the TestCinematic.java example.

You can also create new CinematicEvent by extending AbstractCinematicEvent. An AbstractCinematicEvent implements the CinematicEvent interface and provides duration, time, speed, etc… management. Look at the TestCinematic.java example is to use this for a custom fadeIn/fadeOut effect in combination with a com.jme3.post.filters.FadeFilter.

## Camera Handling

The camera management is handled as follows:

1. Create a camera Node and bind the camera object to the cinematic. Note that we also give the camera node a name in this step.

       CameraNode camNode = cinematic.bindCamera("topView", cam);

2. Position the camera node in its start location.
3. Use activateCamera() to give the control of the camera to this node. You now see the scene from this camera's point of view. For example to see through the camera node named "top view", 6 seconds after the start of the cinematic, you'd write

       cinematic.activateCamera(6, "topView");

4. If desired, attach the camNode to a MotionTrack to let it travel along waypoints. This is demonstrated in the TestCameraMotionPath.java example.

Code samples:

    flyCam.setEnabled(false);

    CameraNode camNodeTop = cinematic.bindCamera("topView", cam);
    camNodeTop.setControlDir(ControlDirection.SpatialToCamera);
    camNodeTop.getControl(0).setEnabled(false);

    CameraNode camNodeSide = cinematic.bindCamera("sideView", cam);
    camNodeSide.setControlDir(ControlDirection.CameraToSpatial);
    camNodeSide.getControl(0).setEnabled(false);

## Physics Interaction

Upcoming.

## More Information

See also: Cinematics by Nehon

view online version