236 lines
8.5 KiB
Markdown
236 lines
8.5 KiB
Markdown
#Actor & Module System
|
||
|
||
• main.js is the first program started by the engine. Once main.js ends (is killed), the engine exits
|
||
(equivalent to clicking the window’s “X”).
|
||
• Files that do not return anything (i.e. do not include a “return …;” statement) are considered programs.
|
||
• Files that do return a single object are modules, imported via the use('filename') function.
|
||
• Actors are running program objects. They can spawn new actors as underlings, with the spawner acting as
|
||
their overling.
|
||
|
||
Modules
|
||
-------
|
||
You can import a module by calling:
|
||
use('some_module')
|
||
This function searches through the engine’s path list (prosperon.PATH) for files such as some_module.js or
|
||
some_module.jsc (among other supported extensions). If found, the module portion is executed once and its
|
||
return value is cached; subsequent calls to use(...) with the same name return the cached object.
|
||
|
||
Key rules:
|
||
1. A module must end with a “return something;” statement.
|
||
2. The value returned by a module is typically an object containing functions or configuration.
|
||
3. A module is loaded at most once per engine run; later use(...) calls return the same module object.
|
||
|
||
Example (config.js):
|
||
---------------------
|
||
// config.js
|
||
---
|
||
return {
|
||
width: 800,
|
||
height: 600
|
||
}
|
||
|
||
In your program you might write:
|
||
var config = use('config.js')
|
||
console.log(config.width) // Outputs: 800
|
||
|
||
Programs
|
||
--------
|
||
Prosperon distinguishes programs from modules by whether they return a value:
|
||
|
||
• If a file does not include a “return …;” statement, it is considered a program.
|
||
• A program can be spawned as an actor.
|
||
• main.js is the special “root” program; when it terminates (or is killed), the engine quits.
|
||
|
||
Mixed Files (Modules + Programs)
|
||
----------------------------------
|
||
A single file can contain both module code and program code if the two sections are separated by a line
|
||
containing just:
|
||
---
|
||
If the first part includes a “return …;” statement, it is treated as the module portion, while the second
|
||
part is treated as the program portion. This design allows one file to serve as both a module (exposing an API)
|
||
and an actor script.
|
||
|
||
Example structure in one file:
|
||
--------------------------------
|
||
// Module portion
|
||
return {
|
||
someUtility() { /* … */ }
|
||
}
|
||
---
|
||
// Program portion
|
||
this.start = function() {
|
||
console.log("Hello from the actor part!");
|
||
}
|
||
|
||
The engine will parse and load the module portion when use('file') is called; if the file is spawned as a
|
||
program, the program portion is executed on the actor.
|
||
|
||
Actor System
|
||
------------
|
||
Creating Actors:
|
||
----------------
|
||
Any running actor can create an underling by calling its built-in spawn method. For example, in main.js
|
||
(the root program):
|
||
|
||
// In main.js
|
||
var child = this.spawn('child.js', { name: "ChildActor" })
|
||
|
||
spawn accepts the following arguments:
|
||
1. script (string): The file name or path to another program file.
|
||
2. config (optional object): Properties to merge into the spawned actor.
|
||
3. callback (optional function): Invoked immediately after creation with (underling, info).
|
||
|
||
The spawned actor’s “overling” is the actor that called spawn. The new actor is recorded in the overling’s set
|
||
of underlings.
|
||
|
||
Overling & Underlings:
|
||
----------------------
|
||
• Overling: The actor that spawns another actor.
|
||
• Underling: An actor that is spawned by an overling.
|
||
|
||
Each actor has:
|
||
– this.overling (read-only): The actor that spawned it.
|
||
– this.underlings (read-only): A set of its child actors.
|
||
|
||
Actor Lifecycle & kill()
|
||
------------------------
|
||
An actor can be removed from the world by calling kill(). For example:
|
||
|
||
child.kill()
|
||
|
||
Killing an actor automatically terminates all of its underlings (recursively). Once killed, an actor is marked
|
||
as dead and will no longer process any calls. When the root actor (main.js) calls kill() on itself or is terminated,
|
||
the entire engine shuts down.
|
||
|
||
Hooks and Functions:
|
||
--------------------
|
||
When an actor is spawned, the engine looks for special hook functions. These functions are optional, but if present,
|
||
they are called at specific times:
|
||
|
||
• awake() – Called immediately after the actor is fully set up and registered with engine updates.
|
||
• garbage() – Called just before the actor is removed; use this to free resources or unhook active listeners.
|
||
• then() – Also called just before removal; can be used for additional cleanup or business logic.
|
||
|
||
Example (child.js):
|
||
-------------------
|
||
// child.js
|
||
this.awake = function() {
|
||
console.log("Awake! My overling is " + this.overling);
|
||
}
|
||
|
||
this.garbage = function() {
|
||
console.log("Time to go away.");
|
||
}
|
||
|
||
Delayed Calls:
|
||
--------------
|
||
To schedule a function to be called in the future on the actor, use:
|
||
this.delay(fn, seconds)
|
||
For example:
|
||
|
||
this.delay(function() {
|
||
console.log("Called after 2 seconds");
|
||
}, 2)
|
||
|
||
The function will be called with “this” bound to the actor. If the actor is killed before the delay expires,
|
||
the scheduled function will not be executed.
|
||
|
||
Actor Registration & Events:
|
||
----------------------------
|
||
Actors can automatically register to receive engine-wide events such as update, gui, etc. If an actor defines
|
||
a function with one of these names, it is registered automatically when the actor is created.
|
||
|
||
Some common event hooks include:
|
||
– update(): Called once per frame.
|
||
– gui(): Called when GUI elements are drawn.
|
||
– draw(): Called when the scene is rendered.
|
||
(Additional events such as appupdate or physupdate may also be supported based on engine configuration.)
|
||
|
||
Example Actor (child.js):
|
||
-------------------------
|
||
// child.js
|
||
this.awake = function() {
|
||
console.log("Child actor awake.");
|
||
}
|
||
|
||
this.update = function() {
|
||
// Called every frame
|
||
console.log("Child actor update.");
|
||
}
|
||
|
||
this.garbage = function() {
|
||
console.log("Child actor is being removed.");
|
||
}
|
||
|
||
When another actor (including main.js) calls spawn("child.js"), the above code executes on the new actor.
|
||
|
||
main.js and the Engine Entry Point
|
||
------------------------------------
|
||
• Prosperon begins by loading and running main.js as the root actor.
|
||
• When main.js terminates or calls kill(), the entire engine shuts down.
|
||
|
||
Example (main.js):
|
||
------------------
|
||
// main.js
|
||
console.log("Hello from main.js");
|
||
|
||
this.awake = function() {
|
||
// Called once when the engine starts up
|
||
var child = this.spawn("child.js", { name: "ChildOne" });
|
||
console.log("Spawned a child actor.");
|
||
}
|
||
|
||
this.update = function() {
|
||
// Called every frame
|
||
// …
|
||
}
|
||
|
||
this.stopGame = function() {
|
||
// Call this function to exit the game
|
||
this.kill();
|
||
}
|
||
|
||
Logging and Console
|
||
-------------------
|
||
Prosperon provides several console logging methods:
|
||
|
||
• console.log(msg) – Info-level output (printed to both the log and console).
|
||
• console.debug(msg) – Debug-level output.
|
||
• console.warn(msg) – Warning-level messages.
|
||
• console.error(err) – Error-level messages, including stack traces.
|
||
|
||
A fatal error will print a stack trace and trigger an engine shutdown.
|
||
|
||
Signals & Engine Shutdown
|
||
-------------------------
|
||
Internally, Prosperon listens for signals such as SIGINT, SIGABRT, SIGSEGV, etc. When these signals occur,
|
||
the engine will exit immediately. This behavior is a safety measure; scripting code typically does not need to handle
|
||
these signals directly.
|
||
|
||
Summary of Key API
|
||
------------------
|
||
this.spawn(script, config, callback)
|
||
• Creates a new actor from the specified program script.
|
||
• Optionally merges properties from the config object into the new actor.
|
||
• Invokes the callback (if provided) with (actor, { message: "created" }).
|
||
|
||
this.kill()
|
||
• Immediately terminates the actor and all its underlings.
|
||
• Calls any garbage/then hooks defined on the actor.
|
||
|
||
this.delay(fn, seconds)
|
||
• Schedules the function fn to be called after the specified number of seconds, provided the actor remains alive.
|
||
|
||
Lifecycle Hooks:
|
||
• awake() – Called immediately after an actor is spawned.
|
||
• garbage() – Called just before the actor is removed.
|
||
• then() – An additional cleanup callback before removal.
|
||
|
||
Event Hooks (automatically registered if defined):
|
||
• update() – Called once per frame.
|
||
• gui(), draw(), appupdate(), etc.
|
||
|
||
Modules:
|
||
• Use modules by calling use('filename'). A module must return a single object from the module portion (i.e. the code
|
||
before the optional '---' if the file also contains a program portion).
|