From b9db31c84ed35a67eaefaf77dbe1bc97b4321b8a Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 29 Nov 2023 18:40:13 +0000 Subject: [PATCH] nodes,gameobjects cleanup --- docs/scripting.md | 12 +- scripts/base.js | 23 ++ scripts/color.js | 202 ++++++++++++++++++ scripts/debug.js | 6 +- scripts/editor.js | 112 +++------- scripts/engine.js | 423 ++----------------------------------- scripts/entity.js | 184 ++++++++-------- scripts/gui.js | 189 ----------------- scripts/physics.js | 13 +- source/engine/gameobject.c | 14 +- source/engine/gameobject.h | 1 + source/engine/input.c | 2 +- source/engine/jsffi.c | 199 +++++++++-------- source/engine/script.c | 8 +- source/engine/sound/dsp.c | 1 + source/engine/sprite.c | 1 + 16 files changed, 501 insertions(+), 889 deletions(-) create mode 100644 scripts/color.js diff --git a/docs/scripting.md b/docs/scripting.md index 1fd7fa8..8a8945c 100644 --- a/docs/scripting.md +++ b/docs/scripting.md @@ -1,5 +1,9 @@ # Yugine Scripting Guide +Primum programs are organized into two different types of source files: scripts and entities. Scripts end with .js, entities end with .jso. + +## Scripts + Script hooks exist to allow to modification of the game. |config.js|called before any game play, including play from editor| @@ -9,7 +13,13 @@ Script hooks exist to allow to modification of the game. |debug.js|called when play in editor is selected, after level load| |dbgret.js|called when play in editor returns to editor| -All objects in the Yugine can have an associated script. This script can perform setup, teardown, and handles responses for the object. +In addition, any script can be run by running "load". + +## Entities + +Entities are defined in a jso file. The "this" parameter in the jso file is a reference to the actor, allowing you to define properties on it. + +Computation takes place in turns. Each entity has functions called, if they exist. If a machine has multiple threads, multiple entities may be taking turns at a time. |function|description| |---|---| diff --git a/scripts/base.js b/scripts/base.js index 9dafa9e..d76f8e4 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -23,6 +23,17 @@ Promise = undefined; Set = undefined; WeakSet = undefined; +var json = {}; +json.encode = function(value, space, replacer, whitelist) +{ + return JSON.stringify(value, space, replacer); +} + +json.decode = function(text, reviver) +{ + return JSON.parse(text,reviver); +} + Object.methods = function(o) { var m = []; @@ -31,6 +42,7 @@ Object.methods = function(o) }); return m; } +Object.methods.doc = "Retun an array of all functions an object has access to."; Object.dig = function(obj, path, def) { @@ -43,6 +55,17 @@ Object.dig = function(obj, path, def) return def; } +Object.samenewkeys = function(a,b) +{ + b ??= a.__proto__; + var ret = {}; + ret.same = []; + ret.unique = []; + Object.keys(a).forEach(key => (key in b) ? ret.same.push(key) : ret.unique.push(key)); + return ret; +} +Object.samenewkeys.doc = "Return an object listing which keys are the same and unique on a compared to b."; + Object.rkeys = function(o) { var keys = []; diff --git a/scripts/color.js b/scripts/color.js new file mode 100644 index 0000000..0abe426 --- /dev/null +++ b/scripts/color.js @@ -0,0 +1,202 @@ +var Color = { + white: [255,255,255], + black: [0,0,0], + blue: [84,110,255], + green: [120,255,10], + yellow: [251,255,43], + red: [255,36,20], + teal: [96, 252, 237], + gray: [181,181,181], + cyan: [0,255,255], + purple: [162,93,227], +}; + +Color.editor = {}; +Color.editor.ur = Color.green; + +Color.tohtml = function(v) +{ + var html = v.map(function(n) { return Number.hex(n*255); }); + return "#" + html.join(''); +} + +Color.toesc = function(v) +{ + return Esc.color(v); +} + +var Esc = {}; +Esc.reset = "\x1b[0"; +Esc.color = function(v) { + var c = v.map(function(n) { return Math.floor(n*255); }); + var truecolor = "\x1b[38;2;" + c.join(';') + ';'; + return truecolor; +} + +Color.Arkanoid = { + orange: [255,143,0], + teal: [0,255,255], + green: [0,255,0], + red: [255,0,0], + blue: [0,112,255], + purple: [255,0,255], + yellow: [255,255,0], + silver: [157,157,157], + gold: [188,174,0], +}; + +Color.Arkanoid.Powerups = { + red: [174,0,0], /* laser */ + blue: [0,0,174], /* enlarge */ + green: [0,174,0], /* catch */ + orange: [224,143,0], /* slow */ + purple: [210,0,210], /* break */ + cyan: [0,174,255], /* disruption */ + gray: [143,143,143] /* 1up */ +}; + +Color.Gameboy = { + darkest: [229,107,26], + dark: [229,189,26], + light: [189,229,26], + lightest: [107,229,26], +}; + +Color.Apple = { + green: [94,189,62], + yellow: [255,185,0], + orange: [247,130,0], + red: [226,56,56], + purple: [151,57,153], + blue: [0,156,223] +}; + +Color.Debug = { + boundingbox: Color.white, + names: [84,110,255], +}; + +Color.Editor = { + grid: [99,255,128], + select: [255,255,55], + newgroup: [120,255,10], +}; + +/* Detects the format of all colors and munges them into a floating point format */ +Color.normalize = function(c) { + var add_a = function(a) { + var n = this.slice(); + n.a = a; + return n; + }; + + for (var p of Object.keys(c)) { + var fmt = "nrm"; + if (typeof c[p] !== 'object') continue; + if (!Array.isArray(c[p])) { + Color.normalize(c[p]); + continue; + } + + for (var color of c[p]) { + if (color > 1) { + fmt = "8b"; + break; + } + } + + switch(fmt) { + case "8b": + c[p] = c[p].map(function(x) { return x/255; }); + } + c[p].alpha = add_a; + } +}; + +Color.normalize(Color); + +Object.deepfreeze(Color); + +var ColorMap = {}; +ColorMap.makemap = function(map) +{ + var newmap = Object.create(ColorMap); + Object.assign(newmap, map); + return newmap; +} +ColorMap.Jet = ColorMap.makemap({ + 0: [0,0,131], + 0.125: [0,60,170], + 0.375: [5,255,255], + 0.625: [255,255,0], + 0.875: [250,0,0], + 1: [128,0,0] +}); + +ColorMap.BlueRed = ColorMap.makemap({ + 0: [0,0,255], + 1: [255,0,0] +}); + +ColorMap.Inferno = ColorMap.makemap({ + 0:[0,0,4], + 0.13: [31,12,72], + 0.25: [85,15,109], + 0.38: [136,34,106], + 0.5: [186,54,85], + 0.63: [227,89,51], + 0.75: [249,140,10], + 0.88: [249,201,50], + 1: [252,255,164] +}); + +ColorMap.Bathymetry = ColorMap.makemap({ + 0: [40,26,44], + 0.13: [59.49,90], + 0.25: [64,76,139], + 0.38: [63,110,151], + 0.5: [72,142,158], + 0.63: [85,174,163], + 0.75: [120,206,163], + 0.88: [187,230,172], + 1: [253,254,204] +}); + +ColorMap.Viridis = ColorMap.makemap({ + 0: [68,1,84], + 0.13: [71,44,122], + 0.25: [59,81,139], + 0.38: [44,113,142], + 0.5: [33,144,141], + 0.63: [39,173,129], + 0.75: [92,200,99], + 0.88: [170,220,50], + 1: [253,231,37] +}); + +Color.normalize(ColorMap); + +ColorMap.sample = function(t, map) +{ + map ??= this; + if (t < 0) return map[0]; + if (t > 1) return map[1]; + + var lastkey = 0; + for (var key of Object.keys(map).sort()) { + if (t < key) { + var b = map[key]; + var a = map[lastkey]; + var tt = (key - lastkey) * t; + return a.lerp(b, tt); + } + lastkey = key; + } + return map[1]; +} + +ColorMap.doc = { + sample: "Sample a given colormap at the given percentage (0 to 1).", +}; + +Object.freeze(ColorMap); diff --git a/scripts/debug.js b/scripts/debug.js index 283080e..935c354 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -85,18 +85,18 @@ var Debug = { draw() { if (this.draw_bb) - Game.objects.forEach(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); }); + Game.all_objects(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); }); if (Game.paused()) GUI.text("PAUSED", [0,0],1); if (this.draw_gizmos) - Game.objects.forEach(function(x) { + Game.all_objects(function(x) { if (!x.icon) return; GUI.image(x.icon, world2screen(x.pos)); }); if (this.draw_names) - Game.objects.forEach(function(x) { + Game.all_objects(function(x) { GUI.text(x, world2screen(x.pos).add([0,32]), 1, Color.Debug.names); }); diff --git a/scripts/editor.js b/scripts/editor.js index 74fa688..06b735c 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -4,23 +4,12 @@ */ prototypes.generate_ur('.'); -var editor_config = { +var editor = { + toString() { return "editor"; }, grid_size: 100, ruler_mark_px: 100, grid_color: Color.green.alpha(0.3), - -}; -var configs = { - toString() { return "configs"; }, - editor: editor_config, - physics: physics, - local: local_conf, - collision: Collision, -}; - -var editor = { - toString() { return "editor"; }, dbg_ur: "arena.level1", machine: undefined, device_test: undefined, @@ -34,7 +23,7 @@ var editor = { working_layer: 0, get cursor() { if (this.selectlist.length === 0 ) return Mouse.worldpos; - return find_com(this.selectlist); + return physics.com(this.selectlist.map(x => x.pos)); }, edit_mode: "basic", @@ -52,9 +41,9 @@ var editor = { }, /* Tries to select id */ - do_select(go) { - var obj = (go >= 0 ? Game.object(go) : undefined); - if (!obj || !obj._ed.selectable) return undefined; + do_select(obj) { + if (!obj) return; +// if (!obj || !obj._ed.selectable) return undefined; if (obj.level !== this.edit_level) { var testlevel = obj.level; @@ -102,7 +91,7 @@ var editor = { step_amt() { return Keys.shift() ? 10 : 1; }, on_grid(pos) { - return pos.every(function(x) { return x % editor_config.grid_size === 0; }); + return pos.every(function(x) { return x % editor.grid_size === 0; }); }, snapper(dir, grid) { @@ -115,7 +104,7 @@ var editor = { key_move(dir) { if (!editor.grabselect) return; if (Keys.ctrl()) - this.selectlist.forEach(this.snapper(dir.scale(1.01), editor_config.grid_size)); + this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size)); else this.selectlist.forEach(this.mover(dir.scale(this.step_amt()))); }, @@ -234,8 +223,6 @@ var editor = { Register.draw.register(editor.draw, 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); Primum.rename_obj(this.desktop.toString(), "desktop"); this.edit_level = this.desktop; @@ -313,17 +300,6 @@ var editor = { this.edit_level.check_dirty(); }, - diff_lvl(d) { - this.unselect(); - for (var key in d) { - if (d[key] === "DELETE") - Game.objects[key].kill(); - } - diffassign(Game.objects, d); - Game.objects.forEach(function(x) { x.sync(); }); - this.curlvl = this.edit_level.save(); - }, - redo() { if (this.backshots.empty) { Log.info("Nothing to redo."); @@ -336,17 +312,6 @@ var editor = { this.edit_level.load(dd); this.edit_level.check_dirty(); this.curlvl = dd; - return; - - var dd = this.backshots.pop(); - this.snapshots.push(dd); - if (this.was_undoing) { - dd = this.backshots.pop(); - this.snapshots.push(dd); - this.was_undoing = false; - } - - this.diff_lvl(dd); }, undo() { @@ -359,17 +324,6 @@ var editor = { var dd = this.snapshots.pop(); Object.dainty_assign(this.edit_level, dd); this.edit_level._ed.check_dirty(); - return; - - this.backshots.push(dd); - - if (!this.was_undoing) { - dd = this.snapshots.pop(); - this.backshots.push(dd); - this.was_undoing = true; - } - - this.diff_lvl(dd); }, restore_buffer() { @@ -511,7 +465,7 @@ var editor = { GUI.text(p, world2screen(x[1].worldpos().add([0,16])),1,editor.color_depths[depth]); }); - var mg = Game.obj_at(Mouse.worldpos); + var mg = physics.pos_query(Mouse.worldpos); if (mg) { var p = mg.path_from(thiso); @@ -536,15 +490,15 @@ var editor = { GUI.image("icons/icons8-lock-16.png", world2screen(obj.worldpos())); }); - Debug.draw_grid(1, editor_config.grid_size, Color.Editor.grid.alpha(0.3)); - var startgrid = screen2world([-20,0]).map(function(x) { return Math.snap(x, editor_config.grid_size); }); + Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3)); + var startgrid = screen2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); }); var endgrid = screen2world([Window.width, Window.height]); - var w_step = Math.round(editor_config.ruler_mark_px/Window.width * (endgrid.x-startgrid.x)/editor_config.grid_size)*editor_config.grid_size; - if (w_step === 0) w_step = editor_config.grid_size; + var w_step = Math.round(editor.ruler_mark_px/Window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size; + if (w_step === 0) w_step = editor.grid_size; - var h_step = Math.round(editor_config.ruler_mark_px/Window.height * (endgrid.y-startgrid.y)/editor_config.grid_size)*editor_config.grid_size; - if (h_step === 0) h_step = editor_config.grid_size; + var h_step = Math.round(editor.ruler_mark_px/Window.height * (endgrid.y-startgrid.y)/editor.grid_size)*editor.grid_size; + if (h_step === 0) h_step = editor.grid_size; while(startgrid[0] <= endgrid[0]) { GUI.text(startgrid[0], [world2screen([startgrid[0], 0])[0],0]); @@ -620,25 +574,6 @@ var editor = { this.unselect(); }, - groupsaveas(group, file) { - if (!file) return; - - file = file+".lvl"; - if (IO.exists(file)) { - this.openpanel(gen_notify("Level already exists with that name. Overwrite?", dosave.bind(this,file))); - return; - } else - dosave(file); - - function dosave(file) { - var com = find_com(group); - Level.saveas(group, file); - editor.addlevel(file, com); - - group.forEach(function(x) { x.kill(); }); - } - }, - /* Checking to save an entity as a subtype. */ /* sub is the name of the (sub)type; obj is the object to save it as */ saveas_check(sub, obj) { @@ -924,7 +859,8 @@ editor.inputs['C-s'] = function() { Object.values(saveobj.objects).forEach(function(x) { x._ed.check_dirty(); }); - Game.objects.forEach(function(x) { + + Game.all_objects(function(x) { if (typeof x !== 'object') return; if (!('_ed' in x)) return; if (x._ed.dirty) return; @@ -1141,7 +1077,7 @@ editor.inputs['C-mm'] = editor.inputs.mm; editor.inputs['C-M-lm'] = function() { - var go = Game.obj_at(Mouse.worldpos); + var go = physics.pos_query(Mouse.worldpos); if (!go) return; editor.edit_level = go.level; } @@ -1312,20 +1248,20 @@ editor.inputs['M-g'] = function() editor.inputs['M-g'].doc = "Move all."; editor.inputs['C-lb'] = function() { - editor_config.grid_size -= Keys.shift() ? 10 : 1; - if (editor_config.grid_size <= 0) editor_config.grid_size = 1; + editor.grid_size -= Keys.shift() ? 10 : 1; + if (editor.grid_size <= 0) editor.grid_size = 1; }; editor.inputs['C-lb'].doc = "Decrease grid size. Hold shift to decrease it more."; editor.inputs['C-lb'].rep = true; -editor.inputs['C-rb'] = function() { editor_config.grid_size += Keys.shift() ? 10 : 1; }; +editor.inputs['C-rb'] = function() { editor.grid_size += Keys.shift() ? 10 : 1; }; editor.inputs['C-rb'].doc = "Increase grid size. Hold shift to increase it more."; editor.inputs['C-rb'].rep = true; editor.inputs['C-c'] = function() { this.killring = []; this.killcom = []; - this.killcom = find_com(this.selectlist); + this.killcom = physics.com(this.selectlist.map(x=>x.pos)); this.selectlist.forEach(function(x) { this.killring.push(x.make_ur()); @@ -1590,7 +1526,7 @@ replpanel.inputs = Object.create(inputpanel.inputs); replpanel.inputs.block = true; replpanel.inputs.lm = function() { - var mg = Game.obj_at(Mouse.worldpos); + var mg = physics.pos_query(Mouse.worldpos); if (!mg) return; var p = mg.path_from(editor.get_this()); this.value = p; @@ -1833,7 +1769,7 @@ var objectexplorer = Object.copy(inputpanel, { // this.obj[key] = this.obj[key]; }); -// Game.objects.forEach(function(x) { x.sync(); }); +// Game.all_objects(function(x) { x.sync(); }); return items; }, diff --git a/scripts/engine.js b/scripts/engine.js index 68bf65f..7dc3832 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -28,208 +28,7 @@ function run_env(file, env) load("scripts/diff.js"); Log.level = 1; -var Color = { - white: [255,255,255], - black: [0,0,0], - blue: [84,110,255], - green: [120,255,10], - yellow: [251,255,43], - red: [255,36,20], - teal: [96, 252, 237], - gray: [181,181,181], - cyan: [0,255,255], - purple: [162,93,227], -}; - -Color.editor = {}; -Color.editor.ur = Color.green; - -Color.tohtml = function(v) -{ - var html = v.map(function(n) { return Number.hex(n*255); }); - return "#" + html.join(''); -} - -Color.toesc = function(v) -{ - return Esc.color(v); -} - -var Esc = {}; -Esc.reset = "\x1b[0"; -Esc.color = function(v) { - var c = v.map(function(n) { return Math.floor(n*255); }); - var truecolor = "\x1b[38;2;" + c.join(';') + ';'; - return truecolor; -} - -Color.Arkanoid = { - orange: [255,143,0], - teal: [0,255,255], - green: [0,255,0], - red: [255,0,0], - blue: [0,112,255], - purple: [255,0,255], - yellow: [255,255,0], - silver: [157,157,157], - gold: [188,174,0], -}; - -Color.Arkanoid.Powerups = { - red: [174,0,0], /* laser */ - blue: [0,0,174], /* enlarge */ - green: [0,174,0], /* catch */ - orange: [224,143,0], /* slow */ - purple: [210,0,210], /* break */ - cyan: [0,174,255], /* disruption */ - gray: [143,143,143] /* 1up */ -}; - -Color.Gameboy = { - darkest: [229,107,26], - dark: [229,189,26], - light: [189,229,26], - lightest: [107,229,26], -}; - -Color.Apple = { - green: [94,189,62], - yellow: [255,185,0], - orange: [247,130,0], - red: [226,56,56], - purple: [151,57,153], - blue: [0,156,223] -}; - -Color.Debug = { - boundingbox: Color.white, - names: [84,110,255], -}; - -Color.Editor = { - grid: [99,255,128], - select: [255,255,55], - newgroup: [120,255,10], -}; - -/* Detects the format of all colors and munges them into a floating point format */ -Color.normalize = function(c) { - var add_a = function(a) { - var n = this.slice(); - n.a = a; - return n; - }; - - for (var p of Object.keys(c)) { - var fmt = "nrm"; - if (typeof c[p] !== 'object') continue; - if (!Array.isArray(c[p])) { - Color.normalize(c[p]); - continue; - } - - for (var color of c[p]) { - if (color > 1) { - fmt = "8b"; - break; - } - } - - switch(fmt) { - case "8b": - c[p] = c[p].map(function(x) { return x/255; }); - } - c[p].alpha = add_a; - } -}; - -Color.normalize(Color); - -Object.deepfreeze(Color); - -var ColorMap = {}; -ColorMap.makemap = function(map) -{ - var newmap = Object.create(ColorMap); - Object.assign(newmap, map); - return newmap; -} -ColorMap.Jet = ColorMap.makemap({ - 0: [0,0,131], - 0.125: [0,60,170], - 0.375: [5,255,255], - 0.625: [255,255,0], - 0.875: [250,0,0], - 1: [128,0,0] -}); - -ColorMap.BlueRed = ColorMap.makemap({ - 0: [0,0,255], - 1: [255,0,0] -}); - -ColorMap.Inferno = ColorMap.makemap({ - 0:[0,0,4], - 0.13: [31,12,72], - 0.25: [85,15,109], - 0.38: [136,34,106], - 0.5: [186,54,85], - 0.63: [227,89,51], - 0.75: [249,140,10], - 0.88: [249,201,50], - 1: [252,255,164] -}); - -ColorMap.Bathymetry = ColorMap.makemap({ - 0: [40,26,44], - 0.13: [59.49,90], - 0.25: [64,76,139], - 0.38: [63,110,151], - 0.5: [72,142,158], - 0.63: [85,174,163], - 0.75: [120,206,163], - 0.88: [187,230,172], - 1: [253,254,204] -}); - -ColorMap.Viridis = ColorMap.makemap({ - 0: [68,1,84], - 0.13: [71,44,122], - 0.25: [59,81,139], - 0.38: [44,113,142], - 0.5: [33,144,141], - 0.63: [39,173,129], - 0.75: [92,200,99], - 0.88: [170,220,50], - 1: [253,231,37] -}); - -Color.normalize(ColorMap); - -ColorMap.sample = function(t, map) -{ - map ??= this; - if (t < 0) return map[0]; - if (t > 1) return map[1]; - - var lastkey = 0; - for (var key of Object.keys(map).sort()) { - if (t < key) { - var b = map[key]; - var a = map[lastkey]; - var tt = (key - lastkey) * t; - return a.lerp(b, tt); - } - lastkey = key; - } - return map[1]; -} - -ColorMap.doc = { - sample: "Sample a given colormap at the given percentage (0 to 1).", -}; - -Object.freeze(ColorMap); +load("scripts/color.js"); function bb2wh(bb) { return [bb.r-bb.l, bb.t-bb.b]; @@ -269,7 +68,6 @@ var Device = { gamegear: [160,144,3.2], }; - load("scripts/gui.js"); var ctimer = { @@ -348,6 +146,7 @@ var timer = { var t = timer.make(fn,secs,desc); t.loop = false; t.restart(); + return t; t.fn = function() { fn(); t.kill(); }; return function() { t.kill(); }; }, @@ -378,78 +177,7 @@ timer.doc = { remain: "The time remianing before the function is executed.", }; -var animation = { - time: 0, - loop: false, - playtime: 0, - playing: false, - keyframes: [], - - create() { - var anim = Object.create(animation); - Register.update.register(anim.update, anim); - return anim; - }, - - start() { - this.playing = true; - this.time = this.keyframes.last[1]; - this.playtime = 0; - }, - - interval(a, b, t) { - return (t - a) / (b - a); - }, - - near_val(t) { - for (var i = 0; i < this.keyframes.length-1; i++) { - if (t > this.keyframes[i+1][1]) continue; - - return this.interval(this.keyframes[i][1], this.keyframes[i+1][1], t) >= 0.5 ? this.keyframes[i+1][0] : this.keyframes[i][0]; - } - - return this.keyframes.last[0]; - }, - - lerp_val(t) { - for (var i = 0; i < this.keyframes.length-1; i++) { - if (t > this.keyframes[i+1][1]) continue; - - var intv = this.interval(this.keyframes[i][1], this.keyframes[i+1][1], t); - return ((1 - intv) * this.keyframes[i][0]) + (intv * this.keyframes[i+1][0]); - } - - return this.keyframes.last[0]; - }, - - cubic_val(t) { - - }, - - mirror() { - if (this.keyframes.length <= 1) return; - for (var i = this.keyframes.length-1; i >= 1; i--) { - this.keyframes.push(this.keyframes[i-1]); - this.keyframes.last[1] = this.keyframes[i][1] + (this.keyframes[i][1] - this.keyframes[i-1][1]); - } - }, - - update(dt) { - if (!this.playing) return; - - this.playtime += dt; - if (this.playtime >= this.time) { - if (this.loop) - this.playtime = 0; - else { - this.playing = false; - return; - } - } - - this.fn(this.lerp_val(this.playtime)); - }, -}; +load("scripts/animation.js"); var Render = { normal() { @@ -717,24 +445,6 @@ Spline.type = { load("scripts/components.js"); -function find_com(objects) -{ - if (!objects || objects.length === 0) - return [0,0]; - var com = [0,0]; - com[0] = objects.reduce(function(acc, val) { - return acc + val.pos[0]; - }, 0); - com[0] /= objects.length; - - com[1] = objects.reduce(function(acc, val) { - return acc + val.pos[1]; - }, 0); - com[1] /= objects.length; - - return com; -}; - var Game = { init() { if (!Game.edit) { @@ -747,29 +457,13 @@ var Game = { editor.enter_editor(); } }, - objects: [], native: Device.pc, edit: true, - register_obj(obj) { - this.objects[obj.body] = obj; - }, - unregister_obj(obj) { - if (this.objects[obj.body] === obj) - this.objects[obj.body] = undefined; - }, - - obj_at(worldpos) { - var idx = physics.pos_query(worldpos); - if (idx === -1) return undefined; - return Game.objects[idx]; - }, - - /* Returns an object given an id */ - object(id) { - return this.objects[id]; + all_objects(fn) { + /* Wind down from Primum */ }, /* Returns a list of objects by name */ @@ -787,35 +481,6 @@ var Game = { }, - groupify(objects, spec) { - var newgroup = { - locked: true, - breakable: true, - objs: objects, -// get pos() { return find_com(objects); }, -// set pos(x) { this.objs.forEach(function(obj) { obj.pos = x; }) }, - }; - - Object.assign(newgroup, spec); - objects.forEach(function(x) { - x.defn('group', newgroup); - }); - - var bb = bb_from_objects(newgroup.objs); - newgroup.startbb = bb2cwh(bb); - newgroup.bboffset = newgroup.startbb.c.sub(newgroup.objs[0].pos); - - newgroup.boundingbox = function() { - newgroup.startbb.c = newgroup.objs[0].pos.add(newgroup.bboffset); - return cwh2bb(newgroup.startbb.c, newgroup.startbb.wh); - }; - - if (newgroup.file) - newgroup.color = Color.Editor.newgroup; - - return newgroup; - }, - quit() { sys_cmd(0); @@ -890,81 +555,21 @@ Register.update.register(Game.exec, Game); load("scripts/entity.js"); + function world_start() { -globalThis.preprimum = Object.create(gameobject); -var preprimum = globalThis.preprimum; -preprimum.objects = {}; -preprimum.worldpos = function() { return [0,0]; }; -preprimum.worldangle = function() { return 0; }; -preprimum.scale = [1,1,1]; -preprimum.gscale = function() { return [1,1,1]; }; -preprimum.pos = [0,0]; -preprimum.angle = 0; -preprimum.remove_obj = function() {}; -preprimum.toString = function() { return "preprimum"; }; -globalThis.World = preprimum.make(preprimum); -globalThis.Primum = World; -var Primum = globalThis.Primum; -Primum.level = undefined; +globalThis.Primum = Object.create(gameobject); +Primum.objects = {}; +Primum._ed = { + selectable:false, + check_dirty() {}, + dirty:false, + namestr(){}, +}; Primum.toString = function() { return "Primum"; }; -Primum._ed.selectable = false; -Primum._ed.check_dirty = function() { }; -Primum._ed.dirty = false; -Primum.revert = function(){}; Primum.ur = undefined; -globalThis.World.reparent = function(parent) { Log.warn("Cannot reparent the Primum."); } Game.view_camera(Primum.spawn(ur.camera2d)); } -/* Load configs */ -function load_configs(file) { - Log.info(`Loading config file ${file}.`); - var configs = JSON.parse(IO.slurp(file)); - for (var key in configs) { - if (typeof globalThis[key] !== "object") continue; - Object.assign(globalThis[key], configs[key]); - } - - Collision.sync(); - Game.objects.forEach(function(x) { x.sync(); }); - - if (!local_conf.mouse) { - Log.info("disabling mouse features"); - Mouse.disabled = function() {}; - Mouse.hidden = function() {}; - }; -}; - -var local_conf = { - mouse: true, -}; - -if (IO.exists("game.config")) - load_configs("game.config"); - -/* Save configs */ -function save_configs() { - Log.info("saving configs"); - var configs = {}; - configs.editor_config = editor_config; - configs.Nuke = Nuke; - configs.local_conf = local_conf; - IO.slurpwrite(JSON.stringify(configs, null, 1), "editor.config"); - - save_game_configs(); -}; - -function save_game_configs() { - var configs = {}; - configs.physics = physics; - configs.Collision = Collision; - Log.info(configs); - IO.slurpwrite(JSON.stringify(configs,null,1), "game.config"); - - Collision.sync(); - Game.objects.forEach(function(x) { x.sync(); }); -}; - load("scripts/physics.js"); Game.view_camera = function(cam) diff --git a/scripts/entity.js b/scripts/entity.js index 6b9726f..a398fc3 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -11,19 +11,34 @@ function grab_from_points(pos, points, slop) { }; var actor = {}; -actor.spawn = function(ur, config){}; -actor.die = function(actor){}; -actor.kill = function(actor){}; -actor.delay = function(fn, seconds) {}; +actor.spawn = function(script, config){ + if (typeof script !== 'string') return; + var padawan = Object.create(actor); + compile_env(script, padawan, "script"); + + if (typeof config === 'object') + Object.merge(padawan, config); + + return padawan; +}; +actor.die = function(actor){ + +}; +actor.kill = function(actor){ + this.timers.forEach(t => t()); + this.timers = undefined; +}; +actor.delay = function(fn, seconds) { + var t = timer.delay(fn.bind(this), seconds, true); + this.timers.push(t); + return function() { t.kill(); }; +}; actor.clock = function(fn){}; -var Empyrean = Object.create(actor); - var gameobject = { - impl: { - full_path() { - return this.path_from(Primum); - }, + full_path() { + return this.path_from(Primum); + }, path_from(o) { var p = this.toString(); @@ -46,8 +61,9 @@ var gameobject = { delay(fn, seconds) { var t = timer.delay(fn.bind(this), seconds, false); - this.timers.push(t); - return t; + var killfn = function() { t.kill(); }; + this.timers.push(killfn); + return killfn; }, tween(prop, values, def){ @@ -98,7 +114,10 @@ var gameobject = { }, set pos(x) { - this.set_worldpos(this.level.this2world(x)); + if (!this.level) + this.set_worldpos(x); + else + this.set_worldpos(this.level.this2world(x)); }, get pos() { @@ -133,7 +152,7 @@ var gameobject = { 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 damping() { return cmd(157,this.body); }, + get damping() { return cmd(157,this.body); }, set_damping(x) { cmd(156, this.body, x); }, get angularvelocity() { return Math.rad2deg(q_body(4, this.body)); }, set angularvelocity(x) { set_body(8, this.body, Math.deg2rad(x)); }, @@ -155,7 +174,6 @@ var gameobject = { var thatpos = this.pos; this.objects.forEach(function(x) { x.rotate(diff); -// x.angle = x.angle + diff; var opos = x.pos; var r = Vector.length(opos); var p = Math.rad2deg(Math.atan2(opos.y, opos.x)); @@ -163,8 +181,11 @@ var gameobject = { p = Math.deg2rad(p); x.pos = [r*Math.cos(p), r*Math.sin(p)]; }); - - set_body(0,this.body, Math.deg2rad(x - this.level.worldangle())); + + if (this.level) + set_body(0,this.body, Math.deg2rad(x - this.level.worldangle())); + else + set_body(0,this.body,x); }, rotate(x) { @@ -222,9 +243,6 @@ var gameobject = { delete this.objects[obj.toString()]; delete this[obj.toString()]; }, - - - }, components: {}, objects: {}, @@ -242,7 +260,6 @@ var gameobject = { pulse(vec) { set_body(4, this.body, vec);}, shove(vec) { set_body(12,this.body,vec);}, shove_at(vec, at) { set_body(14,this.body,vec,at); }, -// torque(val) { cmd(153, this.body, val); }, world2this(pos) { return cmd(70, this.body, pos); }, this2world(pos) { return cmd(71, this.body,pos); }, dir_world2this(dir) { return cmd(160, this.body, dir); }, @@ -281,6 +298,10 @@ var gameobject = { /* Make a unique object the same as its prototype */ revert() { +// var keys = Object.samenewkeys(this, this.__proto__); +// keys.unique.forEach(x => delete this[x]); +// keys.same.forEach(x => this[x] = this.__proto__[x]); + var jobj = this.json_obj(); var lobj = this.level.__proto__.objects[this.toString()]; delete jobj.objects; @@ -328,39 +349,22 @@ var gameobject = { register_collide(1, x.collide, x, obj.body, x.shape); }); }, - pos: [0,0], - angle:0, - velocity:[0,0], - angularvelocity:0, - phys:Physics.static, + flipx() { return this.scale.x < 0; }, flipy() { return this.scale.y < 0; }, - timescale: 1, - scale:[1,1], mirror(plane) { this.scale = Vector.reflect(this.scale, plane); }, - elasticity:0.5, - friction:1, - gravity: true, - max_velocity: Infinity, - max_angularvelocity: Infinity, - mass:1, - layer:0, - draw_layer:0, - worldpos() { return [0,0]; }, - save:true, selectable:true, ed_locked:false, - - disable() { this.components.forEach(function(x) { x.disable(); });}, - enable() { this.components.forEach(function(x) { x.enable(); });}, - sync() { - this.components.forEach(function(x) { x.sync(); }); - this.objects.forEach(function(x) { x.sync(); }); - }, + disable() { this.components.forEach(function(x) { x.disable(); });}, + enable() { this.components.forEach(function(x) { x.enable(); });}, + sync() { + this.components.forEach(function(x) { x.sync(); }); + this.objects.forEach(function(x) { x.sync(); }); + }, /* Bounding box of the object in world dimensions */ boundingbox() { @@ -416,10 +420,6 @@ var gameobject = { return d; }, - full_obj() { - - }, - transform_obj() { var t = this.json_obj(); Object.assign(t, this.transform()); @@ -467,57 +467,43 @@ var gameobject = { Object.totalmerge(n, this.make_ur()); return n; }, - - kill() { - if (this.body === -1) { -// Log.warn(`Object is already dead!`); - return; - } - -// Register.endofloop(() => { -// cmd(2, this.body); - q_body(8,this.body); - Game.unregister_obj(this); + kill() { + this.timers.forEach(t => t()); + + if (this.level) { + this.level.remove_obj(this); + this.level = undefined; + } - this.timers.forEach(t => t()); + Player.do_uncontrol(this); + Register.unregister_obj(this); - if (this.level) { - this.level.remove_obj(this); - this.level = undefined; - } + if (this.__proto__.instances) + this.__proto__.instances.remove(this); - Player.do_uncontrol(this); - Register.unregister_obj(this); + for (var key in this.components) { + Register.unregister_obj(this.components[key]); + Log.info(`Destroying component ${key}`); + this.components[key].kill(); + this.components.gameobject = undefined; + } - if (this.__proto__.instances) - this.__proto__.instances.remove(this); - - this.body = -1; + delete this.components; - for (var key in this.components) { - Register.unregister_obj(this.components[key]); - Log.info(`Destroying component ${key}`); - this.components[key].kill(); - this.components.gameobject = undefined; - } - delete this.components; + this.clear(); - this.clear(); + if (typeof this.stop === 'function') + 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));}, + 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));}, make(level, data) { - level ??= Primum; +// level ??= Primum; var obj = Object.create(this); obj.make = undefined; obj.level = level; @@ -525,10 +511,10 @@ var gameobject = { this.instances.push(obj); obj.body = make_gameobject(); + obj.components = {}; obj.objects = {}; obj.timers = []; - assign_impl(obj, gameobject.impl); obj._ed = { selectable: true, check_dirty() { @@ -547,7 +533,6 @@ var gameobject = { dirty: false, inst: false, - model: Object.create(this), urdiff: {}, namestr() { var s = obj.toString(); @@ -558,10 +543,9 @@ var gameobject = { return s; }, }; + obj.ur = this.toString(); - Game.register_obj(obj); - cmd(113, obj.body, obj); // set the internal obj reference to this obj for (var prop in this) { @@ -579,7 +563,7 @@ var gameobject = { obj.level = undefined; obj.reparent(level); - Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers', 'timescale'); + Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers'); Object.dainty_assign(obj, this); obj.sync(); @@ -596,6 +580,7 @@ var gameobject = { make_objs(objs) { for (var prop in objs) { + Log.warn(prop); var newobj = this.spawn_from_instance(objs[prop]); if (!newobj) continue; this.rename_obj(newobj.toString(), prop); @@ -624,7 +609,8 @@ var gameobject = { }, add_component(comp) { - if (typeof comp['comp'] !== 'string') return; + if (typeof comp.make !== 'function') return; + return {comp:comp.toString()}; }, register_hit(fn, obj) { @@ -642,7 +628,11 @@ var gameobject = { }, } -gameobject.impl.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`; +gameobject.body = make_gameobject(); +cmd(113,gameobject.body, gameobject); +Object.hide(gameobject, 'timescale'); + +gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`; gameobject.doc = { doc: "All objects in the game created through spawning have these attributes.", diff --git a/scripts/gui.js b/scripts/gui.js index fe3d285..1210a3f 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -283,192 +283,3 @@ Mum.debug_colors = { }; Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; }); - -/* Take numbers from 0 to 1 and remap them to easing functions */ -var Ease = { - linear(t) { return t; }, - - in(t) { return t*t; }, - - out(t) { - var d = 1-t; - return 1 - d*d - }, - - inout(t) { - var d = -2*t + 2; - return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2; - }, -}; - - -function make_easing_fns(num) { - var obj = {}; - - obj.in = function(t) { - return Math.pow(t,num); - }; - - obj.out = function(t) { - return 1 - Math.pow(1 - t, num); - }; - - var mult = Math.pow(2, num-1); - - obj.inout = function(t) { - return t < 0.5 ? mult * Math.pow(t, num) : 1 - Math.pow(-2 * t + 2, num) / 2; - }; - - return obj; -}; - -Ease.quad = make_easing_fns(2); -Ease.cubic = make_easing_fns(3); -Ease.quart = make_easing_fns(4); -Ease.quint = make_easing_fns(5); - -Ease.expo = { - in(t) { - return t === 0 ? 0 : Math.pow(2, 10 * t - 10); - }, - - out(t) { - return t === 1 ? 1 : 1 - Math.pow(2, -10 * t); - }, - - inout(t) { - return t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2; - } -}; - -Ease.bounce = { - in(t) { - return 1 - this.out(t - 1); - }, - - out(t) { - var n1 = 7.5625; - var d1 = 2.75; - - if (t < 1 / d1) { return n1 * t * t; } - else if (t < 2 / d1) { return n1 * (t -= 1.5 / d1) * t + 0.75; } - else if (t < 2.5 / d1) { return n1 * (t -= 2.25 / d1) * t + 0.9375; } - else - return n1 * (t -= 2.625 / d1) * t + 0.984375; - }, - - inout(t) { - return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2; - } -}; - -Ease.sine = { - in(t) { return 1 - Math.cos((t * Math.PI)/2); }, - - out(t) { return Math.sin((t*Math.PI)/2); }, - - inout(t) { return -(Math.cos(Math.PI*t) - 1) / 2; } -}; - -Ease.elastic = { - in(t) { - return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10*t-10) * Math.sin((t * 10 - 10.75) * this.c4); - }, - - out(t) { - return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10*t) * Math.sin((t * 10 - 0.75) * this.c4) + 1; - }, - - inout(t) { - t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? - -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 - : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1; - }, -}; - -Ease.elastic.c4 = 2*Math.PI/3; -Ease.elastic.c5 = 2*Math.PI / 4.5; - -var Tween = { - default: { - loop: "restart", - /* - loop types - none: when done, return to first value - hold: hold last value of tween - restart: restart at beginning, looping - yoyo: go up and then back down - circle: go up and back down, looped - */ - time: 1, /* seconds to do */ - ease: Ease.linear, - whole: true, /* True if time is for the entire tween, false if each stage */ - cb: function(){}, - }, - - start(obj, target, tvals, options) - { - var defn = Object.create(this.default); - Object.assign(defn, options); - - if (defn.loop === 'circle') - tvals.push(tvals[0]); - else if (defn.loop === 'yoyo') { - for (var i = tvals.length-2; i >= 0; i--) - tvals.push(tvals[i]); - } - - defn.accum = 0; - - var slices = tvals.length - 1; - var slicelen = 1 / slices; - - defn.fn = function(dt) { - defn.accum += dt; - if (defn.accum >= defn.time && defn.loop === 'hold') { - obj[target] = tvals[tvals.length-1]; - defn.pause(); - defn.cb.call(obj); - return; - } - - defn.pct = (defn.accum % defn.time) / defn.time; - if (defn.loop === 'none' && defn.accum >= defn.time) - defn.stop(); - - var t = defn.whole ? defn.ease(defn.pct) : defn.pct; - - var nval = t / slicelen; - var i = Math.trunc(nval); - nval -= i; - - if (!defn.whole) - nval = defn.ease(nval); - - obj[target] = tvals[i].lerp(tvals[i+1], nval); - }; - - var playing = false; - - defn.play = function() { - if (playing) return; - Register.update.register(defn.fn, defn); - playing = true; - }; - defn.restart = function() { - defn.accum = 0; - obj[target] = tvals[0]; - }; - defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); }; - defn.pause = function() { - Register.update.unregister(defn.fn); - if (!playing) return; - - playing = false; - }; - - return defn; - }, -}; - -Tween.make = Tween.start; diff --git a/scripts/physics.js b/scripts/physics.js index a43f65a..054788f 100644 --- a/scripts/physics.js +++ b/scripts/physics.js @@ -27,7 +27,6 @@ var physics = { /* Returns a list of body ids that a box collides with */ box_query(box) { - var pts = cmd(52,box.pos,box.wh); return cmd(52, box.pos, box.wh); }, @@ -41,6 +40,18 @@ var physics = { shape_query(shape) { return cmd(80,shape); }, + + com(pos) { + if (!Array.isArray(pos)) return; + var com = []; + for (var i = 0; i < pos[0].length; i++) { + com[i] = pos.reduce(function(acc,val) { + return acc + val[i]; + }); + com[i] /= pos.length; + } + return com; + }, }; physics.doc = {}; diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 6f49bca..04c721a 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -233,6 +233,7 @@ int pos2gameobject(HMM_Vec2 pos) { if (dist <= 25) return i; } + return -1; } @@ -373,11 +374,11 @@ int MakeGameobject() { .cgravity = (HMM_Vec2){0,0}, .damping = NAN, .timescale = 1.0, - .ref = JS_NULL, + .ref = JS_UNDEFINED, }; - go.cbs.begin.obj = JS_NULL; - go.cbs.separate.obj = JS_NULL; + go.cbs.begin.obj = JS_UNDEFINED; + go.cbs.separate.obj = JS_UNDEFINED; go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f)); cpBodySetVelocityUpdateFunc(go.body, velocityFn); @@ -432,6 +433,13 @@ void gameobject_delete(int id) { gameobject_clean(id); } +void gameobject_free(int id) +{ + YughWarn("FREED A GAMEOBJECT!!!"); + if (id >= 0) + gameobject_delete(id); +} + void gameobjects_cleanup() { for (int i = 0; i < arrlen(go_toclean); i++) gameobject_clean(go_toclean[i]); diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index 43b2802..c5bc471 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -69,6 +69,7 @@ extern struct gameobject *gameobjects; int MakeGameobject(); void gameobject_apply(struct gameobject *go); void gameobject_delete(int id); +void gameobject_free(int id); void gameobjects_cleanup(); void gameobject_set_sensor(int id, int sensor); diff --git a/source/engine/input.c b/source/engine/input.c index f478bb3..453a40a 100644 --- a/source/engine/input.c +++ b/source/engine/input.c @@ -73,7 +73,7 @@ JSValue input2js(int state) case 3: return jstr("pressrep"); case 4: return jstr("down"); } - return JS_NULL; + return JS_UNDEFINED; } void input_mouse(int btn, int state, uint32_t mod) diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 57c0ba9..27871bf 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -36,7 +36,6 @@ static JSValue globalThis; static JSClassID js_ptr_id; static JSClassDef js_ptr_class = { "POINTER" }; - #define QJSCLASS(TYPE)\ static JSClassID js_ ## TYPE ## _id;\ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ @@ -44,22 +43,25 @@ TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\ TYPE##_free(n);}\ static JSClassDef js_##TYPE##_class = {\ #TYPE,\ - .finalizer = js_##TYPE##_finalizer\ + .finalizer = js_##TYPE##_finalizer,\ };\ static TYPE *js2##TYPE (JSValue val) { return JS_GetOpaque(val,js_##TYPE##_id); }\ -static JSValue js_##TYPE##2js(TYPE *n) { \ +static JSValue TYPE##2js(TYPE *n) { \ JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\ JS_SetOpaque(j,n);\ return j; }\ QJSCLASS(dsp_node) +// gamobject2js, js2gameobject deals with gameobject* +// go2js,js2go deals with gameobject ids + +QJSCLASS(gameobject) + #define QJSCLASSPREP(TYPE) \ JS_NewClassID(&js_##TYPE##_id);\ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\ -//QJSCLASS(sprite) - #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" #define BYTE_TO_BINARY(byte) \ (byte & 0x80 ? '1' : '0'), \ @@ -81,6 +83,21 @@ void js_setprop_num(JSValue obj, uint32_t i, JSValue v) JS_SetPropertyUint32(js, obj, i, v); } +JSValue go2ref(int id) +{ + if (id == -1) return JS_UNDEFINED; + return JS_DupValue(js,id2go(id)->ref); +} + +JSValue gos2ref(int *go) +{ + JSValue array = JS_NewArray(js); + for (int i = 0; i < arrlen(go); i++) + js_setprop_num(array,i,go2ref(go[i])); + return array; +} + + JSValue js_getpropstr(JSValue v, const char *str) { JSValue p = JS_GetPropertyStr(js,v,str); @@ -155,9 +172,11 @@ JSValue num2js(double g) { } struct gameobject *js2go(JSValue v) { - return id2go(js2int(v)); + return id2go(js2gameobject(v)); } +static int jsgo2id(JSValue v) { return go2id(js2go(v)); } + struct sprite *js2sprite(JSValue v) { return id2sprite(js2int(v)); } void *js2ptr(JSValue v) { @@ -343,7 +362,7 @@ JSValue duk_gui_img(JSContext *js, JSValueConst this, int argc, JSValueConst *ar const char *img = JS_ToCString(js, argv[0]); gui_draw_img(img, js2vec2(argv[1]), js2vec2(argv[2]), js2number(argv[3]), js2bool(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6])); JS_FreeCString(js, img); - return JS_NULL; + return JS_UNDEFINED; } struct rect js2rect(JSValue v) { @@ -375,7 +394,6 @@ JSValue bb2js(struct boundingbox bb) return obj; } - JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { // static_assert(sizeof(tsReal) * 2 == sizeof(HMM_Vec2)); @@ -501,7 +519,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) const char *str2 = NULL; const void *d1 = NULL; const void *d2 = NULL; - JSValue ret = JS_NULL; + JSValue ret = JS_UNDEFINED; switch (cmd) { case 0: @@ -700,7 +718,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 44: - ret = JS_NewInt64(js, pos2gameobject(js2vec2(argv[1]))); + ret = go2ref(pos2gameobject(js2vec2(argv[1]))); break; case 45: @@ -732,7 +750,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 52: - ret = ints2js(phys2d_query_box(js2vec2(argv[1]), js2vec2(argv[2]))); + ret = gos2ref(phys2d_query_box(js2vec2(argv[1]), js2vec2(argv[2]))); break; case 53: @@ -803,7 +821,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 69: - gameobject_set_sensor(js2int(argv[1]), JS_ToBool(js, argv[2])); + gameobject_set_sensor(js2go(argv[1]), JS_ToBool(js, argv[2])); break; case 70: @@ -846,7 +864,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 80: - ret = ints2js(phys2d_query_shape(js2ptr(argv[1]))); + ret = gos2ref(phys2d_query_shape(js2ptr(argv[1]))); break; case 81: @@ -854,7 +872,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 82: - gameobject_draw_debug(js2int(argv[1])); + gameobject_draw_debug(js2go(argv[1])); break; case 83: @@ -870,7 +888,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 86: - ret = ints2js(phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4]))); + ret = gos2ref(phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4]))); break; case 87: @@ -985,7 +1003,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 113: - js2go(argv[1])->ref = JS_DupValue(js,argv[2]); + js2go(argv[1])->ref = argv[2];//JS_DupValue(js,argv[2]); break; case 114: @@ -1222,115 +1240,110 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) str = js2str(argv[1]); ds_openvideo(str); break; - case 175: - ret = num2js(((dsp_node*)js2ptr(argv[1]))->gain); + ret = num2js((js2dsp_node(argv[1]))->gain); break; case 176: - ((dsp_node*)js2ptr(argv[1]))->gain = js2number(argv[2]); + js2dsp_node(argv[1])->gain = js2number(argv[2]); break; case 177: plugin_node(js2ptr(argv[1]), js2ptr(argv[2])); break; case 178: - ret = num2js(((dsp_node*)js2ptr(argv[1]))->pan); + ret = num2js(js2dsp_node(argv[1])->pan); break; case 179: - ((dsp_node*)js2ptr(argv[1]))->pan=js2number(argv[2]); + js2dsp_node(argv[1])->pan=js2number(argv[2]); break; case 180: - ret = ptr2js(masterbus); + ret = dsp_node2js(masterbus); break; case 181: - ret = ptr2js(make_node(NULL,NULL,NULL)); + ret = dsp_node2js(make_node(NULL,NULL,NULL)); break; case 182: str = js2str(argv[1]); ret = ptr2js(dsp_source(str)); - ((sound*)((dsp_node*)js2ptr(ret))->data)->hook = JS_DupValue(js,argv[2]); + ((sound*)js2dsp_node(ret)->data)->hook = JS_DupValue(js,argv[2]); break; case 183: - ((dsp_node*)js2ptr(argv[1]))->off = js2bool(argv[2]); + js2dsp_node(argv[1])->off = js2bool(argv[2]); break; case 184: - ((dsp_node*)js2ptr(argv[1]))->pass = js2bool(argv[2]); + js2dsp_node(argv[1])->pass = js2bool(argv[2]); break; case 185: - ret = ptr2js(dsp_delay(js2number(argv[1]), js2number(argv[2]))); + ret = dsp_node2js(dsp_delay(js2number(argv[1]), js2number(argv[2]))); break; case 186: - ret = ptr2js(dsp_lpf(js2number(argv[1]))); + ret = dsp_node2js(dsp_lpf(js2number(argv[1]))); break; case 187: - ret = ptr2js(dsp_hpf(js2number(argv[1]))); + ret = dsp_node2js(dsp_hpf(js2number(argv[1]))); break; case 188: str = js2str(argv[1]); - ret = ptr2js(dsp_mod(str)); + ret = dsp_node2js(dsp_mod(str)); break; case 189: - ret = ptr2js(dsp_bitcrush(js2number(argv[1]), js2number(argv[2]))); + ret = dsp_node2js(dsp_bitcrush(js2number(argv[1]), js2number(argv[2]))); break; case 190: - ret = ptr2js(dsp_compressor()); + ret = dsp_node2js(dsp_compressor()); break; case 191: - ret = ptr2js(dsp_limiter(js2number(argv[1]))); + ret = dsp_node2js(dsp_limiter(js2number(argv[1]))); break; case 192: - ret = ptr2js(dsp_noise_gate(js2number(argv[1]))); + ret = dsp_node2js(dsp_noise_gate(js2number(argv[1]))); break; case 193: - node_free(js2ptr(argv[1])); +// node_free(js2ptr(argv[1])); break; case 194: - ret = bool2js(((sound*)((dsp_node*)js2ptr(argv[1]))->data)->loop); + ret = bool2js(((sound*)js2dsp_node(argv[1])->data)->loop); break; case 195: - ((sound*)((dsp_node*)js2ptr(argv[1]))->data)->loop = js2bool(argv[2]); + ((sound*)js2dsp_node(argv[1])->data)->loop = js2bool(argv[2]); break; case 196: - ret = num2js(((sound*)((dsp_node*)js2ptr(argv[1]))->data)->frame); + ret = num2js(((sound*)js2dsp_node(argv[1])->data)->frame); break; case 197: - ret = num2js(((sound*)((dsp_node*)js2ptr(argv[1]))->data)->data->frames); + ret = num2js(((sound*)js2dsp_node(argv[1])->data)->data->frames); break; case 198: ret = num2js(SAMPLERATE); break; case 199: - ((sound*)((dsp_node*)js2ptr(argv[1]))->data)->frame = js2number(argv[2]); + ((sound*)js2dsp_node(argv[1])->data)->frame = js2number(argv[2]); break; case 200: - ret = ptr2js(dsp_pitchshift(js2number(argv[1]))); + ret = dsp_node2js(dsp_pitchshift(js2number(argv[1]))); break; case 201: - ret = num2js(((sound*)((dsp_node*)js2ptr(argv[1]))->data)->timescale); + ret = num2js(((sound*)js2dsp_node(argv[1])->data)->timescale); break; case 202: YughWarn("%g", js2number(argv[2])); - ((sound*)((dsp_node*)js2ptr(argv[1]))->data)->timescale = js2number(argv[2]); + ((sound*)js2dsp_node(argv[1])->data)->timescale = js2number(argv[2]); break; case 203: - ret = ptr2js(dsp_whitenoise()); + ret = dsp_node2js(dsp_whitenoise()); break; case 204: - ret = ptr2js(dsp_pinknoise()); + ret = dsp_node2js(dsp_pinknoise()); break; case 205: - ret = ptr2js(dsp_rednoise()); + ret = dsp_node2js(dsp_rednoise()); break; case 206: str = js2str(argv[1]); str2 = js2str(argv[2]); - ret = ptr2js(dsp_midi(str, make_soundfont(str2))); + ret = dsp_node2js(dsp_midi(str, make_soundfont(str2))); break; case 207: - ret = ptr2js(dsp_fwd_delay(js2number(argv[1]), js2number(argv[2]))); - break; - case 208: - ret = JS_NewObjectClass(js, js_dsp_node_id); - JS_SetOpaque(ret, dsp_mixer_node()); + ret = dsp_node2js(dsp_fwd_delay(js2number(argv[1]), js2number(argv[2]))); break; } @@ -1347,7 +1360,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) return ret; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_register(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { @@ -1402,7 +1415,7 @@ JSValue duk_register(JSContext *js, JSValueConst this, int argc, JSValueConst *a break; } - return JS_NULL; + return JS_UNDEFINED; } void gameobject_add_shape_collider(int go, struct callee c, struct phys2d_shape *shape) { @@ -1414,7 +1427,7 @@ void gameobject_add_shape_collider(int go, struct callee c, struct phys2d_shape JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { int cmd = js2int(argv[0]); - int go = js2int(argv[3]); + int go = jsgo2id(argv[3]); struct callee c; c.fn = argv[1]; c.obj = argv[2]; @@ -1437,7 +1450,7 @@ JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValue break; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { @@ -1486,11 +1499,11 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar break; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_gameobject(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - return JS_NewInt64(js, MakeGameobject()); + return gameobject2js(MakeGameobject()); } JSValue duk_yughlog(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { @@ -1504,15 +1517,14 @@ JSValue duk_yughlog(JSContext *js, JSValueConst this, int argc, JSValueConst *ar JS_FreeCString(js, s); JS_FreeCString(js, f); - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { int cmd = js2int(argv[0]); - int id = js2int(argv[1]); - struct gameobject *go = get_gameobject_from_id(id); - - if (!go) return JS_NULL; + struct gameobject *go = js2go(argv[1]); + + if (!go) return JS_UNDEFINED; /* TODO: Possible that reindexing shapes only needs done for static shapes? */ switch (cmd) { @@ -1536,7 +1548,7 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a case 4: cpBodyApplyImpulseAtWorldPoint(go->body, js2vec2(argv[2]).cp, cpBodyGetPosition(go->body)); - return JS_NULL; + return JS_UNDEFINED; case 5: // go->flipx = JS_ToBool(js, argv[2]); @@ -1554,11 +1566,11 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a case 8: cpBodySetAngularVelocity(go->body, js2number(argv[2])); - return JS_NULL; + return JS_UNDEFINED; case 9: cpBodySetVelocity(go->body, js2vec2(argv[2]).cp); - return JS_NULL; + return JS_UNDEFINED; case 10: go->e = fmax(js2number(argv[2]), 0); @@ -1570,27 +1582,26 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a case 12: cpBodyApplyForceAtWorldPoint(go->body, js2vec2(argv[2]).cp, cpBodyGetPosition(go->body)); - return JS_NULL; + return JS_UNDEFINED; case 13: cpBodySetMoment(go->body, js2number(argv[2])); - return JS_NULL; + return JS_UNDEFINED; case 14: cpBodyApplyForceAtLocalPoint(go->body, js2vec2(argv[2]).cp, js2vec2(argv[3]).cp); - return JS_NULL; + return JS_UNDEFINED; } cpSpaceReindexShapesForBody(space, go->body); - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { int q = js2int(argv[0]); - int goid = js2int(argv[1]); - struct gameobject *go = get_gameobject_from_id(goid); + struct gameobject *go = js2go(argv[1]); - if (!go) return JS_NULL; + if (!go) return JS_UNDEFINED; switch (q) { case 0: @@ -1618,16 +1629,16 @@ JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *arg return JS_NewBool(js, phys2d_in_air(go->body)); case 8: - gameobject_delete(goid); +// gameobject_delete(goid); break; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_sprite(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue sprite = JS_NewObject(js); - js_setprop_str(sprite,"id",JS_NewInt64(js, make_sprite(js2int(argv[0])))); + js_setprop_str(sprite,"id",JS_NewInt64(js, make_sprite(jsgo2id(argv[0])))); return sprite; } @@ -1645,7 +1656,7 @@ JSValue duk_make_anim2d(JSContext *js, JSValueConst this, int argc, JSValueConst } JSValue duk_make_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - int go = js2int(argv[0]); + int go = jsgo2id(argv[0]); HMM_Vec2 size = js2vec2(argv[1]); struct phys2d_box *box = Make2DBox(go); @@ -1666,7 +1677,7 @@ JSValue duk_cmd_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst * struct phys2d_box *box = js2ptr(argv[1]); HMM_Vec2 arg; - if (!box) return JS_NULL; + if (!box) return JS_UNDEFINED; switch (cmd) { case 0: @@ -1685,11 +1696,11 @@ JSValue duk_cmd_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst * } phys2d_applybox(box); - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - int go = js2int(argv[0]); + int go = jsgo2id(argv[0]); struct phys2d_circle *circle = Make2DCircle(go); @@ -1701,7 +1712,7 @@ JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCon JSValue duk_make_model(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - int go = js2int(argv[0]); + int go = jsgo2id(argv[0]); struct drawmodel *dm = make_drawmodel(go); JSValue ret = JS_NewObject(js); js_setprop_str(ret, "id", ptr2js(dm)); @@ -1712,7 +1723,7 @@ JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCons int cmd = js2int(argv[0]); struct phys2d_circle *circle = js2ptr(argv[1]); - if (!circle) return JS_NULL; + if (!circle) return JS_UNDEFINED; switch (cmd) { case 0: @@ -1731,11 +1742,11 @@ JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCons } phys2d_applycircle(circle); - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - int go = js2int(argv[0]); + int go = jsgo2id(argv[0]); struct phys2d_poly *poly = Make2DPoly(go); phys2d_poly_setverts(poly, NULL); JSValue polyval = JS_NewObject(js); @@ -1748,7 +1759,7 @@ JSValue duk_cmd_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst int cmd = js2int(argv[0]); struct phys2d_poly *poly = js2ptr(argv[1]); - if (!poly) return JS_NULL; + if (!poly) return JS_UNDEFINED; switch (cmd) { case 0: @@ -1756,11 +1767,11 @@ JSValue duk_cmd_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst break; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - int go = js2int(argv[0]); + int go = jsgo2id(argv[0]); struct phys2d_edge *edge = Make2DEdge(go); int n = js_arrlen(argv[1]); @@ -1784,7 +1795,7 @@ JSValue duk_cmd_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst if (!edge) { YughError("Attempted to do a cmd on edge %p. Not found.", edge); - return JS_NULL; + return JS_UNDEFINED; } switch (cmd) { @@ -1798,7 +1809,7 @@ JSValue duk_cmd_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst break; } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_inflate_cpv(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { @@ -1835,7 +1846,7 @@ JSValue duk_anim(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) JS_FreeValue(js,vv); } - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_make_timer(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { @@ -1843,7 +1854,7 @@ JSValue duk_make_timer(JSContext *js, JSValueConst this, int argc, JSValueConst // struct callee *c = make_callee(argv[0], argv[3]); // int id = timer_make(secs, call_callee, c, 1, js2bool(argv[2])); // return JS_NewInt64(js, id); - return JS_NULL; + return JS_UNDEFINED; } JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) @@ -1862,7 +1873,7 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst break; } - return JS_NULL; + return JS_UNDEFINED; } //#include "dlfcn.h" @@ -1885,7 +1896,7 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst ffi_call(&cif, fn, &rc, values); } - return JS_NULL; + return JS_UNDEFINED; } */ #define DUK_FUNC(NAME, ARGS) JS_SetPropertyStr(js, globalThis, #NAME, JS_NewCFunction(js, duk_##NAME, #NAME, ARGS)); @@ -1936,4 +1947,6 @@ void ffi_load() { JS_NewClass(JS_GetRuntime(js), js_ptr_id, &js_ptr_class); QJSCLASSPREP(dsp_node); + QJSCLASSPREP(gameobject); } + diff --git a/source/engine/script.c b/source/engine/script.c index 60fb989..df8f986 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -193,7 +193,7 @@ JSValue script_runfile(const char *file) { size_t len; const char *script = slurp_text(file, &len); - if (!script) return JS_NULL; + if (!script) return JS_UNDEFINED; JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAGS); js_print_exception(obj); @@ -266,13 +266,13 @@ void out_memusage(const char *file) JSValue js_callee_exec(struct callee *c, int argc, JSValue *argv) { - if (JS_IsUndefined(c->fn)) return JS_NULL; - if (JS_IsUndefined(c->obj)) return JS_NULL; + if (JS_IsUndefined(c->fn)) return JS_UNDEFINED; + if (JS_IsUndefined(c->obj)) return JS_UNDEFINED; JSValue ret = JS_Call(js, c->fn, c->obj, argc, argv); js_print_exception(ret); JS_FreeValue(js, ret); - return JS_NULL; + return JS_UNDEFINED; } void call_callee(struct callee *c) { diff --git a/source/engine/sound/dsp.c b/source/engine/sound/dsp.c index 928e488..284170a 100644 --- a/source/engine/sound/dsp.c +++ b/source/engine/sound/dsp.c @@ -151,6 +151,7 @@ dsp_node *make_node(void *data, void (*proc)(void *data, soundbyte *out, int sam void node_free(dsp_node *node) { + YughWarn("FREEING A NODE"); unplug_node(node); if (node->data) if (node->data_free) node->data_free(node->data); diff --git a/source/engine/sprite.c b/source/engine/sprite.c index 216e065..9ecbbce 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -53,6 +53,7 @@ struct slice9_vert { }; int make_sprite(int go) { + YughWarn("Attaching sprite to gameobject %d", go); struct sprite sprite = { .color = color_white, .emissive = {0,0,0,0},