Browse Source

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

Lasse Öörni 13 years ago
parent
commit
312ddc0242

+ 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.
 
+\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
 
 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:
 
-- 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.
 

+ 7 - 6
Docs/ScriptAPI.dox

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

+ 16 - 16
Engine/Engine/ScriptAPI.cpp

@@ -139,7 +139,7 @@ static bool ScriptInstanceExecuteNoParams(const String& declaration, ScriptInsta
     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)
         return;
@@ -151,12 +151,12 @@ static void ScriptInstanceDelayedExecute(float delay, const String& declaration,
     for (unsigned i = 0; i < numParams; ++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()
@@ -164,7 +164,7 @@ static ScriptInstance* GetSelf()
     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();
     if (!ptr || !srcParams)
@@ -177,21 +177,21 @@ static void SelfDelayedExecute(float delay, const String& declaration, CScriptAr
     for (unsigned i = 0; i < numParams; ++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();
     if (ptr)
-        ptr->DelayedExecute(delay, declaration);
+        ptr->DelayedExecute(delay, repeat, declaration);
 }
 
-static void SelfClearDelayedExecute()
+static void SelfClearDelayedExecute(const String& declaration)
 {
     ScriptInstance* ptr = GetScriptContextInstance();
     if (ptr)
-        ptr->ClearDelayedExecute();
+        ptr->ClearDelayedExecute(declaration);
 }
 
 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 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", "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", "bool get_active() const", asMETHOD(ScriptInstance, IsActive), 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);
     
     // 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);
 }
 

+ 30 - 9
Engine/Script/ScriptInstance.cpp

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

+ 8 - 4
Engine/Script/ScriptInstance.h

@@ -50,8 +50,12 @@ enum ScriptInstanceMethod
 /// Delay-executed method call.
 struct DelayedMethodCall
 {
+   /// Period for repeating calls.
+    float period_;
     /// Delay time remaining until execution.
     float delay_;
+    /// Repeat flag.
+    bool repeat_;
     /// Method declaration.
     String declaration_;
     /// Parameters.
@@ -92,10 +96,10 @@ public:
     bool Execute(const String& declaration, const VariantVector& parameters = VariantVector());
     /// Execute a method.
     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.
     ScriptFile* GetScriptFile() const { return scriptFile_; }