diff --git a/docs/scripting.md b/docs/scripting.md index 7f8cd22..7e1b8b5 100644 --- a/docs/scripting.md +++ b/docs/scripting.md @@ -34,4 +34,7 @@ Computation takes place in turns. Each entity has functions called, if they exis |stop|called when the object is killed| |debug|use draw functions with the object's world position, during debug pass| |gui|draw functions in screen space, during gameplay gui pass| -|draw|draw functions in world space| \ No newline at end of file +|draw|draw functions in world space| + +## Guidelines +When dealing with callbacks, callback registration can include objects or functions, but not both. You should either register an object to a list that always has 'update' called on them, or you should register the object's update function as a closure over the object. \ No newline at end of file diff --git a/scripts/debug.js b/scripts/debug.js index f8d5f99..f31210c 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -108,10 +108,6 @@ var Debug = { cmd(82, obj.body); }, - register_call(fn, obj) { - Register.debug.register(fn,obj); - }, - gameobject(go) { cmd(15, go.body); }, draw_bb: false, diff --git a/scripts/editor.js b/scripts/editor.js index 629449a..f97ce5a 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -191,7 +191,8 @@ var editor = { Game.play(); Player.players[0].uncontrol(this); Player.players[0].control(limited_editor); - Register.unregister_obj(this); + editor.cbs.forEach(cb => cb()); + editor.cbs = []; load("predbg.js"); console.warn(`starting game with ${this.dbg_ur}`); editor.dbg_play = Primum.spawn(this.dbg_ur); @@ -205,18 +206,23 @@ var editor = { Game.play(); Player.players[0].uncontrol(this); Player.players[0].control(limited_editor); - Register.unregister_obj(this); + editor.cbs.forEach(cb=>cb()); + editor.cbs = []; load("game.js"); }, + cbs: [], + enter_editor() { Game.pause(); Player.players[0].control(this); Player.players[0].uncontrol(limited_editor); - Register.gui.register(editor.gui, editor); - Register.draw.register(editor.draw, editor); - Debug.register_call(editor.ed_debug, editor); - Register.update.register(gui_controls.update, gui_controls); + + editor.cbs.push(Register.gui.register(editor.gui.bind(editor))); + editor.cbs.push(Register.draw.register(editor.draw.bind(editor))); + editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor))); + editor.cbs.push(Register.update.register(gui_controls.update, gui_controls)); + this.desktop = Primum.spawn(ur.arena); Primum.rename_obj(this.desktop.toString(), "desktop"); this.edit_level = this.desktop; diff --git a/scripts/engine.js b/scripts/engine.js index 4475e15..0c94410 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -81,7 +81,7 @@ var timer = { }, kill() { - Register.unregister_obj(this); + this.end(); this.fn = undefined; }, @@ -90,7 +90,7 @@ var timer = { t.time = secs; t.remain = secs; t.fn = fn; - Register.update.register(t.update, t); + t.end = Register.update.register(timer.update.bind(t)); return function() { t.kill(); }; }, }; @@ -162,12 +162,7 @@ var Register = { }); }, - unregister_obj(obj) { - Register.registries.forEach(function(x) { - x.unregister_obj(obj); - }); - Player.uncontrol(obj); - }, + unregister_obj(obj) { Player.uncontrol(obj); }, endofloop(fn) { if (!this.inloop) @@ -186,34 +181,18 @@ var Register = { registries: [], add_cb(idx, name) { - var entries = []; var n = {}; + var fns = []; + n.register = function(fn, obj) { - if (!obj) { - Log.error("Refusing to register a function without a destroying object."); - return; - } - entries.push({ - fn: fn, - obj: obj - }); - } - - n.unregister = function(fn) { - entries = entries.filter(function(e) { return e.fn !== fn; }); - } - - n.unregister_obj = function(obj) { - entries = entries.filter(function(e) { return e.obj !== obj; }); - } - - n.broadcast = function(...args) { - entries.forEach(x => x.fn.call(x.obj, ...args)); - } - - n.clear = function() { - entries = []; + if (typeof fn !== 'function') return; + if (typeof obj === 'object') + fn = fn.bind(obj); + fns.push(fn); + return function() { fns.remove(fn); }; } + n.broadcast = function(...args) { fns.forEach(x => x(...args)); } + n.clear = function() { fns = []; } register(idx, n.broadcast, n); diff --git a/scripts/entity.js b/scripts/entity.js index 6d1f991..94520f8 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -416,14 +416,19 @@ var gameobject = { this.sync(); }, + unregister() { + this.timers.forEach(t=>t()); + this.timers = []; + }, + check_registers(obj) { - Register.unregister_obj(obj); + obj.unregister(); if (typeof obj.update === 'function') - Register.update.register(obj.update, obj); + obj.timers.push(Register.update.register(obj.update.bind(obj))); if (typeof obj.physupdate === 'function') - Register.physupdate.register(obj.physupdate, obj); + obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj))); if (typeof obj.collide === 'function') obj.register_hit(obj.collide, obj); @@ -432,13 +437,13 @@ var gameobject = { obj.register_separate(obj.separate, obj); if (typeof obj.draw === 'function') - Register.draw.register(obj.draw,obj); + obj.timers.push(Register.draw.register(obj.draw.bind(obj))); if (typeof obj.debug === 'function') - Register.debug.register(obj.debug, obj); + obj.timers.push(Register.debug.register(obj.debug.bind(obj))); if (typeof obj.gui === 'function') - Register.gui.register(obj.gui,obj); + obj.timers.push(Register.gui.register(obj.gui.bind(obj))); for (var k in obj) { if (!k.startswith("on_")) continue; @@ -560,7 +565,7 @@ var gameobject = { this.__kill = true; this.timers.forEach(t => t()); - this.timers = undefined; + this.timers = []; if (this.level) { this.level.remove_obj(this); @@ -568,13 +573,11 @@ var gameobject = { } Player.do_uncontrol(this); - Register.unregister_obj(this); if (this.__proto__.instances) this.__proto__.instances.remove(this); for (var key in this.components) { - Register.unregister_obj(this.components[key]); this.components[key].kill(); this.components[key].gameobject = undefined; delete this.components[key]; diff --git a/scripts/tween.js b/scripts/tween.js index 9fe95d3..2c71260 100644 --- a/scripts/tween.js +++ b/scripts/tween.js @@ -173,7 +173,7 @@ var Tween = { defn.play = function() { if (playing) return; - Register.update.register(defn.fn, defn); + defn._end = Register.update.register(defn.fn.bind(defn)); playing = true; }; defn.restart = function() { @@ -185,7 +185,7 @@ var Tween = { }; defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); }; defn.pause = function() { - Register.update.unregister(defn.fn); + defn._end(); if (!playing) return; playing = false; diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index b963cb7..ef66abe 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -625,9 +625,9 @@ static cpBool handle_collision(cpArbiter *arb, int type) { break; case CTYPE_SEP: -/* if (JS_IsObject(go->cbs.separate.obj)) + if (JS_IsObject(go->cbs.separate.obj)) duk_call_phys_cb(norm1, go->cbs.separate, go2, arb); -*/ + break; } diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 90e4ebb..28ad541 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -1478,11 +1478,9 @@ JSValue duk_register(JSContext *js, JSValueConst this, int argc, JSValueConst *a break; case 4: - // unregister_obj(obj); break; case 5: - // unregister_gui(c); break; case 6: diff --git a/source/engine/particle.c b/source/engine/particle.c index 71c46b2..2f42380 100644 --- a/source/engine/particle.c +++ b/source/engine/particle.c @@ -155,6 +155,7 @@ static struct par_vert pv[MAX_PARTICLES]; void parallel_pv(emitter *e, struct scheduler *sched, struct sched_task_partition t, sched_uint thread_num) { for (int i=t.start; i < t.end; i++) { + if (e->particles[i].life <= 0) continue; particle *p = &e->particles[i]; pv[i].pos = p->pos.xy; pv[i].angle = p->angle; @@ -172,7 +173,7 @@ void emitters_draw() par_bind.fs.images[0] = e->texture->id; struct sched_task task; - scheduler_add(&sched, &task, parallel_pv, e, arrlen(e->particles), arrlen(e->particles)/SCHED_DEFAULT); + scheduler_add(&sched, &task, parallel_pv, e, arrlen(e->particles), arrlen(e->particles)/sched.threads_num); scheduler_join(&sched, &task); sg_append_buffer(par_bind.vertex_buffers[0], &(sg_range){.ptr=&pv, .size=sizeof(struct par_vert)*arrlen(e->particles)}); @@ -191,6 +192,7 @@ static HMM_Vec4 g_accel; void parallel_step(emitter *e, struct scheduler *shed, struct sched_task_partition t, sched_uint thread_num) { for (int i = t.end-1; i >=0; i--) { + if (e->particles[i].life <= 0) continue; if (e->gravity) e->particles[i].v = HMM_AddV4(e->particles[i].v, g_accel); e->particles[i].v = HMM_AddV4(e->particles[i].v, HMM_MulV4F((HMM_Vec4){frand(2)-1, frand(2)-1, 0,0}, 1000*dt)); @@ -200,10 +202,10 @@ void parallel_step(emitter *e, struct scheduler *shed, struct sched_task_partiti e->particles[i].color = sample_sampler(&e->color, (e->life-e->particles[i].life)/e->life); e->particles[i].scale = e->scale; - if (e->particles[i].life <= 0) - arrdelswap(e->particles, i); - else if (query_point(e->particles[i].pos.xy)) - arrdelswap(e->particles,i); +// if (e->particles[i].life <= 0) +// arrdelswap(e->particles, i); +// else if (query_point(e->particles[i].pos.xy)) +// arrdelswap(e->particles,i); } } @@ -212,7 +214,7 @@ void emitter_step(emitter *e, double mdt) { g_accel = HMM_MulV4F((HMM_Vec4){cpSpaceGetGravity(space).x, cpSpaceGetGravity(space).y, 0, 0}, dt); if (arrlen(e->particles) == 0) return; struct sched_task task; - scheduler_add(&sched, &task, parallel_step, e, arrlen(e->particles), arrlen(e->particles)); + scheduler_add(&sched, &task, parallel_step, e, arrlen(e->particles), arrlen(e->particles)/sched.threads_num); scheduler_join(&sched, &task); if (!e->on) return; diff --git a/tests/bind_v_call.js b/tests/bind_v_call.js new file mode 100644 index 0000000..7167be8 --- /dev/null +++ b/tests/bind_v_call.js @@ -0,0 +1,40 @@ +var binds = []; +var cbs = []; +var fats = []; +var count = 1000000; + +var a = { + n: 1 +} + +function test_a() { + this.n++; +} + +var start = Date.now(); +for (var i = 0; i < count; i++) + binds.push(test_a.bind(a)); +console.log(`Make bind time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) + fats.push(() => test_a.call(a)); +console.log(`Make fat time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) { + binds[i](); +} +console.log(`Bind time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) { + fats[i](); +} +console.log(`Fat time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) + test_a.call(a); + +console.log(`Call time: ${Date.now()-start} ms`); diff --git a/tests/bind_v_fn.js b/tests/bind_v_fn.js new file mode 100644 index 0000000..fc5e7d0 --- /dev/null +++ b/tests/bind_v_fn.js @@ -0,0 +1,24 @@ +var binds = []; +var a = { + n: 1, + test() { this.n++; } +}; +var count = 10000000; + +var start = Date.now(); +for (var i = 0; i < count; i++) + binds.push(a.test.bind(a)); + +console.log(`Make bind time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) + binds[i](); + +console.log(`Bind time: ${Date.now()-start} ms`); + +start = Date.now(); +for (var i = 0; i < count; i++) + a['test'](); + +console.log(`Call time: ${Date.now()-start} ms`);