2d physics to javascript

This commit is contained in:
John Alanbrook 2024-05-17 04:23:03 -05:00
parent ee72949029
commit ba2409fc56
3 changed files with 119 additions and 68 deletions

View file

@ -14,13 +14,6 @@ gameobject *shape2go(cpShape *shape) {
return pshape->go; return pshape->go;
} }
HMM_Vec3 go_pos(gameobject *go)
{
cpVect p = cpBodyGetPosition(go->body);
return (HMM_Vec3){p.x, p.y, 0};
}
float go_angle(gameobject *go) { return cpBodyGetAngle(go->body); }
transform go2t(gameobject *go) transform go2t(gameobject *go)
{ {
transform t = {0}; transform t = {0};
@ -75,6 +68,8 @@ void gameobject_apply(gameobject *go) {
if (cpBodyGetMoment(go->body) <= 0.f) if (cpBodyGetMoment(go->body) <= 0.f)
cpBodySetMoment(go->body, 1.f); cpBodySetMoment(go->body, 1.f);
} }
*go->t = go2t(go);
} }
static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt) static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
@ -159,11 +154,6 @@ void gameobject_free(gameobject *go) {
free(go); free(go);
} }
void gameobject_setangle(gameobject *go, float angle) {
cpBodySetAngle(go->body, angle);
phys2d_reindex_body(go->body);
}
void gameobject_setpos(gameobject *go, cpVect vec) { void gameobject_setpos(gameobject *go, cpVect vec) {
if (!go || !go->body) return; if (!go || !go->body) return;
cpBodySetPosition(go->body, vec); cpBodySetPosition(go->body, vec);

View file

@ -42,6 +42,7 @@ struct gameobject {
unsigned int warp_mask; unsigned int warp_mask;
HMM_Vec3 scale; HMM_Vec3 scale;
JSValue ref; JSValue ref;
transform *t; // the transform this body controls
}; };
/* /*
@ -67,16 +68,10 @@ void gameobject_free(gameobject *go);
transform go2t(gameobject *go); transform go2t(gameobject *go);
HMM_Vec3 go_pos(gameobject *go); HMM_Vec3 go_pos(gameobject *go);
void gameobject_setpos(gameobject *go, cpVect vec);
float go_angle(gameobject *go);
void gameobject_setangle(gameobject *go, float angle);
gameobject *body2go(cpBody *body); gameobject *body2go(cpBody *body);
gameobject *shape2go(cpShape *shape); gameobject *shape2go(cpShape *shape);
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go); void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go);
/* Tries a few methods to select a gameobject; if none is selected returns -1 */
void gameobject_draw_debug(gameobject *go);
#endif #endif

View file

@ -33,6 +33,7 @@
#include "par/par_streamlines.h" #include "par/par_streamlines.h"
#include "par/par_shapes.h" #include "par/par_shapes.h"
#include "sokol_glue.h" #include "sokol_glue.h"
#include <chipmunk/chipmunk_unsafe.h>
#if (defined(_WIN32) || defined(__WIN32__)) #if (defined(_WIN32) || defined(__WIN32__))
#include <direct.h> #include <direct.h>
@ -78,6 +79,11 @@ void sg_buffer_free(sg_buffer *b)
free(b); free(b);
} }
void cpShape_free(cpShape *s)
{
cpShapeFree(s);
}
void sg_image_free(sg_image *t){} void sg_image_free(sg_image *t){}
void jsfreestr(const char *s) { JS_FreeCString(js, s); } void jsfreestr(const char *s) { JS_FreeCString(js, s); }
@ -94,6 +100,7 @@ QJSCLASS(constraint)
QJSCLASS(sg_buffer) QJSCLASS(sg_buffer)
QJSCLASS(sg_image) QJSCLASS(sg_image)
QJSCLASS(datastream) QJSCLASS(datastream)
QJSCLASS(cpShape)
static JSValue sound_proto; static JSValue sound_proto;
sound *js2sound(JSValue v) { return js2dsp_node(v)->data; } sound *js2sound(JSValue v) { return js2dsp_node(v)->data; }
@ -563,34 +570,6 @@ int point2segindex(HMM_Vec2 p, HMM_Vec2 *segs, double slop) {
return best; return best;
} }
circle2d *js2circle2d(JSValue v) { return js2ptr(v); }
JSC_CCALL(circle2d_set_radius, js2circle2d(argv[0])->radius = js2number(argv[1]))
JSC_CCALL(circle2d_get_radius, return number2js(js2circle2d(argv[0])->radius))
JSC_CCALL(circle2d_set_offset, js2circle2d(argv[0])->offset = js2vec2(argv[1]))
JSC_CCALL(circle2d_get_offset, return vec22js(js2circle2d(argv[0])->offset))
JSC_CCALL(circle2d_sync, phys2d_shape_apply(&js2circle2d(argv[0])->shape))
static const JSCFunctionListEntry js_circle2d_funcs[] = {
MIST_FUNC_DEF(circle2d, set_radius, 2),
MIST_FUNC_DEF(circle2d, get_radius, 1),
MIST_FUNC_DEF(circle2d, set_offset, 2),
MIST_FUNC_DEF(circle2d, get_offset, 1),
MIST_FUNC_DEF(circle2d, sync, 1),
};
struct phys2d_poly *js2poly2d(JSValue v) { return js2ptr(v); }
JSC_CCALL(poly2d_setverts,
struct phys2d_poly *p = js2poly2d(argv[0]);
HMM_Vec2 *v = js2cpvec2arr(argv[1]);
phys2d_poly_setverts(p,v);
arrfree(v);
)
static const JSCFunctionListEntry js_poly2d_funcs[] = {
MIST_FUNC_DEF(poly2d, setverts, 2),
};
JSC_GETSET(warp_gravity, strength, number) JSC_GETSET(warp_gravity, strength, number)
JSC_GETSET(warp_gravity, decay, number) JSC_GETSET(warp_gravity, decay, number)
@ -1487,16 +1466,18 @@ static const JSCFunctionListEntry js_window_funcs[] = {
MIST_FUNC_DEF(window, set_icon, 1) MIST_FUNC_DEF(window, set_icon, 1)
}; };
JSValue js_gameobject_set_rpos(JSContext *js, JSValue this, JSValue val) { JSValue js_gameobject_set_pos(JSContext *js, JSValue this, JSValue val) {
cpBody *b = js2gameobject(this)->body; cpBody *b = js2gameobject(this)->body;
cpBodySetPosition(b, js2cvec2(val)); cpBodySetPosition(b, js2cvec2(val));
if (cpBodyGetType(b) == CP_BODY_TYPE_STATIC) if (cpBodyGetType(b) == CP_BODY_TYPE_STATIC)
cpSpaceReindexShapesForBody(space, b); cpSpaceReindexShapesForBody(space, b);
gameobject_apply(js2gameobject(this));
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue js_gameobject_get_rpos(JSContext *js, JSValue this) { return cvec22js(cpBodyGetPosition(js2gameobject(this)->body)); } JSValue js_gameobject_get_pos(JSContext *js, JSValue this) { return cvec22js(cpBodyGetPosition(js2gameobject(this)->body)); }
JSValue js_gameobject_set_rangle (JSContext *js, JSValue this, JSValue val) { cpBodySetAngle(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); return JS_UNDEFINED; } JSValue js_gameobject_set_angle (JSContext *js, JSValue this, JSValue val) { cpBodySetAngle(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); return JS_UNDEFINED; }
JSValue js_gameobject_get_rangle (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngle(js2gameobject(this)->body)); } JSValue js_gameobject_get_angle (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngle(js2gameobject(this)->body)); }
JSValue js_gameobject_get_rscale(JSContext *js, JSValue this) { return vec32js(js2gameobject(this)->scale); } JSValue js_gameobject_get_rscale(JSContext *js, JSValue this) { return vec32js(js2gameobject(this)->scale); }
JSValue js_gameobject_set_rscale(JSContext *js, JSValue this, JSValue val) { js2gameobject(this)->scale = js2vec3(val); return JS_UNDEFINED; } JSValue js_gameobject_set_rscale(JSContext *js, JSValue this, JSValue val) { js2gameobject(this)->scale = js2vec3(val); return JS_UNDEFINED; }
JSC_GETSET_BODY(velocity, Velocity, cvec2) JSC_GETSET_BODY(velocity, Velocity, cvec2)
@ -1521,7 +1502,20 @@ JSC_GETSET(gameobject, categories, bitmask)
JSC_GETSET(gameobject, mask, bitmask) JSC_GETSET(gameobject, mask, bitmask)
JSC_CCALL(gameobject_selfsync, gameobject_apply(js2gameobject(this))) JSC_CCALL(gameobject_selfsync, gameobject_apply(js2gameobject(this)))
void body_shape_fn(cpBody *body, cpShape *shape, JSValue *fn) {
JSValue v = cpShape2js(shape);
script_call_sym(*fn, 1, &v);
}
JSC_CCALL(gameobject_eachshape,
gameobject *g = js2gameobject(this);
JSValue fn = argv[0];
cpBodyEachShape(g->body, body_shape_fn, &fn);
)
static const JSCFunctionListEntry js_gameobject_funcs[] = { static const JSCFunctionListEntry js_gameobject_funcs[] = {
CGETSET_ADD(gameobject, pos),
CGETSET_ADD(gameobject, angle),
CGETSET_ADD(gameobject, friction), CGETSET_ADD(gameobject, friction),
CGETSET_ADD(gameobject, elasticity), CGETSET_ADD(gameobject, elasticity),
CGETSET_ADD(gameobject,mass), CGETSET_ADD(gameobject,mass),
@ -1542,6 +1536,7 @@ static const JSCFunctionListEntry js_gameobject_funcs[] = {
MIST_FUNC_DEF(gameobject, force, 1), MIST_FUNC_DEF(gameobject, force, 1),
MIST_FUNC_DEF(gameobject, force_local, 2), MIST_FUNC_DEF(gameobject, force_local, 2),
MIST_FUNC_DEF(gameobject, selfsync, 0), MIST_FUNC_DEF(gameobject, selfsync, 0),
MIST_FUNC_DEF(gameobject, eachshape, 1)
}; };
JSC_CCALL(joint_pin, return constraint2js(constraint_make(cpPinJointNew(js2gameobject(argv[0])->body, js2gameobject(argv[1])->body, cpvzero,cpvzero)))) JSC_CCALL(joint_pin, return constraint2js(constraint_make(cpPinJointNew(js2gameobject(argv[0])->body, js2gameobject(argv[1])->body, cpvzero,cpvzero))))
@ -1795,30 +1790,100 @@ JSC_CCALL(os_gc, script_gc());
JSC_SSCALL(os_eval, ret = script_eval(str, str2)) JSC_SSCALL(os_eval, ret = script_eval(str, str2))
JSC_CCALL(os_make_gameobject, JSC_CCALL(os_make_gameobject,
ret = gameobject2js(MakeGameobject()); gameobject *g = MakeGameobject();
JS_SetPropertyFunctionList(js, ret, js_gameobject_funcs, countof(js_gameobject_funcs)); g->t = js2transform(argv[0]);
js2gameobject(ret)->ref = ret; ret = gameobject2js(g);
// JS_SetPropertyFunctionList(js, ret, js_gameobject_funcs, countof(js_gameobject_funcs));
g->ref = ret;
return ret; return ret;
) )
JSValue js_circle2d_set_radius(JSContext *js, JSValue this, JSValue val) {
cpCircleShapeSetRadius(js2cpShape(this), js2number(val));
}
JSC_CCALL(circle2d_get_radius, return number2js(cpCircleShapeGetRadius(js2cpShape(this))))
JSValue js_circle2d_set_offset(JSContext *js, JSValue this, JSValue val) {
cpCircleShapeSetOffset(js2cpShape(this), js2vec2(val).cp);
}
JSC_CCALL(circle2d_get_offset, return vec22js((HMM_Vec2)cpCircleShapeGetOffset(js2cpShape(this))))
static const JSCFunctionListEntry js_circle2d_funcs[] = {
CGETSET_ADD(circle2d, radius),
CGETSET_ADD(circle2d, offset)
};
JSC_CCALL(os_make_circle2d, JSC_CCALL(os_make_circle2d,
gameobject *go = js2gameobject(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_circle *circle = Make2DCircle(go); cpShape *shape = cpCircleShapeNew(go->body, 10, (cpVect){0,0});
JSValue circleval = JS_NewObject(js); cpSpaceAddShape(space, shape);
js_setprop_str(circleval, "id", ptr2js(circle)); ret = cpShape2js(shape);
js_setprop_str(circleval, "shape", ptr2js(&circle->shape)); JS_SetPropertyFunctionList(js, ret, js_circle2d_funcs, countof(js_circle2d_funcs));
circle->shape.ref = JS_DupValue(js,argv[1]); return ret;
return circleval;
) )
JSC_CCALL(poly2d_setverts,
cpShape *s = js2cpShape(this);
HMM_Vec2 *v = js2cpvec2arr(argv[0]);
cpTransform t = {0};
t.a = 1;
t.b = 0;
t.tx = 0;
t.c = 0;
t.d = 1;
t.ty = 0;
cpPolyShapeSetVerts(s, arrlen(v), v, t);
arrfree(v);
)
JSValue js_poly2d_set_radius(JSContext *js, JSValue this, JSValue val) {
cpPolyShapeSetRadius(js2cpShape(this), js2number(val));
}
JSC_CCALL(poly2d_get_radius, return number2js(cpPolyShapeGetRadius(js2cpShape(this))))
static const JSCFunctionListEntry js_poly2d_funcs[] = {
MIST_FUNC_DEF(poly2d, setverts, 2),
CGETSET_ADD(poly2d, radius)
};
JSC_CCALL(os_make_poly2d, JSC_CCALL(os_make_poly2d,
gameobject *go = js2gameobject(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_poly *poly = Make2DPoly(go); cpShape *shape = cpPolyShapeNew(go->body, 0, NULL, (cpTransform){0}, 0);
phys2d_poly_setverts(poly, NULL); cpSpaceAddShape(space, shape);
JSValue polyval = JS_NewObject(js); ret = cpShape2js(shape);
js_setprop_str(polyval, "id", ptr2js(poly)); JS_SetPropertyFunctionList(js, ret, js_poly2d_funcs, countof(js_poly2d_funcs));
js_setprop_str(polyval, "shape", ptr2js(&poly->shape)); return ret;
poly->shape.ref = JS_DupValue(js,argv[1]); )
return polyval;
JSC_CCALL(seg2d_set_endpoints,
HMM_Vec2 a = js2vec2(argv[0]);
HMM_Vec2 b = js2vec2(argv[1]);
cpSegmentShapeSetEndpoints(js2cpShape(this), a.cp, b.cp);
)
JSValue js_seg2d_set_radius(JSContext *js, JSValue this, JSValue val) {
cpSegmentShapeSetRadius(js2cpShape(this), js2number(val));
}
JSC_CCALL(seg2d_get_radius, return number2js(cpSegmentShapeGetRadius(js2cpShape(this))))
JSC_CCALL(seg2d_set_neighbors,
HMM_Vec2 prev = js2vec2(argv[0]);
HMM_Vec2 next = js2vec2(argv[1]);
cpSegmentShapeSetNeighbors(js2cpShape(this), prev.cp, next.cp);
)
static const JSCFunctionListEntry js_seg2d_funcs[] = {
MIST_FUNC_DEF(seg2d, set_endpoints, 2),
CGETSET_ADD(seg2d, radius),
MIST_FUNC_DEF(seg2d, set_neighbors, 2)
};
JSC_CCALL(os_make_seg2d,
gameobject *go = js2gameobject(argv[0]);
cpShape *shape = cpSegmentShapeNew(go->body, (cpVect){0,0}, (cpVect){0,0}, 0);
cpSpaceAddShape(space, shape);
ret = cpShape2js(shape);
JS_SetPropertyFunctionList(js, ret, js_seg2d_funcs, countof(js_seg2d_funcs));
return ret;
) )
JSC_CCALL(os_make_edge2d, JSC_CCALL(os_make_edge2d,
@ -2064,10 +2129,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, reindex_static, 0), MIST_FUNC_DEF(os, reindex_static, 0),
MIST_FUNC_DEF(os, gc, 0), MIST_FUNC_DEF(os, gc, 0),
MIST_FUNC_DEF(os, eval, 2), MIST_FUNC_DEF(os, eval, 2),
MIST_FUNC_DEF(os, make_gameobject, 0), MIST_FUNC_DEF(os, make_gameobject, 1),
MIST_FUNC_DEF(os, make_circle2d, 2), MIST_FUNC_DEF(os, make_circle2d, 2),
MIST_FUNC_DEF(os, make_poly2d, 2), MIST_FUNC_DEF(os, make_poly2d, 2),
MIST_FUNC_DEF(os, make_edge2d, 2), MIST_FUNC_DEF(os, make_edge2d, 2),
MIST_FUNC_DEF(os, make_seg2d, 1),
MIST_FUNC_DEF(os, make_texture, 1), MIST_FUNC_DEF(os, make_texture, 1),
MIST_FUNC_DEF(os, make_font, 2), MIST_FUNC_DEF(os, make_font, 2),
MIST_FUNC_DEF(os, make_model, 1), MIST_FUNC_DEF(os, make_model, 1),
@ -2128,7 +2194,7 @@ void ffi_load() {
QJSGLOBALCLASS(dspsound); QJSGLOBALCLASS(dspsound);
QJSGLOBALCLASS(pshape); QJSGLOBALCLASS(pshape);
QJSGLOBALCLASS(performance); QJSGLOBALCLASS(performance);
QJSGLOBALCLASS(circle2d);
QJSGLOBALCLASS(poly2d); QJSGLOBALCLASS(poly2d);
QJSGLOBALCLASS(edge2d); QJSGLOBALCLASS(edge2d);