Simplify reparenting; fix deleting objects and copying objects

This commit is contained in:
John Alanbrook 2023-09-25 21:34:48 +00:00
parent 58d4132f4d
commit 9a1f1408a6
7 changed files with 108 additions and 65 deletions

View file

@ -62,9 +62,24 @@ Object.dainty_assign = function(target, source)
}
}
Object.containingKey = function(obj, prop)
{
if (typeof obj !== 'object') return undefined;
if (!(prop in obj)) return undefined;
var o = obj;
while (o.__proto__ && !Object.hasOwn(o, prop))
o = o.__proto__;
return o;
}
Object.isAccessor = function(obj, prop)
{
var desc = Object.getOwnPropertyDescriptor(obj,prop);
var o = Object.containingKey(obj,prop);
if (!o) return false;
var desc = Object.getOwnPropertyDescriptor(o,prop);
if (!desc) return false;
if (desc.get || desc.set) return true;
return false;
@ -78,6 +93,7 @@ Object.mergekey = function(o1,o2,k)
if (Array.isArray(o2[k]))
o1[k] = o2[k].slice();
else {
if (!o1[k]) o1[k] = {};
Object.merge(o1[k], o2[k]);
}
} else

View file

@ -34,7 +34,8 @@ component.sprite = {
toString() { return "sprite"; },
make(go) {
var nsprite = Object.create(component.sprite.maker);
Object.assign(nsprite, make_sprite(go));
nsprite.gameobject = go;
Object.assign(nsprite, make_sprite(go.body));
nsprite.ur = this;
return nsprite;
},
@ -108,7 +109,7 @@ var aseframeset2anim = function(frameset, meta)
};
frameset.forEach(ase_make_frame);
anim.dim = [frameset[0].sourceSize.x, frameset[0].sourceSize.y];
anim.loop = true;
return anim;
}
@ -153,6 +154,9 @@ var gif2anim = function(gif)
anim.frames.push(frame);
}
anim.loop = true;
var dim = cmd(64,gif);
dim.y /= frames;
anim.dim = dim;
return anim;
}
@ -169,6 +173,8 @@ var strip2anim = function(strip)
frame.time = 0.05;
anim.frames.push(frame);
}
anim.dim = cmd(64,strip);
anim.dim.x /= frames;
return anim;
}
@ -183,13 +189,11 @@ component.char2d = Object.copy(sprite, {
get layer() { return this.gameobject.draw_layer; },
boundingbox() {
var dim = cmd(64,this.path);
var dim = this.curplaying.dim.slice();
dim = dim.scale(this.gameobject.scale);
var realpos = [0,0];
// var realpos = this.pos.slice();
// realpos.x = realpos.x * dim.x + (dim.x/2);
// realpos.y = realpos.y * dim.y + (dim.y/2);
var realpos = this.pos.slice();
realpos.x = realpos.x * dim.x + (dim.x/2);
realpos.y = realpos.y * dim.y + (dim.y/2);
return cwh2bb(realpos,dim);
},
@ -205,7 +209,8 @@ component.char2d = Object.copy(sprite, {
make(go) {
var char = Object.create(this);
Object.assign(char, make_sprite(go));
char.gameobject = go;
Object.assign(char, make_sprite(go.body));
char.frame = 0;
char.timer = timer.make(char.advance.bind(char), 1);
char.timer.loop = true;
@ -329,7 +334,8 @@ component.polygon2d = Object.copy(collider2d, {
make(go) {
var poly = Object.create(this);
Object.assign(poly, make_poly2d(go, this.points));
poly.gameobject = go;
Object.assign(poly, make_poly2d(go.body, this.points));
poly.defn('points', this.points.copy());
poly.sync();
@ -502,7 +508,8 @@ component.bucket = Object.copy(collider2d, {
make(go) {
var edge = Object.create(this);
Object.assign(edge, make_edge2d(go, this.points, this.thickness));
edge.gameobject = go;
Object.assign(edge, make_edge2d(go.body, this.points, this.thickness));
Object.assign(edge, {
set thickness(x) {
cmd_edge2d(1,this.id,x);
@ -682,7 +689,8 @@ component.circle2d = Object.copy(collider2d, {
make(go) {
var circle = Object.create(this);
Object.assign(circle, make_circle2d(go, circle.radius, circle.offset));
circle.gameobject = go;
Object.assign(circle, make_circle2d(go.body, circle.radius, circle.offset));
return circle;
},

View file

@ -498,6 +498,7 @@ return;
GUI.text(lvlstr, [0, ypos], 1, ColorMap.Inferno.sample(lvlcolorsample));
lvlcolorsample -= 0.1;
if (!clvl.level) break;
clvl = clvl.level;
if (clvl) {
GUI.text("^^^^^^", [0,ypos-15],1);
@ -990,6 +991,7 @@ editor.inputs['C-f1'].doc = "Enter basic edit mode.";
editor.inputs['C-f2'] = function() { editor.edit_mode = "brush"; };
editor.inputs['C-f2'].doc = "Enter brush mode.";
editor.inputs.f2 = function() {
objectexplorer.on_close = save_configs;
objectexplorer.obj = configs;

View file

@ -567,7 +567,9 @@ var ur_json = function()
return ret;
}
return objdiff(this, this.ur);
var ur = objdiff(this,this.ur);
return ur ? ur : {};
}
@ -744,13 +746,13 @@ Register.update.register(Game.exec, Game);
load("scripts/entity.js");
var preprimum = {};
preprimum.add_child = function() {};
preprimum.objects = [];
var World = gameobject.make(gameobject.ur, preprimum);
var Primum = World;
Primum.level = undefined;
Primum.toString = function() { return "Primum"; };
Primum.selectable = false;
World.reparent = function(parent) { Log.warn("Cannot reparent the Primum."); }
World.unparent = function() { Log.warn("The Primum has no parent, always."); }
/* Load configs */
function load_configs(file) {

View file

@ -187,7 +187,8 @@ var gameobject = {
set pos(x) {
var diff = x.sub(this.pos);
this.objects.forEach(function(x) { x.pos = x.pos.add(diff); });
set_body(2,this.body,x); },
set_body(2,this.body,x);
},
get pos() { return q_body(1,this.body); },
get angle() { return Math.rad2deg(q_body(2,this.body))%360; },
@ -244,7 +245,6 @@ var gameobject = {
return gameobject.make(ur, this);
},
/* Bounding box of the object in world dimensions */
boundingbox() {
var boxes = [];
@ -254,6 +254,8 @@ var gameobject = {
if ('boundingbox' in this.components[key])
boxes.push(this.components[key].boundingbox());
}
for (var key in this.$)
boxes.push(this.$[key].boundingbox());
if (boxes.empty) return cwh2bb([0,0], [0,0]);
@ -276,9 +278,45 @@ var gameobject = {
return bb ? bb : cwh2bb([0,0], [0,0]);
},
json_obj() {
function objdiff(from, to) {
if (!to) return from; // Everything on from is unique
var ret = {};
for (var key in from) {
if (!from[key] || !to[key]) continue;
if (typeof from[key] === 'function') continue;
if (typeof to === 'object' && !(key in to)) continue;
if (typeof from[key] === 'object') {
if ('ur' in from[key]) {
var urdiff = objdiff(from[key],from[key].ur);
if (urdiff && !urdiff.empty) ret[key] = urdiff;
continue;
}
var diff = objdiff(from[key], to[key]);
if (diff && !diff.empty) ret[key] = diff;
continue;
}
if (from[key] !== to[key])
ret[key] = from[key];
}
if (ret.empty) return undefined;
return ret;
}
var ur = objdiff(this,this.ur);
return ur ? ur : {};
},
dup(diff) {
var dup = Primum.spawn(this.__proto__);
Object.assign(dup, this);
var dup = this.level.spawn(this.ur);
var thisur = this.json_obj();
thisur.pos = this.pos;
thisur.angle = this.angle;
Object.totalmerge(dup, thisur);
return dup;
},
@ -307,31 +345,40 @@ var gameobject = {
}
this.objects.forEach(x => x.kill());
this.stop();
if (typeof this.stop === 'function')
this.stop();
});
},
up() { return [0,1].rotate(Math.deg2rad(this.angle));},
// down() { return [0,-1].rotate(Math.deg2rad(this.angle));},
// right() { return [1,0].rotate(Math.deg2rad(this.angle));},
// left() { return [-1,0].rotate(Math.deg2rad(this.angle));},
down() { return [0,-1].rotate(Math.deg2rad(this.angle));},
right() { return [1,0].rotate(Math.deg2rad(this.angle));},
left() { return [-1,0].rotate(Math.deg2rad(this.angle));},
reparent(parent) {
if (this.level === parent) return;
parent.objects.push(this);
if (this.level)
this.level.objects.remove(this);
this.level = parent;
},
make(ur, level) {
level ??= Primum;
var obj = Object.create(gameobject);
obj.defn('body', make_gameobject());
obj.defn('components', {});
obj.body = make_gameobject();
obj.components = {};
obj.objects = [];
Game.register_obj(obj);
gameobject.make_parentable(obj);
cmd(113, obj.body, obj); // set the internal obj reference to this obj
obj.$ = {};
obj.ur = ur;
level.add_child(obj);
obj.reparent(level);
for (var prop in ur) {
var p = ur[prop];
if (typeof p !== 'object') continue;
@ -340,16 +387,16 @@ var gameobject = {
obj[prop] = obj.spawn(prototypes.get_ur(p.ur));
obj.$[prop] = obj[prop];
} else if ('make' in p) {
obj[prop] = p.make(obj.body);
obj[prop] = p.make(obj);
obj.components[prop] = obj[prop];
} else if ('comp' in p) {
obj[prop] = component[p.comp].make(obj.body);
obj[prop] = component[p.comp].make(obj);
obj.components[prop] = obj[prop];
}
};
Object.totalmerge(obj,ur);
obj.check_registers(obj);
obj.check_registers(obj);
if (typeof obj.start === 'function') obj.start();
@ -387,37 +434,6 @@ gameobject.ur = {
layer: 0,
};
gameobject.make_parentable = function(obj) {
var objects = [];
Object.defHidden(obj, 'level');
obj.remove_child = function(child) {
objects.remove(child);
}
obj.add_child = function(child) {
child.unparent();
objects.push(child);
child.level = obj;
}
/* Reparent this object to a new one */
obj.reparent = function(parent) {
if (parent === obj.level)
return;
parent.add_child(obj);
obj.level = parent;
}
obj.unparent = function() {
if (!obj.level) return;
obj.level.remove_child(obj);
obj.parent = undefined;
}
obj.objects = objects;
}
gameobject.entity = {};
/* Default objects */

View file

@ -25,6 +25,7 @@ char *catstr[] = {"engine", "script", "render"};
FILE *logfile = NULL;
#define ERROR_BUFFER 1024
#define CONSOLE_BUF 1024*1024*5 /* 5MB */
char *lastlog;

View file

@ -4,8 +4,6 @@
#include <stdio.h>
#include <stdint.h>
#define ERROR_BUFFER 1024
#define LOG_INFO 0
#define LOG_WARN 1
#define LOG_ERROR 2