You can define movies and play them back using C#.
Tracks can represent a GameObject reference, a Component reference, or a property that should be animated.
Create a reference track that, when played, binds to an object named "Camera".
using Sandbox.MovieMaker;
var objectTrack = MovieClip.RootGameObject( "Camera" );
Create a property track that binds to a property named "LocalPosition" inside of whatever objectTrack is bound to.
Give it a constant value between 0s and 2s, then a different constant value from 2s to 5s. After 5s it has no value.
var positionTrack = objectTrack
.Property<Vector3>( "LocalPosition" )
.WithConstant( timeRange: (0.0, 2.0), new Vector3( 100, 200, 300 ) )
.WithConstant( timeRange: (2.0, 5.0), new Vector3( 200, 100, -800 ) );
Create a property track that binds to the "FieldOfView" property of a CameraComponent attached to whatever objectTrack is bound to. Give it an array of samples between 1s-3s.
var fovTrack = objectTrack
.Component<CameraComponent>()
.Property<float>( "FieldOfView" )
.WithSamples( timeRange: (1f, 3f), sampleRate: 2, [60f, 75f, 65f, 90f, 50f] );
Animate the scene with each track. They will try to bind to root objects in the scene with the matching names and component types, and silently fail if they don't exist.
positionTrack.Update( time );
fovTrack.Update( time );
Group tracks into a clip so we can animate them all together.
var clip = MovieClip.FromTracks( positionTrack, fovTrack );
clip.Update( time );
You can search for tracks by path.
var camTrack = clip.GetReference( "Camera" );
var posTrack = clip.GetProperty<Vector3>( "Camera", "LocalPosition" );
Clips can be serialized to and from JSON.
Log.Info( Json.Serialize( clip ) );
What does objectTrack bind to in the current scene?
var target = TrackBinder.Default.Get( objectTrack );
Log.Info( target.IsBound );
Log.Info( target.Value );
12:59:08 Generic True
12:59:08 Generic GameObject:Camera
Bind the track to something else.
target.Bind( Game.ActiveScene.Camera.GameObject );
Binders can be serialized too.
Log.Info( Json.Serialize( Binder.Default ) );
We can have multiple Binder instances, so the same clip can control different objects.
var binder = new TrackBinder( Game.ActiveScene );
binder.Get( cameraTrack ).Bind( Game.ActiveScene.Camera );
// Using Binder.Default
cameraTrack.Update( time );
// Using our own Binder instance
cameraTrack.Update( time, binder );
| By default, the player will create any GameObjects or Components referenced by the recording that aren't already in the scene. These targets will be flagged as *NotSaved | NotNetworked | Hidden*. You can turn this off with the CreateTargets property. |
moviePlayer.CreateTargets = false;
moviePlayer.Play( clip );
You can also manually create targets through the player's TrackBinder.
// Create targets for every track in the given clip
moviePlayer.Binder.CreateTargets( clip );
// Create targets for a specific set of tracks
var track1 = clip.GetTrack( "Example", "ModelRenderer" );
var track2 = clip.GetTrack( "Player", "PlayerController" );
moviePlayer.Binder.CreateTargets( [track1, track2] );
The MoviePlayer component has a clip, a binder, and a time position.
var moviePlayer = GameObject.AddComponent<MoviePlayer>();
moviePlayer.Clip = clip;
moviePlayer.Binder.Get( clip.GetReference( "Camera" ) ).Bind( Game.ActiveScene.Camera );
// Time in seconds
moviePlayer.Position = 0.75;
The clip can also be from a resource.
moviePlayer.Resource = ResourceLibrary.Get<MovieResource>( "example.movie" );