Noah Petherbridge
a2e1bd1ccb
* Events.OnCollide now receives a CollideEvent object, which makes available the .Actor who collided and the .Overlap rect which is zero-relative to the target actor. Doodad scripts can use the .Overlap to see WHERE in their own box the other actor has intruded. * Update the LockedDoor and ElectricDoor doodads to detect when the player has entered their inner rect (since their doors are narrower than their doodad size) * Update the Button doodads to only press in when the player actually touches them (because their sizes are shorter than their doodad height) * Update the Trapdoor to only trigger its animation when the board along its top has been touched, not when the empty space below was touched from the bottom. * Events.OnLeave now implemented and fires when an actor who was previously intersecting your doodad has left. * The engine detects when an event JS callback returns false. Eventually, the OnCollide can return false to signify the collision is not accepted and the actor should be bumped away as if they hit solid geometry.
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package scripting
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"git.kirsle.net/apps/doodle/lib/events"
|
|
"github.com/robertkrimen/otto"
|
|
)
|
|
|
|
// Event name constants.
|
|
const (
|
|
CollideEvent = "OnCollide" // another doodad collides with us
|
|
EnterEvent = "OnEnter" // a doodad is fully inside us
|
|
LeaveEvent = "OnLeave" // a doodad no longer collides with us
|
|
|
|
// Controllable (player character) doodad events
|
|
KeypressEvent = "OnKeypress" // i.e. arrow keys
|
|
)
|
|
|
|
// Event return errors.
|
|
var (
|
|
ErrReturnFalse = errors.New("JS callback function returned false")
|
|
)
|
|
|
|
// Events API for Doodad scripts.
|
|
type Events struct {
|
|
registry map[string][]otto.Value
|
|
}
|
|
|
|
// NewEvents initializes the Events API.
|
|
func NewEvents() *Events {
|
|
return &Events{
|
|
registry: map[string][]otto.Value{},
|
|
}
|
|
}
|
|
|
|
// OnCollide fires when another actor collides with yours.
|
|
func (e *Events) OnCollide(call otto.FunctionCall) otto.Value {
|
|
return e.register(CollideEvent, call.Argument(0))
|
|
}
|
|
|
|
// RunCollide invokes the OnCollide handler function.
|
|
func (e *Events) RunCollide(v interface{}) error {
|
|
return e.run(CollideEvent, v)
|
|
}
|
|
|
|
// OnLeave fires when another actor stops colliding with yours.
|
|
func (e *Events) OnLeave(call otto.FunctionCall) otto.Value {
|
|
return e.register(LeaveEvent, call.Argument(0))
|
|
}
|
|
|
|
// RunLeave invokes the OnLeave handler function.
|
|
func (e *Events) RunLeave(v interface{}) error {
|
|
return e.run(LeaveEvent, v)
|
|
}
|
|
|
|
// OnKeypress fires when another actor collides with yours.
|
|
func (e *Events) OnKeypress(call otto.FunctionCall) otto.Value {
|
|
return e.register(KeypressEvent, call.Argument(0))
|
|
}
|
|
|
|
// RunKeypress invokes the OnCollide handler function.
|
|
func (e *Events) RunKeypress(ev *events.State) error {
|
|
return e.run(KeypressEvent, ev)
|
|
}
|
|
|
|
// register a named event.
|
|
func (e *Events) register(name string, callback otto.Value) otto.Value {
|
|
if !callback.IsFunction() {
|
|
return otto.Value{} // TODO
|
|
}
|
|
|
|
if _, ok := e.registry[name]; !ok {
|
|
e.registry[name] = []otto.Value{}
|
|
}
|
|
|
|
e.registry[name] = append(e.registry[name], callback)
|
|
return otto.Value{}
|
|
}
|
|
|
|
// Run an event handler. Returns an error only if there was a JavaScript error
|
|
// inside the function. If there are no event handlers, just returns nil.
|
|
func (e *Events) run(name string, args ...interface{}) error {
|
|
if _, ok := e.registry[name]; !ok {
|
|
return nil
|
|
}
|
|
|
|
for _, callback := range e.registry[name] {
|
|
value, err := callback.Call(otto.Value{}, args...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If the event handler returned a boolean false, stop all other
|
|
// callbacks and return the boolean.
|
|
if value.IsBoolean() {
|
|
if b, err := value.ToBoolean(); err == nil && b == false {
|
|
return ErrReturnFalse
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|