Physics fixes; editor fixes

This commit is contained in:
John Alanbrook 2024-04-11 17:17:49 -05:00
parent 0b4231c0b6
commit 17ad44e5a5
11 changed files with 79 additions and 112 deletions

View file

@ -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() {

View file

@ -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) {

View file

@ -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")) {

View file

@ -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);

View file

@ -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 [];

View file

@ -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;
}

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -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;
)

View file

@ -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 = {