fix collisions

This commit is contained in:
John Alanbrook 2024-01-03 23:19:13 +00:00
parent da5b7154d7
commit 913c74db96
10 changed files with 99 additions and 134 deletions

View file

@ -388,10 +388,6 @@ var collider2d = Object.copy(component, {
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */ kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
register_hit(fn, obj) {
register_collide(1, fn, obj, this.gameobject.body, this.shape);
},
impl: { impl: {
set sensor(x) { cmd(18,this.shape,x); }, set sensor(x) { cmd(18,this.shape,x); },
get sensor() { return cmd(21,this.shape); }, get sensor() { return cmd(21,this.shape); },

View file

@ -217,12 +217,12 @@ register(9, Log.stack, this);
Register.gamepad_playermap[0] = Player.players[0]; Register.gamepad_playermap[0] = Player.players[0];
var Signal = { var Signal = {
obj_begin(fn, obj, go) { obj_begin(fn, go) {
register_collide(0, fn, obj, go.body); register_collide(0, fn, go.body);
}, },
obj_separate(fn, obj, go) { obj_separate(fn, go) {
register_collide(3,fn,obj,go.body); register_collide(3,fn, go.body);
}, },
}; };

View file

@ -431,13 +431,13 @@ var gameobject = {
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj))); obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
if (typeof obj.collide === 'function') if (typeof obj.collide === 'function')
obj.register_hit(obj.collide, obj); Signal.obj_begin(obj.collide.bind(obj), obj);
if (typeof obj.separate === 'function') if (typeof obj.separate === 'function')
obj.register_separate(obj.separate, obj); Signal.obj_separate(obj.separate.bind(obj), obj);
if (typeof obj.draw === 'function') if (typeof obj.draw === 'function')
obj.timers.push(Register.draw.register(obj.draw.bind(obj))); obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
if (typeof obj.debug === 'function') if (typeof obj.debug === 'function')
obj.timers.push(Register.debug.register(obj.debug.bind(obj))); obj.timers.push(Register.debug.register(obj.debug.bind(obj)));
@ -453,7 +453,7 @@ var gameobject = {
obj.components.forEach(function(x) { obj.components.forEach(function(x) {
if (typeof x.collide === 'function') if (typeof x.collide === 'function')
register_collide(1, x.collide, x, obj.body, x.shape); register_collide(1, x.collide.bind(x), obj.body, x.shape);
}); });
}, },
toString() { return "new_object"; }, toString() { return "new_object"; },
@ -566,14 +566,15 @@ var gameobject = {
this.timers.forEach(t => t()); this.timers.forEach(t => t());
this.timers = []; this.timers = [];
Event.rm_obj(this);
Player.do_uncontrol(this);
register_collide(2, undefined, this.body);
if (this.level) { if (this.level) {
this.level.remove_obj(this); this.level.remove_obj(this);
this.level = undefined; this.level = undefined;
} }
Player.do_uncontrol(this);
if (this.__proto__.instances) if (this.__proto__.instances)
this.__proto__.instances.remove(this); this.__proto__.instances.remove(this);
@ -585,7 +586,7 @@ var gameobject = {
this.clear(); this.clear();
this.objects = undefined; this.objects = undefined;
Event.rm_obj(this);
if (typeof this.stop === 'function') if (typeof this.stop === 'function')
this.stop(); this.stop();
@ -602,9 +603,6 @@ var gameobject = {
obj.make = undefined; obj.make = undefined;
Object.mixin(obj,gameobject_impl); Object.mixin(obj,gameobject_impl);
// if (this.instances)
// this.instances.push(obj);
obj.body = make_gameobject(); obj.body = make_gameobject();
obj.components = {}; obj.components = {};
@ -692,16 +690,6 @@ var gameobject = {
return this[name]; return this[name];
}, },
register_hit(fn, obj) {
obj ??= this;
Signal.obj_begin(fn, obj, this);
},
register_separate(fn, obj) {
obj ??= this;
Signal.obj_separate(fn,obj,this);
},
obj_descend(fn) { obj_descend(fn) {
fn(this); fn(this);
for (var o in this.objects) for (var o in this.objects)

View file

@ -201,10 +201,7 @@ void phys2d_set_gravity(cpVect v) {
cpSpaceSetGravity(space, v); cpSpaceSetGravity(space, v);
} }
void phys2d_update(float deltaT) { void phys2d_update(float deltaT) { cpSpaceStep(space, deltaT); }
cpSpaceStep(space, deltaT);
flush_collide_cbs();
}
void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) { void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
shape->go = go; shape->go = go;
@ -557,96 +554,92 @@ int shape_get_sensor(struct phys2d_shape *shape) {
void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); } void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); }
struct postphys_cb { int arb_valid(cpArbiter *arb)
struct callee c; {
JSValue send; cpBody *body1;
}; cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
static struct postphys_cb *begins = NULL; gameobject *go2 = cpBodyGetUserData(body2);
return !JS_IsUndefined(go2->ref);
void flush_collide_cbs() {
for (int i = 0; i < arrlen(begins); i++) {
script_callee(begins[i].c, 1, &begins[i].send);
JS_FreeValue(js, begins[i].send);
} }
arrsetlen(begins,0); JSValue arb2js(cpArbiter *arb)
} {
cpBody *body1;
void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, gameobject *hit, cpArbiter *arb) { cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
gameobject *go2 = cpBodyGetUserData(body2);
if (JS_IsUndefined(go2->ref)) return JS_UNDEFINED;
cpShape *shape1; cpShape *shape1;
cpShape *shape2; cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2); cpArbiterGetShapes(arb, &shape1, &shape2);
HMM_Vec2 norm;
norm.cp = cpArbiterGetNormal(arb);
JSValue obj = JS_NewObject(js); JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "normal", vec2js(norm)); JS_SetPropertyStr(js, obj, "normal", vec2js(norm));
JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,hit->ref)); JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,go2->ref));
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2))); JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
HMM_Vec2 srfv; HMM_Vec2 srfv;
srfv.cp = cpArbiterGetSurfaceVelocity(arb); srfv.cp = cpArbiterGetSurfaceVelocity(arb);
JS_SetPropertyStr(js, obj, "velocity", vec2js(srfv)); JS_SetPropertyStr(js, obj, "velocity", vec2js(srfv));
// srfv.cp = cpArbiterGetPointA(arb,0);
// JS_SetPropertyStr(js, obj, "pos", vec2js(srfv));
// JS_SetPropertyStr(js,obj,"depth", num2js(cpArbiterGetDepth(arb,0)));
struct postphys_cb cb; return obj;
cb.c = c;
cb.send = obj;
arrput(begins, cb);
} }
#define CTYPE_BEGIN 0 void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit)
#define CTYPE_SEP 1 {
script_call_fn_arg(*fn, *hit);
JS_FreeValue(js, *hit);
}
/* TODO: Limitation, cannot handle multiple collision same frame */
int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go)
{
if (!arb_valid(arb)) return 1;
if (!JS_IsUndefined(go->cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.begin, &go->cbs.bhit))
go->cbs.bhit = arb2js(arb);
static cpBool handle_collision(cpArbiter *arb, int type) {
cpBody *body1;
cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
gameobject *go = cpBodyGetUserData(body1);
gameobject *go2 = cpBodyGetUserData(body2);
cpShape *shape1; cpShape *shape1;
cpShape *shape2; cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2); cpArbiterGetShapes(arb, &shape1, &shape2);
struct phys2d_shape *pshape1 = cpShapeGetUserData(shape1); struct phys2d_shape *pshape1 = cpShapeGetUserData(shape1);
struct phys2d_shape *pshape2 = cpShapeGetUserData(shape2);
HMM_Vec2 norm1; for (int i = 0; i < arrlen(go->shape_cbs); i++) {
norm1.cp = cpArbiterGetNormal(arb); if (go->shape_cbs[i].shape != pshape1) continue;
if (!JS_IsUndefined(go->shape_cbs[i].cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->shape_cbs[i].cbs.begin, &go->shape_cbs[i].cbs.bhit))
switch (type) { go->shape_cbs[i].cbs.bhit = arb2js(arb);
case CTYPE_BEGIN:
for (int i = 0; i < arrlen(go->shape_cbs); i++)
if (go->shape_cbs[i].shape == pshape1)
duk_call_phys_cb(norm1, go->shape_cbs[i].cbs.begin, go2, arb);
if (JS_IsObject(go->cbs.begin.obj))
duk_call_phys_cb(norm1, go->cbs.begin, go2, arb);
break;
case CTYPE_SEP:
if (JS_IsObject(go->cbs.separate.obj))
duk_call_phys_cb(norm1, go->cbs.separate, go2, arb);
break;
} }
return 1; return 1;
} }
static cpBool script_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) { void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go)
return handle_collision(arb, CTYPE_BEGIN); {
} if (!arb_valid(arb)) return;
if (JS_IsUndefined(go->cbs.separate)) return;
static cpBool script_phys_cb_separate(cpArbiter *arb, cpSpace *space, void *data) { go->cbs.shit = arb2js(arb);
return handle_collision(arb, CTYPE_SEP); cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.separate, &go->cbs.shit);
} }
void phys2d_rm_go_handlers(gameobject *go) { void phys2d_rm_go_handlers(gameobject *go) {
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go); cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
handler->userData = NULL;
handler->beginFunc = NULL; if (!JS_IsUndefined(go->cbs.begin)) {
handler->separateFunc = NULL; JS_FreeValue(js,go->cbs.begin);
go->cbs.begin = JS_UNDEFINED;
}
if (JS_IsFunction(js,go->cbs.separate)) {
JS_FreeValue(js,go->cbs.separate);
go->cbs.separate = JS_UNDEFINED;
}
for (int i = 0; i < arrlen(go->shape_cbs); i++) {
JS_FreeValue(js, go->shape_cbs[i].cbs.begin);
go->shape_cbs[i].cbs.begin = JS_UNDEFINED;
}
} }
void phys2d_setup_handlers(gameobject *go) { void phys2d_setup_handlers(gameobject *go) {

View file

@ -163,8 +163,8 @@ gameobject *MakeGameobject() {
.ref = JS_UNDEFINED, .ref = JS_UNDEFINED,
}; };
go.cbs.begin.obj = JS_UNDEFINED; go.cbs.begin = JS_UNDEFINED;
go.cbs.separate.obj = JS_UNDEFINED; go.cbs.separate = JS_UNDEFINED;
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f)); go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
cpBodySetVelocityUpdateFunc(go.body, velocityFn); cpBodySetVelocityUpdateFunc(go.body, velocityFn);
@ -195,41 +195,23 @@ void rm_body_constraints(cpBody *body, cpConstraint *constraint, void *data)
cpConstraintFree(constraint); cpConstraintFree(constraint);
} }
gameobject **go_toclean = NULL; void gameobject_free(gameobject *go) {
/* Free this gameobject */
void gameobject_clean(gameobject *go) {
arrfree(go->shape_cbs); arrfree(go->shape_cbs);
go->ref = JS_UNDEFINED;
cpBodyEachShape(go->body, rm_body_shapes, NULL); cpBodyEachShape(go->body, rm_body_shapes, NULL);
cpBodyEachConstraint(go->body, rm_body_constraints, NULL); cpBodyEachConstraint(go->body, rm_body_constraints, NULL);
cpSpaceRemoveBody(space, go->body); cpSpaceRemoveBody(space, go->body);
cpBodyFree(go->body); cpBodyFree(go->body);
go->body = NULL; go->body = NULL;
free(go); free(go);
} for (int i = arrlen(gameobjects)-1; i >= 0; i--) {
/* Really more of a "mark for deletion" ... */
void gameobject_free(gameobject *go) {
if (!go) return;
for (int i = arrlen(gameobjects)-1; i >= 0; i--)
if (gameobjects[i] == go) { if (gameobjects[i] == go) {
arrdelswap(gameobjects,i); arrdelswap(gameobjects,i);
break; return;
} }
if (cpSpaceIsLocked(space))
arrpush(go_toclean, go);
else
gameobject_clean(go);
} }
void gameobjects_cleanup() {
for (int i = 0; i < arrlen(go_toclean); i++)
gameobject_clean(go_toclean[i]);
arrsetlen(go_toclean, 0);
} }
void gameobject_setangle(gameobject *go, float angle) { void gameobject_setangle(gameobject *go, float angle) {

View file

@ -53,7 +53,6 @@ gameobject *MakeGameobject();
int go_count(); int go_count();
void gameobject_apply(gameobject *go); void gameobject_apply(gameobject *go);
void gameobject_free(gameobject *go); void gameobject_free(gameobject *go);
void gameobjects_cleanup();
transform2d go2t(gameobject *go); transform2d go2t(gameobject *go);
transform3d go2t3(gameobject *go); transform3d go2t3(gameobject *go);

View file

@ -1506,27 +1506,25 @@ JSValue duk_register(JSContext *js, JSValueConst this, int argc, JSValueConst *a
return JS_UNDEFINED; return JS_UNDEFINED;
} }
void gameobject_add_shape_collider(gameobject *go, struct callee c, struct phys2d_shape *shape) { void gameobject_add_shape_collider(gameobject *go, JSValue fn, struct phys2d_shape *shape) {
struct shape_cb shapecb; struct shape_cb shapecb;
shapecb.shape = shape; shapecb.shape = shape;
shapecb.cbs.begin = c; shapecb.cbs.begin = fn;
arrpush(go->shape_cbs, shapecb); arrpush(go->shape_cbs, shapecb);
} }
JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
gameobject *go = js2gameobject(argv[3]); gameobject *go = js2gameobject(argv[2]);
struct callee c; JSValue fn = argv[1];
c.fn = argv[1];
c.obj = argv[2];
switch (cmd) { switch (cmd) {
case 0: case 0:
go->cbs.begin = c; go->cbs.begin = JS_DupValue(js,fn);
break; break;
case 1: case 1:
gameobject_add_shape_collider(go, c, js2ptr(argv[4])); gameobject_add_shape_collider(go, JS_DupValue(js,fn), js2ptr(argv[3]));
break; break;
case 2: case 2:
@ -1534,7 +1532,7 @@ JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValue
break; break;
case 3: case 3:
go->cbs.separate = c; go->cbs.separate = JS_DupValue(js,fn);
break; break;
} }

View file

@ -254,6 +254,14 @@ void script_call_sym(JSValue sym) {
call_callee(&c); call_callee(&c);
} }
void script_call_fn_arg(JSValue fn, JSValue arg)
{
if (!JS_IsFunction(js,fn)) return;
JSValue ret = JS_Call(js, fn, JS_GetGlobalObject(js), 1, &arg);
js_print_exception(ret);
JS_FreeValue(js, ret);
}
void out_memusage(const char *file) void out_memusage(const char *file)
{ {
FILE *f = fopen(file, "w"); FILE *f = fopen(file, "w");

View file

@ -13,9 +13,12 @@ struct callee {
}; };
struct phys_cbs { struct phys_cbs {
struct callee begin; JSValue begin;
struct callee separate; JSValue bhit;
JSValue separate;
JSValue shit;
}; };
void script_call_fn_arg(JSValue fn, JSValue arg);
extern struct callee stacktrace_callee; extern struct callee stacktrace_callee;
extern JSValue num_cache[100]; extern JSValue num_cache[100];

View file

@ -148,8 +148,6 @@ static void process_frame()
// prof_start(&prof_draw); // prof_start(&prof_draw);
window_render(&mainwin); window_render(&mainwin);
// prof_lap(&prof_draw); // prof_lap(&prof_draw);
gameobjects_cleanup();
} }
void c_frame() void c_frame()