Hi Devs,
I want to create a ULevelSequence from scratch in order to create automatically dialogs sequencer based on data: text + duration + other info.
This system will allow to not create manually thousand of ULevelSequence with manual tick positioning.
I start to implement a very simple system which:
- Create LevelSequence into Actor
- Create Track/Section
- Configure sequence duration
- Add an event tick at the end with call of event code.
Currently the two first points look work, if I check into editor, but I can’t change duration of track/movie or add tick.
I create this code based on many copy/past and samples because c++ doc is not very good about this module.
Questions
- Someone have an idea why it doesn’t work ? Which methods to use ?
- What do you think about this solution to make a generic dialog system ?
Thanks !!
The code : H
UCLASS(Blueprintable)
class AMyDialogSequencer : public ALevelSequenceActor
{
GENERATED_BODY()
public:
AMyDialogSequencer(const FObjectInitializer& Init);
UFUNCTION(BlueprintCallable)
void Initialize();
UFUNCTION(BlueprintCallable)
void OnFinishDialog();
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
ULevelSequence* _sequence;
};
With cpp
AMyDialogSequencer::AMyDialogSequencer(const FObjectInitializer& Init) :
ALevelSequenceActor(Init)
{
SetActorLabel(TEXT("Dialog Sequencer"));
}
void AMyDialogSequencer::Initialize()
{
// Static data time
int32 frameStart = 0;
int32 frameEnd = 120;
// Build LevelSequence
_sequence = NewObject<ULevelSequence>();
_sequence->Initialize();
// Configure LevelSequence
auto scene = _sequence->GetMovieScene();
scene->SetPlaybackRange(TRange<FFrameNumber>::Inclusive(frameStart, frameEnd));
scene->SetWorkingRange(frameStart, frameEnd);
scene->SetViewRange(frameStart, frameEnd);
// Build track
auto* track = _sequence->GetMovieScene()->AddMasterTrack<UMovieSceneEventTrack>();
check(track);
track->SetDisplayName(FText::FromName(TEXT("Events")));
// Build Section
UMovieSceneEventTriggerSection* section = Cast<UMovieSceneEventTriggerSection>(track->CreateNewSection());
check(section);
section->SetRange(TRange<FFrameNumber>::Inclusive(frameStart, frameEnd));
// Add Section to main track
track->AddSection(*section);
// Modify section
if(section->TryModify(true))
{
auto& channelProxy = section->GetChannelProxy();
auto channel = channelProxy.GetChannel<FMovieSceneEventChannel>(0);
check(channel);
// Create key to call OnFinishDialog
TMovieSceneChannelData<FMovieSceneEvent> eventData = channel->GetData();
FMovieSceneEventPayloadVariable Payload;
Payload.Value = "OnFinishDialog";
FMovieSceneEvent sceneEvent;
sceneEvent.PayloadVariables.Add(TEXT("EventTick"), Payload);
FFrameNumber Frame;
Frame.Value = frameEnd;
Frame--;
eventData.AddKey(Frame, sceneEvent);
}
SetSequence(_sequence);
InitializePlayer();
FMovieSceneSequencePlaybackSettings settings;
settings.StartTime = 0.0f;
FLevelSequenceCameraSettings InCameraSettings;
check(GetSequencePlayer());
GetSequencePlayer()->Initialize(_sequence, GetWorld()->GetCurrentLevel(), settings, InCameraSettings);
}
void AMyDialogSequencer::OnFinishDialog()
{
UE_LOG(LogTemp, Verbose, TEXT("Finish Dialog"));
}
Creation of actor
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AMyDialogSequencer* dialogSequencer = GetWorld()->SpawnActor<AMyDialogSequencer>(AMyDialogSequencer::StaticClass(), SpawnInfo);
dialogSequencer->Initialize();