Merge pull request #418 from SHADE-DP/SP3-22-AnimationController

Added Animator events and fixed Animator pause bug
This commit is contained in:
XiaoQiDigipen 2023-03-10 19:07:36 +08:00 committed by GitHub
commit 062c11afa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 569 additions and 24 deletions

View File

@ -25,6 +25,10 @@ namespace SHADE.Test
protected override void awake()
{
Animator = GetComponent<Animator>();
Animator.OnClipStartedPlaying.RegisterAction((_) => Debug.Log("Start Playing"));
Animator.OnClipPaused.RegisterAction((_) => Debug.Log("Pause"));
Animator.OnClipFinished.RegisterAction((_) => Debug.Log("Finished"));
}
protected override void update()
@ -61,6 +65,15 @@ namespace SHADE.Test
AnimationSystem.TimeScale = AnimationSystem.TimeScale > 0.0f ? 0.0f
: AnimationSystem.DefaultTimeScale;
}
if (Input.GetKeyUp(Input.KeyCode.P))
{
if (Animator.IsPlaying)
Animator.Pause();
else
Animator.Play();
}
}
#endregion
}

View File

@ -31,8 +31,7 @@ namespace SHADE
return;
const float SECS_PER_TICK = 1.0f / static_cast<float>(rawAnim->GetTicksPerSecond());
const int ONE_PAST_LAST_FRAME = lastFrame + 1;
duration = static_cast<float>(ONE_PAST_LAST_FRAME - firstFrame) * SECS_PER_TICK;
duration = static_cast<float>(lastFrame - firstFrame) * SECS_PER_TICK;
startTimeStamp = static_cast<float>(firstFrame) * SECS_PER_TICK;
}
}

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHAnimationSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "SHAnimationClip.h"
#include "Events/SHEventManager.hpp"
namespace SHADE
{
@ -55,7 +56,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationController::Update(InstanceData& instData, float dt)
void SHAnimationController::Update(EntityID eid, InstanceData& instData, float dt)
{
// Is there a valid node
if (!instData.CurrentNode)
@ -72,6 +73,7 @@ namespace SHADE
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp() + instData.CurrentNode->Clip->GetTotalDuration();
// Go to next state
Handle<SHAnimationClip> originalClip = instData.CurrentNode->Clip;
bool stateChanged = false;
for (const auto& transition : instData.CurrentNode->Transitions)
{
@ -107,7 +109,29 @@ namespace SHADE
}
// Handle if there is no next state, we repeat
if (!stateChanged)
if (stateChanged)
{
// Raise events
SHEventManager::BroadcastEvent
(
SHAnimationSystem::FinishedEvent
{
eid,
originalClip
},
SH_ANIMATION_FINISHED_EVENT
);
SHEventManager::BroadcastEvent
(
SHAnimationSystem::PlayEvent
{
eid,
instData.CurrentNode ? instData.CurrentNode->Clip : Handle<SHAnimationClip>()
},
SH_ANIMATIONS_PLAY_EVENT
);
}
else
{
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp();
}

View File

@ -18,6 +18,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes
#include "SH_API.h"
#include "Resource/SHHandle.h"
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
@ -162,7 +163,12 @@ namespace SHADE
/// <summary>
/// Runs a single update for the animation controller.
/// </summary>
void Update(InstanceData& instData, float dt);
/// <param name="eid">
/// EntityID of the entity that this animation controller is updating.
/// </param>
/// <param name="instData">Instance data that stores the current state.</param>
/// <param name="dt">Frame time.</param>
void Update(EntityID eid, InstanceData& instData, float dt);
/*---------------------------------------------------------------------------------*/
/* Usage Functions */

View File

@ -19,6 +19,11 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declaration */
/*-----------------------------------------------------------------------------------*/
class SHAnimationClip;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
@ -29,7 +34,7 @@ namespace SHADE
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/* Type Definitions - System Routines */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Responsible for updating the playback of all animator components and computing
@ -42,6 +47,40 @@ namespace SHADE
void Execute(double dt) noexcept override final;
};
/*---------------------------------------------------------------------------------*/
/* Type Definitions - Event Data */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Event data for the SH_ANIMATIONS_PLAY_EVENT event which is raised on the frame
/// that an animation has started playing.
/// </summary>
struct PlayEvent
{
EntityID Entity;
Handle<SHAnimationClip> PlayingClip;
float CurrentTimeStamp;
};
/// <summary>
/// Event data for the SH_ANIMATIONS_PAUSED_EVENT event which is raised on the frame
/// that an animation is paused.
/// </summary>
struct PausedEvent
{
EntityID Entity;
Handle<SHAnimationClip> PausedClip;
float PauseTimeStamp;
};
/// <summary>
/// Event data for the SH_ANIMATIONS_FINISHED_EVENT event which is raised on the
/// frame that an animation has finished playing. This will not be called for any
/// animation that loops.
/// </summary>
struct FinishedEvent
{
EntityID Entity;
Handle<SHAnimationClip> FinishedClip;
};
/*---------------------------------------------------------------------------------*/
/* Constants */
/*---------------------------------------------------------------------------------*/

View File

@ -25,6 +25,7 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Tools/SHDebugDraw.h"
#include "Events/SHEventManager.hpp"
namespace SHADE
{
@ -35,6 +36,8 @@ namespace SHADE
{
isPlaying = true;
playOnce = false;
raisePlayEvent();
}
void SHAnimatorComponent::Play(Handle<SHAnimationClip> clip)
@ -91,11 +94,13 @@ namespace SHADE
isPlaying = true;
currPlaybackTime = 0.0f;
raisePlayEvent();
}
void SHAnimatorComponent::Pause()
{
isPlaying = false;
raisePauseEvent();
}
void SHAnimatorComponent::Stop()
@ -119,9 +124,13 @@ namespace SHADE
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Do not do anything if is not playing or there's nothing to animate
if (!isPlaying || !rig || !rig->GetRootNode())
if (!rig || !rig->GetRootNode())
return;
// We want to still display a paused pose, so we only prevent progression
if (!isPlaying)
dt = 0.0f;
// Update the animation controller if any, this will set the currClip
if (animController)
{
@ -210,7 +219,20 @@ namespace SHADE
return animController->SetTrigger(animInstanceData, paramName);
}
/*-----------------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------------*/
Handle<SHAnimationClip> SHAnimatorComponent::GetCurrentClip() const noexcept
{
if (animController)
{
return animInstanceData.CurrentNode ? animInstanceData.CurrentNode->Clip : Handle<SHAnimationClip>();
}
return currClip;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Update */
/*-----------------------------------------------------------------------------------*/
@ -221,7 +243,7 @@ namespace SHADE
return;
// Update the animation controller
animController->Update(animInstanceData, dt);
animController->Update(GetEID(), animInstanceData, dt);
// Get current clip
currClip = animInstanceData.CurrentNode->Clip;
@ -241,6 +263,7 @@ namespace SHADE
playOnce = false;
isPlaying = false;
currPlaybackTime = currClip->GetStartTimeStamp() + currClip->GetTotalDuration();
raiseFinishEvent();
}
else
{
@ -251,7 +274,7 @@ namespace SHADE
void SHAnimatorComponent::updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime)
{
// Nothing to animate
if (!clip || !isPlaying || !rig || !rig->GetRootNode())
if (!clip || !rig || !rig->GetRootNode())
return;
// Check that we have animation data
@ -299,6 +322,50 @@ namespace SHADE
updatePoseWithClip(poseTime, rawAnimData, child, transformMatrix);
}
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Event */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::raisePlayEvent()
{
SHEventManager::BroadcastEvent
(
SHAnimationSystem::PlayEvent
{
GetEID(),
GetCurrentClip(),
GetCurrentClipPlaybackTime()
},
SH_ANIMATIONS_PLAY_EVENT
);
}
void SHAnimatorComponent::raisePauseEvent()
{
SHEventManager::BroadcastEvent
(
SHAnimationSystem::PausedEvent
{
GetEID(),
GetCurrentClip(),
GetCurrentClipPlaybackTime()
},
SH_ANIMATIONS_PAUSED_EVENT
);
}
void SHAnimatorComponent::raiseFinishEvent()
{
SHEventManager::BroadcastEvent
(
SHAnimationSystem::FinishedEvent
{
GetEID(),
GetCurrentClip()
},
SH_ANIMATION_FINISHED_EVENT
);
}
}
/*-------------------------------------------------------------------------------------*/

