CinematicEntry
The CinematicEntry
does not have any decentends, but is very customizable. When a entry is needed in a cinematic page, it needs to inherid this.
CinematicEntry
works by having at least 1 list of Segment
's. Segments are the parts of the cinematic and may have sub-properties defined. A segment needs to have at least a startFrame
and endFrame
which are the integers of the frames.
Frames are the ticks in a second. So there are 20 frames in a second. A cinematic takes as long as the latest endFrame
of a segment from all it's entries.
Segments are defined in the entry using the @Segments
annotation. And it needs to be a list of Segment
's.
A CinematicEntry
can have multiple different segment tracks.
For example, a cinematic entry may have a TextSegment
and a SoundSegment
.
Though this is supported in the plugin, it is not yet implemented in the cinematic editor. If you need this, reach out to me on Discord.
As entries are not allowed to have any state, we create a CinematicAction
everytime a entry is used in a cinematic for a player.
Usage
@Entry("example_cinematic", "An example cinematic entry.", Colors.CYAN, Icons.TERMINAL)
class ExampleCinematicEntry(
override val id: String,
override val name: String,
override val criteria: List<Criteria>,
@Segments(Colors.CYAN, Icons.TERMINAL)
override val segments: List<ExampleSegment>,
): CinematicEntry {
override fun create(player: Player): CinematicAction {
return ExampleCinematicAction(player, this)
}
}
Segments sometimes need a minimum or maximum duration. This can be done using the @InnerMin
and @InnerMax
annotations.
@Segments(Colors.CYAN, Icons.TERMINAL)
@InnerMin(Min(10))
@InnerMax(Max(20))
override val segments: List<ExampleSegment>,
This will make sure that the segment will be at least 10 frames long and at most 20 frames long.
ExampleSegment
data class ExampleSegment(
override val startFrame: Int,
override val endFrame: Int,
): Segment
ExampleCinematicAction
The CinematicAction
is the action that is created when a cinematic is started. It is used to keep track of the current frame and to execute the segments.
There are a few different lifecycle methods that can be used.
setup()
is called when the cinematic is created. This is the place to initialize any variables, spawn entities, etc.tick(frame: Int)
is called every frame. This is the place to execute the segments. It is even executed when no segments are active.teardown()
is called when the cinematic is finished. This is the place to remove any entities, etc.canFinish(frame: Int)
the only method that needs to be implemented. It is used by theCinematicSequence
to determine if the cinematic is finished.
If you need all the customization, you can can implement the CinematicAction
directly:
class ExampleCinematicAction(
override val player: Player,
override val entry: ExampleCinematicEntry,
): CinematicAction {
override fun setup() {
// Initialize variables, spawn entities, etc.
}
override fun tick(frame: Int) {
val segment = entry.segments activeSegmentAt frame
// Can be null if no segment is active
// Execute segments
}
override fun teardown() {
// Remove entities, etc.
}
override fun canFinish(frame: Int): Boolean = entry.segments canFinishAt frame
}
SimpleCinematicAction
Sometimes you don't need all the customization and flexiblity. If you only care about 1 segment track, and only need to do something when a segment starts or ends, you can use the SimpleCinematicAction
.
class ExampleCinematicAction(
override val player: Player,
override val entry: ExampleCinematicEntry,
): SimpleCinematicAction<ExampleSegment>() {
override val segments: List<ExampleSegment> = entry.segments
override suspend fun startSegment(segment: ExampleSegment) {
// Called when a segment starts
}
override suspend fun endSegment(segment: ExampleSegment) {
// Called when a segment ends
}
}