From 17ad44e5a5eb64467a6f2b97be1d6fa8a52f4d97 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 11 Apr 2024 17:17:49 -0500 Subject: [PATCH] Physics fixes; editor fixes --- scripts/editor.js | 14 ++++++------ scripts/engine.js | 17 +++++++++------ scripts/entity.js | 39 ++++++++++++--------------------- scripts/gui.js | 3 +-- scripts/physics.js | 14 ++++++++++-- source/engine/2dphysics.c | 25 ++++++++++++++++------ source/engine/2dphysics.h | 1 + source/engine/gameobject.c | 44 +++++++++----------------------------- source/engine/gameobject.h | 4 ---- source/engine/jsffi.c | 28 ++++++------------------ source/engine/render.c | 2 +- 11 files changed, 79 insertions(+), 112 deletions(-) diff --git a/scripts/editor.js b/scripts/editor.js index 810518b..2270583 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -458,7 +458,7 @@ var editor = { render.point(x[1].screenpos(), 1, Color.red); }); - var mg = physics.pos_query(input.mouse.worldpos(),10); + var mg = physics.pos_query(input.mouse.worldpos()); if (mg && mg._ed?.selectable) { var p = mg.path_from(thiso); @@ -655,7 +655,7 @@ editor.inputs.drop = function(str) { return; } - var mg = physics.pos_query(input.mouse.worldpos(),10); + var mg = physics.pos_query(input.mouse.worldpos()); if (!mg) return; var img = mg.get_comp_by_name('sprite'); if (!img) return; @@ -785,16 +785,14 @@ editor.inputs['C-f'] = function() { }; editor.inputs['C-f'].doc = "Tunnel into the selected level object to edit it."; -editor.inputs['C-F'] = function() { - console.info("PRESSED C-F"); - if (editor.edit_level.master === world) return; +editor.inputs['M-f'] = function() { + if (editor.edit_level.master === world) return; editor.edit_level = editor.edit_level.master; editor.unselect(); editor.reset_undos(); }; -editor.inputs['C-F'].doc = "Tunnel out of the level you are editing, saving it in the process."; - +editor.inputs['M-f'].doc = "Tunnel out of the level you are editing, saving it in the process."; editor.inputs['C-r'] = function() { editor.selectlist.forEach(function(x) { x.rotate(-x.angle*2); }); } editor.inputs['C-r'].doc = "Negate the selected's angle."; @@ -1532,7 +1530,7 @@ var replpanel = Object.copy(inputpanel, { this.caret = 0; var ret = function() {return eval(ecode);}.call(repl_obj); if (typeof ret === 'object') ret = json.encode(ret,null,1); - say(ret); + if (ret) say(ret); }, resetscroll() { diff --git a/scripts/engine.js b/scripts/engine.js index d1457fc..ad484c6 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -312,17 +312,20 @@ game.timescale = 1; var eachobj = function(obj,fn) { - fn(obj); + var val = fn(obj); + if (val) return val; for (var o in obj.objects) { - if (obj.objects[o] === obj) { - //console.error(`Object ${obj.toString()} is referenced by itself.`); - continue; - } - eachobj(obj.objects[o],fn); + if (obj.objects[o] === obj) + console.error(`Object ${obj.toString()} is referenced by itself.`); + val = eachobj(obj.objects[o],fn); + if (val) return val; } } -game.all_objects = function(fn, startobj = world) { eachobj(startobj,fn); }; +game.all_objects = function(fn, startobj = world) { return eachobj(startobj,fn); }; +game.find_object = function(fn, startobj = world) { + +} game.tags = {}; game.tag_add = function(tag, obj) { diff --git a/scripts/entity.js b/scripts/entity.js index 7350ce4..65a3cb1 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -238,8 +238,10 @@ var gameobject = { Object.merge(ent, json.decode(Resources.replstrs(config))); else if (Array.isArray(config)) config.forEach(function(path) { - if (typeof path === 'string') + if (typeof path === 'string') { + console.info(`ingesting ${path} ...`); Object.merge(ent, json.decode(Resources.replstrs(path))); + } else if (typeof path === 'object') Object.merge(ent,path); }); @@ -278,6 +280,7 @@ var gameobject = { if (!Object.empty(ent.objects)) { var o = ent.objects; delete ent.objects; + ent.objects = {}; for (var i in o) { console.info(`creating ${i} on ${ent.toString()}`); var newur = o[i].ur; @@ -302,6 +305,7 @@ var gameobject = { /* Reparent 'this' to be 'parent's child */ reparent(parent) { assert(parent, `Tried to reparent ${this.toString()} to nothing.`); + console.info(`parenting ${this.toString()} to ${parent.toString()}`); if (this.master === parent) { console.warn("not reparenting ..."); console.warn(`${this.master} is the same as ${parent}`); @@ -363,18 +367,7 @@ var gameobject = { }, /* Make a unique object the same as its prototype */ - revert() { - var jobj = this.json_obj(); - var lobj = this.master.__proto__.objects[this.toString()]; - delete jobj.objects; - Object.keys(jobj).forEach(function(x) { - if (lobj && x in lobj) - this[x] = lobj[x]; - else - this[x] = this.__proto__[x]; - }, this); - this.sync(); - }, + revert() { Object.merge(this, this.ur.fresh); }, toString() { return "new_object"; }, @@ -488,9 +481,6 @@ var gameobject = { this.master = undefined; } - if (this.__proto__.instances) - delete this.__proto__.instances[this.toString()]; - for (var key in this.components) { this.components[key].kill?.(); this.components[key].gameobject = undefined; @@ -664,7 +654,7 @@ function apply_ur(u, ent) { if (typeof data === 'string') Object.merge(ent, json.decode(Resources.replstrs(data))); else if (Array.isArray(data)) { - data.forEach(function(path)) { + data.forEach(function(path) { if (typeof path === 'string') Object.merge(ent, json.decode(Resources.replstrs(data))); else if (typeof path === 'object') @@ -716,14 +706,13 @@ game.loadurs = function() { if (file[0] === '.' || file[0] === '_') continue; var newur = ur_from_file(file); if (!newur) continue; - var datastr = file.set_ext(".json"); - var data; - if (io.exists(datastr)) - data = datastr; - Object.assign(newur, { - text: file, - data: datastr - }; + newur.text = file; + + var data = file.set_ext(".json"); + if (io.exists(data)) { + console.info(`Found matching json ${data} for ${file}`); + newur.data = data; + } } for (var file of io.glob("**.json")) { diff --git a/scripts/gui.js b/scripts/gui.js index 8967a16..0c2c3ef 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -2,7 +2,7 @@ gui functions take screen space coordinates */ -gui.scissor_win = function() { gui.scissor(0,0,window.width,window.height); } +gui.scissor_win = function() { gui.scissor(0,0,window.size.x,window.y); } gui.input_lmouse_pressed = function() { if (gui.selected) @@ -174,7 +174,6 @@ Mum.window = Mum.extend({ render.window(p,this.wh, this.color); this.bb = bbox.blwh(p, this.wh); gui.flush(); - gui.scissor(p.x,p.y,this.wh.x,this.wh.y); this.max_width = this.width; if (this.selectable) gui.controls.check_bb(this); var pos = [this.bb.l, this.bb.t].add(this.padding); diff --git a/scripts/physics.js b/scripts/physics.js index 2bf69e1..d8d70ca 100644 --- a/scripts/physics.js +++ b/scripts/physics.js @@ -9,8 +9,18 @@ var HIT = { }; */ -var pq = physics.pos_query; -physics.pos_query = function(pos,give = 25) { return pq(pos,give); } +physics.pos_query = function(pos, start = world, give = 10) { + var ret; + ret = physics.point_query_nearest(pos, 0); + + if (ret) + return ret.entity; + + return game.all_objects(function(o) { + var dist = Vector.length(o.pos.sub(pos)); + if (dist <= give) return o; + }); +} physics.box_point_query = function(box,points) { if (!box || !points) return []; diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 0d843bb..44a0f7f 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -67,6 +67,12 @@ void bbhit(cpShape *shape, int *data) qhit++; } +cpShapeFilter nofilter = { + .group = CP_NO_GROUP, + .mask = ~CP_ALL_CATEGORIES, + .categories = ~CP_ALL_CATEGORIES +}; + cpShapeFilter allfilter = { .group = CP_NO_GROUP, .mask = CP_ALL_CATEGORIES, @@ -508,10 +514,13 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) { /************ COLLIDER ****************/ void shape_enabled(struct phys2d_shape *shape, int enabled) { - if (enabled) - cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_ALL); - else - cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_NONE); + cpShapeFilter set = enabled ? CP_SHAPE_FILTER_ALL : CP_SHAPE_FILTER_NONE; + if (!shape->shape) { + struct phys2d_edge *edge = shape->data; + for (int i = 0; i < arrlen(edge->shapes[i]); i++) + cpShapeSetFilter(edge->shapes[i], set); + } else + cpShapeSetFilter(shape->shape, set); } int shape_is_enabled(struct phys2d_shape *shape) { @@ -578,6 +587,7 @@ void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit) void register_hit(cpArbiter *arb, gameobject *go, const char *name) { + if (JS_IsUndefined(go->ref)) return; JSValue cb = JS_GetPropertyStr(js, go->ref, name); if (!JS_IsUndefined(cb)) { JSValue jarb = arb2js(arb); @@ -588,7 +598,9 @@ void register_hit(cpArbiter *arb, gameobject *go, const char *name) } cpShape *s1, *s2; - cpArbiterGetShapes(arb, &s1, &s2); + cpArbiterGetShapes(arb, &s1, &s2); + if (JS_IsUndefined(shape2go(s1)->ref)) return; + if (JS_IsUndefined(shape2go(s2)->ref)) return; struct phys2d_shape *pshape1 = cpShapeGetUserData(s1); if (JS_IsUndefined(pshape1->ref)) return; @@ -603,12 +615,11 @@ void register_hit(cpArbiter *arb, gameobject *go, const char *name) } void script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "collide"); } - void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "separate"); } void phys2d_setup_handlers(gameobject *go) { cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go); handler->userData = go; - handler->postSolveFunc = script_phys_cb_begin; + handler->beginFunc = script_phys_cb_begin; handler->separateFunc = script_phys_cb_separate; } diff --git a/source/engine/2dphysics.h b/source/engine/2dphysics.h index 48a8941..dca4f74 100644 --- a/source/engine/2dphysics.h +++ b/source/engine/2dphysics.h @@ -18,6 +18,7 @@ extern struct rgba static_color; extern struct rgba sleep_color; extern cpShapeFilter allfilter; +extern cpShapeFilter nofilter; typedef struct constraint { cpConstraint *c; diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 0bb3edf..f7ac15f 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -8,12 +8,12 @@ #include "stb_ds.h" -static gameobject **gameobjects; - -int go_count() { return arrlen(gameobjects); } - gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); } -gameobject *shape2go(cpShape *shape) { return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; } +gameobject *shape2go(cpShape *shape) { + struct phys2d_shape *pshape = cpShapeGetUserData(shape); + if (!pshape) return NULL; + return pshape->go; +} HMM_Vec2 go_pos(gameobject *go) { @@ -44,20 +44,6 @@ HMM_Mat3 t_world2go(gameobject *go) { return HMM_InvGeneralM3(t_go2world(go)); } HMM_Mat4 t3d_go2world(gameobject *go) { return transform3d2mat(go2t3(go)); } HMM_Mat4 t3d_world2go(gameobject *go) { return HMM_InvGeneralM4(t3d_go2world(go)); } -gameobject *pos2gameobject(HMM_Vec2 pos, float give) { - cpShape *hit = phys2d_query_pos(pos.cp); - - if (hit) - return shape2go(hit); - - for (int i = 0; i < arrlen(gameobjects); i++) { - float dist = HMM_DistV2(go_pos(gameobjects[i]),pos); - if (dist <= give) return gameobjects[i]; - } - - return NULL; -} - transform2d go2t(gameobject *go) { transform2d t; @@ -151,33 +137,33 @@ gameobject *MakeGameobject() { .mass = 1.f, .next = -1, .drawlayer = 0, - .shape_cbs = NULL, .damping = INFINITY, .timescale = 1.0, .ref = 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); *ngo = go; cpBodySetUserData(go.body, ngo); phys2d_setup_handlers(ngo); - arrpush(gameobjects, ngo); return ngo; } void rm_body_shapes(cpBody *body, cpShape *shape, void *data) { struct phys2d_shape *s = cpShapeGetUserData(shape); + if (s) { + JS_FreeValue(js, s->ref); + s->ref = JS_UNDEFINED; if (s->free) s->free(s->data); else free(s->data); } + + cpShapeSetFilter(shape, nofilter); cpSpaceRemoveShape(space, shape); cpShapeFree(shape); @@ -189,22 +175,12 @@ void rm_body_constraints(cpBody *body, cpConstraint *constraint, void *data) } 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); - for (int i = arrlen(gameobjects)-1; i >= 0; i--) { - if (gameobjects[i] == go) { - arrdelswap(gameobjects,i); - return; - } - } } void gameobject_setangle(gameobject *go, float angle) { diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index ce0c516..a181877 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -41,8 +41,6 @@ struct gameobject { unsigned int layer; cpShapeFilter filter; unsigned int warp_filter; - struct phys_cbs cbs; - struct shape_cb *shape_cbs; JSValue ref; HMM_Mat4 world; float drawlayer; @@ -66,7 +64,6 @@ struct gameobject { typedef struct gameobject gameobject; gameobject *MakeGameobject(); -int go_count(); void gameobject_apply(gameobject *go); void gameobject_free(gameobject *go); @@ -92,7 +89,6 @@ gameobject *shape2go(cpShape *shape); void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go); /* Tries a few methods to select a gameobject; if none is selected returns -1 */ -gameobject *pos2gameobject(HMM_Vec2 pos, float give); void gameobject_draw_debug(gameobject *go); #endif diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 68e817c..a30d69a 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -517,13 +517,6 @@ int point2segindex(HMM_Vec2 p, HMM_Vec2 *segs, double slop) { return best; } -void gameobject_add_shape_collider(gameobject *go, JSValue fn, struct phys2d_shape *shape) { - struct shape_cb shapecb; - shapecb.shape = shape; - shapecb.cbs.begin = fn; - arrpush(go->shape_cbs, shapecb); -} - circle2d *js2circle2d(JSValue v) { return js2ptr(v); } JSC_CCALL(circle2d_set_radius, js2circle2d(argv[0])->radius = js2number(argv[1])) @@ -653,7 +646,7 @@ static const JSCFunctionListEntry js_render_funcs[] = { }; JSC_CCALL(gui_flush, text_flush(&useproj)); -JSC_CCALL(gui_scissor, sg_apply_scissor_rectf(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0)) +JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0)) JSC_CCALL(gui_text, const char *s = JS_ToCString(js, argv[0]); HMM_Vec2 pos = js2vec2(argv[1]); @@ -733,11 +726,8 @@ static const JSCFunctionListEntry js_vector_funcs[] = { JSC_CCALL(game_engine_start, engine_start(argv[0],argv[1])) -JSValue js_game_object_count(JSContext *js, JSValue this) { return number2js(go_count()); } - static const JSCFunctionListEntry js_game_funcs[] = { MIST_FUNC_DEF(game, engine_start, 2), - MIST_FUNC_DEF(game, object_count, 0) }; JSC_CCALL(input_show_keyboard, sapp_show_keyboard(js2boolean(argv[0]))) @@ -930,11 +920,6 @@ JSC_CCALL(physics_sgscale, JSC_CCALL(physics_set_cat_mask, set_cat_mask(js2number(argv[0]), js2bitmask(argv[1]))) -JSC_CCALL(physics_pos_query, - gameobject *go = pos2gameobject(js2vec2(argv[0]), js2number(argv[1])); - return go ? JS_DupValue(js,go->ref) : JS_UNDEFINED; -) - JSC_CCALL(physics_closest_point, void *v1 = js2cpvec2arr(argv[1]); JSValue ret = number2js(point2segindex(js2vec2(argv[0]), v1, js2number(argv[2]))); @@ -1024,10 +1009,9 @@ JSC_CCALL(physics_point_query_nearest, static const JSCFunctionListEntry js_physics_funcs[] = { MIST_FUNC_DEF(physics, sgscale, 2), MIST_FUNC_DEF(physics, set_cat_mask, 2), - MIST_FUNC_DEF(physics, pos_query, 2), MIST_FUNC_DEF(physics, point_query, 3), - MIST_FUNC_DEF(physics, point_query_nearest, 3), - MIST_FUNC_DEF(physics, ray_query, 2), + MIST_FUNC_DEF(physics, point_query_nearest, 2), + MIST_FUNC_DEF(physics, ray_query, 4), MIST_FUNC_DEF(physics, box_query, 2), MIST_FUNC_DEF(physics, shape_query, 1), MIST_FUNC_DEF(physics, closest_point, 3), @@ -1471,7 +1455,7 @@ JSC_CCALL(os_make_circle2d, JSValue circleval = JS_NewObject(js); js_setprop_str(circleval, "id", ptr2js(circle)); js_setprop_str(circleval, "shape", ptr2js(&circle->shape)); - circle->shape.ref = argv[1]; + circle->shape.ref = JS_DupValue(js,argv[1]); return circleval; ) @@ -1482,7 +1466,7 @@ JSC_CCALL(os_make_poly2d, JSValue polyval = JS_NewObject(js); js_setprop_str(polyval, "id", ptr2js(poly)); js_setprop_str(polyval, "shape", ptr2js(&poly->shape)); - poly->shape.ref = argv[1]; + poly->shape.ref = JS_DupValue(js,argv[1]); return polyval; ) @@ -1496,7 +1480,7 @@ JSC_CCALL(os_make_edge2d, JSValue edgeval = JS_NewObject(js); js_setprop_str(edgeval, "id", ptr2js(edge)); js_setprop_str(edgeval, "shape", ptr2js(&edge->shape)); - edge->shape.ref = argv[1]; + edge->shape.ref = JS_DupValue(js, argv[1]); return edgeval; ) diff --git a/source/engine/render.c b/source/engine/render.c index 0a2d29b..3f09b54 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -203,7 +203,7 @@ SG_TRACE_SET(attachments) void trace_append_buffer(sg_buffer id, sg_range *data, void *user) { sg_buffer_desc desc = sg_query_buffer_desc(id); - YughSpam("Appending buffer %d [%s]", id, desc.label); +// YughSpam("Appending buffer %d [%s]", id, desc.label); } static sg_trace_hooks hooks = {