View File

@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/SHQuaternion.h"
#include "SHRawAnimation.h"
#include "SHAnimationController.h"
#include "SHAnimationSystem.h"
namespace SHADE
{
@ -166,6 +167,20 @@ namespace SHADE
/// </summary>
/// <returnsHandle to the currently set animtion controller.</returns>
Handle<SHAnimationController> GetAnimationController() const noexcept { return animController; }
/// <summary>
/// Retrieves the currently playing clip. If there is an Animation Controller, it
/// will be retrieved from it. Otherwise, the currently assigned Animation Clip is provided.
/// </summary>
/// <returns>Handle to the currently playing Animation Clip if any.</returns>
Handle<SHAnimationClip> GetCurrentClip() const noexcept;
/// <summary>
/// Retrieves the current timestamp of the currently playing clip. This is relative
/// to the start frame of the Animation Clip. This function will retrieve the correct
/// playback time depending on the current playback mode (Animation Controller or
/// Manual).
/// </summary>
/// <returns>Time in seconds of the current timestamp of the current clip.</returns>
float GetCurrentClipPlaybackTime() const noexcept { return animController ? animInstanceData.ClipPlaybackTime : currPlaybackTime; }
private:
/*---------------------------------------------------------------------------------*/
@ -201,6 +216,10 @@ namespace SHADE
void updatePoseWithClip(float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
template<typename T>
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, float poseTime);
// Event Functions
void raisePlayEvent();
void raisePauseEvent();
void raiseFinishEvent();
/*---------------------------------------------------------------------------------*/
/* RTTR */

View File

@ -31,4 +31,6 @@ constexpr SHEventIdentifier SH_BUTTON_HOVER_ENTER_EVENT { 22 };
constexpr SHEventIdentifier SH_BUTTON_HOVER_EXIT_EVENT { 23 };
constexpr SHEventIdentifier SH_ASSET_COMPILE_EVENT { 24 };
constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_DELETE_EVENT { 25 };
constexpr SHEventIdentifier SH_ANIMATIONS_PAUSED_EVENT { 26 };
constexpr SHEventIdentifier SH_ANIMATIONS_PLAY_EVENT { 27 };
constexpr SHEventIdentifier SH_ANIMATION_FINISHED_EVENT { 28 };

View File

@ -34,6 +34,8 @@ of DigiPen Institute of Technology is prohibited.
#include "UI/Events/SHButtonClickEvent.h"
#include "UI/SHUIComponent.h"
#include "Editor/EditorWindow/MenuBar/SHEditorMenuBar.h"
#include "Animation/SHAnimatorComponent.h"
#include "Resource/SHResourceManager.h"
namespace SHADE
{
@ -412,6 +414,49 @@ namespace SHADE
return eventData->handle;
}
SHEventHandle SHScriptEngine::onAnimatorRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(eventPtr.get());
if (eventData->data->removedComponentType == ComponentFamily::GetID<SHAnimatorComponent>())
csAnimatorOnRemoved(eventData->data->eid);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onAnimatorClipStartedPlaying(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHAnimationSystem::PlayEvent>*>(eventPtr.get());
csAnimatorOnClipStartPlaying
(
eventData->data->Entity,
SHResourceManager::GetAssetID(eventData->data->PlayingClip).value_or(INVALID_ASSET_ID),
eventData->data->CurrentTimeStamp
);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onAnimatorClipPaused(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHAnimationSystem::PausedEvent>*>(eventPtr.get());
csAnimatorOnClipPaused
(
eventData->data->Entity,
SHResourceManager::GetAssetID(eventData->data->PausedClip).value_or(INVALID_ASSET_ID),
eventData->data->PauseTimeStamp
);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onAnimatorClipFinished(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHAnimationSystem::FinishedEvent>*>(eventPtr.get());
csAnimatorOnClipFinished
(
eventData->data->Entity,
SHResourceManager::GetAssetID(eventData->data->FinishedClip).value_or(INVALID_ASSET_ID)
);
return eventData->handle;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
@ -578,6 +623,30 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".UIElement",
"OnHoverExited"
);
csAnimatorOnRemoved = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Animator",
"OnComponentRemoved"
);
csAnimatorOnClipStartPlaying = dotNet.GetFunctionPtr<CsEventRelayAnimTimeFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Animator",
"RaiseOnClipStartedPlaying"
);
csAnimatorOnClipPaused = dotNet.GetFunctionPtr<CsEventRelayAnimTimeFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Animator",
"RaiseOnClipPaused"
);
csAnimatorOnClipFinished = dotNet.GetFunctionPtr<CsEventRelayAnimFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Animator",
"RaiseOnClipFinished"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
@ -663,6 +732,28 @@ namespace SHADE
};
SHEventManager::SubscribeTo(SH_BUTTON_HOVER_EXIT_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(hoverExitedUIElementEventReceiver));
/* Animator */
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedAnimatorEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onAnimatorRemoved)
};
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedAnimatorEventReceiver));
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> animStartedPlayingEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onAnimatorClipStartedPlaying)
};
SHEventManager::SubscribeTo(SH_ANIMATIONS_PLAY_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(animStartedPlayingEventReceiver));
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> animPausedEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onAnimatorClipPaused)
};
SHEventManager::SubscribeTo(SH_ANIMATIONS_PAUSED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(animPausedEventReceiver));
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> animFinishedEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onAnimatorClipFinished)
};
SHEventManager::SubscribeTo(SH_ANIMATION_FINISHED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(animFinishedEventReceiver));
/* SceneGraph */
// Register for SceneNode child added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addChildEventReceiver

