Feature Request
As far I'm concerned AngelScript works well in an event driven programming model. You'll just have to write an application object with which events and their corresponding script functions can be registered. The object would also have methods to raise events.
Example script:
void Init(){ eventMgr.RegisterEvent(HITME, "onHitMe"); eventMgr.NewEvent(HITME);}void onHitMe(){ print("A HitMe event occurred");}
When the event manager receives a call to NewEvent, it creates a context (or reuses an existing one) and calls the script function registered for that event.
Regards,
Andreas
PS. I will implement script function pointers soon, which may help in this regard.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
I'll have to think a little while as to what my particular needs are but what I can initially tell is something along these lines:
Main script begins execution.
Script registers functions to handle desired events.
Script creates GUI.
User interacts with GUI.
GUI fires event.
Event handler executes and interacts with main script to notify it of
any user actions.
For example lets say I have this situation.
The main script has an array of integers. Everytime the user presses a button on the GUI, a corresponding integer is placed into the vector.
The main script then does some processing on the contents of the array.
perhaps something like this:
int[] myArrray;void main(){ CreateGUI(); while(!done) HandleEvents()}void CreateGUI(){ Button b(5, 5, 5, 5); b.OnClick = HandleClick;}void HandleClick(int myargs){ myArray.PushBack(myargs);}
The example obviously is incomplete, but it should show the general idea.
Perhaps something like this is already possible, or can be easily done.
Since your main script is a long running script, and you want to be able to call other scripts without having to wait for the main script to terminate, you'll have to do a little scripted "multi-threading". You'll have to execute a small part of the main script, pause it, verify if the user has clicked on some GUI elements, call the event scripts, then resume execution of the main script. This is all done in a single OS thread, but to the script it will look like it was done in a multithreaded way.
You can use the line callback to suspend the main script after a short while.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
#include <iostream> // cout#include <assert.h> // assert()#include <conio.h> // kbhit(), getch()#include <windows.h> // timeGetTime()#include <angelscript.h>#include "../../../add_on/scriptstring/scriptstring.h"using namespace std;// Function prototypesvoid ConfigureEngine(asIScriptEngine *engine);int CompileScript(asIScriptEngine *engine);void PrintString(string &str);void LineCallback(asIScriptContext *ctx, DWORD *timeOut);int main(int argc, char **argv){ int r; // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); if( engine == 0 ) { cout << "Failed to create script engine." << endl; return -1; } // Configure the script engine with all the functions, // and variables that the script should be able to use. ConfigureEngine(engine); // Compile the script code r = CompileScript(engine); if( r < 0 ) return -1; // Create a script context that will execute the long running script asIScriptContext *ctx; r = engine->CreateContext(&ctx); if( r < 0 ) { cout << "Failed to create the context." << endl; return -1; } // Prepare the script context with the function we wish to execute r = ctx->Prepare(engine->GetFunctionIDByDecl(0, "void main()")); if( r < 0 ) { cout << "Failed to prepare the context." << endl; return -1; } // Set the line callback so that we can suspend the script execution // after a certain time. Before executing the script the timeOut variable // will be set to the time when the script must stop executing. This // way we will be able to do more than one thing, almost at the same time. DWORD timeOut; r = ctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL); if( r < 0 ) { cout << "Failed to set the line callback function." << endl; return -1; } // Print some useful information and start the input loop cout << "Sample event driven script execution using AngelScript " << asGetLibraryVersion() << "." << endl; cout << "The main script continuosly prints a short string." << endl; cout << "Press any key to fire an event that will print another string." << endl; cout << "Press ESC to terminate the application." << endl << endl; DWORD time = timeGetTime(); for(;;) { // Check if any key was pressed if( kbhit() ) { int key = getch(); if( key == 27 ) break; else { // Fire an event by calling the script function. // Using ExecuteString() for this is actually rather slow. // It would be more efficient to create a context outside // the main loop. We would also determine and store the // function id of the event function outside the loop. At // this location we would then just prepare the context and // execute it. But, since I'm a bit lazy and don't need the // extra performance, I'll use ExecuteString(). engine->ExecuteString(0, "Print(\"event fired\\n\")"); } } // Allow the long running script to execute for 10ms timeOut = timeGetTime() + 10; r = ctx->Execute(); if( r != asEXECUTION_SUSPENDED ) { cout << "The script execution finished early." << endl; break; } } // Abort the long running script. // It would have been better to allow the script to terminate by itself, // perhaps by setting a global variable that it would poll every now and // then. But Abort() can be used, and AngelScript makes sure everything // is correctly freed. ctx->Abort(); // We must release the context when no longer using it ctx->Release(); // Release the engine engine->Release(); return 0;}void ConfigureEngine(asIScriptEngine *engine){ int r; // Register the script string type // Look at the implementation for this function for more information // on how to register a custom string type, and other object types. // The implementation is in "/add_on/scriptstring/scriptstring.cpp" RegisterScriptString(engine); // Register the functions that the scripts will be allowed to use r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("uint GetSystemTime()", asFUNCTION(timeGetTime), asCALL_STDCALL); assert( r >= 0 );}class asCOutputStream : public asIOutputStream{public: void Write(const char *text) { buffer += text; } string buffer;};int CompileScript(asIScriptEngine *engine){ int r; // This script prints a . approximately 10 times per second const char *script = "void main() " "{ " " uint time = GetSystemTime(); " " for(;;) " " { " " uint t = GetSystemTime(); " " if( t - time > 100 ) " " { " " time = t; " " Print(\".\"); " " } " " } " "} "; // Add the script sections that will be compiled into executable code r = engine->AddScriptSection(0, "script", script, strlen(script), 0, false); if( r < 0 ) { cout << "AddScriptSection() failed" << endl; return -1; } // The script compiler will send any compiler messages to the outstream asCOutputStream out; // Compile the script r = engine->Build(0, &out); if( r < 0 ) { cout << "Build() failed" << endl; return -1; } return 0;}void PrintString(string &str){ cout << str;}void LineCallback(asIScriptContext *ctx, DWORD *timeOut){ // If the time out is reached we suspend the script if( *timeOut < timeGetTime() ) ctx->Suspend();}
regards,
Andreas
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
I'll update the sample to show that the variables are shared.
The name asIScriptContext is actually slightly misleading, and I intend to change it to asIScriptThread in a future version. asIScriptThread would more closely show what the role of the interface is.
Regards,
Andreas
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game