浏览代码

Added repeat flag to delayed method calls.
Added possibility to remove delayed method calls selectively.
Documented delayed method calls.

Lasse Öörni 13 年之前
父节点
当前提交
312ddc0242
共有 5 个文件被更改,包括 87 次插入36 次删除
  1. 26 1
      Docs/Reference.dox
  2. 7 6
      Docs/ScriptAPI.dox
  3. 16 16
      Engine/Engine/ScriptAPI.cpp
  4. 30 9
      Engine/Script/ScriptInstance.cpp
  5. 8 4
      Engine/Script/ScriptInstance.h

+ 26 - 1
Docs/Reference.dox

@@ -312,6 +312,31 @@ ScriptObject@ object = node.CreateScriptObject("Scripts/MyClass.as", "MyClass");
 
 
 Note that these are not actual Node member functions on the C++ side, as the %Scene library is not allowed to depend on scripting.
 Note that these are not actual Node member functions on the C++ side, as the %Scene library is not allowed to depend on scripting.
 
 
+\section Script_DelayedCalls Delayed method calls
+
+Delayed method calls can be used in script objects to implement time-delayed actions. Use the DelayedExecute() function in script object code to add a method to be executed later. The parameters are the delay in seconds, repeat flag, the full declaration of the function, and optionally parameters, which must be placed in a Variant array. For example:
+
+\code
+class Test : ScriptObject
+{
+    void Start()
+    {
+        Array<Variant> parameters;
+        parameters.Push(Variant(100));
+        DelayedExecute(1.0, false, "void Trigger(int)", parameters);
+    }
+    
+    void Trigger(int parameter)
+    {
+        Print("Delayed function triggered with parameter " + parameter);
+    }
+}
+\endcode
+
+Delayed method calls can be removed by full declaration using the ClearDelayedExecute() function. If an empty declaration (default) is given as parameter, all delayed calls are removed.
+
+When a scene is saved/loaded, any pending delayed calls are also saved and restored properly.
+
 \section Script_ScriptAPI The script API
 \section Script_ScriptAPI The script API
 
 
 Much of the Urho3D classes are exposed to scripts, however things that require low-level access or high performance (like direct vertex buffer access) are not. Also for scripting convenience some things have been changed from the C++ API:
 Much of the Urho3D classes are exposed to scripts, however things that require low-level access or high performance (like direct vertex buffer access) are not. Also for scripting convenience some things have been changed from the C++ API:
@@ -346,7 +371,7 @@ Much of the Urho3D classes are exposed to scripts, however things that require l
 
 
 There are some complexities of the scripting system one has to watch out for:
 There are some complexities of the scripting system one has to watch out for:
 
 
-- During the execution of the script object's constructor, the object is not yet associated with the ScriptInstance, and therefore subscribing to events, or trying to access the node or scene will fail. The use of the constructor is best reserved for initializing member variables only.
+- During the execution of the script object's constructor, the object is not yet associated with the ScriptInstance, and therefore subscribing to events, adding delayed method calls, or trying to access the node or scene will fail. The use of the constructor is best reserved for initializing member variables only.
 
 
 - When the resource request for a particular ScriptFile is initially made, the script file and the files it includes are compiled into an AngelScript script module. Each script module has its own class hierarchy that is not usable from other script modules, unless the classes are declared shared. See AngelScript documentation for more details.
 - When the resource request for a particular ScriptFile is initially made, the script file and the files it includes are compiled into an AngelScript script module. Each script module has its own class hierarchy that is not usable from other script modules, unless the classes are declared shared. See AngelScript documentation for more details.
 
 

+ 7 - 6
Docs/ScriptAPI.dox

@@ -65,9 +65,9 @@
 - uint GetRGBAFormat()
 - uint GetRGBAFormat()
 - uint GetFloatFormat()
 - uint GetFloatFormat()
 - uint GetDepthStencilFormat()
 - uint GetDepthStencilFormat()