View File

@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Events/SHEventDefines.h"
#include "Events/SHEvent.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE
{
@ -251,6 +252,8 @@ namespace SHADE
using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*);
using CsScriptEditorFuncPtr = void(*)(EntityID);
using CsEventRelayFuncPtr = void(*)(EntityID);
using CsEventRelayAnimFuncPtr = void(*)(EntityID, AssetID);
using CsEventRelayAnimTimeFuncPtr = void(*)(EntityID, AssetID, float);
/*-----------------------------------------------------------------------------*/
/* Constants */
@ -295,6 +298,12 @@ namespace SHADE
CsEventRelayFuncPtr csUIElementOnReleased = nullptr;
CsEventRelayFuncPtr csUIElementOnHoverEntered = nullptr;
CsEventRelayFuncPtr csUIElementOnHoverExited = nullptr;
CsEventRelayFuncPtr csAnimatorOnRemoved = nullptr;
CsEventRelayAnimTimeFuncPtr csAnimatorOnClipStartPlaying = nullptr;
CsEventRelayAnimTimeFuncPtr csAnimatorOnClipPaused = nullptr;
CsEventRelayAnimFuncPtr csAnimatorOnClipFinished = nullptr;
// - Editor
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
CsFuncPtr csEditorUndo = nullptr;
@ -315,6 +324,10 @@ namespace SHADE
SHEventHandle onSceneNodeChildrenAdded(SHEventPtr eventPtr);
SHEventHandle onSceneNodeChildrenRemoved(SHEventPtr eventPtr);
SHEventHandle onSceneDestroyed(SHEventPtr eventPtr);
SHEventHandle onAnimatorRemoved(SHEventPtr eventPtr);
SHEventHandle onAnimatorClipStartedPlaying(SHEventPtr eventPtr);
SHEventHandle onAnimatorClipPaused(SHEventPtr eventPtr);
SHEventHandle onAnimatorClipFinished(SHEventPtr eventPtr);
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Animator.hxx"
#include "Assets/NativeAsset.hxx"
#include "Utility/Convert.hxx"
#include "Utility/Debug.hxx"
namespace SHADE
{
@ -69,6 +70,65 @@ namespace SHADE
return Convert::ToCLI(CURR_NODE->Name);
return nullptr;
}
bool Animator::IsPlaying::get()
{
return GetNativeComponent()->IsPlaying();
}
float Animator::CurrentClipPlaybackTime::get()
{
return GetNativeComponent()->GetCurrentClipPlaybackTime();
}
CallbackEvent<ClipStartPlayingEventData>^ Animator::OnClipStartedPlaying::get()
{
// Create map if it wasn't before
if (onClipStartPlayingEventMap == nullptr)
{
onClipStartPlayingEventMap = gcnew System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipStartPlayingEventData>^>();
}
// Create event if it wasn't before
if (!onClipStartPlayingEventMap->ContainsKey(owner.EntityId))
{
onClipStartPlayingEventMap->Add(owner.EntityId, gcnew CallbackEvent<ClipStartPlayingEventData>());
}
// Return the event
return onClipStartPlayingEventMap[owner.EntityId];
}
CallbackEvent<ClipPausedEventData>^ Animator::OnClipPaused::get()
{
// Create map if it wasn't before
if (onClipPausedEventMap == nullptr)
{
onClipPausedEventMap = gcnew System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipPausedEventData>^>();
}
// Create event if it wasn't before
if (!onClipPausedEventMap->ContainsKey(owner.EntityId))
{
onClipPausedEventMap->Add(owner.EntityId, gcnew CallbackEvent<ClipPausedEventData>());
}
// Return the event
return onClipPausedEventMap[owner.EntityId];
}
CallbackEvent<ClipFinishedEventData>^ Animator::OnClipFinished::get()
{
// Create map if it wasn't before
if (onClipFinishedEventMap == nullptr)
{
onClipFinishedEventMap = gcnew System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipFinishedEventData>^>();
}
// Create event if it wasn't before
if (!onClipFinishedEventMap->ContainsKey(owner.EntityId))
{
onClipFinishedEventMap->Add(owner.EntityId, gcnew CallbackEvent<ClipFinishedEventData>());
}
// Return the event
return onClipFinishedEventMap[owner.EntityId];
}
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
@ -156,4 +216,82 @@ namespace SHADE
{
return GetBoolParameter(paramName);
}
/*---------------------------------------------------------------------------------*/
/* Static Clear Functions */
/*---------------------------------------------------------------------------------*/
void Animator::ClearStaticEventData()
{
if (onClipStartPlayingEventMap != nullptr)
onClipStartPlayingEventMap->Clear();
if (onClipPausedEventMap != nullptr)
onClipPausedEventMap->Clear();
if (onClipFinishedEventMap != nullptr)
onClipFinishedEventMap->Clear();
}
/*---------------------------------------------------------------------------------*/
/* Event Handling Functions */
/*---------------------------------------------------------------------------------*/
void Animator::OnComponentRemoved(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN
// Remove the event if it contained an event
if (onClipStartPlayingEventMap != nullptr && onClipStartPlayingEventMap->ContainsKey(entity))
{
onClipStartPlayingEventMap->Remove(entity);
}
if (onClipPausedEventMap != nullptr && onClipPausedEventMap->ContainsKey(entity))
{
onClipPausedEventMap->Remove(entity);
}
if (onClipFinishedEventMap != nullptr && onClipFinishedEventMap->ContainsKey(entity))
{
onClipFinishedEventMap->Remove(entity);
}
SAFE_NATIVE_CALL_END("Animator.OnComponentRemoved")
}
void Animator::RaiseOnClipStartedPlaying(EntityID entity, AssetID animAssetId, float currTimeStamp)
{
SAFE_NATIVE_CALL_BEGIN
// Remove the event if it contained an event
if (onClipStartPlayingEventMap != nullptr && onClipStartPlayingEventMap->ContainsKey(entity))
{
ClipStartPlayingEventData data;
data.PlayingClip = AnimationClipAsset(animAssetId);
data.CurrentTimeStamp = currTimeStamp;
onClipStartPlayingEventMap[entity]->Invoke(data);
}
SAFE_NATIVE_CALL_END("Animator.OnClipStartedPlaying")
}
void Animator::RaiseOnClipPaused(EntityID entity, AssetID animAssetId, float currTimeStamp)
{
SAFE_NATIVE_CALL_BEGIN
// Remove the event if it contained an event
if (onClipPausedEventMap != nullptr && onClipPausedEventMap->ContainsKey(entity))
{
ClipPausedEventData data;
data.PausedClip = AnimationClipAsset(animAssetId);
data.PauseTimeStamp = currTimeStamp;
onClipPausedEventMap[entity]->Invoke(data);
}
SAFE_NATIVE_CALL_END("Animator.OnClipPaused")
}
void Animator::RaiseOnClipFinished(EntityID entity, AssetID animAssetId)
{
SAFE_NATIVE_CALL_BEGIN
// Remove the event if it contained an event
if (onClipFinishedEventMap != nullptr && onClipFinishedEventMap->ContainsKey(entity))
{
ClipFinishedEventData data;
data.FinishedClip = AnimationClipAsset(animAssetId);
onClipFinishedEventMap[entity]->Invoke(data);
}
SAFE_NATIVE_CALL_END("Animator.OnClipFinished")
}
}

