From e392f65485cea83b73bebb241c84d782f01b688b Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 14 Sep 2023 22:37:04 +0000 Subject: [PATCH] Vastly simplified entity stringifying and diffing --- source/engine/ffi.c | 4 +- source/engine/gameobject.c | 2 +- source/engine/sprite.c | 14 +- source/engine/sprite.h | 22 ++- source/scripts/components.js | 46 +++---- source/scripts/debug.js | 2 +- source/scripts/editor.js | 11 +- source/scripts/entity.js | 259 ++++++++++++++--------------------- 8 files changed, 153 insertions(+), 207 deletions(-) diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 83f6628..df23d06 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -979,10 +979,10 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) return num2js(js2go(argv[1])->scale); case 104: - return bool2js(js2go(argv[1])->flipx); + return bool2js(js2go(argv[1])->flipx == -1 ? 1 : 0); case 105: - return bool2js(js2go(argv[1])->flipy); + return bool2js(js2go(argv[1])->flipy == -1 ? 1 : 0); case 106: js2go(argv[1])->e = js2number(argv[2]); diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index e091459..403362c 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -107,7 +107,7 @@ void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) { moment += s->moi(s->data, go->mass); if (moment < 0) moment = 1; - cpBodySetMoment(go->body, moment); + cpBodySetMoment(go->body, 1); } void gameobject_apply(struct gameobject *go) { diff --git a/source/engine/sprite.c b/source/engine/sprite.c index a28d6ed..12cf248 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -57,22 +57,23 @@ int make_sprite(int go) { .layer = 0, .enabled = 1}; + int slot = 0; if (first < 0) { arrput(sprites, sprite); - arrlast(sprites).id = arrlen(sprites) - 1; - return arrlen(sprites) - 1; + slot = arrlen(sprites)-1; } else { - int slot = first; + slot = first; first = id2sprite(first)->next; *id2sprite(slot) = sprite; - - return slot; } + + return slot; } void sprite_delete(int id) { struct sprite *sp = id2sprite(id); sp->go = -1; + sp->enabled = 0; sp->next = first; first = id; } @@ -121,6 +122,7 @@ void sprite_draw_all() { for (int i = 0; i < arrlen(sprites); i++) if (sprites[i].go >= 0 && sprites[i].enabled) arrpush(layers[sprites[i].layer], &sprites[i]); + for (int i = 4; i >= 0; i--) for (int j = 0; j < arrlen(layers[i]); j++) @@ -137,8 +139,6 @@ void sprite_settex(struct sprite *sprite, struct Texture *tex) { sprite_setframe(sprite, &ST_UNIT); } - - void sprite_initialize() { shader_sprite = sg_compile_shader("shaders/spritevert.glsl", "shaders/spritefrag.glsl", &(sg_shader_desc){ .vs.uniform_blocks[0] = { diff --git a/source/engine/sprite.h b/source/engine/sprite.h index e5c7be1..2600667 100644 --- a/source/engine/sprite.h +++ b/source/engine/sprite.h @@ -7,22 +7,20 @@ #include "HandmadeMath.h" #include "render.h" - struct datastream; struct gameobject; struct sprite { - HMM_Vec2 pos; - HMM_Vec2 size; - float rotation; - struct rgba color; - int go; - int id; - struct Texture *tex; - struct glrect frame; - int next; - int enabled; - int layer; + HMM_Vec2 pos; + HMM_Vec2 size; + float rotation; + struct rgba color; + int go; /* id of gameobject */ + struct Texture *tex; + struct glrect frame; + int enabled; + int layer; + int next; }; int make_sprite(int go); diff --git a/source/scripts/components.js b/source/scripts/components.js index b2e2a48..3d53118 100644 --- a/source/scripts/components.js +++ b/source/scripts/components.js @@ -30,26 +30,28 @@ var sprite = clone(component, { pos: [0,0], get visible() { return this.enabled; }, set visible(x) { this.enabled = x; }, - set asset(str) { this.path = str; this.sync();}, + asset(str) { this.path = str; this.sync();}, angle: 0, rect: {s0:0, s1: 1, t0: 0, t1: 1}, - get dimensions() { return cmd(64,this.path); }, - get width() { return cmd(64,this.path).x; }, - get height() { return cmd(64,this.path).y; }, + dimensions() { return cmd(64,this.path); }, + width() { return cmd(64,this.path).x; }, + height() { return cmd(64,this.path).y; }, make(go) { var sprite = Object.create(this); - sprite.id = make_sprite(go,this.path,this.pos); + var id = make_sprite(go,this.path,this.pos); complete_assign(sprite, { - get enabled() { return cmd(114,this.id); }, - set enabled(x) { cmd(20,this.id,x); }, - set color(x) { cmd(96,this.id,x); }, - get pos() { return cmd(111, this.id); }, - set pos(x) { cmd(37,this.id,x); }, - set layer(x) { cmd(60, this.id, x); }, + get enabled() { return cmd(114,id); }, + set enabled(x) { cmd(20,id,x); }, + set color(x) { cmd(96,id,x); }, + get color() {return undefined; }, + get pos() { return cmd(111, id); }, + set pos(x) { cmd(37,id,x); }, + set layer(x) { cmd(60, id, x); }, + get layer() { return undefined; }, - get boundingbox() { + boundingbox() { var dim = this.dimensions; dim = dim.scale(this.gameobject.scale); var realpos = this.pos.copy(); @@ -60,12 +62,12 @@ var sprite = clone(component, { sync() { if (this.path) - cmd(12,this.id,this.path,this.rect); + cmd(12,id,this.path,this.rect); }, - kill() { cmd(9,sprite.id); }, + kill() { cmd(9,id); }, }); - sprite.obscure('boundingbox'); + sprite.layer = 1; return sprite; }, @@ -115,7 +117,7 @@ var char2d = clone(sprite, { set layer(x) { cmd(60, this.id, x); }, get layer() { return this.gameobject.draw_layer; }, - get boundingbox() { + boundingbox() { var dim = cmd(64,this.path); dim = dim.scale(this.gameobject.scale); dim.x *= 1/6; @@ -273,15 +275,13 @@ var polygon2d = clone(collider2d, { complete_assign(poly, this.make_fns); complete_assign(poly, { - get boundingbox() { + boundingbox() { return points2bb(this.spoints); }, sync() { cmd_poly2d(0, this.id, this.spoints); } }); - poly.obscure('boundingbox'); - poly.defn('points', this.points.copy()); Object.defineProperty(poly, 'id', {enumerable:false}); @@ -467,7 +467,7 @@ var bucket = clone(collider2d, { }, get thickness() { return cmd(112,this.id); }, - get boundingbox() { + boundingbox() { return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); }, @@ -479,8 +479,6 @@ var bucket = clone(collider2d, { }, }); - edge.obscure('boundingbox'); - complete_assign(edge, this.make_fns); Object.defineProperty(edge, 'id', {enumerable:false}); @@ -649,7 +647,7 @@ var circle2d = clone(collider2d, { set offset(x) { cmd_circle2d(1,this.id,x); }, get offset() { return cmd_circle2d(3,this.id); }, - get boundingbox() { + boundingbox() { var diameter = this.radius*2*this.gameobject.scale; return cwh2bb(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]); }, @@ -657,8 +655,6 @@ var circle2d = clone(collider2d, { complete_assign(circle, this.make_fns); - circle.obscure('boundingbox'); - return circle; }, diff --git a/source/scripts/debug.js b/source/scripts/debug.js index 723b505..8a61c52 100644 --- a/source/scripts/debug.js +++ b/source/scripts/debug.js @@ -85,7 +85,7 @@ var Debug = { draw() { if (this.draw_bb) - Game.objects.forEach(function(x) { bb_draw(x.boundingbox); }); + Game.objects.forEach(function(x) { bb_draw(x.boundingbox()); }); if (Game.paused()) gui_text("PAUSED", [0,0],1); diff --git a/source/scripts/editor.js b/source/scripts/editor.js index c8e51b9..ef617a9 100644 --- a/source/scripts/editor.js +++ b/source/scripts/editor.js @@ -166,7 +166,8 @@ var editor = { objs.forEach(function(x) { var newobj = this.edit_level.spawn(x.ur); - dainty_assign(newobj, x); + //dainty_assign(newobj, x); + Object.assign(newobj,x); newobj.pos = x.pos; newobj.angle = x.angle; duped.push(newobj); @@ -545,7 +546,7 @@ var editor = { var color = x.color ? x.color : [255,255,255]; GUI.text(x.toString(), world2screen(x.pos).add([0, 16]), 1, color); GUI.text(x.pos.map(function(x) { return Math.round(x); }), world2screen(x.pos), 1, color); - Debug.arrow(world2screen(x.pos), world2screen(x.pos.add(x.up.scale(40))), Color.yellow, 1); + Debug.arrow(world2screen(x.pos), world2screen(x.pos.add(x.up().scale(40))), Color.yellow, 1); if (x.hasOwn('varname')) GUI.text(x.varname, world2screen(x.pos).add([0,32]), 1, [84,110,255]); if ('gizmo' in x && typeof x['gizmo'] === 'function' ) x.gizmo(); @@ -763,6 +764,8 @@ editor.inputs['C-d'] = function() { }; editor.inputs['C-d'].doc = "Duplicate all selected objects."; +editor.inputs.f3 = function() { editor.selectlist.forEach(x => Log.say(JSON.stringify(x,null,2))); }; + editor.inputs['C-m'] = function() { if (editor.sel_comp) { if (editor.sel_comp.flipy) @@ -792,8 +795,8 @@ editor.inputs.q.doc = "Toggle help for the selected component."; editor.inputs.f = function() { if (editor.selectlist.length === 0) return; - var bb = editor.selectlist[0].boundingbox; - editor.selectlist.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox); }); + var bb = editor.selectlist[0].boundingbox(); + editor.selectlist.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox()); }); editor.zoom_to_bb(bb); }; editor.inputs.f.doc = "Find the selected objects."; diff --git a/source/scripts/entity.js b/source/scripts/entity.js index 2938f51..f51414a 100644 --- a/source/scripts/entity.js +++ b/source/scripts/entity.js @@ -22,6 +22,12 @@ var gameobject = { return ur.type.make(this); }, + clone(name, ext) { + var obj = Object.create(this); + complete_assign(obj, ext); + return obj; + }, + layer: 0, /* Collision layer; should probably have been called "mask" */ layer_nuke() { Nuke.label("Collision layer"); @@ -38,21 +44,7 @@ var gameobject = { this.draw_layer = Nuke.radio(i, this.draw_layer, i); }, - in_air() { - return q_body(7, this.body); - }, - on_ground() { return !this.in_air(); }, - - name: "gameobject", - - toString() { return this.name; }, - - clone(name, ext) { - var obj = Object.create(this); - complete_assign(obj, ext); - return obj; - }, dup(diff) { var dup = World.spawn(gameobjects[this.from]); @@ -60,12 +52,6 @@ var gameobject = { return dup; }, - instandup() { - var dup = World.spawn(gameobjects[this.from]); - dup.pos = this.pos; - dup.velocity = this.velocity; - }, - ed_locked: false, _visible: true, @@ -85,9 +71,6 @@ var gameobject = { kinematic: 1, static: 2 }, - - get moi() { return q_body(6, this.body); }, - set moi(x) { set_body(13, this.body, x); }, phys: 2, phys_nuke() { @@ -103,11 +86,6 @@ var gameobject = { flipx: false, flipy: false, - body: -1, - get controlled() { - return Player.obj_controlled(this); - }, - set_center(pos) { var change = pos.sub(this.pos); this.pos = pos; @@ -138,65 +116,24 @@ var gameobject = { }, angle: 0, - get relangle() { if (!this.level) return this.angle; - return this.angle - this.level.angle; }, + + velocity: [0,0], + angularvelocity: 0, - get velocity() { return q_body(3, this.body); }, - set velocity(x) { set_body(9, this.body, x); }, - get angularvelocity() { return Math.rad2deg(q_body(4, this.body)); }, - set angularvelocity(x) { if (this.alive) set_body(8, this.body, Math.deg2rad(x)); }, - - get alive() { return this.body >= 0; }, - - disable() { - this.components.forEach(function(x) { x.disable(); }); - - }, - - enable() { - this.components.forEach(function(x) { x.enable(); }); - }, - - sync() { - if (this.body === -1) return; - cmd(55, this.body, this.flipx); - cmd(56, this.body, this.flipy); - set_body(2, this.body, this.pos); - set_body(0, this.body, Math.deg2rad(this.angle)); - cmd(36, this.body, this.scale); - set_body(10,this.body,this.elasticity); - set_body(11,this.body,this.friction); - set_body(1, this.body, this.phys); - cmd(75,this.body,this.layer); - cmd(54, this.body); - }, - - syncall() { - this.instances.forEach(function(x) { x.sync(); }); - }, - - pulse(vec) { /* apply impulse */ - set_body(4, this.body, vec); - }, - - push(vec) { /* apply force */ - set_body(12,this.body,vec); - }, - gizmo: "", /* Path to an image to draw for this gameobject */ /* Bounding box of the object in world dimensions */ - get boundingbox() { + boundingbox() { var boxes = []; boxes.push({t:0, r:0,b:0,l:0}); for (var key in this.components) { if ('boundingbox' in this.components[key]) - boxes.push(this.components[key].boundingbox); + boxes.push(this.components[key].boundingbox()); } if (boxes.empty) return cwh2bb([0,0], [0,0]); @@ -220,71 +157,21 @@ var gameobject = { return bb ? bb : cwh2bb([0,0], [0,0]); }, - set width(x) {}, - get width() { - var bb = this.boundingbox; + width() { + var bb = this.boundingbox(); return bb.r - bb.l; }, - set height(x) {}, - get height() { - var bb = this.boundingbox; + + height() { + var bb = this.boundingbox(); return bb.t-bb.b; }, stop() {}, - kill() { - if (this.body === -1) { - Log.warn(`Object is already dead!`); - return; - } - - - - Register.endofloop(() => { - cmd(2, this.body); - delete Game.objects[this.body]; - - if (this.level) - this.level.unregister(this); - - Player.uncontrol(this); - this.instances.remove(this); - Register.unregister_obj(this); -// Signal.clear_obj(this); - - this.body = -1; - for (var key in this.components) { - Register.unregister_obj(this.components[key]); - this.components[key].kill(); - } - - this.objects.forEach(x => x.kill()); - - this.stop(); - }); - }, - - get up() { - return [0,1].rotate(Math.deg2rad(this.angle)); - }, - - get down() { - return [0,-1].rotate(Math.deg2rad(this.angle)); - }, - - get right() { - return [1,0].rotate(Math.deg2rad(this.angle)); - }, - - get left() { - return [-1,0].rotate(Math.deg2rad(this.angle)); - }, - /* Make a unique object the same as its prototype */ revert() { - unmerge(this, this.prop_obj()); - this.sync(); +// unmerge(this, this.prop_obj()); }, gui() { @@ -298,8 +185,6 @@ var gameobject = { } }, - world2this(pos) { return cmd(70, this.body, pos); }, - this2world(pos) { return cmd(71, this.body,pos); }, check_registers(obj) { Register.unregister_obj(this); @@ -344,7 +229,7 @@ var gameobject = { this.mass, this.friction, this.elasticity) ); - obj.sync(); + obj.defn('components', {}); Game.register_obj(obj); @@ -353,33 +238,101 @@ var gameobject = { /* Now that it's concrete in the engine, these functions update to return engine data */ complete_assign(obj, { - set scale(x) { cmd(36, obj.body, x); }, - get scale() { return cmd(103, obj.body); }, - get flipx() { return cmd(104,obj.body); }, - set flipx(x) { cmd(55, obj.body, x); }, - get flipy() { return cmd(105,obj.body); }, - set flipy(x) { cmd(56, obj.body, x); }, + set scale(x) { cmd(36, this.body, x); }, + get scale() { return cmd(103, this.body); }, + get flipx() { return cmd(104,this.body); }, + set flipx(x) { cmd(55, this.body, x); }, + get flipy() { return cmd(105,this.body); }, + set flipy(x) { cmd(56, this.body, x); }, - get angle() { return Math.rad2deg(q_body(2,obj.body))%360; }, - set angle(x) { set_body(0,obj.body, Math.deg2rad(x)); }, + get angle() { return Math.rad2deg(q_body(2,this.body))%360; }, + set angle(x) { set_body(0,this.body, Math.deg2rad(x)); }, set pos(x) { var diff = x.sub(this.pos); this.objects.forEach(function(x) { x.pos = x.pos.add(diff); }); - set_body(2,obj.body,x); }, - get pos() { return q_body(1,obj.body); }, + set_body(2,this.body,x); }, + get pos() { return q_body(1,this.body); }, - get elasticity() { return cmd(107,obj.body); }, - set elasticity(x) { cmd(106,obj.body,x); }, + get elasticity() { return cmd(107,this.body); }, + set elasticity(x) { cmd(106,this.body,x); }, - get friction() { return cmd(109,obj.body); }, - set friction(x) { cmd(108,obj.body,x); }, + get friction() { return cmd(109,this.body); }, + set friction(x) { cmd(108,this.body,x); }, - set mass(x) { set_body(7,obj.body,x); }, - get mass() { return q_body(5, obj.body); }, + set mass(x) { set_body(7,this.body,x); }, + get mass() { return q_body(5, this.body); }, - set phys(x) { set_body(1, obj.body, x); }, - get phys() { return q_body(0,obj.body); }, + set phys(x) { set_body(1, this.body, x); }, + get phys() { return q_body(0,this.body); }, + get velocity() { return q_body(3, this.body); }, + set velocity(x) { set_body(9, this.body, x); }, + get angularvelocity() { return Math.rad2deg(q_body(4, this.body)); }, + set angularvelocity(x) { set_body(8, this.body, Math.deg2rad(x)); }, + pulse(vec) { set_body(4, this.body, vec);}, + + push(vec) { set_body(12,this.body,vec);}, + world2this(pos) { return cmd(70, this.body, pos); }, + this2world(pos) { return cmd(71, this.body,pos); }, + set layer(x) { cmd(75,this.body,x); }, + get layer() { return 0; }, + alive() { return this.body >= 0; }, + in_air() { return q_body(7, this.body);}, + on_ground() { return !this.in_air(); }, + + disable() { this.components.forEach(function(x) { x.disable(); });}, + enable() { this.components.forEach(function(x) { x.enable(); });}, + sync() { }, + + kill() { + if (this.body === -1) { + Log.warn(`Object is already dead!`); + return; + } + + Register.endofloop(() => { + cmd(2, this.body); + delete Game.objects[this.body]; + + if (this.level) + this.level.unregister(this); + + Player.uncontrol(this); + this.instances.remove(this); + Register.unregister_obj(this); + // Signal.clear_obj(this); + + this.body = -1; + for (var key in this.components) { + Register.unregister_obj(this.components[key]); + this.components[key].kill(); + } + + this.objects.forEach(x => x.kill()); + + 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));}, + + toJSON() { + var ret = {}; + for (var key in this) { + var prop = Object.getOwnPropertyDescriptor(this, key); + if (!prop) continue; + if (prop.get) { + if (prop.get() !== Object.getPrototypeOf(this)[key]) + ret[key] = prop.get(); + } + else + ret[key] = this[key]; + } + return ret; + }, }); for (var prop in obj) { @@ -449,10 +402,6 @@ gameobject.make_parentable = function(obj) { obj.objects = objects; } -var locks = ['height', 'width', 'visible', 'body', 'controlled', 'selectable', 'save', 'velocity', 'angularvelocity', 'alive', 'boundingbox', 'name', 'scale', 'angle', 'properties', 'moi', 'relpos', 'relangle', 'up', 'down', 'right', 'left', 'bodytype', 'gizmo', 'pos']; -locks.forEach(x => gameobject.obscure(x)); - - /* Default objects */ var prototypes = {}; prototypes.ur = {};