easier saving

This commit is contained in:
John Alanbrook 2023-10-05 22:30:17 +00:00
parent 03f209ddef
commit 272719736c
9 changed files with 129 additions and 150 deletions

View file

@ -45,9 +45,10 @@ Object.dainty_assign = function(target, source)
{ {
Object.keys(target).forEach(function(key) { Object.keys(target).forEach(function(key) {
if (!(key in source)) return; if (!(key in source)) return;
if (typeof target[key] === 'function') return;
if (Array.isArray(target[key])) if (Array.isArray(target[key]))
target[key] = source[key]; target[key] = deep_copy(source[key]);
else if (typeof target[key] === 'object') else if (typeof target[key] === 'object')
Object.dainty_assign(target[key], source[key]); Object.dainty_assign(target[key], source[key]);
else else
@ -736,7 +737,7 @@ Math.angledist = function (a1, a2) {
return wrap; return wrap;
}; };
Math.angledist.doc = "Find the shortest angle between two angles."; Math.angledist.doc = "Find the shortest angle between two angles.";
Math.patan2 = function(p) { return Math.atan2(p.y,p.x); };
Math.deg2rad = function(deg) { return deg * 0.0174533; }; Math.deg2rad = function(deg) { return deg * 0.0174533; };
Math.rad2deg = function(rad) { return rad / 0.0174533; }; Math.rad2deg = function(rad) { return rad / 0.0174533; };
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); }; Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };

View file

@ -24,6 +24,13 @@ var component = {
}, },
}; };
component.assign_impl = function(o)
{
for (var key in o.impl)
if (typeof o[key] !== 'undefined' && typeof o[key] !== 'function')
o[key] = o.impl[key];
}
component.sprite = Object.copy(component, { component.sprite = Object.copy(component, {
pos:[0,0], pos:[0,0],
color:[1,1,1], color:[1,1,1],
@ -37,20 +44,23 @@ component.sprite = Object.copy(component, {
nsprite.gameobject = go; nsprite.gameobject = go;
Object.assign(nsprite, make_sprite(go.body)); Object.assign(nsprite, make_sprite(go.body));
Object.mixin(nsprite, component.sprite.impl); Object.mixin(nsprite, component.sprite.impl);
nsprite.kill = component.sprite.impl.kill;
Object.hide(nsprite, 'gameobject', 'id'); Object.hide(nsprite, 'gameobject', 'id');
for (var p in component.sprite.impl) for (var p in component.sprite.impl)
if (typeof this[p] !== 'undefined') if (typeof this[p] !== 'undefined' && typeof this[p] !== 'function')
nsprite[p] = this[p]; nsprite[p] = this[p];
return nsprite; return nsprite;
}, },
}); });
component.sprite.impl = { component.sprite.impl = {
set path(x) { set path(x) {
cmd(12,this.id,prototypes.resani(this.gameobject.ur, x),this.rect); cmd(12,this.id,prototypes.resani(this.gameobject.__proto__.toString(), x),this.rect);
}, },
get path() { get path() {
return prototypes.resavi(this.gameobject.ur, cmd(116,this.id)); return prototypes.resavi(this.gameobject.__proto__.toString(), cmd(116,this.id));
}, },
hide() { this.enabled = false; }, hide() { this.enabled = false; },
show() { this.enabled = true; }, show() { this.enabled = true; },
@ -324,9 +334,7 @@ collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; }
collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled."; collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled.";
component.polygon2d = Object.copy(collider2d, { component.polygon2d = Object.copy(collider2d, {
sync() { toString() { return "poly2d"; },
cmd_poly2d(0, this.id, this.spoints);
},
boundingbox() { boundingbox() {
return points2bb(this.spoints); return points2bb(this.spoints);
@ -339,9 +347,13 @@ component.polygon2d = Object.copy(collider2d, {
poly.flipx = false; poly.flipx = false;
poly.flipy = false; poly.flipy = false;
Object.assign(poly, make_poly2d(go.body, poly.points)); Object.assign(poly, make_poly2d(go.body, poly.points));
Object.mixin(poly, poly.impl);
Object.hide(poly, 'id', 'shape', 'gameobject', 'flipx', 'flipy');
return poly; return poly;
}, },
points:[],
/* EDITOR */ /* EDITOR */
get spoints() { get spoints() {
var spoints = this.points.slice(); var spoints = this.points.slice();
@ -361,7 +373,6 @@ component.polygon2d = Object.copy(collider2d, {
spoints.push(newpoint); spoints.push(newpoint);
}); });
} }
return spoints; return spoints;
}, },
@ -376,6 +387,9 @@ component.polygon2d = Object.copy(collider2d, {
}, },
pick(pos) { pick(pos) {
if (!Object.hasOwn(this,'points'))
this.points = deep_copy(this.__proto__.points);
var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points); var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
if (p) { if (p) {
return { return {
@ -390,11 +404,16 @@ component.polygon2d = Object.copy(collider2d, {
return undefined; return undefined;
}, },
});
component.polygon2d.impl = {
sync() {
cmd_poly2d(0, this.id, this.spoints);
},
query() { query() {
return cmd(80, this.shape); return cmd(80, this.shape);
}, },
}); };
var polygon2d = component.polygon2d; var polygon2d = component.polygon2d;
@ -424,11 +443,13 @@ polygon2d.inputs['C-b'] = function() {
}; };
polygon2d.inputs['C-b'].doc = "Freeze mirroring in place."; polygon2d.inputs['C-b'].doc = "Freeze mirroring in place.";
Object.freeze(polygon2d); //Object.freeze(polygon2d);
component.edge2d = Object.copy(collider2d, { component.edge2d = Object.copy(collider2d, {
degrees:2, degrees:2,
dimensions:2, dimensions:2,
thickness:0,
points: [],
/* open: 0 /* open: 0
clamped: 1 clamped: 1
beziers: 2 beziers: 2
@ -444,6 +465,7 @@ component.edge2d = Object.copy(collider2d, {
flipx: false, flipx: false,
flipy: false, flipy: false,
toString() { return "edge2d"; },
hollow: false, hollow: false,
hollowt: 0, hollowt: 0,
@ -508,11 +530,6 @@ component.edge2d = Object.copy(collider2d, {
return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n); return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n);
}, },
set thickness(x) {
cmd_edge2d(1,this.id,x);
},
get thickness() { return cmd(112,this.id); },
samples: 10, samples: 10,
@ -523,20 +540,14 @@ component.edge2d = Object.copy(collider2d, {
make(go) { make(go) {
var edge = Object.create(this); var edge = Object.create(this);
edge.gameobject = go; edge.gameobject = go;
edge.cpoints = []; // edge.cpoints = [];
edge.points = []; // edge.points = [];
Object.assign(edge, make_edge2d(go.body, edge.points, 0)); Object.assign(edge, make_edge2d(go.body, edge.points, 0));
edge.thickness = 0; Object.mixin(edge,edge.impl);
Object.hide(edge, 'gameobject', 'id', 'shape');
return edge; return edge;
}, },
sync() {
var sensor = this.sensor;
this.points = this.sample(this.samples);
cmd_edge2d(0,this.id,this.points);
this.sensor = sensor;
},
/* EDITOR */ /* EDITOR */
gizmo() { gizmo() {
this.spoints.forEach(function(x) { this.spoints.forEach(function(x) {
@ -565,6 +576,19 @@ component.edge2d = Object.copy(collider2d, {
}, },
}); });
component.edge2d.impl = {
set thickness(x) {
cmd_edge2d(1,this.id,x);
},
get thickness() { return cmd(112,this.id); },
sync() {
var sensor = this.sensor;
this.points = this.sample(this.samples);
cmd_edge2d(0,this.id,this.points);
this.sensor = sensor;
},
};
var bucket = component.edge2d; var bucket = component.edge2d;
bucket.inputs = {}; bucket.inputs = {};
bucket.inputs.h = function() { this.hollow = !this.hollow; }; bucket.inputs.h = function() { this.hollow = !this.hollow; };
@ -684,7 +708,7 @@ component.circle2d = Object.copy(collider2d, {
set radius(x) { cmd_circle2d(0,this.id,x); }, set radius(x) { cmd_circle2d(0,this.id,x); },
get radius() { return cmd_circle2d(2,this.id); }, get radius() { return cmd_circle2d(2,this.id); },
set scale(x) { Log.warn(x);this.radius = x; }, set scale(x) { this.radius = x; },
get scale() { return this.radius; }, get scale() { return this.radius; },
set offset(x) { cmd_circle2d(1,this.id,x); }, set offset(x) { cmd_circle2d(1,this.id,x); },
@ -707,7 +731,9 @@ component.circle2d = Object.copy(collider2d, {
Object.assign(circle, make_circle2d(go.body)); Object.assign(circle, make_circle2d(go.body));
Object.mixin(circle,this.impl); Object.mixin(circle,this.impl);
Object.hide(circle, 'gameobject', 'id', 'shape', 'scale'); Object.hide(circle, 'gameobject', 'id', 'shape', 'scale');
component.assign_impl(circle);
for (var key in this.impl) for (var key in this.impl)
if (typeof this[key] !== 'undefined' && typeof this[key] !== 'function')
if (this[key]) circle[key] = this[key]; if (this[key]) circle[key] = this[key];
return circle; return circle;

View file

@ -47,7 +47,7 @@ var Debug = {
numbered_point(pos, n) { numbered_point(pos, n) {
Debug.point(world2screen(pos), 3); Debug.point(world2screen(pos), 3);
gui_text(n, world2screen(pos).add([0,4]), 1); GUI.text(n, world2screen(pos).add([0,4]), 1);
}, },
phys_drawing: false, phys_drawing: false,

View file

@ -83,60 +83,43 @@ function diffassign(target, from) {
} }
}; };
function positive_diff(from, to) function ediff(from,to)
{ {
var diff = {};
}
function vdiff(from,to)
{
if (typeof from === 'function') return undefined;
if (typeof from === 'number') {
var a = Number.prec(from);
return a === to ? undefined : a;
}
if (typeof from === 'object') {
var ret = {}; var ret = {};
Object.keys(from).forEach(function(k) {
var diff = vdiff(from[k], to[k]);
if (diff) ret[k] = diff;
});
return ret.empty ? undefined : ret;
}
}
function gdiff(from, to) { Object.entries(from).forEach(function([key,v]) {
var obj = {};
Object.entries(from).forEach(function([k,v]) {
if (typeof v === 'function') return; if (typeof v === 'function') return;
if (typeof v === 'undefined') return;
var diff = vdiff(v, to[k]); if (Array.isArray(v)) {
if (diff) { if (!Array.isArray(to[key]) || v.length !== to[key].length)
if (Array.isArray(v)) ret[key] = Object.values(ediff(v, []));
obj[k] = Object.values(diff);
else if (!diff.empty) var diff = ediff(from[key], to[key]);
obj[k] = diff; if (diff && !diff.empty)
ret[key] = Object.values(ediff(v,[]));
return;
} }
if (typeof v === 'object') {
var diff = ediff(v, to[key]);
if (diff && !diff.empty)
ret[key] = diff;
return;
}
if (typeof v === 'number') {
var a = Number.prec(v);
if (!to || a !== to[key])
ret[key] = a;
return;
}
if (!to || v !== to[key])
ret[key] = v;
}); });
return obj; if (ret.empty) return undefined;
}; return ret;
}
function diff(from, to) {
var obj = {};
for (var e in to) {
if (typeof to[e] === 'object' && from.hasOwnProperty(e)) {
obj[e] = diff(from[e], to[e]);
if (obj[e].empty)
delete obj[e];
} else {
if (from[e] !== to[e])
obj[e] = to[e];
}
}
return obj;
};

View file

@ -421,7 +421,7 @@ var editor = {
this.selectlist.forEach(function(x) { this.selectlist.forEach(function(x) {
var sname = x.__proto__.toString(); var sname = x.__proto__.toString();
if (!x.json_obj().empty) if (!x.level_obj().empty)
x._ed.dirty = true; x._ed.dirty = true;
else else
x._ed.dirty = false; x._ed.dirty = false;
@ -789,12 +789,12 @@ editor.inputs['C-s'] = function() {
}; };
if (editor.selectlist.length !== 1 || !editor.selectlist[0]._ed.dirty) return; if (editor.selectlist.length !== 1 || !editor.selectlist[0]._ed.dirty) return;
Object.merge(editor.selectlist[0].ur, editor.selectlist[0].level_obj()); Object.merge(editor.selectlist[0].__proto__, editor.selectlist[0].level_obj());
var path = editor.selectlist[0].ur.toString(); var path = editor.selectlist[0].ur.toString();
path = path.replaceAll('.','/'); path = path.replaceAll('.','/');
path = path + "/" + path.name() + ".json"; path = path + "/" + path.name() + ".json";
IO.slurpwrite(JSON.stringify(editor.selectlist[0].ur,null,1), path); IO.slurpwrite(JSON.stringify(editor.selectlist[0].__proto__,null,1), path);
}; };
editor.inputs['C-s'].doc = "Save selected."; editor.inputs['C-s'].doc = "Save selected.";
@ -1273,12 +1273,11 @@ var inputpanel = {
guibody() { guibody() {
return [ return [
Mum.text({str:this.value, color:Color.green}), Mum.text({str:this.value, color:Color.green}),
Mum.button({str:"Submit", action:this.submit}) // Mum.button({str:"Submit", action:this.submit})
]; ];
}, },
open(steal) { open(steal) {
Log.warn(gameobject.angle);
this.on = true; this.on = true;
this.value = ""; this.value = "";
if (steal) { if (steal) {

View file

@ -692,6 +692,7 @@ load("scripts/entity.js");
var preprimum = {}; var preprimum = {};
preprimum.objects = {}; preprimum.objects = {};
preprimum.worldpos = function() { return [0,0]; }; preprimum.worldpos = function() { return [0,0]; };
preprimum.worldangle = function() { return 0; };
preprimum.pos = [0,0]; preprimum.pos = [0,0];
preprimum.angle = 0; preprimum.angle = 0;
var World = gameobject.make(preprimum); var World = gameobject.make(preprimum);

View file

@ -81,21 +81,30 @@ var gameobject = {
set_body(2,this.body,x); set_body(2,this.body,x);
}, },
get angle() { return Math.rad2deg(q_body(2,this.body))%360; }, worldangle() { return Math.rad2deg(q_body(2,this.body))%360; },
get angle() {
if (!this.level) return this.worldangle();
return this.worldangle() - this.level.worldangle();
},
set angle(x) { set angle(x) {
var diff = x - this.angle; var diff = x - this.angle;
var thatpos = this.pos; var thatpos = this.pos;
this.objects.forEach(function(x) { this.objects.forEach(function(x) {
x.angle = x.angle + diff; x.rotate(diff);
var pos = x.pos.sub(thatpos); // x.angle = x.angle + diff;
var r = Vector.length(pos); var opos = x.pos;
var p = Math.rad2deg(Math.atan2(pos.y, pos.x)); var r = Vector.length(opos);
var p = Math.rad2deg(Math.atan2(opos.y, opos.x));
p += diff; p += diff;
p = Math.deg2rad(p); p = Math.deg2rad(p);
x.set_worldpos(thatpos.add([r*Math.cos(p), r*Math.sin(p)])); x.pos = [r*Math.cos(p), r*Math.sin(p)];
}, this); }, this);
set_body(0,this.body, Math.deg2rad(x)); set_body(0,this.body, Math.deg2rad(x - this.level.worldangle()));
},
rotate(x) {
this.angle = this.angle + x;
}, },
@ -164,7 +173,7 @@ var gameobject = {
/* Make a unique object the same as its prototype */ /* Make a unique object the same as its prototype */
revert() { revert() {
Object.totalmerge(this,this.__proto__); Object.merge(this,this.__proto__);
}, },
check_registers(obj) { check_registers(obj) {
@ -249,52 +258,8 @@ var gameobject = {
return bb ? bb : cwh2bb([0,0], [0,0]); return bb ? bb : cwh2bb([0,0], [0,0]);
}, },
diff(from, to) {
var ret = {};
for (var key in from) {
if (!Object.hasOwn(from, key) && !Object.isAccessor(from,key)) continue;
if (typeof from[key] === 'undefined' || typeof to[key] === 'undefined') continue;
if (typeof from[key] === 'function') continue;
// if (typeof to === 'object' && !(key in to)) continue;
if (Array.isArray(from[key])) {
if (!Array.isArray(to[key]))
ret[key] = Object.values(gameobject.diff(from[key], []));
if (from[key].length !== to[key].length)
ret[key] = Object.values(gameobject.diff(from[key], []));
var diff = gameobject.diff(from[key], to[key]);
if (diff && !diff.empty)
ret[key] = Object.values(diff);
continue;
}
if (typeof from[key] === 'object') {
var diff = gameobject.diff(from[key], to[key]);
if (diff && !diff.empty)
ret[key] = diff;
continue;
}
if (typeof from[key] === 'number') {
var a = Number.prec(from[key]);
if (a !== to[key])
ret[key] = a;
continue;
}
if (from[key] !== to[key])
ret[key] = from[key];
}
if (ret.empty) return undefined;
return ret;
},
json_obj() { json_obj() {
var d = gdiff(this,this.__proto__); var d = ediff(this,this.__proto__);
delete d.pos; delete d.pos;
delete d.angle; delete d.angle;
delete d.velocity; delete d.velocity;
@ -309,7 +274,7 @@ var gameobject = {
}, },
level_obj() { level_obj() {
var json = gdiff(this,this.__proto__); var json = this.json_obj();
var objects = {}; var objects = {};
this.__proto__.objects ??= {}; this.__proto__.objects ??= {};
@ -321,7 +286,7 @@ var gameobject = {
} else { } else {
for (var o in this.objects) { for (var o in this.objects) {
var obj = this.objects[o].json_obj(); var obj = this.objects[o].json_obj();
Object.assign(obj, gameobject.diff(this.objects[o].transform(), this.__proto__.objects[o])); Object.assign(obj, ediff(this.objects[o].transform(), this.__proto__.objects[o]));
if (!obj.empty) if (!obj.empty)
objects[o] = obj; objects[o] = obj;
} }
@ -414,11 +379,12 @@ var gameobject = {
obj.components = {}; obj.components = {};
obj.objects = {}; obj.objects = {};
Object.mixin(obj, gameobject.impl); Object.mixin(obj, gameobject.impl);
Object.hide(obj, 'components'); Object.hide(obj, 'components');
Object.hide(obj, 'objects'); Object.hide(obj, 'objects');
obj._ed = {}; obj._ed = {};
Object.hide(obj, '_ed'); Object.hide(obj, '_ed');
obj.ur = this.toString();
Object.hide(obj,'ur');
Game.register_obj(obj); Game.register_obj(obj);
@ -440,13 +406,12 @@ var gameobject = {
if (this.objects) { if (this.objects) {
for (var prop in this.objects) { for (var prop in this.objects) {
var o = this.objects[prop]; var o = this.objects[prop];
var newobj = obj.spawn(prototypes.get_ur(o.ur)); var newobj = obj.spawn(o.ur);
if (!newobj) continue; if (!newobj) continue;
obj.rename_obj(newobj.toString(), prop); obj.rename_obj(newobj.toString(), prop);
Object.assign(newobj,o); Object.assign(newobj,o);
} }
} }
Object.dainty_assign(obj, this); Object.dainty_assign(obj, this);
obj.components.forEach(function(x) { if ('sync' in x) x.sync(); }); obj.components.forEach(function(x) { if ('sync' in x) x.sync(); });
@ -467,7 +432,6 @@ var gameobject = {
Log.warn(`Already an object with name ${newname}.`); Log.warn(`Already an object with name ${newname}.`);
return; return;
} }
Log.warn(`Renaming from ${name} to ${newname}.`);
this.objects[newname] = this.objects[name]; this.objects[newname] = this.objects[name];
delete this.objects[name]; delete this.objects[name];
@ -573,15 +537,14 @@ prototypes.from_file = function(file)
if (typeof v !== 'object') return; if (typeof v !== 'object') return;
if (!v.comp) return; if (!v.comp) return;
v.__proto__ = component[v.comp]; v.__proto__ = component[v.comp];
delete v.comp;
}); });
newur.__proto__ = upperur; newur.__proto__ = upperur;
newur.instances = []; newur.instances = [];
Object.hide(newur, 'instances');
prototypes.list.push(urpath); prototypes.list.push(urpath);
newur.toString = function() { return urpath; }; newur.toString = function() { return urpath; };
newur.ur = urpath;
ur[urpath] = newur; ur[urpath] = newur;
return ur[urpath]; return ur[urpath];

View file

@ -390,8 +390,13 @@ void phys2d_polyaddvert(struct phys2d_poly *poly) {
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) { void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
if (!verts) return; if (!verts) return;
if (poly->points)
arrfree(poly->points); arrfree(poly->points);
poly->points = verts;
arrsetlen(poly->points, arrlen(verts));
for (int i = 0; i < arrlen(verts); i++)
poly->points[i] = verts[i];
phys2d_applypoly(poly); phys2d_applypoly(poly);
} }

View file

@ -229,6 +229,7 @@ cpBitmask js2bitmask(JSValue v) {
cpVect *cpvecarr = NULL; cpVect *cpvecarr = NULL;
/* Must be freed */
cpVect *js2cpvec2arr(JSValue v) { cpVect *js2cpvec2arr(JSValue v) {
if (cpvecarr) if (cpvecarr)
arrfree(cpvecarr); arrfree(cpvecarr);