Files
cell/docs/actors.md

236 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 windows “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 engines 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 actors “overling” is the actor that called spawn. The new actor is recorded in the overlings 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).