-- void DelayedExecute(float, const String&, const Variant[]@)
-- void DelayedExecute(float, const String&)
-- void ClearDelayedExecute()
+- void DelayedExecute(float, bool, const String&, const Variant[]@)
+- void DelayedExecute(float, bool, const String&)
+- void ClearDelayedExecute(const String& arg0 = String ( ))
 - void Remove()
 - void Remove()
 \section ScriptAPI_GlobalProperties Global properties
 \section ScriptAPI_GlobalProperties Global properties
 - Time@ time
 - Time@ time
@@ -2083,6 +2083,7 @@ Methods:<br>
 - void RemoveAnimationState(Animation@)
 - void RemoveAnimationState(Animation@)
 - void RemoveAnimationState(const String&)
 - void RemoveAnimationState(const String&)
 - void RemoveAnimationState(AnimationState@)
 - void RemoveAnimationState(AnimationState@)
+- void RemoveAnimationState(uint)
 - void RemoveAllAnimationStates()
 - void RemoveAllAnimationStates()
 - void SetMorphWeight(uint, float)
 - void SetMorphWeight(uint, float)
 - void ResetMorphWeights()
 - void ResetMorphWeights()
@@ -4395,9 +4396,9 @@ Methods:<br>
 - bool CreateObject(ScriptFile@, const String&)
 - bool CreateObject(ScriptFile@, const String&)
 - bool Execute(const String&, const Variant[]@)
 - bool Execute(const String&, const Variant[]@)
 - bool Execute(const String&)
 - bool Execute(const String&)
-- void DelayedExecute(float, const String&, const Variant[]@)
-- void DelayedExecute(float, const String&)
-- void ClearDelayedExecute()
+- void DelayedExecute(float, bool, const String&, const Variant[]@)
+- void DelayedExecute(float, bool, const String&)
+- void ClearDelayedExecute(const String& arg0 = String ( ))
 
 
 Properties:<br>
 Properties:<br>
 - ShortStringHash type (readonly)
 - ShortStringHash type (readonly)

+ 16 - 16
Engine/Engine/ScriptAPI.cpp

@@ -139,7 +139,7 @@ static bool ScriptInstanceExecuteNoParams(const String& declaration, ScriptInsta
     return ptr->Execute(declaration);
     return ptr->Execute(declaration);
 }
 }
 
 
-static void ScriptInstanceDelayedExecute(float delay, const String& declaration, CScriptArray* srcParams, ScriptInstance* ptr)
+static void ScriptInstanceDelayedExecute(float delay, bool repeat, const String& declaration, CScriptArray* srcParams, ScriptInstance* ptr)
 {
 {
     if (!srcParams)
     if (!srcParams)
         return;
         return;
@@ -151,12 +151,12 @@ static void ScriptInstanceDelayedExecute(float delay, const String& declaration,
     for (unsigned i = 0; i < numParams; ++i)
     for (unsigned i = 0; i < numParams; ++i)
         destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
         destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
     
     
-    ptr->DelayedExecute(delay, declaration, destParams);
+    ptr->DelayedExecute(delay, repeat, declaration, destParams);
 }
 }
 
 
-static void ScriptInstanceDelayedExecuteNoParams(float delay, const String& declaration, ScriptInstance* ptr)
+static void ScriptInstanceDelayedExecuteNoParams(float delay, bool repeat, const String& declaration, ScriptInstance* ptr)
 {
 {
-    ptr->DelayedExecute(delay, declaration);
+    ptr->DelayedExecute(delay, repeat, declaration);
 }
 }
 
 
 static ScriptInstance* GetSelf()
 static ScriptInstance* GetSelf()
@@ -164,7 +164,7 @@ static ScriptInstance* GetSelf()
     return GetScriptContextInstance();
     return GetScriptContextInstance();
 }
 }
 
 
