diff --git a/scripts/base.js b/scripts/base.js index dcb57a4..e3e3514 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -17,13 +17,49 @@ Reflect = {}; Symbol = {}; URIError = {}; -/* Prototypes out an object and extends with values */ -function clone(proto, binds) { - var c = Object.create(proto); - complete_assign(c, binds); - return c; +Object.complete_assign = function(target, source) +{ +var descriptors = {}; + var assigns = {}; + if (typeof source === 'undefined') return target; + Object.keys(source).forEach(function (k) { + var desc = Object.getOwnPropertyDescriptor(source, k); + + if (desc.value) { + if (typeof desc.value === 'object' && desc.value.hasOwn('value')) + descriptors[k] = desc.value; + else + assigns[k] = desc.value; + } else + descriptors[k] = desc; + }); + + Object.defineProperties(target, descriptors); + Object.assign(target, assigns); + return target; }; +Object.dainty_assign = function(target, source) +{ + for (var key in source) { + + if (typeof source[key] === 'function') { + target[key] = source[key]; + continue; + } + if (!Object.hasOwn(target, key)) continue; + if (!Object.getOwnPropertyDescriptor(target, key).writable) continue; + + if (Array.isArray(target[key])) + target[key] = source[key]; + else if (typeof target[key] === 'object') + Object.dainty_assign(target[key], source[key]); + else { + target[key] = source[key]; + } + } +} + Object.totalassign = function(to, from) { for (var key in from) @@ -31,11 +67,13 @@ Object.totalassign = function(to, from) } /* Prototypes out an object and assigns values */ -function copy(proto, binds) { +Object.copy = function(proto, ...objs) +{ var c = Object.create(proto); - Object.assign(c, binds); + for (var obj of objs) + Object.complete_assign(c, obj); return c; -}; +} /* OBJECT DEFININTIONS */ Object.defHidden = function(obj, prop) diff --git a/scripts/components.js b/scripts/components.js index 80c7bef..905427c 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -1,4 +1,5 @@ var component = { + components: [], toString() { if ('gameobject' in this) return this.name + " on " + this.gameobject; @@ -18,14 +19,14 @@ var component = { prepare_center() {}, finish_center() {}, - clone(spec) { - return clone(this, spec); + extend(spec) { + return Object.copy(this, spec); }, }; component.toJSON = ur_json; -var sprite = clone(component, { +component.sprite = Object.copy(component, { name: "sprite", path: "", layer: 0, @@ -36,30 +37,30 @@ var sprite = clone(component, { angle: 0, rect: {s0:0, s1: 1, t0: 0, t1: 1}, -get enabled() { return cmd(114,this.id); }, -set enabled(x) { cmd(20,this.id,x); }, -set color(x) { cmd(96,this.id,x); }, -get color() {return undefined; }, -get pos() { return cmd(111, this.id); }, -set pos(x) { cmd(37,this.id,x); }, -set layer(x) { cmd(60, this.id, x); }, -get layer() { return undefined; }, + get enabled() { return cmd(114,this.id); }, + set enabled(x) { cmd(20,this.id,x); }, + set color(x) { cmd(96,this.id,x); }, + get color() {return undefined; }, + get pos() { return cmd(111, this.id); }, + set pos(x) { cmd(37,this.id,x); }, + set layer(x) { cmd(60, this.id, x); }, + get layer() { return undefined; }, -boundingbox() { - var dim = this.dimensions(); - dim = dim.scale(this.gameobject.scale); - var realpos = this.pos.copy(); - realpos.x = realpos.x * dim.x + (dim.x/2); - realpos.y = realpos.y * dim.y + (dim.y/2); - return cwh2bb(realpos,dim); -}, + boundingbox() { + var dim = this.dimensions(); + dim = dim.scale(this.gameobject.scale); + var realpos = this.pos.copy(); + realpos.x = realpos.x * dim.x + (dim.x/2); + realpos.y = realpos.y * dim.y + (dim.y/2); + return cwh2bb(realpos,dim); + }, -sync() { - if (this.path) - cmd(12,this.id,this.path,this.rect); -}, + sync() { + if (this.path) + cmd(12,this.id,this.path,this.rect); + }, -kill() { cmd(9,this.id); }, + kill() { cmd(9,this.id); }, dimensions() { return cmd(64,this.path); }, width() { return cmd(64,this.path).x; }, height() { return cmd(64,this.path).y; }, @@ -67,19 +68,20 @@ kill() { cmd(9,this.id); }, make(go) { var sprite = Object.create(this); sprite.id = make_sprite(go); - sprite.layer = 1; - Log.say(`made sprite with pos ${sprite.pos}`); + sprite.sync(); return sprite; }, POS_MID: [-0.5, -0.5], }); -sprite.ur = { +var sprite = component.sprite; + +component.sprite.ur = { pos:[0,0], color:[1,1,1], layer:0, - enabled:true + enabled:true, }; sprite.inputs = {}; @@ -93,15 +95,8 @@ sprite.inputs.kp3 = function() { this.pos = [0, -1]; }; sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; }; sprite.inputs.kp1 = function() { this.pos = [-1,-1]; }; - /* Container to play sprites and anim2ds */ -var char2d = clone(sprite, { - clone(anims) { - var char = clone(this); - char.anims = anims; - return char; - }, - +component.char2d = Object.copy(sprite, { name: "char 2d", frame2rect(frames, frame) { @@ -115,7 +110,7 @@ var char2d = clone(sprite, { }, make(go) { - var char = clone(this, { + var char = Object.copy(this, { get enabled() { return cmd(114,this.id); }, set enabled(x) { cmd(20,this.id,x); }, set color(x) { cmd(96,this.id,x); }, @@ -237,7 +232,7 @@ var Geometry = { }; /* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */ -var collider2d = clone(component, { +var collider2d = Object.copy(component, { name: "collider 2d", sensor: false, @@ -260,25 +255,18 @@ collider2d.inputs['M-s'].doc = "Toggle if this collider is a sensor."; collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; } collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled."; -var polygon2d = clone(collider2d, { +component.polygon2d = Object.copy(collider2d, { name: "polygon 2d", points: [], flipx: false, flipy: false, - clone(spec) { - var obj = Object.create(this); - obj.points = this.points.copy(); - Object.assign(obj, spec); - return obj; - }, - make(go) { var poly = Object.create(this); Object.assign(poly, make_poly2d(go, this.points)); - complete_assign(poly, this.make_fns); - complete_assign(poly, { + Object.assign(poly, this.make_fns); + Object.assign(poly, { boundingbox() { return points2bb(this.spoints); }, @@ -340,6 +328,8 @@ var polygon2d = clone(collider2d, { }, }); +var polygon2d = component.polygon2d; + polygon2d.inputs = {}; polygon2d.inputs.post = function() { this.sync(); }; polygon2d.inputs.f10 = function() { @@ -366,15 +356,10 @@ polygon2d.inputs['C-b'] = function() { }; polygon2d.inputs['C-b'].doc = "Freeze mirroring in place."; -var bucket = clone(collider2d, { - name: "bucket", - clone(spec) { - var obj = Object.create(this); - obj.cpoints = this.cpoints.copy(); - dainty_assign(obj, spec); - return obj; - }, +Object.freeze(polygon2d); +component.bucket = Object.copy(collider2d, { + name: "bucket", cpoints:[], degrees:2, dimensions:2, @@ -465,7 +450,7 @@ var bucket = clone(collider2d, { make(go) { var edge = Object.create(this); Object.assign(edge, make_edge2d(go, this.points, this.thickness)); - complete_assign(edge, { + Object.assign(edge, { set thickness(x) { cmd_edge2d(1,this.id,x); }, @@ -483,7 +468,7 @@ var bucket = clone(collider2d, { }, }); - complete_assign(edge, this.make_fns); + Object.assign(edge, this.make_fns); Object.defineProperty(edge, 'id', {enumerable:false}); Object.defineProperty(edge, 'shape', {enumerable:false}); @@ -513,6 +498,7 @@ var bucket = clone(collider2d, { pick(pos) { return Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints); }, }); +var bucket = component.bucket; bucket.inputs = {}; bucket.inputs.h = function() { this.hollow = !this.hollow; }; bucket.inputs.h.doc = "Toggle hollow."; @@ -626,7 +612,7 @@ bucket.inputs.rb = function() { bucket.inputs.rb.doc = "Rotate the points CW."; bucket.inputs.rb.rep = true; -var circle2d = clone(collider2d, { +component.circle2d = Object.copy(collider2d, { name: "circle 2d", set radius(x) { cmd_circle2d(0,this.id,x); }, get radius() { return cmd_circle2d(2,this.id); }, @@ -654,12 +640,12 @@ var circle2d = clone(collider2d, { this.radius = Nuke.pprop("Radius", this.radius); this.offset = Nuke.pprop("offset", this.offset); }, -}); -circle2d.ur = { - radius:10, - offset:[0,0], -}; + ur: { + radius:10, + offset:[0,0], + }, +}); /* ASSETS */ @@ -691,3 +677,5 @@ var Resources = { }, }; + +Log.warn("bottom of components"); diff --git a/scripts/diff.js b/scripts/diff.js index cbfe867..37d38d3 100644 --- a/scripts/diff.js +++ b/scripts/diff.js @@ -29,50 +29,6 @@ var walk_up_get_prop = function(obj, prop, endobj) { return props; }; - -function complete_assign(target, source) { - var descriptors = {}; - var assigns = {}; - if (typeof source === 'undefined') return target; - Object.keys(source).forEach(function (k) { - var desc = Object.getOwnPropertyDescriptor(source, k); - - if (desc.value) { - if (typeof desc.value === 'object' && desc.value.hasOwn('value')) - descriptors[k] = desc.value; - else - assigns[k] = desc.value; - } else - descriptors[k] = desc; - }); - - Object.defineProperties(target, descriptors); - Object.assign(target, assigns); - return target; -}; - -/* Assigns properties from source to target, only if they exist in target */ -function dainty_assign(target, source) -{ - for (var key in source) { - - if (typeof source[key] === 'function') { - target[key] = source[key]; - continue; - } - if (!Object.hasOwn(target, key)) continue; - if (!Object.getOwnPropertyDescriptor(target, key).writable) continue; - - if (Array.isArray(target[key])) - target[key] = source[key]; - else if (typeof target[key] === 'object') - dainty_assign(target[key], source[key]); - else { - target[key] = source[key]; - } - } -}; - /* Deeply remove source keys from target, not removing objects */ function unmerge(target, source) { for (var key in source) { diff --git a/scripts/editor.js b/scripts/editor.js index d590b4f..c857f01 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -98,7 +98,7 @@ var editor = { slurpwrite(JSON.stringify(protos, undefined, 2), "proto.json"); /* Save object changes to parent */ - dainty_assign(this.selectlist[0].__proto__, tobj); + Object.dainty_assign(this.selectlist[0].__proto__, tobj); /* Remove the local from this object */ unmerge(this.selectlist[0], tobj); @@ -124,7 +124,7 @@ var editor = { if (typeof newp[key] === 'object' && 'clone' in newp[key]) newp[key] = newp[key].clone(); - dainty_assign(newp, this.selectlist[0].prop_obj()); + Object.dainty_assign(newp, this.selectlist[0].prop_obj()); this.selectlist[0].kill(); var gopos = this.selectlist[0].pos; this.unselect(); @@ -152,7 +152,7 @@ var editor = { deep_merge(pobj, tobj); - dainty_assign(newp, pobj); + Object.dainty_assign(newp, pobj); this.selectlist[0].kill(); this.unselect(); var proto = this.edit_level.spawn(gameobjects[name]); @@ -620,7 +620,7 @@ var editor = { Log.info(path); var fn = function(x) { return path.endsWith(x); }; if (images.any(fn)) { - var newtex = copy(texgui, { path: path }); + var newtex = Object.copy(texgui, { path: path }); this.addpanel(newtex); } else if (sounds.any(fn)) @@ -1479,7 +1479,7 @@ function proto_children(name) { load("scripts/textedit.js"); -var objectexplorer = copy(inputpanel, { +var objectexplorer = Object.copy(inputpanel, { title: "object explorer", obj: undefined, previous: [], @@ -1625,7 +1625,7 @@ var objectexplorer = copy(inputpanel, { }); -var helppanel = copy(inputpanel, { +var helppanel = Object.copy(inputpanel, { title: "help", start() { @@ -1637,7 +1637,7 @@ var helppanel = copy(inputpanel, { }, }); -var openlevelpanel = copy(inputpanel, { +var openlevelpanel = Object.copy(inputpanel, { title: "open entity", action() { editor.load(this.value); @@ -1678,33 +1678,33 @@ var openlevelpanel = copy(inputpanel, { }, }); -var saveaspanel = copy(inputpanel, { +var saveaspanel = Object.copy(inputpanel, { title: "save level as", action() { editor.saveas_check(this.value); }, }); -var groupsaveaspanel = copy(inputpanel, { +var groupsaveaspanel = Object.copy(inputpanel, { title: "group save as", action() { editor.groupsaveas(editor.selectlist, this.value); } }); -var saveprototypeas = copy(inputpanel, { +var saveprototypeas = Object.copy(inputpanel, { title: "save prototype as", action() { editor.save_proto_as(this.value); }, }); -var savetypeas = copy(inputpanel, { +var savetypeas = Object.copy(inputpanel, { title: "save type as", action() { editor.save_type_as(this.value); }, }); -var quitpanel = copy(inputpanel, { +var quitpanel = Object.copy(inputpanel, { title: "really quit?", action() { quit(); @@ -1718,7 +1718,7 @@ var quitpanel = copy(inputpanel, { }, }); -var notifypanel = copy(inputpanel, { +var notifypanel = Object.copy(inputpanel, { title: "notification", msg: "Refusing to save. File already exists.", action() { @@ -1759,7 +1759,7 @@ var allfiles = []; allfiles.push(scripts, images, sounds); allfiles = allfiles.flat(); -var assetexplorer = copy(openlevelpanel, { +var assetexplorer = Object.copy(openlevelpanel, { title: "asset explorer", extensions: allfiles, closeonsubmit: false, @@ -1798,7 +1798,7 @@ function tab_complete(val, list) { return ret; } -var texgui = clone(inputpanel, { +var texgui = Object.copy(inputpanel, { get path() { return this._path; }, set path(x) { this._path = x; @@ -1811,7 +1811,7 @@ var texgui = clone(inputpanel, { }, }); -var entitylistpanel = copy(inputpanel, { +var entitylistpanel = Object.copy(inputpanel, { title: "Level object list", level: {}, start() { diff --git a/scripts/engine.js b/scripts/engine.js index 25af732..a82a3c2 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -577,7 +577,7 @@ load("scripts/entity.js"); var preprimum = {}; preprimum.add_child = function() {}; -var World = gameobject.make(preprimum); +var World = gameobject.make(gameobject.ur, preprimum); var Primum = World; Primum.selectable = false; World.reparent = function(parent) { Log.warn("Cannot reparent the Primum."); } diff --git a/scripts/entity.js b/scripts/entity.js index fb3349b..a714afa 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -14,13 +14,6 @@ var gameobject = { save: true, selectable: true, - /* Make a duplicate of this exact object */ - clone(name, ext) { - var obj = Object.create(this); - complete_assign(obj, ext); - return obj; - }, - layer_nuke() { Nuke.label("Collision layer"); Nuke.newline(Collision.num); @@ -198,8 +191,8 @@ var gameobject = { if (typeof ur === 'string') ur = prototypes.get_ur(ur); if (!ur) Log.warn("Failed to make UR from " + ur); - - return ur.make(this); + + return gameobject.make(ur, this); }, @@ -275,35 +268,44 @@ var gameobject = { // right() { return [1,0].rotate(Math.deg2rad(this.angle));}, // left() { return [-1,0].rotate(Math.deg2rad(this.angle));}, - make(level) { + make(ur, level) { level ??= Primum; var obj = Object.create(this); obj.defn('body', make_gameobject()); obj.defn('components', {}); Game.register_obj(obj); + gameobject.make_parentable(obj); cmd(113, obj.body, obj); // set the internal obj reference to this obj + Object.totalassign(obj, ur); + for (var prop in obj) { - if (typeof obj[prop] === 'object' && 'make' in obj[prop]) { - obj[prop] = obj[prop].make(obj.body); - obj[prop].defn('gameobject', obj); - obj.components[prop] = obj[prop]; + if (typeof obj[prop] === 'object' && 'comp' in obj[prop]) { + var newcomp = component[obj[prop].comp].make(obj.body); + Object.assign(newcomp, obj[prop]); + newcomp.sync?.(); + obj[prop] = newcomp; + obj[prop].defn('gameobject', obj); + obj.components[prop] = obj[prop]; } }; obj.check_registers(obj); - - gameobject.make_parentable(obj); /* Spawn subobjects defined */ - if (obj.$) { - for (var e in obj.$) - obj.$[e] = obj.spawn(prototypes.get_ur(obj.$[e].ur)); - } - Object.totalassign(obj, obj.ur); + if (obj.$) { + for (var e in obj.$) { + var newobj = obj.spawn(prototypes.get_ur(obj.$[e].ur)); + Object.assign(newobj, obj.$[e].diff); + obj.$[e] = newobj; + } + } + + + if (typeof obj.start === 'function') obj.start(); @@ -386,7 +388,7 @@ if (IO.exists("proto.json")) for (var key in prototypes) { if (key in gameobjects) - dainty_assign(gameobjects[key], prototypes[key]); + Object.dainty_assign(gameobjects[key], prototypes[key]); else { /* Create this gameobject fresh */ Log.info("Making new prototype: " + key + " from " + prototypes[key].from); @@ -397,13 +399,14 @@ for (var key in prototypes) { if (typeof newproto[pkey] === 'object' && newproto[pkey] && 'clone' in newproto[pkey]) newproto[pkey] = newproto[pkey].clone(); - dainty_assign(gameobjects[key], prototypes[key]); + Object.dainty_assign(gameobjects[key], prototypes[key]); } } } prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); }; +/* Makes a new ur-type from a file. The file can define components. */ prototypes.from_file = function(file) { if (!IO.exists(file)) { @@ -411,20 +414,20 @@ prototypes.from_file = function(file) return; } - var newur = gameobject.clone(file, {}); + var newur = Object.create(gameobject.ur); var script = IO.slurp(file); - Object.defHidden(newur, '$'); - newur.$ = {}; - var json = {}; +// Object.defHidden(newur, '$'); +// newur.$ = {}; +/* var json = {}; if (IO.exists(file.name() + ".json")) { json = JSON.parse(IO.slurp(file.name() + ".json")); Object.assign(newur.$, json.$); delete json.$; } - - compile_env(`var self = this; var $ = self.$; ${script}`, newur, file); - dainty_assign(newur, json); +*/ + compile_env(`var self = this; ${script}`, newur, file); +// Object.dainty_assign(newur, json); file = file.replaceAll('/', '.'); var path = file.name().split('.'); @@ -450,8 +453,9 @@ prototypes.list = []; prototypes.from_obj = function(name, obj) { - var newobj = gameobject.clone(name, obj); + var newobj = Object.copy(gameobject.ur, obj); prototypes.ur[name] = newobj; + Log.say(Object.keys(newobj)); newobj.toString = function() { return name; }; return prototypes.ur[name]; } @@ -498,18 +502,6 @@ prototypes.get_ur = function(name) return prototypes.ur[name]; } -prototypes.from_obj("polygon2d", { - polygon2d: polygon2d.clone(), -}); - -prototypes.from_obj("edge2d", { - edge2d: bucket.clone(), -}); - -prototypes.from_obj("sprite", { - sprite: sprite.clone(), -}); - prototypes.generate_ur = function(path) { var ob = IO.glob("**.js"); @@ -541,7 +533,6 @@ prototypes.from_obj("camera2d", { world2this(pos) { return cmd(70, this.body, pos); }, this2world(pos) { return cmd(71, this.body,pos); }, - view2world(pos) { return cmd(137,pos); diff --git a/scripts/textedit.js b/scripts/textedit.js index c8ab36f..5b785d6 100644 --- a/scripts/textedit.js +++ b/scripts/textedit.js @@ -1,4 +1,4 @@ -var texteditor = clone(inputpanel, { +var texteditor = Object.copy(inputpanel, { title: "text editor", _cursor:0, /* Text cursor: [char,line] */ get cursor() { return this._cursor; },