11/*
2- * Copyright (c) 2009-2021 jMonkeyEngine
2+ * Copyright (c) 2009-2025 jMonkeyEngine
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
5454import java .util .logging .Logger ;
5555
5656/**
57- * An appstate for composing and playing cutscenes in a game. The cinematic
58- * schedules CinematicEvents over a timeline. Once the Cinematic created it has
59- * to be attached to the stateManager.
57+ * An AppState for composing and playing cutscenes in a game.
6058 *
61- * You can add various CinematicEvents to a Cinematic, see package
62- * com.jme3.cinematic.events
59+ * <p>A cinematic schedules and plays {@link CinematicEvent}s over a timeline.
60+ * Once a Cinematic is created, you must attach it to the `AppStateManager` to
61+ * run it. You can add various `CinematicEvent`s, see the `com.jme3.cinematic.events`
62+ * package for built-in event types.
6363 *
64- * Two main methods can be used to add an event :
64+ * <p>Events can be added in two main ways:
65+ * <ul>
66+ * <li>{@link Cinematic#addCinematicEvent(float, CinematicEvent)} adds an event
67+ * at a specific time from the cinematic's start.</li>
68+ * <li>{@link Cinematic#enqueueCinematicEvent(CinematicEvent)} adds events
69+ * one after another, with each starting at the end of the previous one.</li>
70+ * </ul>
6571 *
66- * @see Cinematic#addCinematicEvent(float,
67- * com.jme3.cinematic.events.CinematicEvent) , that adds an event at the given
68- * time form the cinematic start.
72+ * <p>Playback can be controlled with methods like:
73+ * <ul>
74+ * <li>{@link Cinematic#play()}</li>
75+ * <li>{@link Cinematic#pause()}</li>
76+ * <li>{@link Cinematic#stop()}</li>
77+ * </ul>
6978 *
70- * @see
71- * Cinematic#enqueueCinematicEvent(com.jme3.cinematic.events.CinematicEvent)
72- * that enqueue events one after the other according to their initialDuration
79+ * <p>Since `Cinematic` itself extends `CinematicEvent`, you can nest cinematics
80+ * within each other. Nested cinematics should not be attached to the `AppStateManager`.
7381 *
74- * A Cinematic has convenient methods to manage playback:
75- * @see Cinematic#play()
76- * @see Cinematic#pause()
77- * @see Cinematic#stop()
78- *
79- * A Cinematic is itself a CinematicEvent, meaning you can embed several
80- * cinematics. Embedded cinematics must not be added to the stateManager though.
81- *
82- * Cinematic can handle several points of view by creating camera nodes
83- * and activating them on schedule.
84- * @see Cinematic#bindCamera(java.lang.String, com.jme3.renderer.Camera)
85- * @see Cinematic#activateCamera(float, java.lang.String)
86- * @see Cinematic#setActiveCamera(java.lang.String)
82+ * <p>This class also handles multiple camera points of view by creating and
83+ * activating camera nodes on a schedule.
84+ * <ul>
85+ * <li>{@link Cinematic#bindCamera(java.lang.String, com.jme3.renderer.Camera)}</li>
86+ * <li>{@link Cinematic#activateCamera(float, java.lang.String)}</li>
87+ * <li>{@link Cinematic#setActiveCamera(java.lang.String)}</li>
88+ * </ul>
8789 *
8890 * @author Nehon
8991 */
9092public class Cinematic extends AbstractCinematicEvent implements AppState {
9193
9294 private static final Logger logger = Logger .getLogger (Cinematic .class .getName ());
95+
96+ private Application app ;
9397 private Node scene ;
9498 protected TimeLine timeLine = new TimeLine ();
9599 private int lastFetchedKeyFrame = -1 ;
96- private final List <CinematicEvent > cinematicEvents = new ArrayList <>();
100+ private List <CinematicEvent > cinematicEvents = new ArrayList <>();
97101 private Map <String , CameraNode > cameras = new HashMap <>();
98102 private CameraNode currentCam ;
99103 private boolean initialized = false ;
@@ -109,14 +113,30 @@ protected Cinematic() {
109113 super ();
110114 }
111115
116+ /**
117+ * Creates a cinematic with a specific duration.
118+ *
119+ * @param initialDuration The total duration of the cinematic in seconds.
120+ */
112121 public Cinematic (float initialDuration ) {
113122 super (initialDuration );
114123 }
115124
125+ /**
126+ * Creates a cinematic that loops based on the provided loop mode.
127+ *
128+ * @param loopMode The loop mode. See {@link LoopMode}.
129+ */
116130 public Cinematic (LoopMode loopMode ) {
117131 super (loopMode );
118132 }
119133
134+ /**
135+ * Creates a cinematic with a specific duration and loop mode.
136+ *
137+ * @param initialDuration The total duration of the cinematic in seconds.
138+ * @param loopMode The loop mode. See {@link LoopMode}.
139+ */
120140 public Cinematic (float initialDuration , LoopMode loopMode ) {
121141 super (initialDuration , loopMode );
122142 }
@@ -221,10 +241,9 @@ public void onPause() {
221241 public void write (JmeExporter ex ) throws IOException {
222242 super .write (ex );
223243 OutputCapsule oc = ex .getCapsule (this );
224- oc .write ( cinematicEvents . toArray ( new CinematicEvent [ cinematicEvents . size ()]) , "cinematicEvents" , null );
244+ oc .writeSavableArrayList (( ArrayList ) cinematicEvents , "cinematicEvents" , null );
225245 oc .writeStringSavableMap (cameras , "cameras" , null );
226246 oc .write (timeLine , "timeLine" , null );
227-
228247 }
229248
230249 /**
@@ -238,12 +257,7 @@ public void write(JmeExporter ex) throws IOException {
238257 public void read (JmeImporter im ) throws IOException {
239258 super .read (im );
240259 InputCapsule ic = im .getCapsule (this );
241-
242- Savable [] events = ic .readSavableArray ("cinematicEvents" , null );
243- for (Savable c : events ) {
244- // addCinematicEvent(((CinematicEvent) c).getTime(), (CinematicEvent) c)
245- cinematicEvents .add ((CinematicEvent ) c );
246- }
260+ cinematicEvents = ic .readSavableArrayList ("cinematicEvents" , null );
247261 cameras = (Map <String , CameraNode >) ic .readStringSavableMap ("cameras" , null );
248262 timeLine = (TimeLine ) ic .readSavable ("timeLine" , null );
249263 }
@@ -273,6 +287,7 @@ public void setSpeed(float speed) {
273287 */
274288 @ Override
275289 public void initialize (AppStateManager stateManager , Application app ) {
290+ this .app = app ;
276291 initEvent (app , this );
277292 for (CinematicEvent cinematicEvent : cinematicEvents ) {
278293 cinematicEvent .initEvent (app , this );
@@ -443,7 +458,7 @@ public KeyFrame addCinematicEvent(float timeStamp, CinematicEvent cinematicEvent
443458 keyFrame .cinematicEvents .add (cinematicEvent );
444459 cinematicEvents .add (cinematicEvent );
445460 if (isInitialized ()) {
446- cinematicEvent .initEvent (null , this );
461+ cinematicEvent .initEvent (app , this );
447462 }
448463 return keyFrame ;
449464 }
@@ -488,7 +503,6 @@ public boolean removeCinematicEvent(CinematicEvent cinematicEvent) {
488503 * @return true if the element has been removed
489504 */
490505 public boolean removeCinematicEvent (float timeStamp , CinematicEvent cinematicEvent ) {
491- cinematicEvent .dispose ();
492506 KeyFrame keyFrame = timeLine .getKeyFrameAtTime (timeStamp );
493507 return removeCinematicEvent (keyFrame , cinematicEvent );
494508 }
@@ -536,6 +550,9 @@ public void postRender() {
536550 */
537551 @ Override
538552 public void cleanup () {
553+ initialized = false ;
554+ clear ();
555+ clearCameras ();
539556 }
540557
541558 /**
@@ -591,9 +608,9 @@ public CameraNode getCamera(String cameraName) {
591608 }
592609
593610 /**
594- * enable/disable the camera control of the cameraNode of the current cam
611+ * Enables or disables the camera control of the cameraNode of the current cam.
595612 *
596- * @param enabled
613+ * @param enabled `true` to enable, `false` to disable.
597614 */
598615 private void setEnableCurrentCam (boolean enabled ) {
599616 if (currentCam != null ) {
@@ -713,6 +730,15 @@ public Node getScene() {
713730 return scene ;
714731 }
715732
733+ /**
734+ * Gets the application instance associated with this cinematic.
735+ *
736+ * @return The application.
737+ */
738+ public Application getApplication () {
739+ return app ;
740+ }
741+
716742 /**
717743 * Remove all events from the Cinematic.
718744 */
@@ -725,6 +751,18 @@ public void clear() {
725751 }
726752 }
727753
754+ /**
755+ * Clears all camera nodes bound to the cinematic from the scene node.
756+ * This method removes all previously bound CameraNodes and clears the
757+ * internal camera map, effectively detaching all cameras from the scene.
758+ */
759+ public void clearCameras () {
760+ for (CameraNode cameraNode : cameras .values ()) {
761+ scene .detachChild (cameraNode );
762+ }
763+ cameras .clear ();
764+ }
765+
728766 /**
729767 * used internally to clean up the cinematic. Called when the clear() method
730768 * is called
0 commit comments