Add support for PrefabObject tracks and automated animation instancing with UsePrefabObjects enabled
This commit is contained in:
@@ -26,6 +26,11 @@ namespace FlaxEditor.GUI.Timeline
|
||||
/// The loop flag. Looped tracks are doing a playback of its data in a loop.
|
||||
/// </summary>
|
||||
Loop = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The prefab object reference flag for tracks used to animate objects in prefabs (for reusable instanced animations).
|
||||
/// </summary>
|
||||
PrefabObject = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -62,8 +62,57 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
/// </summary>
|
||||
public Actor Actor
|
||||
{
|
||||
get => FlaxEngine.Object.TryFind<Actor>(ref ActorID);
|
||||
set => ActorID = value?.ID ?? Guid.Empty;
|
||||
get
|
||||
{
|
||||
if (Flags.HasFlag(TrackFlags.PrefabObject))
|
||||
{
|
||||
// TODO: reuse cached actor to improve perf
|
||||
foreach (var window in Editor.Instance.Windows.Windows)
|
||||
{
|
||||
if (window is Windows.Assets.PrefabWindow prefabWindow && prefabWindow.Graph.MainActor)
|
||||
{
|
||||
var actor = FindActorWithPrefabObjectID(prefabWindow.Graph.MainActor, ref ActorID);
|
||||
if (actor != null)
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return FlaxEngine.Object.TryFind<Actor>(ref ActorID);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (value.HasPrefabLink && value.Scene == null)
|
||||
{
|
||||
// Track with prefab object reference assigned in Editor
|
||||
ActorID = value.PrefabObjectID;
|
||||
Flags |= TrackFlags.PrefabObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
ActorID = value.ID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ActorID = Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Actor FindActorWithPrefabObjectID(Actor a, ref Guid id)
|
||||
{
|
||||
if (a.PrefabObjectID == id)
|
||||
return a;
|
||||
for (int i = 0; i < a.ChildrenCount; i++)
|
||||
{
|
||||
var e = FindActorWithPrefabObjectID(a.GetChild(i), ref id);
|
||||
if (e != null)
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
|
||||
var obj = Object;
|
||||
var hasObject = obj != null;
|
||||
TitleTintColor = hasObject ? Color.White : Color.Red;
|
||||
TitleTintColor = hasObject ? (Flags.HasFlag(TrackFlags.PrefabObject) ? Style.Current.ProgressNormal : Color.White) : Color.Red;
|
||||
if (hasObject != _hasObject)
|
||||
OnObjectExistenceChanged(obj);
|
||||
_hasObject = hasObject;
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
None = 0,
|
||||
Mute = 1,
|
||||
Loop = 2,
|
||||
PrefabObject = 4,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -473,3 +474,5 @@ protected:
|
||||
void unload(bool isReloading) override;
|
||||
AssetChunksFlag getChunksToPreload() const override;
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(SceneAnimation::Track::Flags);
|
||||
|
||||
@@ -1124,6 +1124,7 @@ void SceneAnimationPlayer::Serialize(SerializeStream& stream, const void* otherO
|
||||
SERIALIZE(RandomStartTime);
|
||||
SERIALIZE(RestoreStateOnStop);
|
||||
SERIALIZE(UpdateMode);
|
||||
SERIALIZE(UsePrefabObjects);
|
||||
}
|
||||
|
||||
void SceneAnimationPlayer::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -1140,6 +1141,30 @@ void SceneAnimationPlayer::Deserialize(DeserializeStream& stream, ISerializeModi
|
||||
DESERIALIZE(RandomStartTime);
|
||||
DESERIALIZE(RestoreStateOnStop);
|
||||
DESERIALIZE(UpdateMode);
|
||||
DESERIALIZE(UsePrefabObjects);
|
||||
|
||||
if (UsePrefabObjects && Animation && !Animation->WaitForLoaded())
|
||||
{
|
||||
// When loading from prefab automatically map objects from prefab instance into animation tracks with object references
|
||||
for (auto& track : Animation->Tracks)
|
||||
{
|
||||
if (track.Disabled || !(track.Flag & SceneAnimation::Track::Flags::PrefabObject))
|
||||
continue;
|
||||
switch (track.Type)
|
||||
{
|
||||
case SceneAnimation::Track::Types::Actor:
|
||||
case SceneAnimation::Track::Types::Script:
|
||||
case SceneAnimation::Track::Types::CameraCut:
|
||||
{
|
||||
const auto trackData = track.GetData<SceneAnimation::ObjectTrack::Data>();
|
||||
Guid id;
|
||||
if (modifier->IdsMapping.TryGet(trackData->ID, id))
|
||||
_objectsMapping[trackData->ID] = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneAnimationPlayer::Collect(RenderContext& renderContext)
|
||||
|
||||
@@ -128,6 +128,12 @@ public:
|
||||
API_FIELD(Attributes="EditorDisplay(\"Scene Animation\"), EditorOrder(80), DefaultValue(UpdateModes.EveryUpdate)")
|
||||
UpdateModes UpdateMode = UpdateModes::EveryUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the scene animation should automatically map prefab objects from scene animation into prefab instances. Useful for reusable animations to automatically link prefab objects.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorDisplay(\"Scene Animation\"), EditorOrder(100)")
|
||||
bool UsePrefabObjects = false;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user