Change physics collisions and masks

This commit is contained in:
John Alanbrook 2024-04-12 13:53:00 -05:00
parent 17ad44e5a5
commit c05cb3c6d2
9 changed files with 103 additions and 97 deletions

View file

@ -1530,7 +1530,7 @@ var replpanel = Object.copy(inputpanel, {
this.caret = 0; this.caret = 0;
var ret = function() {return eval(ecode);}.call(repl_obj); var ret = function() {return eval(ecode);}.call(repl_obj);
if (typeof ret === 'object') ret = json.encode(ret,null,1); if (typeof ret === 'object') ret = json.encode(ret,null,1);
if (ret) say(ret); if (typeof ret !== 'undefined') say(ret);
}, },
resetscroll() { resetscroll() {

View file

@ -524,10 +524,10 @@ var Event = {
Object.keys(this.events).forEach(name => Event.unobserve(name,obj)); Object.keys(this.events).forEach(name => Event.unobserve(name,obj));
}, },
notify(name) { notify(name, ...args) {
if (!this.events[name]) return; if (!this.events[name]) return;
this.events[name].forEach(function(x) { this.events[name].forEach(function(x) {
x[1].call(x[0]); x[1].call(x[0], ...args);
}); });
}, },
}; };

View file

@ -220,14 +220,42 @@ var gameobject = {
ent.components = {}; ent.components = {};
ent.objects = {}; ent.objects = {};
ent.timers = []; ent.timers = [];
Object.mixin(ent, {
set category(n) {
if (n === 0) {
this.categories = n;
return;
}
var cat = (1 << (n-1));
this.categories = cat;
},
get category() {
if (this.categories === 0) return 0;
var pos = 0;
var num = this.categories;
while (num > 0) {
if (num & 1) {
break;
}
pos++;
num >>>= 1;
}
return pos+1;
}
});
if (typeof text === 'object' && text) // assume it's an ur if (typeof text === 'object' && text) {// assume it's an ur
ent.ur = text; ent.ur = text;
else text = ent.ur.text;
config = [ent.ur.data, config].filter(x => x).flat();
}
else {
ent.ur = getur(text, config); ent.ur = getur(text, config);
text = ent.ur.text;
text = ent.ur.text; config = [ent.ur.data, config];
config = [ent.ur.data, config]; }
if (typeof text === 'string') if (typeof text === 'string')
use(text, ent); use(text, ent);
@ -264,7 +292,7 @@ var gameobject = {
if (sim.playing()) if (sim.playing())
if (typeof ent.start === 'function') ent.start(); if (typeof ent.start === 'function') ent.start();
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master'); Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master', 'categories');
ent._ed = { ent._ed = {
selectable: true, selectable: true,
@ -406,7 +434,7 @@ var gameobject = {
}, },
/* The unique components of this object. Its diff. */ /* The unique components of this object. Its diff. */
json_obj() { json_obj(depth=0) {
var fresh = this.ur.fresh; var fresh = this.ur.fresh;
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components. var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
var d = ediff(thiso, fresh); var d = ediff(thiso, fresh);
@ -698,7 +726,8 @@ game.loadurs = function() {
for (var file of io.glob("**.ur")) { for (var file of io.glob("**.ur")) {
var newur = ur_from_file(file); var newur = ur_from_file(file);
if (!newur) continue; if (!newur) continue;
var urjson = json.decode(io.slurp(file)); var uur = Resources.replstrs(file);
var urjson = json.decode(uur);
Object.assign(newur, urjson); Object.assign(newur, urjson);
} }
@ -725,4 +754,31 @@ game.loadurs = function() {
} }
}; };
game.ur = {};
game.ur.load = function(str) {}
game.ur.add_data = function(str, data)
{
var nur = ur[str];
if (!nur) {
console.warn(`Cannot add data to the ur ${str}.`);
return;
}
if (!Array.isArray(ur.data)) {
var arr = [];
if (ur.data) arr.push(ur.data);
ur.data = arr;
}
ur.data.push(data);
}
game.ur.save = function(str)
{
var nur = ur[str];
if (!nur) {
console.warn(`Cannot save ur ${str}.`);
return;
}
}
return { go_init } return { go_init }

View file

@ -47,33 +47,11 @@ physics.doc.pos_query = "Returns any object colliding with the given point.";
physics.doc.box_query = "Calls a given function on every shape object in the given bbox."; physics.doc.box_query = "Calls a given function on every shape object in the given bbox.";
physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box."; physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box.";
physics.collision = {
types: {},
num: 32,
set_collide(a, b, x) {
this.types[a][b] = x;
this.types[b][a] = x;
this.sync();
},
sync() {
for (var i = 0; i < this.num; i++)
physics.set_cat_mask(i,this.types[i]);
},
};
for (var i = 0; i < physics.collision.num; i++) {
physics.collision.types[i] = [];
for (var j = 0; j < physics.collision.num; j++)
physics.collision.types[i][j] = false;
};
physics.collision.sync();
physics.gravity = physics.make_gravity(); physics.gravity = physics.make_gravity();
physics.gravity.mask = [true]; physics.gravity.mask = ~1;
physics.gravity.strength = 500; physics.gravity.strength = 500;
physics.damp = physics.make_damp(); physics.damp = physics.make_damp();
physics.damp.mask = [true]; physics.damp.mask = ~1;
return { return {
physics physics

View file

@ -35,10 +35,6 @@ static int cb_idx = 0;
static const unsigned char col_alpha = 40; static const unsigned char col_alpha = 40;
static const float sensor_seg = 10; static const float sensor_seg = 10;
unsigned int category_masks[32];
void set_cat_mask(int cat, unsigned int mask) { category_masks[cat] = mask; }
cpTransform m3_to_cpt(HMM_Mat3 m) cpTransform m3_to_cpt(HMM_Mat3 m)
{ {
cpTransform t; cpTransform t;
@ -52,7 +48,7 @@ cpTransform m3_to_cpt(HMM_Mat3 m)
} }
cpShape *phys2d_query_pos(cpVect pos) { cpShape *phys2d_query_pos(cpVect pos) {
return cpSpacePointQueryNearest(space, pos, 0.f, allfilter, NULL); return cpSpacePointQueryNearest(space, pos, 0.f, CP_SHAPE_FILTER_ALL, NULL);
} }
@ -67,23 +63,11 @@ void bbhit(cpShape *shape, int *data)
qhit++; 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,
.categories = CP_ALL_CATEGORIES,
};
int query_point(HMM_Vec2 pos) int query_point(HMM_Vec2 pos)
{ {
qhit = 0; qhit = 0;
// cpSpacePointQuery(space, pos.cp, 0, filter, qpoint, &qhit); // cpSpacePointQuery(space, pos.cp, 0, filter, qpoint, &qhit);
cpSpaceBBQuery(space, cpBBNewForCircle(pos.cp, 2), allfilter, bbhit, &qhit); cpSpaceBBQuery(space, cpBBNewForCircle(pos.cp, 2), CP_SHAPE_FILTER_ALL, bbhit, &qhit);
return qhit; return qhit;
} }
@ -599,8 +583,13 @@ void register_hit(cpArbiter *arb, gameobject *go, const char *name)
cpShape *s1, *s2; cpShape *s1, *s2;
cpArbiterGetShapes(arb, &s1, &s2); cpArbiterGetShapes(arb, &s1, &s2);
if (JS_IsUndefined(shape2go(s1)->ref)) return; gameobject *g1, *g2;
if (JS_IsUndefined(shape2go(s2)->ref)) return; g1 = shape2go(s1);
g2 = shape2go(g2);
if (!g1) return;
if (!g2) return;
if (JS_IsUndefined(g1->ref)) return;
if (JS_IsUndefined(g2->ref)) return;
struct phys2d_shape *pshape1 = cpShapeGetUserData(s1); struct phys2d_shape *pshape1 = cpShapeGetUserData(s1);
if (JS_IsUndefined(pshape1->ref)) return; if (JS_IsUndefined(pshape1->ref)) return;
@ -614,7 +603,7 @@ 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"); } int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "collide"); return 1; }
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "separate"); } void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "separate"); }
void phys2d_setup_handlers(gameobject *go) { void phys2d_setup_handlers(gameobject *go) {

View file

@ -17,9 +17,6 @@ extern struct rgba kinematic_color;
extern struct rgba static_color; extern struct rgba static_color;
extern struct rgba sleep_color; extern struct rgba sleep_color;
extern cpShapeFilter allfilter;
extern cpShapeFilter nofilter;
typedef struct constraint { typedef struct constraint {
cpConstraint *c; cpConstraint *c;
JSValue break_cb; /* function called when it is forcibly broken */ JSValue break_cb; /* function called when it is forcibly broken */
@ -129,7 +126,5 @@ void phys2d_setup_handlers(gameobject *go);
int query_point(HMM_Vec2 pos); int query_point(HMM_Vec2 pos);
void phys2d_reindex_body(cpBody *body); void phys2d_reindex_body(cpBody *body);
extern unsigned int category_masks[32];
void set_cat_mask(int cat, unsigned int mask);
#endif #endif

View file

@ -55,8 +55,6 @@ transform2d go2t(gameobject *go)
return t; return t;
} }
unsigned int editor_cat = 1<<31;
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) { void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
cpShapeSetFriction(shape, go->friction); cpShapeSetFriction(shape, go->friction);
cpShapeSetElasticity(shape, go->elasticity); cpShapeSetElasticity(shape, go->elasticity);
@ -64,8 +62,8 @@ void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
cpShapeFilter filter; cpShapeFilter filter;
filter.group = (cpCollisionType)go; filter.group = (cpCollisionType)go;
filter.categories = 1<<go->layer | editor_cat; filter.categories = go->categories;
filter.mask = category_masks[go->layer] | editor_cat; filter.mask = go->mask;
// filter.mask = CP_ALL_CATEGORIES; // filter.mask = CP_ALL_CATEGORIES;
cpShapeSetFilter(shape, filter); cpShapeSetFilter(shape, filter);
@ -106,7 +104,7 @@ static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt
{ {
gameobject *go = body2go(body); gameobject *go = body2go(body);
cpVect pos = cpBodyGetPosition(body); cpVect pos = cpBodyGetPosition(body);
HMM_Vec2 g = warp_force((HMM_Vec3){pos.x, pos.y, 0}, go->warp_filter).xy; HMM_Vec2 g = warp_force((HMM_Vec3){pos.x, pos.y, 0}, go->warp_mask).xy;
if (!go) { if (!go) {
cpBodyUpdateVelocity(body,g.cp,damping,dt); cpBodyUpdateVelocity(body,g.cp,damping,dt);
return; return;
@ -140,6 +138,9 @@ gameobject *MakeGameobject() {
.damping = INFINITY, .damping = INFINITY,
.timescale = 1.0, .timescale = 1.0,
.ref = JS_UNDEFINED, .ref = JS_UNDEFINED,
.mask = ~0,
.categories = 1,
.warp_mask = ~0
}; };
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f)); go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
@ -163,7 +164,7 @@ void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
free(s->data); free(s->data);
} }
cpShapeSetFilter(shape, nofilter); cpShapeSetFilter(shape, CP_SHAPE_FILTER_NONE);
cpSpaceRemoveShape(space, shape); cpSpaceRemoveShape(space, shape);
cpShapeFree(shape); cpShapeFree(shape);

View file

@ -39,8 +39,9 @@ struct gameobject {
float maxvelocity; float maxvelocity;
float maxangularvelocity; float maxangularvelocity;
unsigned int layer; unsigned int layer;
cpShapeFilter filter; cpBitmask categories;
unsigned int warp_filter; cpBitmask mask;
unsigned int warp_mask;
JSValue ref; JSValue ref;
HMM_Mat4 world; HMM_Mat4 world;
float drawlayer; float drawlayer;

View file

@ -336,18 +336,11 @@ JSValue vec32js(HMM_Vec3 v)
} }
cpBitmask js2bitmask(JSValue v) { cpBitmask js2bitmask(JSValue v) {
cpBitmask mask = 0; cpBitmask a;
int len = js_arrlen(v); JS_ToUint32(js, &a, v);
return a;
for (int i = 0; i < len; i++) {
int val = js2boolean(js_getpropidx( v, i));
if (!val) continue;
mask |= 1 << i;
}
return mask;
} }
JSValue bitmask2js(cpBitmask mask) { return JS_NewUint32(js, mask); }
HMM_Vec2 *js2cpvec2arr(JSValue v) { HMM_Vec2 *js2cpvec2arr(JSValue v) {
HMM_Vec2 *arr = NULL; HMM_Vec2 *arr = NULL;
@ -370,14 +363,6 @@ HMM_Vec2 *jsfloat2vec(JSValue v)
return arr; return arr;
} }
JSValue bitmask2js(cpBitmask mask) {
JSValue arr = JS_NewArray(js);
for (int i = 0; i < 11; i++)
js_setprop_num(arr,i,boolean2js(mask & 1 << i));
return arr;
}
JSValue vecarr2js(HMM_Vec2 *points, int n) { JSValue vecarr2js(HMM_Vec2 *points, int n) {
JSValue array = JS_NewArray(js); JSValue array = JS_NewArray(js);
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
@ -918,8 +903,6 @@ JSC_CCALL(physics_sgscale,
cpSpaceReindexShapesForBody(space, js2gameobject(argv[0])->body); cpSpaceReindexShapesForBody(space, js2gameobject(argv[0])->body);
) )
JSC_CCALL(physics_set_cat_mask, set_cat_mask(js2number(argv[0]), js2bitmask(argv[1])))
JSC_CCALL(physics_closest_point, JSC_CCALL(physics_closest_point,
void *v1 = js2cpvec2arr(argv[1]); void *v1 = js2cpvec2arr(argv[1]);
JSValue ret = number2js(point2segindex(js2vec2(argv[0]), v1, js2number(argv[2]))); JSValue ret = number2js(point2segindex(js2vec2(argv[0]), v1, js2number(argv[2])));
@ -945,7 +928,7 @@ JSC_CCALL(physics_box_query,
bbox.r = pos.x+wh.x/2; bbox.r = pos.x+wh.x/2;
bbox.t = pos.y+wh.y/2; bbox.t = pos.y+wh.y/2;
bbox.b = pos.y-wh.y/2; bbox.b = pos.y-wh.y/2;
cpSpaceBBQuery(space, bbox, allfilter, bb_query_fn, &argv[3]); cpSpaceBBQuery(space, bbox, CP_SHAPE_FILTER_ALL, bb_query_fn, &argv[3]);
return ret; return ret;
) )
@ -972,7 +955,7 @@ static void ray_query_fn(cpShape *shape, float t, cpVect n, float a, JSValue *cb
} }
JSC_CCALL(physics_ray_query, JSC_CCALL(physics_ray_query,
cpSpaceSegmentQuery(space, js2vec2(argv[0]).cp, js2vec2(argv[1]).cp, js2number(argv[2]), allfilter, ray_query_fn, &argv[3]); cpSpaceSegmentQuery(space, js2vec2(argv[0]).cp, js2vec2(argv[1]).cp, js2number(argv[2]), CP_SHAPE_FILTER_ALL, ray_query_fn, &argv[3]);
); );
static void point_query_fn(cpShape *shape, float dist, cpVect point, JSValue *cb) static void point_query_fn(cpShape *shape, float dist, cpVect point, JSValue *cb)
@ -987,7 +970,7 @@ static void point_query_fn(cpShape *shape, float dist, cpVect point, JSValue *cb
} }
JSC_CCALL(physics_point_query, JSC_CCALL(physics_point_query,
cpSpacePointQuery(space, js2vec2(argv[0]).cp, js2number(argv[1]), allfilter, point_query_fn, &argv[2]); cpSpacePointQuery(space, js2vec2(argv[0]).cp, js2number(argv[1]), CP_SHAPE_FILTER_ALL, point_query_fn, &argv[2]);
); );
JSValue pointinfo2js(cpPointQueryInfo info) JSValue pointinfo2js(cpPointQueryInfo info)
@ -1001,14 +984,13 @@ JSValue pointinfo2js(cpPointQueryInfo info)
JSC_CCALL(physics_point_query_nearest, JSC_CCALL(physics_point_query_nearest,
cpPointQueryInfo info; cpPointQueryInfo info;
cpShape *sh = cpSpacePointQueryNearest(space, js2vec2(argv[0]).cp, js2number(argv[1]), allfilter, &info); cpShape *sh = cpSpacePointQueryNearest(space, js2vec2(argv[0]).cp, js2number(argv[1]), CP_SHAPE_FILTER_ALL, &info);
if (!sh) return JS_UNDEFINED; if (!sh) return JS_UNDEFINED;
return pointinfo2js(info); return pointinfo2js(info);
) )
static const JSCFunctionListEntry js_physics_funcs[] = { static const JSCFunctionListEntry js_physics_funcs[] = {
MIST_FUNC_DEF(physics, sgscale, 2), MIST_FUNC_DEF(physics, sgscale, 2),
MIST_FUNC_DEF(physics, set_cat_mask, 2),
MIST_FUNC_DEF(physics, point_query, 3), MIST_FUNC_DEF(physics, point_query, 3),
MIST_FUNC_DEF(physics, point_query_nearest, 2), MIST_FUNC_DEF(physics, point_query_nearest, 2),
MIST_FUNC_DEF(physics, ray_query, 4), MIST_FUNC_DEF(physics, ray_query, 4),
@ -1153,8 +1135,10 @@ JSC_GETSET(gameobject, damping, number)
JSC_GETSET(gameobject, timescale, number) JSC_GETSET(gameobject, timescale, number)
JSC_GETSET(gameobject, maxvelocity, number) JSC_GETSET(gameobject, maxvelocity, number)
JSC_GETSET(gameobject, maxangularvelocity, number) JSC_GETSET(gameobject, maxangularvelocity, number)
JSC_GETSET(gameobject, warp_filter, bitmask) JSC_GETSET(gameobject, warp_mask, bitmask)
JSC_GETSET(gameobject, drawlayer, number) JSC_GETSET(gameobject, drawlayer, number)
JSC_GETSET(gameobject, categories, bitmask)
JSC_GETSET(gameobject, mask, bitmask)
JSC_CCALL(gameobject_selfsync, gameobject_apply(js2gameobject(this))) JSC_CCALL(gameobject_selfsync, gameobject_apply(js2gameobject(this)))
JSC_CCALL(gameobject_world2this, return vec22js(world2go(js2gameobject(this), js2vec2(argv[0])))) JSC_CCALL(gameobject_world2this, return vec22js(world2go(js2gameobject(this), js2vec2(argv[0]))))
JSC_CCALL(gameobject_this2world, return vec22js(go2world(js2gameobject(this), js2vec2(argv[0])))) JSC_CCALL(gameobject_this2world, return vec22js(go2world(js2gameobject(this), js2vec2(argv[0]))))
@ -1170,8 +1154,10 @@ static const JSCFunctionListEntry js_gameobject_funcs[] = {
CGETSET_ADD(gameobject,maxvelocity), CGETSET_ADD(gameobject,maxvelocity),
CGETSET_ADD(gameobject,maxangularvelocity), CGETSET_ADD(gameobject,maxangularvelocity),
CGETSET_ADD(gameobject,layer), CGETSET_ADD(gameobject,layer),
CGETSET_ADD(gameobject,warp_filter), CGETSET_ADD(gameobject,warp_mask),
CGETSET_ADD(gameobject,drawlayer), CGETSET_ADD(gameobject,drawlayer),
CGETSET_ADD(gameobject, categories),
CGETSET_ADD(gameobject, mask),
CGETSET_ADD_HID(gameobject, rpos), CGETSET_ADD_HID(gameobject, rpos),
CGETSET_ADD_HID(gameobject, rangle), CGETSET_ADD_HID(gameobject, rangle),
CGETSET_ADD_HID(gameobject, rscale), CGETSET_ADD_HID(gameobject, rscale),