From 8f455476f133154f842c6d51ec4ebd56fd82e0f3 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 11 Oct 2023 22:22:41 +0000 Subject: [PATCH] Start and restart play mode --- scripts/base.js | 41 +++++------- scripts/components.js | 73 ++++++++++----------- scripts/debug.js | 4 +- scripts/editor.js | 133 ++++++++++++++------------------------ scripts/engine.js | 5 ++ scripts/entity.js | 35 +++++----- scripts/input.js | 4 +- scripts/sound.js | 2 +- source/engine/2dphysics.c | 4 +- 9 files changed, 129 insertions(+), 172 deletions(-) diff --git a/scripts/base.js b/scripts/base.js index c242997..3e38e51 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -43,6 +43,14 @@ Object.rkeys = function(o) return keys; } +Object.extend = function(from, src) +{ + var n = {}; + Object.mixin(n, from); + Object.mixin(n, src); + return n; +} + Object.mixin = function(target, source) { if (typeof source !== 'object') return target; @@ -57,6 +65,15 @@ Object.mixin = function(target, source) return target; }; +Object.deepmixin = function(target, source) +{ + var o = source; + while (o !== Object.prototype) { + Object.mixin(target, o); + o = o.__proto__; + }; +} + Object.deepfreeze = function(obj) { for (var key in obj) { @@ -67,23 +84,6 @@ Object.deepfreeze = function(obj) } /* Goes through each key and overwrites if it's present */ -/* -Object.dainty_assign = function(target, source) -{ -Object.keys(target).forEach(function(key) { - if (!(key in source)) return; - - if (typeof target[key] === 'function') return; - - if (Array.isArray(target[key])) - target[key] = deep_copy(source[key]); - else if (typeof target[key] === 'object') - Object.dainty_assign(target[key], source[key]); - else - target[key] = source[key]; - }); -} -*/ Object.dainty_assign = function(target, source) { Object.keys(source).forEach(function(k) { @@ -230,13 +230,6 @@ Object.defineProperty(Object.prototype, 'nulldef', { } }); -/*Object.defineProperty(Object.prototype, 'writable', { - value: function(name) { - return Object.getPropertyDescriptor(this, name).writable; - } -}); -*/ - Object.defineProperty(Object.prototype, 'prop_obj', { value: function() { return JSON.parse(JSON.stringify(this)); } }); diff --git a/scripts/components.js b/scripts/components.js index 8071d8f..cf1e68c 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -324,11 +324,14 @@ var collider2d = Object.copy(component, { register_hit(fn, obj) { register_collide(1, fn, obj, this.gameobject.body, this.shape); }, -/* set sensor(x) { cmd(18,this.shape,x); }, + + impl: { + set sensor(x) { cmd(18,this.shape,x); }, get sensor() { return cmd(21,this.shape); }, - set enabled(x) { cmd(22,this.shape,x); }, - get enabled() { return cmd(23,this.shape); } -*/ +// set enabled(x) { cmd(22,this.shape,x); }, +// get enabled() { return cmd(23,this.shape); } + }, + }); collider2d.inputs = {}; @@ -403,14 +406,14 @@ component.polygon2d = Object.copy(collider2d, { }, }); -component.polygon2d.impl = { +component.polygon2d.impl = Object.extend(collider2d.impl, { sync() { cmd_poly2d(0, this.id, this.spoints); }, query() { return cmd(80, this.shape); }, -}; +}); var polygon2d = component.polygon2d; @@ -448,7 +451,6 @@ component.edge2d = Object.copy(collider2d, { degrees:2, dimensions:2, thickness:0, - points: [], /* open: 0 clamped: 1 beziers: 2 @@ -524,7 +526,7 @@ component.edge2d = Object.copy(collider2d, { assert knots%order != 0 */ - if (this.type === typeid.this.looped) + if (this.type === component.edge2d.typeid.this.looped) return spline_cmd(0, this.degrees, this.dimensions, 0, spoints.wrapped(this.degrees), n); return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n); @@ -536,17 +538,9 @@ component.edge2d = Object.copy(collider2d, { return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); }, - make(go) { - var edge = Object.create(this); - edge.gameobject = go; -// edge.cpoints = []; -// edge.points = []; - Object.assign(edge, make_edge2d(go.body, edge.points, 0)); - Object.mixin(edge,edge.impl); - Object.hide(edge, 'gameobject', 'id', 'shape'); - return edge; - }, - + hides: ['gameobject', 'id', 'shape', 'points'], + _enghook: make_edge2d, + /* EDITOR */ gizmo() { this.spoints.forEach(function(x) { @@ -569,24 +563,23 @@ component.edge2d = Object.copy(collider2d, { get pos() { return p; }, sync: this.sync.bind(this), }; - return undefined; }, }); -component.edge2d.impl = { +component.edge2d.impl = Object.extend(collider2d.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); + var points = this.sample(this.samples); + cmd_edge2d(0,this.id,points); this.sensor = sensor; }, -}; +}); var bucket = component.edge2d; bucket.inputs = {}; @@ -655,6 +648,8 @@ bucket.inputs['C-M-lm'] = function() { }; bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline."; +bucket.inputs.lm = function(){}; + bucket.inputs['C-lm'] = function() { var idx = 0; @@ -670,13 +665,15 @@ bucket.inputs['C-lm'] = function() { }; bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position."; -bucket.inputs['S-lm'] = function() { - var idx = grab_from_points(screen2world(Mouse.pos), this.cpoints.map(function(x) {return x.add(this.gameobject.pos); }, this), 25); +bucket.inputs['C-M-lm'] = function() { + var idx = cmd(59, Mouse.worldpos.sub(this.gameobject.pos), this.cpoints, 250); + Log.warn(idx); +// var idx = grab_from_points(screen2world(Mouse.pos), this.cpoints.map(function(x) {return x.add(this.gameobject.pos); }, this), 25); if (idx === -1) return; this.cpoints.splice(idx, 1); }; -bucket.inputs['S-lm'].doc = "Remove point from the spline."; +bucket.inputs['C-M-lm'].doc = "Remove point from the spline."; bucket.inputs.lb = function() { var np = []; @@ -703,17 +700,6 @@ bucket.inputs.rb.doc = "Rotate the points CW."; bucket.inputs.rb.rep = true; component.circle2d = Object.copy(collider2d, { - impl: { - set radius(x) { cmd_circle2d(0,this.id,x); }, - get radius() { return cmd_circle2d(2,this.id); }, - - set scale(x) { this.radius = x; }, - get scale() { return this.radius; }, - - set offset(x) { cmd_circle2d(1,this.id,x); }, - get offset() { return cmd_circle2d(3,this.id); }, - }, - radius:10, offset:[0,0], toString() { return "circle2d"; }, @@ -727,6 +713,17 @@ component.circle2d = Object.copy(collider2d, { _enghook: make_circle2d, }); +component.circle2d.impl = Object.extend(collider2d.impl, { + set radius(x) { cmd_circle2d(0,this.id,x); }, + get radius() { return cmd_circle2d(2,this.id); }, + + set scale(x) { this.radius = x; }, + get scale() { return this.radius; }, + + set offset(x) { cmd_circle2d(1,this.id,x); }, + get offset() { return cmd_circle2d(3,this.id); }, +}); + /* ASSETS */ var Texture = { diff --git a/scripts/debug.js b/scripts/debug.js index cf12e67..691f115 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -154,8 +154,8 @@ DebugControls.inputs.f1.doc = "Draw physics debugging aids."; //DebugControls.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; }; //DebugControls.inputs.f3.doc = "Toggle drawing bounding boxes."; DebugControls.inputs.f4 = function() { - Debug.draw_names = !Debug.draw_names; - Debug.draw_gizmos = !Debug.draw_gizmos; +// Debug.draw_names = !Debug.draw_names; +// Debug.draw_gizmos = !Debug.draw_gizmos; }; DebugControls.inputs.f4.doc = "Toggle drawing gizmos and names of objects."; diff --git a/scripts/editor.js b/scripts/editor.js index 9de23b6..8495c63 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -197,10 +197,10 @@ var editor = { stash: undefined, start_play_ed() { - this.stash = this.edit_level.json_obj(); - this.edit_level.kill(); -// load_configs("game.config"); + this.stash = this.desktop.instance_obj(); + Primum.clear(); Game.play(); + Game.editor_mode(false); Player.players[0].uncontrol(this); Player.players[0].control(limited_editor); Register.unregister_obj(this); @@ -215,6 +215,16 @@ var editor = { Debug.register_call(editor.ed_debug, editor); Register.update.register(gui_controls.update, gui_controls); Player.players[0].control(gui_controls); + + this.desktop = Primum.spawn(ur.arena); + this.edit_level = this.desktop; + editor.edit_level._ed.selectable = false; + if (this.stash) { + this.desktop.make_objs(this.stash.objects); + Object.dainty_assign(this.desktop, this.stash); + } + this.selectlist = []; + Game.view_camera(editor.camera); }, end_debug() { @@ -356,23 +366,6 @@ var editor = { } }, - clear_level() { - if (this.edit_level) { - if (this.edit_level.level) { - this.openpanel(gen_notify("Can't close a nested level. Save up to the root before continuing.")); - return; - } - this.unselect(); - this.edit_level.kill(); - } - - this.edit_level = Primum.spawn(ur.arena); - this.desktop = this.edit_level; - if (this.stash) - - editor.edit_level._ed.selectable = false; - }, - load_desktop(d) { }, @@ -663,13 +656,13 @@ editor.inputs['C-e'].doc = "Open asset explorer."; editor.inputs['C-l'] = function() { editor.openpanel(entitylistpanel); }; editor.inputs['C-l'].doc = "Open list of spawned entities."; -/*editor.inputs['C-i'] = function() { +editor.inputs['C-i'] = function() { if (editor.selectlist.length !== 1) return; objectexplorer.obj = editor.selectlist[0]; editor.openpanel(objectexplorer); }; editor.inputs['C-i'].doc = "Open the object explorer for a selected object."; -*/ + editor.inputs['C-d'] = function() { if (editor.selectlist.length === 0) return; var duped = editor.dup_objects(editor.selectlist); @@ -854,13 +847,14 @@ editor.inputs['M-t'] = function() { editor.edit_level.objects.forEach(function(x editor.inputs['M-t'].doc = "Unlock all objects in current level."; editor.inputs['C-n'] = function() { - if (editor.edit_level._ed.dirty) { +/* if (editor.edit_level._ed.dirty) { Log.info("Level has changed; save before starting a new one."); editor.openpanel(gen_notify("Level is changed. Are you sure you want to close it?", _ => editor.clear_level())); return; } - editor.clear_level(); + editor.clear_level(); +*/ }; editor.inputs['C-n'].doc = "Open a new level."; @@ -1631,23 +1625,23 @@ var objectexplorer = Object.copy(inputpanel, { obj: undefined, previous: [], start() { - this.previous = []; Input.setnuke(); }, - on_close() { Input.setgame(); }, - - input_enter_pressed() {}, - goto_obj(obj) { if (obj === this.obj) return; this.previous.push(this.obj); this.obj = obj; }, + prev_obj() { + this.obj = this.previous.pop(); + }, + guibody() { - Nuke.label("Examining " + this.obj); + var items = []; + items.push(Mum.text({str:"Examining " + this.obj})); var n = 0; var curobj = this.obj; @@ -1657,23 +1651,14 @@ var objectexplorer = Object.copy(inputpanel, { } n--; - Nuke.newline(n); curobj = this.obj.__proto__; while (curobj) { - if (Nuke.button(curobj.toString())) - this.goto_obj(curobj); - + items.push(Mum.text({str:curobj.toString(), action:this.goto_obj(curobj)})); curobj = curobj.__proto__; } - Nuke.newline(2); - - if (this.previous.empty) - Nuke.label(""); - else { - if (Nuke.button("prev: " + this.previous.last)) - this.obj = this.previous.pop(); - } + if (!this.previous.empty) + items.push(Mum.text({str:"prev: " + this.previous.last, action: this.prev_obj})); Object.getOwnPropertyNames(this.obj).forEach(key => { var descriptor = Object.getOwnPropertyDescriptor(this.obj, key); @@ -1688,70 +1673,52 @@ var objectexplorer = Object.copy(inputpanel, { var name = (hidden ? "[hidden] " : "") + key; var val = this.obj[key]; - var nuke_str = key + "_nuke"; - if (nuke_str in this.obj) { - this.obj[nuke_str](); - if (key in this.obj.__proto__) { - if (Nuke.button("delete " + key)) { - if (("_" + key) in this.obj) - delete this.obj["_"+key]; - else - delete this.obj[key]; - } - } - } else switch (typeof val) { case 'object': if (val) { if (Array.isArray(val)) { - this.obj[key] = Nuke.pprop(key,val); +// this.obj[key] = Nuke.pprop(key,val); break; } - Nuke.newline(2); - Nuke.label(name); - if (Nuke.button(val.toString())) this.goto_obj(val); +// Nuke.newline(2); + items.push(Mum.text({str:name})); + items.push(Mum.text({str:val.toString(), action: this.goto_obj.bind(val)})); } else { - this.obj[key] = Nuke.pprop(key,val); +// this.obj[key] = Nuke.pprop(key,val); } break; case 'function': - Nuke.newline(2); - Nuke.label(name); - Nuke.label("function"); + items.push(Mum.text({str:name})); + items.push(Mum.text({str:"function"})); break; default: if (!hidden) {// && Object.getOwnPropertyDescriptor(this.obj, key).writable) { - if (key.startsWith('_')) key = key.slice(1); +// this.obj[key] = Nuke.pprop(key, this.obj[key]); - this.obj[key] = Nuke.pprop(key, this.obj[key]); - - if (key in this.obj.__proto__) { +/* if (key in this.obj.__proto__) { if (Nuke.button("delete " + key)) { if ("_"+key in this.obj) delete this.obj["_"+key]; else delete this.obj[key]; } - } + }*/ } else { - Nuke.newline(2); - Nuke.label(name); - Nuke.label(val.toString()); + items.push(Mum.text({str:name})); + items.push(Mum.text({str:val.toString()})); } break; } }); - Nuke.newline(); - Nuke.label("Properties that can be pulled in ..."); - Nuke.newline(3); + items.push(Mum.text({str:"Properties that can be pulled in ..."})); +// Nuke.newline(3); var pullprops = []; for (var key in this.obj.__proto__) { - if (key.startsWith('_')) key = key.slice(1); if (!this.obj.hasOwn(key)) { if (typeof this.obj[key] === 'object' || typeof this.obj[key] === 'function') continue; pullprops.push(key); @@ -1761,13 +1728,12 @@ var objectexplorer = Object.copy(inputpanel, { pullprops = pullprops.sort(); pullprops.forEach(function(key) { - if (Nuke.button(key)) - this.obj[key] = this.obj[key]; - }, this); + items.push(Mum.text({str:key})); +// this.obj[key] = this.obj[key]; + }); - Game.objects.forEach(function(x) { x.sync(); }); - - Nuke.newline(); +// Game.objects.forEach(function(x) { x.sync(); }); + return items; }, @@ -1994,10 +1960,9 @@ limited_editor.inputs['M-p'] = function() limited_editor.inputs['C-q'] = function() { Sound.killall(); + Primum.clear(); + editor.enter_editor(); - Primum.clear_all(); - editor.load_json(editor.stash); - Game.view_camera(editor.camera); } limited_editor.inputs['M-q'] = function() @@ -2013,10 +1978,10 @@ if (IO.exists("editor.config")) load_configs("editor.config"); /* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */ -editor.clear_level(); editor.camera = Game.camera; Game.stop(); Game.editor_mode(true); +Debug.draw_phys(true); editor.enter_editor(); diff --git a/scripts/engine.js b/scripts/engine.js index c523a73..17732d4 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -600,6 +600,11 @@ var Game = { register_obj(obj) { this.objects[obj.body] = obj; }, + + unregister_obj(obj) { + if (this.objects[obj.body] === obj) + this.objects[obj.body] = undefined; + }, /* Returns an object given an id */ object(id) { diff --git a/scripts/entity.js b/scripts/entity.js index 9bffd26..ad80fbb 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -131,9 +131,9 @@ var gameobject = { in_air() { return q_body(7, this.body);}, on_ground() { return !this.in_air(); }, spawn_from_instance(inst) { - var ur = prototypes.get_ur(inst.ur); - + return this.spawn(inst.ur, inst); }, + spawn(ur, data) { if (typeof ur === 'string') ur = prototypes.get_ur(ur); @@ -380,19 +380,24 @@ var gameobject = { // Register.endofloop(() => { cmd(2, this.body); - delete Game.objects[this.body]; - if (this.level) + Game.unregister_obj(this); + + if (this.level) { this.level.remove_obj(this); + this.level = undefined; + } Player.uncontrol(this); Register.unregister_obj(this); - this.instances.remove(this); +// this.instances.remove(this); this.body = -1; for (var key in this.components) { Register.unregister_obj(this.components[key]); this.components[key].kill(); + this.components.gameobject = undefined; } + delete this.components; for (var key in this.objects) this.objects[key].kill(); @@ -406,13 +411,12 @@ var gameobject = { 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));}, - instances: [], make(level, data) { level ??= Primum; var obj = Object.create(this); obj.level = level; - this.instances.push(obj); +// this.instances.push(obj); obj.body = make_gameobject(); obj.components = {}; obj.objects = {}; @@ -441,33 +445,24 @@ var gameobject = { } }; - if (this.objects) { - for (var prop in this.objects) { - var o = this.objects[prop]; - var newobj = obj.spawn(o.ur, o); - if (!newobj) continue; - obj.rename_obj(newobj.toString(), prop); - } - } + if (this.objects) + obj.make_objs(this.objects); Object.dainty_assign(obj, this); obj.sync(); gameobject.check_registers(obj); - if (typeof obj.start === 'function') obj.start(); + if (Game.playing() && typeof obj.start === 'function') obj.start(); return obj; }, make_objs(objs) { for (var prop in objs) { - var o = objs[prop]; - var newobj = this.spawn(o.ur, o); + var newobj = this.spawn_from_instance(objs[prop]); if (!newobj) continue; this.rename_obj(newobj.toString(), prop); - Log.warn(`setting object ${prop} to ${JSON.stringify(o)}`); -// Object.assign(newobj,o); } }, diff --git a/scripts/input.js b/scripts/input.js index 1ed6299..f4ddecc 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -153,9 +153,9 @@ var Player = { if (typeof fn === 'function') { fn.call(pawn, ... args); pawn.inputs.post?.call(pawn); - if (!pawn.inputs.fallthru) - return; } + + if (!pawn.inputs.fallthru) return; } }, diff --git a/scripts/sound.js b/scripts/sound.js index d4d9f8b..22ae55c 100644 --- a/scripts/sound.js +++ b/scripts/sound.js @@ -20,7 +20,7 @@ var Sound = { sounds: [], /* array of loaded sound files */ play(file) { if (!IO.exists(file)) { - Log.warn(`Cannot play sound ${file}: does not exist.`); + Log.error(`Cannot play sound ${file}: does not exist.`); return; } this.id = cmd(14,file); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 365b0fa..22f09ad 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -607,8 +607,10 @@ struct postphys_cb { static struct postphys_cb *begins = NULL; void flush_collide_cbs() { - for (int i = 0; i < arrlen(begins); i++) + for (int i = 0; i < arrlen(begins); i++) { script_callee(begins[i].c, 1, &begins[i].send); + JS_FreeValue(js, begins[i].send); + } arrsetlen(begins,0); }