flip replaced with mirroring'
This commit is contained in:
parent
f6161d04b0
commit
563bacdb9c
|
@ -296,6 +296,16 @@ Object.defineProperty(Object.prototype, 'forEach', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'map', {
|
||||
value: function(fn) {
|
||||
var a = [];
|
||||
Object.values(this).forEach(function(x) {
|
||||
a.push(fn(x));
|
||||
});
|
||||
return a;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'empty', {
|
||||
get: function() {
|
||||
return Object.keys(this).empty;
|
||||
|
@ -1082,7 +1092,7 @@ var Vector = {
|
|||
},
|
||||
|
||||
dot(a, b) {
|
||||
|
||||
return cmd(88,a,b);
|
||||
},
|
||||
|
||||
random() {
|
||||
|
@ -1116,6 +1126,11 @@ var Vector = {
|
|||
return eql;
|
||||
},
|
||||
|
||||
reflect(vec, plane) {
|
||||
var p = Vector.norm(plane);
|
||||
return vec.sub(p.scale(2*Vector.dot(vec, p)));
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/* POINT ASSISTANCE */
|
||||
|
|
|
@ -11,7 +11,6 @@ var editor_config = {
|
|||
|
||||
};
|
||||
|
||||
|
||||
var configs = {
|
||||
toString() { return "configs"; },
|
||||
editor: editor_config,
|
||||
|
@ -740,6 +739,7 @@ editor.inputs['C-d'] = function() {
|
|||
};
|
||||
editor.inputs['C-d'].doc = "Duplicate all selected objects.";
|
||||
|
||||
|
||||
editor.inputs['C-m'] = function() {
|
||||
if (editor.sel_comp) {
|
||||
if ('flipy' in editor.sel_comp)
|
||||
|
@ -748,7 +748,7 @@ editor.inputs['C-m'] = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
editor.selectlist.forEach(function(x) { x.flipy = !x.flipy; });
|
||||
editor.selectlist.forEach(function(x) { x.mirror([0,1]);});
|
||||
};
|
||||
editor.inputs['C-m'].doc = "Mirror selected objects on the Y axis.";
|
||||
|
||||
|
@ -760,10 +760,11 @@ editor.inputs.m = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
editor.selectlist.forEach(function(x) { x.flipx = !x.flipx; });
|
||||
editor.selectlist.forEach(x => x.mirror([1,0]));
|
||||
};
|
||||
editor.inputs.m.doc = "Mirror selected objects on the X axis.";
|
||||
|
||||
|
||||
editor.inputs.q = function() { editor.comp_info = !editor.comp_info; };
|
||||
editor.inputs.q.doc = "Toggle help for the selected component.";
|
||||
|
||||
|
@ -1166,7 +1167,7 @@ editor.inputs.mouse.move = function(pos, dpos)
|
|||
|
||||
editor.scalelist?.forEach(function(x) {
|
||||
var scalediff = dist / x.scaleoffset;
|
||||
x.obj.scale = x.scale * scalediff;
|
||||
x.obj.scale = x.scale.map(x=> x * scalediff);
|
||||
if (x.offset)
|
||||
x.obj.pos = editor.cursor.add(x.offset.scale(scalediff));
|
||||
});
|
||||
|
|
|
@ -819,8 +819,8 @@ var preprimum = globalThis.preprimum;
|
|||
preprimum.objects = {};
|
||||
preprimum.worldpos = function() { return [0,0]; };
|
||||
preprimum.worldangle = function() { return 0; };
|
||||
preprimum.scale = 1;
|
||||
preprimum.gscale = function() { return 1; };
|
||||
preprimum.scale = [1,1,1];
|
||||
preprimum.gscale = function() { return [1,1,1]; };
|
||||
preprimum.pos = [0,0];
|
||||
preprimum.angle = 0;
|
||||
preprimum.remove_obj = function() {};
|
||||
|
|
|
@ -57,39 +57,38 @@ var gameobject = {
|
|||
gscale() { return cmd(103,this.body); },
|
||||
sgscale(x) {
|
||||
if (typeof x === 'number')
|
||||
cmd(36,this.body, [x,x]);
|
||||
else
|
||||
x = [x,x];
|
||||
cmd(36,this.body,x)
|
||||
},
|
||||
get scale() {
|
||||
if (!this.level) return this.gscale();
|
||||
return this.gscale()/this.level.gscale();
|
||||
return this.gscale().map((x,i) => x/this.level.gscale()[i]);
|
||||
},
|
||||
set scale(x) {
|
||||
if (this.level)
|
||||
x *= this.level.gscale();
|
||||
var pct = x/this.gscale();
|
||||
if (typeof x === 'number')
|
||||
x = [x,x];
|
||||
|
||||
if (this.level) {
|
||||
var g = this.level.gscale();
|
||||
x = x.map((y,i) => y * g[i]);
|
||||
}
|
||||
|
||||
var pct = x.map(function(y,i) { return y/this.gscale()[i]; }, this);
|
||||
|
||||
this.sgscale(x);
|
||||
// cmd(36, this.body, x);
|
||||
|
||||
this.objects?.forEach(function(obj) {
|
||||
obj.sgscale(obj.gscale()*pct);
|
||||
obj.pos = obj.pos.scale(pct);
|
||||
});
|
||||
/* TRANSLATE ALL SUB OBJECTS */
|
||||
},
|
||||
|
||||
set pos(x) {
|
||||
this.set_worldpos(Vector.rotate(x.scale(this.level.gscale()),Math.deg2rad(this.level.worldangle())).add(this.level.worldpos()));
|
||||
if (!x[0] || !x[1]) return;
|
||||
this.set_worldpos(this.level.this2world(x));
|
||||
},
|
||||
|
||||
get pos() {
|
||||
if (!this.level) return this.worldpos();
|
||||
var offset = this.worldpos().sub(this.level.worldpos());
|
||||
offset = Vector.rotate(offset, -Math.deg2rad(this.level.angle));
|
||||
offset = offset.scale(1/this.level.gscale());
|
||||
return offset;
|
||||
return this.level.world2this(this.worldpos());
|
||||
},
|
||||
|
||||
get elasticity() { return cmd(107,this.body); },
|
||||
set elasticity(x) { cmd(106,this.body,x); },
|
||||
|
||||
|
@ -118,9 +117,9 @@ var gameobject = {
|
|||
set angularvelocity(x) { set_body(8, this.body, Math.deg2rad(x)); },
|
||||
worldpos() { return q_body(1,this.body); },
|
||||
set_worldpos(x) {
|
||||
var diff = x.sub(this.worldpos());
|
||||
this.objects.forEach(function(x) { x.set_worldpos(x.worldpos().add(diff)); });
|
||||
var poses = this.objects.map(x => x.pos);
|
||||
set_body(2,this.body,x);
|
||||
this.objects.forEach((o,i) => o.set_worldpos(this.this2world(poses[i])));
|
||||
},
|
||||
|
||||
worldangle() { return Math.rad2deg(q_body(2,this.body))%360; },
|
||||
|
@ -150,7 +149,6 @@ var gameobject = {
|
|||
this.sworldangle(this.worldangle()+x);
|
||||
},
|
||||
|
||||
|
||||
spawn_from_instance(inst) {
|
||||
return this.spawn(inst.ur, inst);
|
||||
},
|
||||
|
@ -301,9 +299,12 @@ var gameobject = {
|
|||
velocity:[0,0],
|
||||
angularvelocity:0,
|
||||
phys:Physics.static,
|
||||
flipx:false,
|
||||
flipy:false,
|
||||
scale:1,
|
||||
flipx() { return this.scale.x < 0; },
|
||||
flipy() { return this.scale.y < 0; },
|
||||
scale:[1,1,1],
|
||||
mirror(plane) {
|
||||
this.scale = Vector.reflect(this.scale, plane);
|
||||
},
|
||||
elasticity:0.5,
|
||||
friction:1,
|
||||
gravity: true,
|
||||
|
@ -618,8 +619,8 @@ gameobject.doc = {
|
|||
velocity: "Velocity of the object, relative to world.",
|
||||
angularvelocity: "Angular velocity of the object, relative to the world.",
|
||||
scale: "Scale of the object, relative to its level.",
|
||||
flipx: "Set the object to be flipped on its x axis.",
|
||||
flipy: "Set the object to be flipped on its y axis.",
|
||||
flipx: "Check if the object is flipped on its x axis.",
|
||||
flipy: "Check if the object is flipped on its y axis.",
|
||||
elasticity: `When two objects collide, their elasticities are multiplied together. Their velocities are then multiplied by this value to find their resultant velocities.`,
|
||||
friction: `When one object touches another, friction slows them down.`,
|
||||
gravity: 'True if this object should be affected by gravity.',
|
||||
|
|
|
@ -220,15 +220,9 @@ void phys2d_circledel(struct phys2d_circle *c) {
|
|||
phys2d_shape_del(&c->shape);
|
||||
}
|
||||
|
||||
HMM_Vec2 bodytransformpoint(cpBody *body, cpVect offset) {
|
||||
HMM_Vec2 pos;
|
||||
pos.cp = offset;
|
||||
struct gameobject *go = id2go(body2id(body));
|
||||
return go2world(go, pos);
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawcpcirc(cpCircleShape *c) {
|
||||
HMM_Vec2 pos = bodytransformpoint(cpShapeGetBody(c), cpCircleShapeGetOffset(c));
|
||||
HMM_Mat3 rt = mt_rt(go2t(shape2go(c)));
|
||||
HMM_Vec2 pos = mat_t_pos(rt, (HMM_Vec2)cpCircleShapeGetOffset(c));
|
||||
float radius = cpCircleShapeGetRadius(c);
|
||||
struct rgba color = shape_color(c);
|
||||
float seglen = cpShapeGetSensor(c) ? 5 : -1;
|
||||
|
@ -272,12 +266,12 @@ float phys2d_box_moi(struct phys2d_box *box, float m) {
|
|||
return cpMomentForBox(m, box->w, box->h);
|
||||
}
|
||||
|
||||
cpTransform trs2cpt(HMM_Vec2 t, float angle, HMM_Vec2 s) {
|
||||
cpTransform trs2cpt(HMM_Vec2 t, float r, HMM_Vec2 s) {
|
||||
cpTransform T;
|
||||
T.a = cos(angle) * s.X;
|
||||
T.b = -sin(angle) * s.X;
|
||||
T.c = sin(angle) * s.Y;
|
||||
T.d = cos(angle) * s.Y;
|
||||
T.a = cos(r) * s.X;
|
||||
T.b = -sin(r) * s.X;
|
||||
T.c = sin(r) * s.Y;
|
||||
T.d = cos(r) * s.Y;
|
||||
T.tx = t.X * s.X;
|
||||
T.ty = t.Y * s.Y;
|
||||
return T;
|
||||
|
@ -370,7 +364,7 @@ void phys2d_applypoly(struct phys2d_poly *poly) {
|
|||
if (arrlen(poly->points) <= 0) return;
|
||||
struct gameobject *go = id2go(poly->shape.go);
|
||||
|
||||
cpTransform T = trs2cpt((HMM_Vec2){0,0}, 0, (HMM_Vec2){1,1});
|
||||
cpTransform T = trs2cpt((HMM_Vec2){0,0}, 0, go->scale.XY);
|
||||
|
||||
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
|
||||
cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
|
||||
|
@ -384,9 +378,9 @@ void phys2d_dbgdrawpoly(struct phys2d_poly *poly) {
|
|||
if (arrlen(poly->points) >= 3) {
|
||||
int n = cpPolyShapeGetCount(poly->shape.shape);
|
||||
HMM_Vec2 points[n];
|
||||
|
||||
HMM_Mat3 rt = mt_rt(go2t(shape2go(poly->shape.shape)));
|
||||
for (int i = 0; i < n; i++)
|
||||
points[i] = bodytransformpoint(cpShapeGetBody(poly->shape.shape), cpPolyShapeGetVert(poly->shape.shape, i));
|
||||
points[i] = mat_t_pos(rt, (HMM_Vec2)cpPolyShapeGetVert(poly->shape.shape, i));
|
||||
|
||||
draw_poly(points, n, color);
|
||||
float seglen = cpShapeGetSensor(poly->shape.shape) ? sensor_seg : 0;
|
||||
|
@ -512,10 +506,10 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
|
|||
HMM_Vec2 drawpoints[arrlen(edge->points)];
|
||||
struct gameobject *go = id2go(edge->shape.go);
|
||||
|
||||
for (int i = 0; i < arrlen(edge->points); i++) {
|
||||
drawpoints[i] = goscale(go, edge->points[i]);
|
||||
drawpoints[i] = bodytransformpoint(cpShapeGetBody(edge->shapes[0]), drawpoints[i].cp);
|
||||
}
|
||||
|
||||
HMM_Mat3 g2w = t_go2world(go);
|
||||
for (int i = 0; i < arrlen(edge->points); i++)
|
||||
drawpoints[i] = mat_t_pos(g2w, edge->points[i]);
|
||||
|
||||
float seglen = cpShapeGetSensor(edge->shapes[0]) ? sensor_seg : 0;
|
||||
struct rgba color = shape_color(edge->shapes[0]);
|
||||
|
|
|
@ -64,7 +64,7 @@ struct phys2d_box {
|
|||
|
||||
/* An edge with no volume. Cannot collide with each other. Join to make levels. Static only. */
|
||||
struct phys2d_edge {
|
||||
HMM_Vec2 *points;
|
||||
HMM_Vec2 *points; /* Points defined relative to the gameobject */
|
||||
float thickness;
|
||||
cpShape **shapes;
|
||||
int closed; /* True if the first and last points should be connected */
|
||||
|
|
|
@ -68,31 +68,57 @@ float go2angle(struct gameobject *go)
|
|||
|
||||
transform2d mat2transform2d(HMM_Mat3 mat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HMM_Mat3 mt_t(transform2d t)
|
||||
{
|
||||
HMM_Mat3 p = HMM_M3D(1);
|
||||
p.Columns[2].X = t.pos.X;
|
||||
p.Columns[2].Y = t.pos.Y;
|
||||
return p;
|
||||
}
|
||||
|
||||
HMM_Mat3 mt_s(transform2d t)
|
||||
{
|
||||
HMM_Mat3 s = HMM_M3D(1);
|
||||
s.Columns[0].X = t.scale.X;
|
||||
s.Columns[1].Y = t.scale.Y;
|
||||
return s;
|
||||
}
|
||||
|
||||
HMM_Mat3 mt_r(transform2d t)
|
||||
{
|
||||
HMM_Mat3 r = HMM_M3D(1);
|
||||
r.Columns[0] = (HMM_Vec3){cos(t.angle), sin(t.angle), 0};
|
||||
r.Columns[1] = (HMM_Vec3){-sin(t.angle), cos(t.angle), 0};
|
||||
return r;
|
||||
}
|
||||
|
||||
HMM_Mat3 transform2d2mat(transform2d t)
|
||||
{
|
||||
HMM_Mat3 m = HMM_M3D(1);
|
||||
HMM_Mat3 p = HMM_M3D(1);
|
||||
p.Columns[2].X = t.pos.X;
|
||||
p.Columns[2].Y = t.pos.Y;
|
||||
return HMM_MulM3(mt_t(t), HMM_MulM3(mt_r(t), mt_s(t)));
|
||||
}
|
||||
|
||||
HMM_Mat3 s = HMM_M3D(1);
|
||||
s.Columns[0].X = t.scale.X;
|
||||
s.Columns[1].Y = t.scale.Y;
|
||||
HMM_Mat3 mt_rst(transform2d t)
|
||||
{
|
||||
return transform2d2mat(t);
|
||||
}
|
||||
|
||||
HMM_Mat3 r = HMM_M3D(1);
|
||||
r.Columns[0] = (HMM_Vec3){cos(t.angle), sin(t.angle), 0};
|
||||
r.Columns[1] = (HMM_Vec3){-sin(t.angle), cos(t.angle), 0};
|
||||
HMM_Mat3 mt_st(transform2d t)
|
||||
{
|
||||
return HMM_MulM3(mt_t(t), mt_s(t));
|
||||
}
|
||||
|
||||
m = HMM_MulM3(r, s);
|
||||
m = HMM_MulM3(p, m);
|
||||
return m;
|
||||
HMM_Mat3 mt_rt(transform2d t)
|
||||
{
|
||||
return HMM_MulM3(mt_t(t), mt_r(t));
|
||||
}
|
||||
|
||||
HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos)
|
||||
{
|
||||
return HMM_MulM3V3(t_go2world(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY;
|
||||
HMM_Vec2 v = HMM_MulM3V3(t_go2world(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY;
|
||||
return v;
|
||||
}
|
||||
|
||||
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos)
|
||||
|
@ -100,6 +126,17 @@ HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos)
|
|||
return HMM_MulM3V3(t_world2go(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY;
|
||||
}
|
||||
|
||||
HMM_Vec2 mat_t_pos(HMM_Mat3 m, HMM_Vec2 pos)
|
||||
{
|
||||
return HMM_MulM3V3(m, (HMM_Vec3){pos.x, pos.y, 1}).XY;
|
||||
}
|
||||
|
||||
HMM_Vec2 mat_t_dir(HMM_Mat3 m, HMM_Vec2 dir)
|
||||
{
|
||||
m.Columns[2] = (HMM_Vec3){0,0,1};
|
||||
return HMM_MulM3V3(m, (HMM_Vec3){dir.x, dir.y, 1}).XY;
|
||||
}
|
||||
|
||||
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos)
|
||||
{
|
||||
return HMM_MulV2(go->scale.XY, pos);
|
||||
|
@ -149,10 +186,11 @@ void gameobject_set_sensor(int id, int sensor) {
|
|||
transform2d go2t(gameobject *go)
|
||||
{
|
||||
transform2d t;
|
||||
cpVect p = cpBodyGetPosition(go->body);
|
||||
t.pos.X = p.x; t.pos.Y = p.y;
|
||||
t.pos.cp = cpBodyGetPosition(go->body);
|
||||
t.angle = cpBodyGetAngle(go->body);
|
||||
t.scale = go->scale.XY;
|
||||
if (isnan(t.scale.X)) t.scale.X = 1;
|
||||
if (isnan(t.scale.Y)) t.scale.Y = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,15 @@ HMM_Mat3 t_world2go(struct gameobject *go);
|
|||
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos);
|
||||
HMM_Vec2 gotpos(struct gameobject *go, HMM_Vec2 pos);
|
||||
|
||||
HMM_Mat3 mt_rst(transform2d t);
|
||||
HMM_Mat3 mt_st(transform2d t);
|
||||
HMM_Mat3 mt_rt(transform2d t);
|
||||
|
||||
/* Transform a position via the matrix */
|
||||
HMM_Vec2 mat_t_pos(HMM_Mat3 m, HMM_Vec2 pos);
|
||||
/* Transform a direction via the matrix - does not take into account translation of matrix */
|
||||
HMM_Vec2 mat_t_dir(HMM_Mat3 m, HMM_Vec2 dir);
|
||||
|
||||
struct gameobject *get_gameobject_from_id(int id);
|
||||
struct gameobject *id2go(int id);
|
||||
int id_from_gameobject(struct gameobject *go);
|
||||
|
|
|
@ -271,12 +271,6 @@ JSValue vec2js(HMM_Vec2 v) {
|
|||
return array;
|
||||
}
|
||||
|
||||
JSValue v22js(HMM_Vec2 v)
|
||||
{
|
||||
HMM_Vec2 c = { v.X, v.Y };
|
||||
return vec2js(c);
|
||||
}
|
||||
|
||||
JSValue vecarr2js(HMM_Vec2 *points, int n) {
|
||||
JSValue array = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
|
@ -855,12 +849,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 87:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
// str = JS_ToCString(js, argv[1]);
|
||||
// mini_music_play(str);
|
||||
break;
|
||||
|
||||
case 88:
|
||||
// mini_music_pause();
|
||||
ret = num2js(HMM_DotV2(js2vec2(argv[1]), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 89:
|
||||
|
@ -926,7 +920,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 103:
|
||||
ret = num2js(js2go(argv[1])->scale.X);
|
||||
ret = vec2js(js2go(argv[1])->scale.XY);
|
||||
break;
|
||||
|
||||
case 104:
|
||||
|
@ -958,7 +952,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 111:
|
||||
ret = v22js(js2sprite(argv[1])->pos);
|
||||
ret = vec2js(js2sprite(argv[1])->pos);
|
||||
break;
|
||||
|
||||
case 112:
|
||||
|
@ -1062,11 +1056,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 136:
|
||||
ret = v22js(world2screen(js2vec2(argv[1])));
|
||||
ret = vec2js(world2screen(js2vec2(argv[1])));
|
||||
break;
|
||||
|
||||
case 137:
|
||||
ret = v22js(screen2world(js2vec2(argv[1])));
|
||||
ret = vec2js(screen2world(js2vec2(argv[1])));
|
||||
break;
|
||||
|
||||
case 138:
|
||||
|
|
Loading…
Reference in a new issue