From 5bdf311da995c51f922e03678e91983187e756fa Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 28 Dec 2023 23:38:17 +0000 Subject: [PATCH] initial physics constraints --- scripts/base.js | 1 + scripts/entity.js | 20 ++++++++++++++++--- source/engine/2dphysics.c | 40 ++++++++++++++++++++++++++------------ source/engine/2dphysics.h | 10 ++++++---- source/engine/gameobject.c | 10 +++++----- source/engine/jsffi.c | 16 +++++++++++++-- 6 files changed, 71 insertions(+), 26 deletions(-) diff --git a/scripts/base.js b/scripts/base.js index ca1fbe9..f913029 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -1245,6 +1245,7 @@ Object.defineProperty(Number.prototype, 'lerp', { Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; } Math.random_range = function(min,max) { return Math.random() * (max-min) + min; }; +Math.rand_int = function(max) { return Math.floor(Math.random()*max); }; Math.snap = function(val, grid) { if (!grid || grid === 1) return Math.round(val); diff --git a/scripts/entity.js b/scripts/entity.js index a1f208c..4be029d 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -193,7 +193,20 @@ var gameobject = { full_path() { return this.path_from(Primum); }, - + /* pin this object to the to object */ + pin(to) { + var p = cmd(222,this.body, to.body); + }, + pivot(to, piv) { + piv ??= this.worldpos(); + var p = cmd(221,this.body,to.body,piv); + }, + gear(to, phase, ratio) { + phase ??= 1; + ratio ??= 1; + var p = cmd(223,this.body,to.body,phase,ratio); + }, + path_from(o) { var p = this.toString(); var c = this.level; @@ -516,8 +529,9 @@ var gameobject = { Player.do_uncontrol(this); Register.unregister_obj(this); - - this.__proto__.instances.remove(this); + + if (this.__proto__.instances) + this.__proto__.instances.remove(this); for (var key in this.components) { Register.unregister_obj(this.components[key]); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index cf8cda0..d069724 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -213,10 +213,9 @@ struct phys2d_circle *Make2DCircle(gameobject *go) { return new; } -float phys2d_circle_moi(struct phys2d_circle *c, float m) { - return 1; - //TODO: Calculate correctly - //return cpMomentForCircle(m, 0, c->radius, c->offset); +float phys2d_circle_moi(struct phys2d_circle *c) { + float m = c->shape.go->mass; + return cpMomentForCircle(m, 0, cpCircleShapeGetRadius(c->shape.shape), cpCircleShapeGetOffset(c->shape.shape)); } void phys2d_circledel(struct phys2d_circle *c) { @@ -233,6 +232,18 @@ void phys2d_dbgdrawcpcirc(cpShape *c) { draw_circle(pos,radius,radius,color,-1); } +void phys2d_shape_apply(struct phys2d_shape *s) +{ + float moment = cpBodyGetMoment(s->go->body); + float moi = s->moi(s->data); + + s->apply(s->data); + float newmoi = s->moi(s->data); + moment-=moi; + moment += newmoi; + cpBodySetMoment(s->go->body, moment); +} + void phys2d_dbgdrawcircle(struct phys2d_circle *circle) { phys2d_dbgdrawcpcirc(circle->shape.shape); } @@ -268,12 +279,16 @@ void phys2d_poly_free(struct phys2d_poly *poly) free(poly); } -float phys2d_poly_moi(struct phys2d_poly *poly, float m) { - float moi = cpMomentForPoly(m, arrlen(poly->points), (cpVect*)poly->points, cpvzero, poly->radius); - if (isnan(moi)) { -// YughError("Polygon MOI returned an error. Returning 0."); +float phys2d_poly_moi(struct phys2d_poly *poly) { + float m = poly->shape.go->mass; + int len = cpPolyShapeGetCount(poly->shape.shape); + cpVect points[len]; + for (int i = 0; i < len; i++) + points[i] = cpPolyShapeGetVert(poly->shape.shape, i); + + float moi = cpMomentForPoly(m, len, points, cpvzero, poly->radius); + if (!isfinite(moi)) return 0; - } return moi; } @@ -296,8 +311,8 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, HMM_Vec2 *verts) { for (int i = 0; i < arrlen(verts); i++) poly->points[i] = verts[i]; - - phys2d_applypoly(poly); + + phys2d_shape_apply(&poly->shape); } void phys2d_applypoly(struct phys2d_poly *poly) { @@ -365,7 +380,8 @@ void phys2d_edge_free(struct phys2d_edge *edge) free(edge); } -float phys2d_edge_moi(struct phys2d_edge *edge, float m) { +float phys2d_edge_moi(struct phys2d_edge *edge) { + float m = edge->shape.go->mass; float moi = 0; for (int i = 0; i < arrlen(edge->points) - 1; i++) moi += cpMomentForSegment(m, edge->points[i].cp, edge->points[i + 1].cp, edge->thickness); diff --git a/source/engine/2dphysics.h b/source/engine/2dphysics.h index 59da98e..6232318 100644 --- a/source/engine/2dphysics.h +++ b/source/engine/2dphysics.h @@ -23,11 +23,13 @@ struct phys2d_shape { gameobject *go; void *data; /* The specific subtype; phys2d_circle, etc */ void (*debugdraw)(void *data); - float (*moi)(void *data, float mass); + float (*moi)(void *data); void (*apply)(void *data); void (*free)(void *data); }; +void phys2d_shape_apply(struct phys2d_shape *s); + /* Circles are the fastest colldier type */ struct phys2d_circle { float radius; @@ -56,7 +58,7 @@ struct phys2d_circle *Make2DCircle(gameobject *go); void phys2d_circledel(struct phys2d_circle *c); void phys2d_applycircle(struct phys2d_circle *circle); void phys2d_dbgdrawcircle(struct phys2d_circle *circle); -float phys2d_circle_moi(struct phys2d_circle *c, float m); +float phys2d_circle_moi(struct phys2d_circle *c); struct phys2d_poly *Make2DPoly(gameobject *go); void phys2d_poly_free(struct phys2d_poly *poly); @@ -65,7 +67,7 @@ void phys2d_applypoly(struct phys2d_poly *poly); void phys2d_dbgdrawpoly(struct phys2d_poly *poly); void phys2d_polyaddvert(struct phys2d_poly *poly); void phys2d_poly_setverts(struct phys2d_poly *poly, HMM_Vec2 *verts); -float phys2d_poly_moi(struct phys2d_poly *poly, float m); +float phys2d_poly_moi(struct phys2d_poly *poly); struct phys2d_edge *Make2DEdge(gameobject *go); void phys2d_edge_free(struct phys2d_edge *edge); @@ -74,7 +76,7 @@ void phys2d_applyedge(struct phys2d_edge *edge); void phys2d_dbgdrawedge(struct phys2d_edge *edge); void phys2d_edgeaddvert(struct phys2d_edge *edge, HMM_Vec2 v); void phys2d_edge_rmvert(struct phys2d_edge *edge, int index); -float phys2d_edge_moi(struct phys2d_edge *edge, float m); +float phys2d_edge_moi(struct phys2d_edge *edge); void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val); void phys2d_edge_clearverts(struct phys2d_edge *edge); diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 2886a0a..101aad2 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -93,16 +93,16 @@ void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) { } void go_shape_moi(cpBody *body, cpShape *shape, gameobject *go) { - float moment = cpBodyGetMoment(go->body); + float moment = cpBodyGetMoment(body); struct phys2d_shape *s = cpShapeGetUserData(shape); if (!s) { - cpBodySetMoment(go->body, moment + 1); + cpBodySetMoment(body, moment + 1); return; } - moment += s->moi(s->data, go->mass); - if (moment < 0) moment = 1; - cpBodySetMoment(go->body, 1); + moment += s->moi(s->data); + if (moment < 0) moment = 0; + cpBodySetMoment(body, moment); } void gameobject_apply(gameobject *go) { diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index f2e8845..5dd93a3 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -1370,6 +1370,18 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 220: ret = num2js(js2sprite(argv[1])->drawmode); break; + case 221: + ret = ptr2js(cpPivotJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body,js2vec2(argv[3]).cp)); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 222: + ret = ptr2js(cpPinJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, cpvzero,cpvzero)); + cpSpaceAddConstraint(space, js2ptr(ret)); + break; + case 223: + ret = ptr2js(cpGearJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2number(argv[3]), js2number(argv[4]))); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; } if (str) @@ -1706,8 +1718,8 @@ JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCons case 3: return vec2js(circle->offset); } - - phys2d_applycircle(circle); + phys2d_shape_apply(&circle->shape); + return JS_UNDEFINED; }