View File

@ -25,6 +25,47 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/// <summary>
/// Simple struct that holds event data for the Animator.OnClipStartedPlaying event.
/// </summary>
public value struct ClipStartPlayingEventData
{
/// <summary>
/// Animation Clip that started playing.
/// </summary>
AnimationClipAsset PlayingClip;
/// <summary>
/// Timestamp that the Animation Clip started playing at. This is relative to
/// the first frame of the Animation Clip.
/// </summary>
float CurrentTimeStamp;
};
/// <summary>
/// Simple struct that holds event data for the Animator.OnClipPaused event.
/// </summary>
public value struct ClipPausedEventData
{
/// <summary>
/// Animation Clip that was paused.
/// </summary>
AnimationClipAsset PausedClip;
/// <summary>
/// Timestamp that the Animation Clip was paused at. This is relative to
/// the first frame of the Animation Clip.
/// </summary>
float PauseTimeStamp;
};
/// <summary>
/// Simple struct that holds event data for the Animator.OnClipFinished event.
/// </summary>
public value struct ClipFinishedEventData
{
/// <summary>
/// Animation Clip that just finished.
/// </summary>
AnimationClipAsset FinishedClip;
};
/// <summary>
/// CLR version of the SHADE Engine's SHAnimatorComponent.
/// </summary>
@ -70,6 +111,45 @@ namespace SHADE
{
System::String^ get();
}
/// <summary>
/// Whether an animation is currently playing.
/// </summary>
property bool IsPlaying
{
bool get();
}
/// <summary>
/// Retrieves the current timestamp of the currently playing clip. This is
/// relative to the start frame of the Animation Clip. This will retrieve the
/// correct playback time depending on the current playback mode
/// (Animation Controller or via direct Animation Clip).
/// </summary>
property float CurrentClipPlaybackTime
{
float get();
}
/// <summary>
/// Event which is raised on the frame that an animation has started playing.
/// </summary>
property CallbackEvent<ClipStartPlayingEventData>^ OnClipStartedPlaying
{
CallbackEvent<ClipStartPlayingEventData>^ get();
}
/// <summary>
/// Event which is raised on the frame that an animation is paused.
/// </summary>
property CallbackEvent<ClipPausedEventData>^ OnClipPaused
{
CallbackEvent<ClipPausedEventData>^ get();
}
/// <summary>
/// Event which is raised on the frame that an animation has finished playing.
/// This will not be called for any animation that loops.
/// </summary>
property CallbackEvent<ClipFinishedEventData>^ OnClipFinished
{
CallbackEvent<ClipFinishedEventData>^ get();
}
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
@ -159,6 +239,55 @@ namespace SHADE
/// <param name="paramName">Name of the parameter.</param>
/// <returns>True if the trigger is set.</returns>
System::Nullable<bool> GetTriggerState(System::String^ paramName);
internal:
/*-----------------------------------------------------------------------------*/
/* Static Clear Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Disposes static event data which may contains data from SHADE_Scripting.
/// </summary>
static void ClearStaticEventData();
private:
/*-----------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// To be called from native code when this component is removed.
/// </summary>
/// <param name="entity">The entity which has it's component removed.</param>
static void OnComponentRemoved(EntityID entity);
/// <summary>
/// To be called from native code when a clip for this component has started
/// playing.
/// </summary>
/// <param name="entity">The entity which has a clip start playing.</param>
/// <param name="animAssetId">AssetID of the animation clip.</param>
/// <param name="currTimeStamp">Timestamp that the clip was started at.</param>
static void RaiseOnClipStartedPlaying(EntityID entity, AssetID animAssetId, float currTimeStamp);
/// <summary>
/// To be called from native code when a clip for this component has been paused.
/// </summary>
/// <param name="entity">The entity which a clip has paused.</param>
/// <param name="animAssetId">AssetID of the animation clip.</param>
/// <param name="currTimeStamp">Timestamp that the clip was paused at.</param>
static void RaiseOnClipPaused(EntityID entity, AssetID animAssetId, float currTimeStamp);
/// <summary>
/// To be called from native code when a clip for this component has finished
/// playing.
/// </summary>
/// <param name="entity">The entity which a clip has finished playing.</param>
/// <param name="animAssetId">AssetID of the animation clip.</param>
static void RaiseOnClipFinished(EntityID entity, AssetID animAssetId);
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
// As these hold references to code in SHADE_Scripting, we must remember to dispose of them when changing scenes
static System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipStartPlayingEventData>^>^ onClipStartPlayingEventMap;
static System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipPausedEventData>^>^ onClipPausedEventMap;
static System::Collections::Generic::Dictionary<Entity, CallbackEvent<ClipFinishedEventData>^>^ onClipFinishedEventMap;
};
}

View File

@ -28,18 +28,6 @@ namespace SHADE
: Component(entity)
{}
void UIElement::ClearStaticEventData()
{
if (onClickEventMap != nullptr)
onClickEventMap->Clear();
if (onReleasedEventMap != nullptr)
onReleasedEventMap->Clear();
if (onHoverEnterEventMap != nullptr)
onHoverEnterEventMap->Clear();
if (onHoverExitEventMap != nullptr)
onHoverExitEventMap->Clear();
}
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
@ -112,9 +100,24 @@ namespace SHADE
return onHoverExitEventMap[owner.EntityId];
}
/*---------------------------------------------------------------------------------*/
/* Static Clear Functions */
/*---------------------------------------------------------------------------------*/
void UIElement::ClearStaticEventData()
{
if (onClickEventMap != nullptr)
onClickEventMap->Clear();
if (onReleasedEventMap != nullptr)
onReleasedEventMap->Clear();
if (onHoverEnterEventMap != nullptr)
onHoverEnterEventMap->Clear();
if (onHoverExitEventMap != nullptr)
onHoverExitEventMap->Clear();
}
/*---------------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------a----*/
/*---------------------------------------------------------------------------------*/
void UIElement::OnComponentRemoved(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN

View File

@ -22,6 +22,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Utility/Debug.hxx"
#include "Scripts/ScriptStore.hxx"
#include "Components/UIElement.hxx"
#include "Components/Animator.hxx"
namespace SHADE
{
@ -46,6 +47,7 @@ namespace SHADE
// Unload static data of components that have access to the assembly
UIElement::ClearStaticEventData();
Animator::ClearStaticEventData();
// Unload the script
scriptContext->Unload();