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 */
register_hit(fn, obj) {
register_collide(1, fn, obj, this.gameobject.body, this.shape);
},
impl: {
set sensor(x) { cmd(18,this.shape,x); },
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];
var Signal = {
obj_begin(fn, obj, go) {
register_collide(0, fn, obj, go.body);
obj_begin(fn, go) {
register_collide(0, fn, go.body);
},
obj_separate(fn, obj, go) {
register_collide(3,fn,obj,go.body);
obj_separate(fn, go) {
register_collide(3,fn, go.body);
},
};

View file

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

View file

@ -201,10 +201,7 @@ void phys2d_set_gravity(cpVect v) {
cpSpaceSetGravity(space, v);
}
void phys2d_update(float deltaT) {
cpSpaceStep(space, deltaT);
flush_collide_cbs();
}
void phys2d_update(float deltaT) { cpSpaceStep(space, deltaT); }
void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
shape->go = go;
@ -557,96 +554,92 @@ int shape_get_sensor(struct phys2d_shape *shape) {
void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); }
struct postphys_cb {
struct callee c;
JSValue send;
};
static struct postphys_cb *begins = NULL;
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);
int arb_valid(cpArbiter *arb)
{
cpBody *body1;
cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
gameobject *go2 = cpBodyGetUserData(body2);
return !JS_IsUndefined(go2->ref);
}
void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, gameobject *hit, cpArbiter *arb) {
JSValue arb2js(cpArbiter *arb)
{
cpBody *body1;
cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
gameobject *go2 = cpBodyGetUserData(body2);
if (JS_IsUndefined(go2->ref)) return JS_UNDEFINED;
cpShape *shape1;
cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2);
HMM_Vec2 norm;
norm.cp = cpArbiterGetNormal(arb);
JSValue obj = JS_NewObject(js);
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)));
HMM_Vec2 srfv;
srfv.cp = cpArbiterGetSurfaceVelocity(arb);
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;
cb.c = c;
cb.send = obj;
arrput(begins, cb);
return obj;
}
#define CTYPE_BEGIN 0
#define CTYPE_SEP 1
void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit)
{
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 *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2);
struct phys2d_shape *pshape1 = cpShapeGetUserData(shape1);
struct phys2d_shape *pshape2 = cpShapeGetUserData(shape2);
HMM_Vec2 norm1;
norm1.cp = cpArbiterGetNormal(arb);
switch (type) {
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;
for (int i = 0; i < arrlen(go->shape_cbs); i++) {
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))
go->shape_cbs[i].cbs.bhit = arb2js(arb);
}
return 1;
}
static cpBool script_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) {
return handle_collision(arb, CTYPE_BEGIN);
}
static cpBool script_phys_cb_separate(cpArbiter *arb, cpSpace *space, void *data) {
return handle_collision(arb, CTYPE_SEP);
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go)
{
if (!arb_valid(arb)) return;
if (JS_IsUndefined(go->cbs.separate)) return;
go->cbs.shit = arb2js(arb);
cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.separate, &go->cbs.shit);
}
void phys2d_rm_go_handlers(gameobject *go) {
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
handler->userData = NULL;
handler->beginFunc = NULL;
handler->separateFunc = NULL;
if (!JS_IsUndefined(go->cbs.begin)) {
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) {

View file

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

View file

@ -53,7 +53,6 @@ gameobject *MakeGameobject();
int go_count();
void gameobject_apply(gameobject *go);
void gameobject_free(gameobject *go);
void gameobjects_cleanup();
transform2d go2t(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;
}
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;
shapecb.shape = shape;
shapecb.cbs.begin = c;
shapecb.cbs.begin = fn;
arrpush(go->shape_cbs, shapecb);
}
JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]);
gameobject *go = js2gameobject(argv[3]);
struct callee c;
c.fn = argv[1];
c.obj = argv[2];
gameobject *go = js2gameobject(argv[2]);
JSValue fn = argv[1];
switch (cmd) {
case 0:
go->cbs.begin = c;
go->cbs.begin = JS_DupValue(js,fn);
break;
case 1:
gameobject_add_shape_collider(go, c, js2ptr(argv[4]));
gameobject_add_shape_collider(go, JS_DupValue(js,fn), js2ptr(argv[3]));
break;
case 2:
@ -1534,7 +1532,7 @@ JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValue
break;
case 3:
go->cbs.separate = c;
go->cbs.separate = JS_DupValue(js,fn);
break;
}

View file

@ -254,6 +254,14 @@ void script_call_sym(JSValue sym) {
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)
{
FILE *f = fopen(file, "w");

View file

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

View file

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