Răsfoiți Sursa

Animation now properly calls animation event callback methods
Animation event edit window now displays a drop down of components to call the event on

BearishSun 9 ani în urmă
părinte
comite
469ec40aa4

+ 1 - 1
Source/MBansheeEditor/GUI/GUIListBoxField.cs

@@ -26,7 +26,7 @@ namespace BansheeEditor
         public event OnSelectionChangedDelegate OnSelectionChanged;
 
         /// <summary>
-        /// Index of the list box entry currently selected.
+        /// Index of the list box entry currently selected. Returns -1 if nothing is selected.
         /// </summary>
         public int Index
         {

+ 0 - 2
Source/MBansheeEditor/Windows/Animation/GUIAnimEvents.cs

@@ -54,8 +54,6 @@ namespace BansheeEditor
                 AnimationEvent evnt = events[i];
 
                 int xPos = (int)(((evnt.Time - rangeOffset) / GetRange()) * drawableWidth) + PADDING;
-
-                Debug.Log(i + ". " + xPos);
                 if (relativeCoords.x >= (xPos - EVENT_HALF_WIDTH) && relativeCoords.x <= (xPos + EVENT_HALF_WIDTH))
                 {
                     eventIdx = i;

+ 57 - 6
Source/MBansheeEditor/Windows/Animation/GUICurveEditor.cs

@@ -63,7 +63,7 @@ namespace BansheeEditor
         private const int SIDEBAR_WIDTH = 30;
         private const int DRAG_START_DISTANCE = 3;
 
-        private EditorWindow window;
+        private AnimationWindow window;
         private GUILayout gui;
         private GUIPanel drawingPanel;
         private GUIPanel eventsPanel;
@@ -232,7 +232,7 @@ namespace BansheeEditor
         /// <param name="gui">GUI layout into which to place the GUI element.</param>
         /// <param name="width">Width in pixels.</param>
         /// <param name="height">Height in pixels.</param>
-        public GUICurveEditor(EditorWindow window, GUILayout gui, int width, int height)
+        public GUICurveEditor(AnimationWindow window, GUILayout gui, int width, int height)
         {
             this.window = window;
             this.gui = gui;
@@ -1056,8 +1056,14 @@ namespace BansheeEditor
             Rect2I eventBounds = GUIUtility.CalculateBounds(eventsPanel, window.GUI);
             Vector2I windowPos = position + new Vector2I(eventBounds.x, eventBounds.y);
 
+            SceneObject so = window.SelectedSO;
+            Component[] components = so.GetComponents();
+            string[] componentNames = new string[components.Length];
+            for (int i = 0; i < components.Length; i++)
+                componentNames[i] = components[i].GetType().Name;
+
             EventEditWindow editWindow = DropDownWindow.Open<EventEditWindow>(window, windowPos);
-            editWindow.Initialize(animEvent, () =>
+            editWindow.Initialize(animEvent, componentNames, () =>
             {
                 UpdateEventsGUI();
                 OnEventModified?.Invoke();
@@ -1068,7 +1074,7 @@ namespace BansheeEditor
     /// <summary>
     /// Drop down window that displays input boxes used for editing an event.
     /// </summary>
-    [DefaultSize(200, 50)]
+    [DefaultSize(200, 80)]
     internal class EventEditWindow : DropDownWindow
     {
         /// <summary>
@@ -1076,16 +1082,57 @@ namespace BansheeEditor
         /// use.
         /// </summary>
         /// <param name="animEvent">Event whose properties to edit.</param>
+        /// <param name="componentNames">List of component names that the user can select from.</param>
         /// <param name="updateCallback">Callback triggered when event values change.</param>
-        internal void Initialize(AnimationEvent animEvent, Action updateCallback)
+        internal void Initialize(AnimationEvent animEvent, string[] componentNames, Action updateCallback)
         {
+            int selectedIndex = -1;
+            if (!string.IsNullOrEmpty(animEvent.Name))
+            {
+                string[] nameEntries = animEvent.Name.Split('/');
+                if (nameEntries.Length > 1)
+                {
+                    string typeName = nameEntries[0];
+                    for (int i = 0; i < componentNames.Length; i++)
+                    {
+                        if (componentNames[i] == typeName)
+                        {
+                            selectedIndex = i;
+                            break;
+                        }
+                    }
+                }
+            }
+
             GUIFloatField timeField = new GUIFloatField(new LocEdString("Time"), 40, "");
             timeField.Value = animEvent.Time;
             timeField.OnChanged += x => { animEvent.Time = x; updateCallback(); }; // TODO UNDOREDO  
 
+            GUIListBoxField componentField = new GUIListBoxField(componentNames, new LocEdString("Component"), 40);
+            if (selectedIndex != -1)
+                componentField.Index = selectedIndex;
+
+            componentField.OnSelectionChanged += x =>
+            {
+                string compName = "";
+                if (x != -1)
+                    compName = componentNames[x] + "/";
+
+                animEvent.Name = compName + x;
+                updateCallback();
+            };// TODO UNDOREDO 
+
             GUITextField methodField = new GUITextField(new LocEdString("Method"), 40, false, "", GUIOption.FixedWidth(190));
             methodField.Value = animEvent.Name;
-            methodField.OnChanged += x => { animEvent.Name = x; updateCallback(); }; // TODO UNDOREDO 
+            methodField.OnChanged += x =>
+            {
+                string compName = "";
+                if(componentField.Index != -1)
+                    compName = componentNames[componentField.Index] + "/";
+
+                animEvent.Name = compName + x;
+                updateCallback();
+            }; // TODO UNDOREDO 
 
             GUILayoutY vertLayout = GUI.AddLayoutY();
 
@@ -1097,6 +1144,10 @@ namespace BansheeEditor
             timeLayout.AddSpace(5);
             timeLayout.AddElement(timeField);
             timeLayout.AddFlexibleSpace();
+            GUILayout componentLayout = contentLayout.AddLayoutX();
+            componentLayout.AddSpace(5);
+            componentLayout.AddElement(componentField);
+            componentLayout.AddFlexibleSpace();
             GUILayout methodLayout = contentLayout.AddLayoutX();
             methodLayout.AddSpace(5);
             methodLayout.AddElement(methodField);

+ 12 - 4
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -24,6 +24,14 @@ namespace BansheeEditor
 
         private SceneObject selectedSO;
 
+        /// <summary>
+        /// Scene object for which are we currently changing the animation for.
+        /// </summary>
+        internal SceneObject SelectedSO
+        {
+            get { return selectedSO; }
+        }
+
         #region Overrides
 
         /// <summary>
@@ -45,7 +53,7 @@ namespace BansheeEditor
         {
             Selection.OnSelectionChanged += OnSelectionChanged;
 
-            UpdateSelectedSO();
+            UpdateSelectedSO(true);
         }
 
         private void OnEditorUpdate()
@@ -562,10 +570,10 @@ namespace BansheeEditor
             return ProjectLibrary.IsSubresource(resourcePath);
         }
 
-        private void UpdateSelectedSO()
+        private void UpdateSelectedSO(bool force)
         {
             SceneObject so = Selection.SceneObject;
-            if (selectedSO != so)
+            if (selectedSO != so || force)
             {
                 if (selectedSO != null && so == null)
                 {
@@ -1079,7 +1087,7 @@ namespace BansheeEditor
 
         private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
         {
-            UpdateSelectedSO();
+            UpdateSelectedSO(false);
         }
 
         private void OnFrameSelected(int frameIdx)

+ 20 - 1
Source/MBansheeEngine/Animation/Animation.cs

@@ -684,7 +684,26 @@ namespace BansheeEngine
         /// <param name="name">Name of the event.</param>
         private void EventTriggered(AnimationClip clip, string name)
         {
-            // TODO - Find a scene object, component and method based on the event name, and call it
+            // Event should be in format "ComponentType/MethodName"
+            if (string.IsNullOrEmpty(name))
+                return;
+
+            string[] nameEntries = name.Split('/');
+            if (nameEntries.Length != 2)
+                return;
+
+            string typeName = nameEntries[0];
+            string methodName = nameEntries[1];
+
+            Component[] components = SceneObject.GetComponents();
+            for (int i = 0; i < components.Length; i++)
+            {
+                if (components[i].GetType().Name == typeName)
+                {
+                    components[i].Invoke(methodName);
+                    break;
+                }
+            }
         }
 
         /// <summary>

+ 13 - 1
Source/MBansheeEngine/Scene/Component.cs

@@ -72,7 +72,7 @@ namespace BansheeEngine
         /// <param name="box">Bounds in world space represented as an axis aligned bounding box.</param>
         /// <param name="sphere">Bounds in world space represented as a sphere.</param>
         /// <returns>True if the bounds have non-zero volume, false otherwise.</returns>
-        internal protected virtual bool CalculateBounds(out AABox box, out Sphere sphere)
+        protected internal virtual bool CalculateBounds(out AABox box, out Sphere sphere)
         {
             Vector3 pos = SceneObject.Position;
 
@@ -82,6 +82,15 @@ namespace BansheeEngine
             return false;
         }
 
+        /// <summary>
+        /// Calls a parameterless method with the specified name, on the component. 
+        /// </summary>
+        /// <param name="name">Name of the method to call.</param>
+        protected internal void Invoke(string name)
+        {
+            Internal_Invoke(mCachedPtr, name);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern Component Internal_AddComponent(SceneObject parent, Type type);
 
@@ -106,6 +115,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern void Internal_SetNotifyFlags(IntPtr nativeInstance, TransformChangedFlags flags);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_Invoke(IntPtr nativeInstance, string name);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
     }

+ 4 - 0
Source/SBansheeEngine/Include/BsManagedComponent.h

@@ -26,6 +26,9 @@ namespace BansheeEngine
 		/**	Returns managed component object instance. */
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
+		/**	Returns managed class of the component. */
+		MonoClass* getClass() const { return mManagedClass; }
+
 		/**	Returns managed type of the component. */
 		MonoReflectionType* getRuntimeType() const { return mRuntimeType; }
 
@@ -90,6 +93,7 @@ namespace BansheeEngine
 		typedef void(__stdcall *OnTransformChangedThunkDef) (MonoObject*, TransformChangedFlags, MonoException**);
 
 		MonoObject* mManagedInstance;
+		MonoClass* mManagedClass;
 		MonoReflectionType* mRuntimeType;
 		uint32_t mManagedHandle;
 

+ 1 - 0
Source/SBansheeEngine/Include/BsScriptComponent.h

@@ -64,6 +64,7 @@ namespace BansheeEngine
 		static MonoObject* internal_getSceneObject(ScriptComponent* nativeInstance);
 		static TransformChangedFlags internal_getNotifyFlags(ScriptComponent* nativeInstance);
 		static void internal_setNotifyFlags(ScriptComponent* nativeInstance, TransformChangedFlags flags);
+		static void internal_Invoke(ScriptComponent* nativeInstance, MonoString* name);
 		static void internal_destroy(ScriptComponent* nativeInstance, bool immediate);
 	};
 

+ 24 - 23
Source/SBansheeEngine/Source/BsManagedComponent.cpp

@@ -16,17 +16,17 @@
 namespace BansheeEngine
 {
 	ManagedComponent::ManagedComponent()
-		: mManagedInstance(nullptr), mRuntimeType(nullptr), mManagedHandle(0), mRunInEditor(false), mRequiresReset(true)
-		, mMissingType(false), mOnInitializedThunk(nullptr), mOnUpdateThunk(nullptr), mOnResetThunk(nullptr)
-		, mOnDestroyThunk(nullptr), mOnDisabledThunk(nullptr), mOnEnabledThunk(nullptr), mOnTransformChangedThunk(nullptr)
-		, mCalculateBoundsMethod(nullptr)
-	{ }
-
-	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
-		: Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType), mManagedHandle(0), mRunInEditor(false)
+		: mManagedInstance(nullptr), mManagedClass(nullptr), mRuntimeType(nullptr), mManagedHandle(0), mRunInEditor(false)
 		, mRequiresReset(true), mMissingType(false), mOnInitializedThunk(nullptr), mOnUpdateThunk(nullptr)
 		, mOnResetThunk(nullptr), mOnDestroyThunk(nullptr), mOnDisabledThunk(nullptr), mOnEnabledThunk(nullptr)
 		, mOnTransformChangedThunk(nullptr), mCalculateBoundsMethod(nullptr)
+	{ }
+
+	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
+		: Component(parent), mManagedInstance(nullptr), mManagedClass(nullptr), mRuntimeType(runtimeType)
+		, mManagedHandle(0), mRunInEditor(false), mRequiresReset(true), mMissingType(false), mOnInitializedThunk(nullptr)
+		, mOnUpdateThunk(nullptr), mOnResetThunk(nullptr), mOnDestroyThunk(nullptr), mOnDisabledThunk(nullptr)
+		, mOnEnabledThunk(nullptr), mOnTransformChangedThunk(nullptr), mCalculateBoundsMethod(nullptr)
 	{
 		MonoUtil::getClassName(mRuntimeType, mNamespace, mTypeName);
 		setName(mTypeName);
@@ -84,6 +84,7 @@ namespace BansheeEngine
 				mManagedHandle = 0;
 			}
 
+			mManagedClass = nullptr;
 			mRuntimeType = nullptr;
 			mOnInitializedThunk = nullptr;
 			mOnUpdateThunk = nullptr;
@@ -132,7 +133,7 @@ namespace BansheeEngine
 		mFullTypeName = mNamespace + "." + mTypeName;
 		mManagedInstance = object;
 		
-		MonoClass* managedClass = nullptr;
+		mManagedClass = nullptr;
 		if (mManagedInstance != nullptr)
 		{
 			mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
@@ -140,7 +141,7 @@ namespace BansheeEngine
 			::MonoClass* monoClass = MonoUtil::getClass(object);
 			mRuntimeType = MonoUtil::getType(monoClass);
 
-			managedClass = MonoManager::instance().findClass(monoClass);
+			mManagedClass = MonoManager::instance().findClass(monoClass);
 		}
 
 		mOnInitializedThunk = nullptr;
@@ -152,69 +153,69 @@ namespace BansheeEngine
 		mOnTransformChangedThunk = nullptr;
 		mCalculateBoundsMethod = nullptr;
 
-		while(managedClass != nullptr)
+		while(mManagedClass != nullptr)
 		{
 			if (mOnInitializedThunk == nullptr)
 			{
-				MonoMethod* onInitializedMethod = managedClass->getMethod("OnInitialize", 0);
+				MonoMethod* onInitializedMethod = mManagedClass->getMethod("OnInitialize", 0);
 				if (onInitializedMethod != nullptr)
 					mOnInitializedThunk = (OnInitializedThunkDef)onInitializedMethod->getThunk();
 			}
 
 			if (mOnUpdateThunk == nullptr)
 			{
-				MonoMethod* onUpdateMethod = managedClass->getMethod("OnUpdate", 0);
+				MonoMethod* onUpdateMethod = mManagedClass->getMethod("OnUpdate", 0);
 				if (onUpdateMethod != nullptr)
 					mOnUpdateThunk = (OnUpdateThunkDef)onUpdateMethod->getThunk();
 			}
 
 			if (mOnResetThunk == nullptr)
 			{
-				MonoMethod* onResetMethod = managedClass->getMethod("OnReset", 0);
+				MonoMethod* onResetMethod = mManagedClass->getMethod("OnReset", 0);
 				if (onResetMethod != nullptr)
 					mOnResetThunk = (OnResetThunkDef)onResetMethod->getThunk();
 			}
 
 			if (mOnDestroyThunk == nullptr)
 			{
-				MonoMethod* onDestroyMethod = managedClass->getMethod("OnDestroy", 0);
+				MonoMethod* onDestroyMethod = mManagedClass->getMethod("OnDestroy", 0);
 				if (onDestroyMethod != nullptr)
 					mOnDestroyThunk = (OnDestroyedThunkDef)onDestroyMethod->getThunk();
 			}
 
 			if (mOnDisabledThunk == nullptr)
 			{
-				MonoMethod* onDisableMethod = managedClass->getMethod("OnDisable", 0);
+				MonoMethod* onDisableMethod = mManagedClass->getMethod("OnDisable", 0);
 				if (onDisableMethod != nullptr)
 					mOnDisabledThunk = (OnDisabledThunkDef)onDisableMethod->getThunk();
 			}
 
 			if (mOnEnabledThunk == nullptr)
 			{
-				MonoMethod* onEnableMethod = managedClass->getMethod("OnEnable", 0);
+				MonoMethod* onEnableMethod = mManagedClass->getMethod("OnEnable", 0);
 				if (onEnableMethod != nullptr)
 					mOnEnabledThunk = (OnInitializedThunkDef)onEnableMethod->getThunk();
 			}
 
 			if (mOnTransformChangedThunk == nullptr)
 			{
-				MonoMethod* onTransformChangedMethod = managedClass->getMethod("OnTransformChanged", 1);
+				MonoMethod* onTransformChangedMethod = mManagedClass->getMethod("OnTransformChanged", 1);
 				if (onTransformChangedMethod != nullptr)
 					mOnTransformChangedThunk = (OnTransformChangedThunkDef)onTransformChangedMethod->getThunk();
 			}
 
 			if(mCalculateBoundsMethod == nullptr)
-				mCalculateBoundsMethod = managedClass->getMethod("CalculateBounds", 2);
+				mCalculateBoundsMethod = mManagedClass->getMethod("CalculateBounds", 2);
 
 			// Search for methods on base class if there is one
-			MonoClass* baseClass = managedClass->getBaseClass();
+			MonoClass* baseClass = mManagedClass->getBaseClass();
 			if (baseClass != ScriptComponent::getMetaData()->scriptClass)
-				managedClass = baseClass;
+				mManagedClass = baseClass;
 			else
 				break;
 		}
 
-		if (managedClass != nullptr)
+		if (mManagedClass != nullptr)
 		{
 			MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);
 			if (bansheeEngineAssembly == nullptr)
@@ -224,7 +225,7 @@ namespace BansheeEngine
 			if (runInEditorAttrib == nullptr)
 				BS_EXCEPT(InvalidStateException, "Cannot find RunInEditor managed class.");
 
-			mRunInEditor = managedClass->getAttribute(runInEditorAttrib) != nullptr;
+			mRunInEditor = mManagedClass->getAttribute(runInEditorAttrib) != nullptr;
 		}
 		else
 			mRunInEditor = false;

+ 36 - 0
Source/SBansheeEngine/Source/BsScriptComponent.cpp

@@ -199,6 +199,42 @@ namespace BansheeEngine
 			nativeInstance->mManagedComponent->mNotifyFlags = flags;
 	}
 
+	void ScriptComponent::internal_Invoke(ScriptComponent* nativeInstance, MonoString* name)
+	{
+		HManagedComponent comp = nativeInstance->mManagedComponent;
+		if (checkIfDestroyed(nativeInstance->mManagedComponent))
+			return;
+
+		MonoObject* compObj = comp->getManagedInstance();
+		MonoClass* compClass = comp->getClass();
+
+		bool found = false;
+		String methodName = MonoUtil::monoToString(name);
+		while (compClass != nullptr)
+		{
+			MonoMethod* method = compClass->getMethod(methodName);
+			if (method != nullptr)
+			{
+				method->invoke(compObj, nullptr);
+				found = true;
+				break;
+			}
+
+			// Search for methods on base class if there is one
+			MonoClass* baseClass = compClass->getBaseClass();
+			if (baseClass != metaData.scriptClass)
+				compClass = baseClass;
+			else
+				break;
+		}
+
+		if (!found)
+		{
+			LOGWRN("Cannot find method \"" + methodName + "\" to invoke on component of type \"" + 
+				compClass->getTypeName() + "\".");
+		}
+	}
+
 	void ScriptComponent::internal_destroy(ScriptComponent* nativeInstance, bool immediate)
 	{
 		if (!checkIfDestroyed(nativeInstance->mManagedComponent))