-static void SelfDelayedExecute(float delay, const String& declaration, CScriptArray* srcParams)
+static void SelfDelayedExecute(float delay, bool repeat, const String& declaration, CScriptArray* srcParams)
 {
 {
     ScriptInstance* ptr = GetScriptContextInstance();
     ScriptInstance* ptr = GetScriptContextInstance();
     if (!ptr || !srcParams)
     if (!ptr || !srcParams)
@@ -177,21 +177,21 @@ static void SelfDelayedExecute(float delay, const String& declaration, CScriptAr
     for (unsigned i = 0; i < numParams; ++i)
     for (unsigned i = 0; i < numParams; ++i)
         destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
         destParams[i] = *(static_cast<Variant*>(srcParams->At(i)));
     
     
-    ptr->DelayedExecute(delay, declaration, destParams);
+    ptr->DelayedExecute(delay, repeat, declaration, destParams);
 }
 }
 
 
-static void SelfDelayedExecuteNoParams(float delay, const String& declaration)
+static void SelfDelayedExecuteNoParams(float delay, bool repeat, const String& declaration)
 {
 {
     ScriptInstance* ptr = GetScriptContextInstance();
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
     if (ptr)
-        ptr->DelayedExecute(delay, declaration);
+        ptr->DelayedExecute(delay, repeat, declaration);
 }
 }
 
 
-static void SelfClearDelayedExecute()
+static void SelfClearDelayedExecute(const String& declaration)
 {
 {
     ScriptInstance* ptr = GetScriptContextInstance();
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
     if (ptr)
-        ptr->ClearDelayedExecute();
+        ptr->ClearDelayedExecute(declaration);
 }
 }
 
 
 static void SelfRemove()
 static void SelfRemove()
@@ -214,9 +214,9 @@ static void RegisterScriptInstance(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ScriptInstance", "bool CreateObject(ScriptFile@+, const String&in)", asMETHODPR(ScriptInstance, CreateObject, (ScriptFile*, const String&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool CreateObject(ScriptFile@+, const String&in)", asMETHODPR(ScriptInstance, CreateObject, (ScriptFile*, const String&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool Execute(const String&in, const Array<Variant>@+)", asFUNCTION(ScriptInstanceExecute), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "bool Execute(const String&in, const Array<Variant>@+)", asFUNCTION(ScriptInstanceExecute), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "bool Execute(const String&in)", asFUNCTION(ScriptInstanceExecuteNoParams), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "bool Execute(const String&in)", asFUNCTION(ScriptInstanceExecuteNoParams), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, const String&in, const Array<Variant>@+)", asFUNCTION(ScriptInstanceDelayedExecute), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, const String&in)", asFUNCTION(ScriptInstanceDelayedExecuteNoParams), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("ScriptInstance", "void ClearDelayedExecute()", asMETHOD(ScriptInstance, ClearDelayedExecute), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, bool, const String&in, const Array<Variant>@+)", asFUNCTION(ScriptInstanceDelayedExecute), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, bool, const String&in)", asFUNCTION(ScriptInstanceDelayedExecuteNoParams), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ScriptInstance", "void ClearDelayedExecute(const String&in declaration = String())", asMETHOD(ScriptInstance, ClearDelayedExecute), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_active(bool)", asMETHOD(ScriptInstance, SetActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_active(bool)", asMETHOD(ScriptInstance, SetActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool get_active() const", asMETHOD(ScriptInstance, IsActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "bool get_active() const", asMETHOD(ScriptInstance, IsActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_fixedUpdateFps(int)", asMETHOD(ScriptInstance, SetFixedUpdateFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_fixedUpdateFps(int)", asMETHOD(ScriptInstance, SetFixedUpdateFps), asCALL_THISCALL);
@@ -229,9 +229,9 @@ static void RegisterScriptInstance(asIScriptEngine* engine)
     engine->RegisterGlobalFunction("ScriptInstance@+ get_self()", asFUNCTION(GetSelf), asCALL_CDECL);
     engine->RegisterGlobalFunction("ScriptInstance@+ get_self()", asFUNCTION(GetSelf), asCALL_CDECL);
     
     
     // Register convenience functions for controlling delayed execution on self, similar to event sending
     // Register convenience functions for controlling delayed execution on self, similar to event sending
-    engine->RegisterGlobalFunction("void DelayedExecute(float, const String&in, const Array<Variant>@+)", asFUNCTION(SelfDelayedExecute), asCALL_CDECL);
-    engine->RegisterGlobalFunction("void DelayedExecute(float, const String&in)", asFUNCTION(SelfDelayedExecuteNoParams), asCALL_CDECL);
-    engine->RegisterGlobalFunction("void ClearDelayedExecute()", asFUNCTION(SelfClearDelayedExecute), asCALL_CDECL);
+    engine->RegisterGlobalFunction("void DelayedExecute(float, bool, const String&in, const Array<Variant>@+)", asFUNCTION(SelfDelayedExecute), asCALL_CDECL);
+    engine->RegisterGlobalFunction("void DelayedExecute(float, bool, const String&in)", asFUNCTION(SelfDelayedExecuteNoParams), asCALL_CDECL);
+    engine->RegisterGlobalFunction("void ClearDelayedExecute(const String&in declaration = String())", asFUNCTION(SelfClearDelayedExecute), asCALL_CDECL);
     engine->RegisterGlobalFunction("void Remove()", asFUNCTION(SelfRemove), asCALL_CDECL);
     engine->RegisterGlobalFunction("void Remove()", asFUNCTION(SelfRemove), asCALL_CDECL);
 }
 }
 
 

+ 30 - 9
Engine/Script/ScriptInstance.cpp

@@ -168,13 +168,14 @@ bool ScriptInstance::Execute(asIScriptFunction* method, const VariantVector& par
     return scriptFile_->Execute(scriptObject_, method, parameters);
     return scriptFile_->Execute(scriptObject_, method, parameters);
 }
 }
 
 
-void ScriptInstance::DelayedExecute(float delay, const String& declaration, const VariantVector& parameters)
+void ScriptInstance::DelayedExecute(float delay, bool repeat, const String& declaration, const VariantVector& parameters)
 {
 {
     if (!scriptObject_)
     if (!scriptObject_)
         return;
         return;
     
     
     DelayedMethodCall call;
     DelayedMethodCall call;
-    call.delay_ = Max(delay, 0.0f);
+    call.period_ = call.delay_ = Max(delay, 0.0f);
+    call.repeat_ = repeat;
     call.declaration_ = declaration;
     call.declaration_ = declaration;
     call.parameters_ = parameters;
     call.parameters_ = parameters;
     delayedMethodCalls_.Push(call);
     delayedMethodCalls_.Push(call);
@@ -184,9 +185,15 @@ void ScriptInstance::DelayedExecute(float delay, const String& declaration, cons
         SubscribeToEvent(GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
         SubscribeToEvent(GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
 }
 }
 
 
-void ScriptInstance::ClearDelayedExecute()
+void ScriptInstance::ClearDelayedExecute(const String& declaration)
 {
 {
-    delayedMethodCalls_.Clear();
+    for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End();)
+    {
+        if (declaration.Empty() || declaration == i->declaration_)
+            i = delayedMethodCalls_.Erase(i);
+        else
+            ++i;
+    }
 }
 }
 
 
 void ScriptInstance::AddEventHandler(StringHash eventType, const String& handlerName)
 void ScriptInstance::AddEventHandler(StringHash eventType, const String& handlerName)
@@ -249,7 +256,9 @@ void ScriptInstance::SetDelayedMethodCallsAttr(PODVector<unsigned char> value)
     delayedMethodCalls_.Resize(buf.ReadVLE());
     delayedMethodCalls_.Resize(buf.ReadVLE());
     for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
     for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
     {
     {
+        i->period_ = buf.ReadFloat();
         i->delay_ = buf.ReadFloat();
         i->delay_ = buf.ReadFloat();
+        i->repeat_ = buf.ReadBool();
         i->declaration_ = buf.ReadString();
         i->declaration_ = buf.ReadString();
         i->parameters_ = buf.ReadVariantVector();
         i->parameters_ = buf.ReadVariantVector();
     }
     }
@@ -283,7 +292,9 @@ PODVector<unsigned char> ScriptInstance::GetDelayedMethodCallsAttr() const
     buf.WriteVLE(delayedMethodCalls_.Size());
     buf.WriteVLE(delayedMethodCalls_.Size());
     for (Vector<DelayedMethodCall>::ConstIterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
     for (Vector<DelayedMethodCall>::ConstIterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
     {
     {
+        buf.WriteFloat(i->period_);
         buf.WriteFloat(i->delay_);
         buf.WriteFloat(i->delay_);
+        buf.WriteBool(i->repeat_);
         buf.WriteString(i->declaration_);
         buf.WriteString(i->declaration_);
         buf.WriteVariantVector(i->parameters_);
         buf.WriteVariantVector(i->parameters_);
     }
     }
@@ -390,14 +401,24 @@ void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventDa
     float timeStep = eventData[P_TIMESTEP].GetFloat();
     float timeStep = eventData[P_TIMESTEP].GetFloat();
     
     
     // Execute delayed method calls
     // Execute delayed method calls
-    for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End();)
+    for (unsigned i = 0; i < delayedMethodCalls_.Size();)
     {
     {
-        i->delay_ -= timeStep;
-        if (i->delay_ <= 0.0f)
+        DelayedMethodCall& call = delayedMethodCalls_[i];
+        bool remove = false;
+        
+        call.delay_ -= timeStep;
+        if (call.delay_ <= 0.0f)
         {
         {
-            Execute(i->declaration_, i->parameters_);
-            i = delayedMethodCalls_.Erase(i);
+            if (!call.repeat_)
+                remove = true;
+            else
+                call.delay_ += call.period_;
+            
+            Execute(call.declaration_, call.parameters_);
         }
         }
+        
+        if (remove)
+            delayedMethodCalls_.Erase(i);
         else
         else
             ++i;
             ++i;
     }
     }

+ 8 - 4
Engine/Script/ScriptInstance.h

@@ -50,8 +50,12 @@ enum ScriptInstanceMethod
 /// Delay-executed method call.
 /// Delay-executed method call.
 struct DelayedMethodCall
 struct DelayedMethodCall
 {
 {
+   /// Period for repeating calls.
+    float period_;
     /// Delay time remaining until execution.
     /// Delay time remaining until execution.
     float delay_;
     float delay_;
+    /// Repeat flag.
+    bool repeat_;
     /// Method declaration.
     /// Method declaration.
     String declaration_;
     String declaration_;
     /// Parameters.
     /// Parameters.
@@ -92,10 +96,10 @@ public:
     bool Execute(const String& declaration, const VariantVector& parameters = VariantVector());
     bool Execute(const String& declaration, const VariantVector& parameters = VariantVector());
     /// Execute a method.
     /// Execute a method.
     bool Execute(asIScriptFunction* method, const VariantVector& parameters = VariantVector());
     bool Execute(asIScriptFunction* method, const VariantVector& parameters = VariantVector());
-    /// Add a delay-executed method call.
-    void DelayedExecute(float delay, const String& declaration, const VariantVector& parameters = VariantVector());
-    /// Clear pending delay-executed method calls.
-    void ClearDelayedExecute();
+    /// Add a delay-executed method call, optionally repeating.
+    void DelayedExecute(float delay, bool repeat, const String& declaration, const VariantVector& parameters = VariantVector());
+    /// Clear pending delay-executed method calls. If empty declaration given, clears all.
+    void ClearDelayedExecute(const String& declaration = String());
     
     
     /// Return script file.
     /// Return script file.
     ScriptFile* GetScriptFile() const { return scriptFile_; }
     ScriptFile* GetScriptFile() const { return scriptFile_; }