Procedurally Setting Transform Of FMovieScenePossessables At Generation Time

We are currently procedurally generating portions of our Sequences at edit time: Tracks, bindables, possessables, and spawnables.

We’re doing this to build a skeletal version of our Sequences for our designers and artists to fill in the finer details. However, spawnables have been heavily deprecated internally, and creating a spawnable just creates a possessable now.

We need to set the transform on a possessable from C++. The best way I could find is something like this:

if (UMovieSceneSequence* MovieSceneSequence = MovieScene.GetTypedOuter<UMovieSceneSequence>()) { if (FMovieSceneBindingReferences* BindingReferences = MovieSceneSequence->GetBindingReferences()) { if (UMovieSceneCustomBinding* CustomBinding = BindingReferences->GetCustomBinding(BindingId, BindingIndex)) { if (UMovieSceneSpawnableBindingBase* SpawnableBinding = CustomBinding->AsSpawnable(SharedPlaybackState)) {But all of the important details are Protected (SpawnTransform, specifically).

Is there an intended method to accomplish this without using the UI? I have tried many different solutions, and they all lead back to manually setting them through the UI (specifically, the ISequencer and FSequencer functions).

Steps to Reproduce
Create a Level Sequence in C++

Create a Spawnable within that Level Sequence

Access that Spawnable (which is now technically a Possessable)

Attempt to set the Transform for the actor you wish to spawn

Hey there,

Possessables and Spawnables handle these types of things differently.

For Spawnables, they have a GetObjectTemplate() which returns the object and its default values. You can reset and store that ObjectTemplate to have a different spawn position value.

Possessables don’t have an ObjectTemplate, and so there data needs to be stored on the Transform track, either as a key or as a default value.

This is rough, but something more akin to:

// Using your binding, get the tracks for it. TArray<FMovieSceneBindingProxy> Bindings = UMovieSceneSequenceExtensions::GetBindings(Sequence); for (FMovieSceneBindingProxy Binding : Bindings) { Binding.BindingID = MyID; TArray<UMovieSceneTrack*> TransformTracks = UMovieSceneBindingExtensions::FindTracksByType(Binding, UMovieScene3DTransformTrack::StaticClass()); //Get transform tracks specifically. for (UMovieSceneTrack* Track : TransformTracks) { Track->Modify(); TArray<UMovieSceneSection*> Sections = Track->GetAllSections(); //Get the sections. More that likely you'll only need one, but you'll want to think about that. for (UMovieSectionSection* Section : Sections) { if (UMovieScene3DTransformSection* TransformSection = Cast<UMovieScene3DTransformSection>(Section)) { // We need to go through the scripting channel interface because the channels are private and protected by more generic code. TArray<UMovieSceneScriptingChannel*> Channels = UMovieSceneSectionExtensions::GetAllChannels(Section); //You could also use UMovieSceneSectionExtensions::GetChannel for (UMovieSceneScriptingChannel* Channel : Channels) { if (Channel->ChannelName.IsEqual(FName("Translation"), ENameCase::CaseSensitive)) { FMovieSceneDoubleChannel* DoubleChannel = Cast<FMovieSceneDoubleChannel>(Channel); DoubleChannel[0]->SetDefault(0.0f); DoubleChannel[0]->SetDefault(0.0f); DoubleChannel[0]->SetDefault(100.0f); } } } } } }Hopefully this points you in the right direction.

Dustin