From 033b7c5109f0c4bfbd5c576b8921e6b597894914 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 3 Apr 2024 00:44:08 -0500 Subject: [PATCH] Add guid; tags; physics point checking --- scripts/actor.js | 2 +- scripts/camera2d.jso | 19 +++++++-- scripts/components.js | 19 +++++---- scripts/debug.js | 12 +++--- scripts/editor.js | 86 +++++++++++++++++++-------------------- scripts/engine.js | 54 ++++++++++++++---------- scripts/entity.js | 30 ++++++++------ scripts/gui.js | 2 +- scripts/input.js | 56 ++++++++++++------------- scripts/std.js | 1 + source/engine/2dphysics.c | 7 ++-- source/engine/jsffi.c | 64 +++++++++++++++++++++++------ source/engine/render.c | 24 +---------- source/engine/sprite.c | 3 +- 14 files changed, 212 insertions(+), 167 deletions(-) diff --git a/scripts/actor.js b/scripts/actor.js index d6d04b7..ea6cdc9 100644 --- a/scripts/actor.js +++ b/scripts/actor.js @@ -12,7 +12,7 @@ actor.spawn = function(script, config, callback){ padawan.padawans = []; padawan.timers = []; padawan.master = this; - Object.hide(padawan, "master","timers", "padawans"); + Object.hide(padawan, "master", "timers", "padawans"); check_registers(padawan); this.padawans.push(padawan); return padawan; diff --git a/scripts/camera2d.jso b/scripts/camera2d.jso index 7796f7a..7bdbc48 100644 --- a/scripts/camera2d.jso +++ b/scripts/camera2d.jso @@ -1,10 +1,23 @@ this.phys = physics.kinematic; this.dir_view2world = function(dir) { return dir.scale(this.realzoom()); }; -this.view2world = function(pos) { return render.view2world(pos); }; -this.world2view = function(pos) { return render.world2view(pos); }; +this.view2world = function(pos) { + pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]); + pos = pos.sub(window.rendersize.scale(0.5)); + pos = pos.scale(this.zoom); + pos = pos.add(this.pos); + return pos; +}; +this.world2view = function(pos) { + pos = pos.sub(this.pos); + pos = pos.scale(1.0/this.zoom); + pos = pos.add(window.rendersize); + return pos; +}; this.realzoom = function() { return render.get_zoom(); }; -this.screenright = function() { return this.pos.x + (window.rendersize.x/2); } +this.screenright = function() { + return this.view2world(window.size).x; +} this.screenleft = function() { return this.pos.x - (window.rendersize.x/2); } this.zoom = 1; diff --git a/scripts/components.js b/scripts/components.js index ee70e35..0f8a40f 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -76,6 +76,7 @@ function json_from_whitelist(whitelist) } Object.mixin(os.sprite(true), { + loop: true, toJSON:json_from_whitelist([ "path", "pos", @@ -96,7 +97,7 @@ Object.mixin(os.sprite(true), { self.del_anim = undefined; self = undefined; advance = undefined; - stop(); + stop?.(); } str ??= 0; var playing = self.anim[str]; @@ -112,8 +113,7 @@ Object.mixin(os.sprite(true), { f = (f+1)%playing.frames.length; if (f === 0) { self.anim_done?.(); - self.anim_done = undefined; -// if (!self.loop) { self.stop(); return; } + if (!self.loop) { self.stop(); return; } } stop = self.gameobject.delay(advance, playing.frames[f].time); } @@ -149,6 +149,7 @@ Object.mixin(os.sprite(true), { this.del_anim?.(); this.anim = undefined; this.gameobject = undefined; + this.anim_done = undefined; }, toString() { return "sprite"; }, move(d) { this.pos = this.pos.add(d); }, @@ -461,14 +462,14 @@ polygon2d.inputs.f10 = function() { polygon2d.inputs.f10.doc = "Sort all points to be CCW order."; polygon2d.inputs['C-lm'] = function() { - this.points.push(this.gameobject.world2this(Mouse.worldpos())); + this.points.push(this.gameobject.world2this(input.mouse.worldpos())); }; polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse."; polygon2d.inputs.lm = function(){}; polygon2d.inputs.lm.released = function(){}; polygon2d.inputs['C-M-lm'] = function() { - var idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); + var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); if (idx === -1) return; this.points.splice(idx, 1); }; @@ -777,7 +778,7 @@ bucket.inputs['C-o'].doc = "Set spline to linear."; bucket.inputs['C-M-lm'] = function() { if (Spline.is_catmull(this.type)) { - var idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); + var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); if (idx === -1) return; } else { @@ -787,16 +788,16 @@ bucket.inputs['C-M-lm'] = function() { }; bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline."; -bucket.inputs['C-lm'] = function() { this.add_node(Mouse.worldpos()); } +bucket.inputs['C-lm'] = function() { this.add_node(input.mouse.worldpos()); } bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position."; bucket.inputs['C-M-lm'] = function() { var idx = -1; if (Spline.is_catmull(this.type)) - idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); + idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); else { var nodes = Spline.bezier_nodes(this.points); - idx = Math.grab_from_points(Mouse.worldpos(), nodes.map(p => this.gameobject.this2world(p)), 25); + idx = Math.grab_from_points(input.mouse.worldpos(), nodes.map(p => this.gameobject.this2world(p)), 25); idx *= 3; } diff --git a/scripts/debug.js b/scripts/debug.js index c03d422..8ebfe20 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -22,12 +22,12 @@ debug.draw = function() { if (this.draw_gizmos) game.all_objects(function(x) { if (!x.icon) return; - GUI.image(x.icon, window.world2screen(x.pos)); + GUI.image(x.icon, game.camera.world2view(x.pos)); }); if (this.draw_names) game.all_objects(function(x) { - render.text(x, window.world2screen(x.pos).add([0,32]), 1, Color.debug.names); + render.text(x, game.camera.view2screen(x.pos).add([0,32]), 1, Color.debug.names); }); if (debug.gif.rec) { @@ -41,10 +41,10 @@ debug.draw = function() { render.text(sim.playing() ? "PLAYING" : sim.stepping() ? - "STEP" : - sim.paused() ? - "PAUSED; EDITING" : - "EDIT", [0, 0], 1); + "STEP" : + sim.paused() ? + "PAUSED; EDITING" : + "EDIT", [0, 0], 1); } function assert(op, str) diff --git a/scripts/editor.js b/scripts/editor.js index 0dab9ad..b3ef2ec 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -24,7 +24,7 @@ var editor = { desktop: undefined, /* The editor desktop, where all editing objects live */ working_layer: 0, get cursor() { - if (this.selectlist.length === 0 ) return Mouse.worldpos(); + if (this.selectlist.length === 0 ) return input.mouse.worldpos(); return physics.com(this.selectlist.map(x => x.pos)); }, edit_mode: "basic", @@ -32,7 +32,7 @@ var editor = { get_this() { return this.edit_level; }, try_select() { /* nullify true if it should set selected to null if it doesn't find an object */ - var go = physics.pos_query(Mouse.worldpos()); + var go = physics.pos_query(input.mouse.worldpos()); return this.do_select(go); }, @@ -82,7 +82,7 @@ var editor = { return function(go) { go.pos = go.pos.add(amt)}; }, - step_amt() { return Keys.shift() ? 10 : 1; }, + step_amt() { return input.keyboard.down("shift") ? 10 : 1; }, on_grid(pos) { return pos.every(function(x) { return x % editor.grid_size === 0; }); @@ -97,7 +97,7 @@ var editor = { key_move(dir) { if (!editor.grabselect) return; - if (Keys.ctrl()) + if (input.keyboard.down('ctrl')) this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size)); else this.selectlist.forEach(this.mover(dir.scale(this.step_amt()))); @@ -154,7 +154,7 @@ var editor = { }, input_num_pressed(num) { - if (Keys.ctrl()) { + if (input.keyboard.down('ctrl')) { this.camera_recalls[num] = { pos:this.camera.pos, zoom:this.camera.zoom @@ -375,7 +375,7 @@ var editor = { /* Draw selection box */ if (this.sel_start) { - var endpos = Mouse.worldpos(); + var endpos = input.mouse.worldpos(); var c = []; c[0] = (endpos[0] - this.sel_start[0]) / 2; c[0] += this.sel_start[0]; @@ -393,7 +393,7 @@ var editor = { gui() { /* Clean out killed objects */ this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); - render.text([0,0], window.world2screen([0,0])); + render.text([0,0], game.camera.world2view([0,0])); render.text("WORKING LAYER: " + this.working_layer, [0,520]); render.text("MODE: " + this.edit_mode, [0,500]); @@ -455,15 +455,15 @@ var editor = { render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3)); }); - var mg = physics.pos_query(Mouse.worldpos(),10); + var mg = physics.pos_query(input.mouse.worldpos(),10); if (mg) { var p = mg.path_from(thiso); - render.text(p, Mouse.screenpos(),1,Color.teal); + render.text(p, input.mouse.screenpos(),1,Color.teal); } if (this.rotlist.length === 1) - render.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal); + render.text(Math.trunc(this.rotlist[0].obj.angle), input.mouse.screenpos(), 1, Color.teal); if (this.selectlist.length === 1) { var i = 1; @@ -484,8 +484,8 @@ var editor = { }); render.grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3)); - var startgrid = window.screen2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); }); - var endgrid = window.screen2world([window.width, window.height]); + var startgrid = game.camera.view2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); }); + var endgrid = game.camera.view2world([window.width, window.height]); 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; @@ -494,12 +494,12 @@ var editor = { if (h_step === 0) h_step = editor.grid_size; while(startgrid[0] <= endgrid[0]) { - render.text(startgrid[0], [window.world2screen([startgrid[0], 0])[0],0]); + render.text(startgrid[0], [game.camera.world2view([startgrid[0], 0])[0],0]); startgrid[0] += w_step; } while(startgrid[1] <= endgrid[1]) { - render.text(startgrid[1], [0, window.world2screen([0, startgrid[1]])[1]]); + render.text(startgrid[1], [0, game.camera.world2view([0, startgrid[1]])[1]]); startgrid[1] += h_step; } @@ -523,7 +523,7 @@ var editor = { load(urstr) { var obj = editor.edit_level.spawn(urstr); - obj.set_worldpos(Mouse.worldpos()); + obj.set_worldpos(input.mouse.worldpos()); this.selectlist = [obj]; }, @@ -604,7 +604,7 @@ var editor = { editor.new_object = function() { var obj = editor.edit_level.spawn(); - obj.set_worldpos(Mouse.worldpos()); + obj.set_worldpos(input.mouse.worldpos()); this.selectlist = [obj]; return obj; } @@ -650,7 +650,7 @@ editor.inputs.drop = function(str) { return; } - var mg = physics.pos_query(Mouse.worldpos(),10); + var mg = physics.pos_query(input.mouse.worldpos(),10); if (!mg) return; var img = mg.get_comp_by_name('sprite'); if (!img) return; @@ -794,7 +794,7 @@ editor.inputs['C-r'].doc = "Negate the selected's angle."; editor.inputs.r = function() { if (editor.sel_comp && 'angle' in editor.sel_comp) { - var relpos = Mouse.worldpos().sub(editor.sel_comp.gameobject.worldpos()); + var relpos = input.mouse.worldpos().sub(editor.sel_comp.gameobject.worldpos()); editor.startoffset = Math.atan2(relpos.y, relpos.x); editor.startrot = editor.sel_comp.angle; @@ -803,7 +803,7 @@ editor.inputs.r = function() { editor.rotlist = []; editor.selectlist.forEach(function(x) { - var relpos = Mouse.worldpos().sub(editor.cursor); + var relpos = input.mouse.worldpos().sub(editor.cursor); editor.rotlist.push({ obj: x, angle: x.angle, @@ -1016,11 +1016,11 @@ editor.inputs.f3 = function() { this.openpanel(componentexplorer); }; -editor.inputs.lm = function() { editor.sel_start = Mouse.worldpos(); }; +editor.inputs.lm = function() { editor.sel_start = input.mouse.worldpos(); }; editor.inputs.lm.doc = "Selection box."; editor.inputs.lm.released = function() { - Mouse.normal(); + input.mouse.normal(); editor.unselect(); if (!editor.sel_start) return; @@ -1033,11 +1033,11 @@ editor.inputs.lm.released = function() { var selects = []; /* TODO: selects somehow gets undefined objects in here */ - if (Vector.equal(Mouse.worldpos(), editor.sel_start, 5)) { + if (Vector.equal(input.mouse.worldpos(), editor.sel_start, 5)) { var sel = editor.try_select(); if (sel) selects.push(sel); } else { - var box = bbox.frompoints([editor.sel_start, Mouse.worldpos()]); + var box = bbox.frompoints([editor.sel_start, input.mouse.worldpos()]); physics.box_query(bbox.tocwh(box), function(entity) { var obj = editor.do_select(entity); @@ -1051,7 +1051,7 @@ editor.inputs.lm.released = function() { if (Object.empty(selects)) return; - if (Keys.shift()) { + if (input.keyboard.down('shift')) { selects.forEach(function(x) { this.selectlist.push_unique(x); }, this); @@ -1059,7 +1059,7 @@ editor.inputs.lm.released = function() { return; } - if (Keys.ctrl()) { + if (input.keyboard.down('ctrl')) { selects.forEach(function(x) { delete this.selectlist[x.toString()]; }, this); @@ -1091,7 +1091,7 @@ editor.try_pick = function() editor.grabselect = []; if (editor.sel_comp && 'pick' in editor.sel_comp) - return editor.sel_comp.pick(Mouse.worldpos()); + return editor.sel_comp.pick(input.mouse.worldpos()); return editor.try_select(); } @@ -1099,7 +1099,7 @@ editor.try_pick = function() editor.inputs.mm = function() { if (editor.brush_obj) { editor.selectlist = editor.dup_objects([editor.brush_obj]); - editor.selectlist[0].pos = Mouse.worldpos(); + editor.selectlist[0].pos = input.mouse.worldpos(); editor.grabselect = editor.selectlist[0]; return; } @@ -1113,30 +1113,30 @@ editor.inputs['C-mm'] = editor.inputs.mm; editor.inputs['C-M-lm'] = function() { - var go = physics.pos_query(Mouse.worldpos()); + var go = physics.pos_query(input.mouse.worldpos()); if (!go) return; editor.edit_level = go.master; } editor.inputs['C-M-mm'] = function() { - editor.mousejoy = Mouse.screenpos(); + editor.mousejoy = input.mouse.screenpos(); editor.joystart = editor.camera.pos; }; editor.inputs['C-M-rm'] = function() { - editor.mousejoy = Mouse.screenpos(); + editor.mousejoy = input.mouse.screenpos(); editor.z_start = editor.camera.zoom; - Mouse.disabled(); + input.mouse.disabled(); }; editor.inputs.rm.released = function() { editor.mousejoy = undefined; editor.z_start = undefined; - Mouse.normal(); + input.mouse.normal(); }; editor.inputs.mm.released = function () { - Mouse.normal(); + input.mouse.normal(); this.grabselect = []; editor.mousejoy = undefined; editor.joystart = undefined; @@ -1157,7 +1157,7 @@ editor.inputs.mouse.move = function(pos, dpos) x.sync(); }); - var relpos = Mouse.worldpos().sub(editor.cursor); + var relpos = input.mouse.worldpos().sub(editor.cursor); var dist = Vector.length(relpos); editor.scalelist?.forEach(function(x) { @@ -1174,7 +1174,7 @@ editor.inputs.mouse.move = function(pos, dpos) editor.rotlist?.forEach(function(x) { var anglediff = Math.atan2(relpos.y, relpos.x) - x.rotoffset; x.obj.angle = x.angle + Math.rad2turn(anglediff); - if (Keys.shift()) + if (input.keyboard.down('shift')) x.obj.angle = Math.nearest(x.obj.angle, (1/24)); if (x.pos) x.obj.pos = x.pos.sub(x.offset).add(x.offset.rotate(anglediff)); @@ -1192,7 +1192,7 @@ editor.inputs.mouse['C-scroll'] = function(scroll) editor.camera.zoom += scroll.y/100; } -editor.inputs['C-M-S-lm'] = function() { editor.selectlist[0].set_center(Mouse.worldpos()); }; +editor.inputs['C-M-S-lm'] = function() { editor.selectlist[0].set_center(input.mouse.worldpos()); }; editor.inputs['C-M-S-lm'].doc = "Set world center to mouse position."; editor.inputs.delete = function() { @@ -1229,7 +1229,7 @@ editor.inputs.g = function() { if (editor.sel_comp) { if ('pick' in editor.sel_comp) { - editor.grabselect = [editor.sel_comp.pick(Mouse.worldpos())]; + editor.grabselect = [editor.sel_comp.pick(input.mouse.worldpos())]; return; } @@ -1246,7 +1246,7 @@ editor.inputs.g = function() { } if (editor.sel_comp && 'pick' in editor.sel_comp) { - var o = editor.sel_comp.pick(Mouse.worldpos()); + var o = editor.sel_comp.pick(input.mouse.worldpos()); if (o) editor.grabselect = [o]; return; } @@ -1255,7 +1255,7 @@ editor.inputs.g = function() { }; editor.inputs.g.doc = "Move selected objects."; -editor.inputs.g.released = function() { editor.grabselect = []; Mouse.normal(); }; +editor.inputs.g.released = function() { editor.grabselect = []; input.mouse.normal(); }; editor.inputs.up = function() { this.key_move([0,1]); }; editor.inputs.up.rep = true; @@ -1302,13 +1302,13 @@ editor.inputs['M-g'] = function() editor.inputs['M-g'].doc = "Move all."; editor.inputs['C-lb'] = function() { - editor.grid_size -= Keys.shift() ? 10 : 1; + editor.grid_size -= input.keyboard.down('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.grid_size += Keys.shift() ? 10 : 1; }; +editor.inputs['C-rb'] = function() { editor.grid_size += input.keyboard.down('shift') ? 10 : 1; }; editor.inputs['C-rb'].doc = "Increase grid size. Hold shift to increase it more."; editor.inputs['C-rb'].rep = true; @@ -1373,7 +1373,7 @@ compmode.inputs['C-x'] = function() {}; editor.scalelist = []; editor.inputs.s = function() { - var scaleoffset = Vector.length(Mouse.worldpos().sub(editor.cursor)); + var scaleoffset = Vector.length(input.mouse.worldpos().sub(editor.cursor)); editor.scalelist = []; if (editor.sel_comp) { @@ -1580,7 +1580,7 @@ replpanel.inputs = Object.create(inputpanel.inputs); replpanel.inputs.block = true; replpanel.inputs.lm = function() { - var mg = physics.pos_query(Mouse.worldpos()); + var mg = physics.pos_query(input.mouse.worldpos()); if (!mg) return; var p = mg.path_from(editor.get_this()); this.value = p; diff --git a/scripts/engine.js b/scripts/engine.js index 1ee30e7..bf9e5b2 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -254,7 +254,6 @@ var sim = { } var physlag = 0; -var timescale = 1; var gggstart = game.engine_start; game.engine_start = function(s) { @@ -288,8 +287,8 @@ function process() while (physlag > phys_step) { physlag -= phys_step; - prosperon.phys2d_step(phys_step*timescale); - prosperon.physupdate(phys_step*timescale); + prosperon.phys2d_step(phys_step*game.timescale); + prosperon.physupdate(phys_step*game.timescale); } if (!game.camera) @@ -314,20 +313,43 @@ function process() game.timescale = 1; -var eachobj = function(obj,fn) -{ - fn(obj); - for (var o in obj.objects) - eachobj(obj.objects[o],fn); +game.all_objects = function(fn) { + var eachobj = function(obj,fn) + { + fn(obj); + for (var o in obj.objects) + eachobj(obj.objects[o],fn); + } + + eachobj(world,fn); +}; + +game.tags = {}; +game.tag_add = function(tag, obj) { + game.tags[tag] ??= {}; + game.tags[tag][obj.guid] = obj; } -game.all_objects = function(fn) { eachobj(world,fn); }; +game.tag_rm = function(tag, obj) { + delete game.tags[tag][obj.guid]; +} + +game.tag_clear_guid = function(guid) +{ + for (var tag in game.tags) + delete game.tags[tag][guid]; +} + +game.objects_with_tag = function(tag) +{ + if (!game.tags[tag]) return; + return Object.values(game.tags[tag]); +} game.doc = {}; game.doc.object = "Returns the entity belonging to a given id."; game.doc.pause = "Pause game simulation."; game.doc.play = "Resume or start game simulation."; -game.doc.dt = "Current frame dt."; game.doc.camera = "Current camera."; game.texture = function(path) @@ -344,7 +366,6 @@ game.texture = function(path) } game.texture.cache = {}; - prosperon.semver = {}; prosperon.semver.valid = function(v, range) { @@ -519,17 +540,6 @@ window.modetypes = { window.size = [640, 480]; -window.screen2world = function(screenpos) { - if (game.camera) - return game.camera.view2world(screenpos); - - return screenpos; -} - -window.world2screen = function(worldpos) { - return game.camera.world2view(worldpos); -} - window.set_icon.doc = "Set the icon of the window using the PNG image at path."; global.mixin("scripts/spline"); diff --git a/scripts/entity.js b/scripts/entity.js index d245d15..2058db3 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -239,7 +239,7 @@ var gameobject = { this.pos = x; this.objects.forEach((o, i) => o.set_worldpos(this.this2world(poses[i]))); }, - screenpos() { return window.world2screen(this.worldpos()); }, + screenpos() { return game.camera.world2view(this.worldpos()); }, worldangle() { return this.angle; }, sworldangle(x) { this.angle = x; }, @@ -253,11 +253,20 @@ var gameobject = { nothing */ spawn(text, config, callback) { - var ent = os.make_gameobject(); + var ent = os.make_gameobject(); + ent.guid = prosperon.guid(); ent.setref(ent); ent.components = {}; ent.objects = {}; ent.timers = []; + ent.reparent(this); + ent._ed = { + selectable: true, + dirty: false, + inst: false, + urdiff: {}, + }; + if (typeof text === 'object') // assume it's an ur { config = text.data; @@ -268,15 +277,6 @@ var gameobject = { use(text, ent); if (config) Object.assign(ent, json.decode(io.slurp(config))); - - ent.reparent(this); - - ent._ed = { - selectable: true, - dirty: false, - inst: false, - urdiff: {}, - }; ent.ur = text + "+" + config; @@ -320,6 +320,8 @@ var gameobject = { n.sync(); } } + + if (ent.tag) game.tag_add(ent.tag, ent); return ent; }, @@ -368,8 +370,8 @@ var gameobject = { objects: {}, master: undefined, - this2screen(pos) { return window.world2screen(this.this2world(pos)); }, - screen2this(pos) { return this.world2this(window.screen2world(pos)); }, + this2screen(pos) { return game.camera.world2view(this.this2world(pos)); }, + screen2this(pos) { return this.world2this(game.camera.view2world(pos)); }, in_air() { return this.in_air(); }, @@ -544,6 +546,8 @@ var gameobject = { this.clear(); if (typeof this.stop === 'function') this.stop(); + game.tag_clear_guid(this.guid); + for (var i in this) { if (typeof this[i] === 'object') delete this[i]; if (typeof this[i] === 'function') delete this[i]; diff --git a/scripts/gui.js b/scripts/gui.js index bb1efc9..73b2dc7 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -69,7 +69,7 @@ GUI.controls.set_mum = function(mum) } GUI.controls.check_bb = function(mum) { - if (bbox.pointin(mum.bb, Mouse.screenpos())) + if (bbox.pointin(mum.bb, input.mouse.screenpos())) GUI.controls.set_mum(mum); } GUI.controls.inputs = {}; diff --git a/scripts/input.js b/scripts/input.js index 682da78..0eb33f8 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -1,4 +1,4 @@ -var keycodes = { +input.keycodes = { 259: "back", 258: "tab", 257: "enter", @@ -17,9 +17,9 @@ var keycodes = { 45: "minus", }; -var codekeys = {}; -for (var code in keycodes) - codekeys[keycodes[code]] = code; +input.codekeys = {}; +for (var code in input.keycodes) + input.codekeys[input.keycodes[code]] = code; var mod = { shift: 0, @@ -48,7 +48,7 @@ function keyname_extd(key) return `kp${num}`; } - if (keycodes[key]) return keycodes[key]; + if (input.keycodes[key]) return input.keycodes[key]; if (key >= 32 && key <= 126) return String.fromCharCode(key).lc(); return undefined; @@ -120,32 +120,32 @@ prosperon.mousescroll = function(dx){ player[0].mouse_input(modstr() + "scroll", dx); }; prosperon.mousedown = function(b){ - player[0].raw_input(modstr() + Mouse.button[b], "pressed"); + player[0].raw_input(modstr() + input.mouse.button[b], "pressed"); }; prosperon.mouseup = function(b){ - player[0].raw_input(modstr() + Mouse.button[b], "released"); + player[0].raw_input(modstr() + input.mouse.button[b], "released"); }; -var Mouse = { +input.mouse = { screenpos() { return mousepos.slice(); }, - worldpos() { return window.screen2world(mousepos); }, + worldpos() { return game.camera.view2world(mousepos); }, disabled() { input.mouse_mode(1); }, normal() { input.mouse_mode(0); }, mode(m) { - if (Mouse.custom[m]) - input.cursor_img(Mouse.custom[m]); + if (input.mouse.custom[m]) + input.cursor_img(input.mouse.custom[m]); else input.mouse_cursor(m); }, set_custom_cursor(img, mode) { - mode ??= Mouse.cursor.default; + mode ??= input.mouse.cursor.default; if (!img) - delete Mouse.custom[mode]; + delete input.mouse.custom[mode]; else { input.cursor_img(img); - Mouse.custom[mode] = img; + input.mouse.custom[mode] = img; } }, @@ -170,17 +170,18 @@ var Mouse = { }, }; -Mouse.doc = {}; -Mouse.doc.pos = "The screen position of the mouse."; -Mouse.doc.worldpos = "The position in the game world of the mouse."; -Mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game and hides it, but still provides movement and click events."; -Mouse.normal.doc = "Set the mouse to show again after hiding."; +input.mouse.doc = {}; +input.mouse.doc.pos = "The screen position of the mouse."; +input.mouse.doc.worldpos = "The position in the game world of the mouse."; +input.mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game and hides it, but still provides movement and click events."; +input.mouse.normal.doc = "Set the mouse to show again after hiding."; -var Keys = { - down(code) { - return prosperon.keys[code]; - }, -}; +input.keyboard = {}; +input.keyboard.down = function(code) { + if (typeof code === 'number') return prosperon.keys[code]; + if (typeof code === 'string') return prosperon.keys[keyname_extd(code)]; + return undefined; +} input.state2str = function(state) { if (typeof state === 'string') return state; @@ -370,10 +371,5 @@ Player.doc.players = "A list of current players."; var player = Player; return { - Mouse, - Keys, - Player, - player, - keycodes, - codekeys + player }; diff --git a/scripts/std.js b/scripts/std.js index 83c9ac4..3598064 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -246,6 +246,7 @@ Cmdline.register_order("play", function(argv) { global.mixin("scripts/sound.js"); global.app = actor.spawn("game.js"); if (project.icon) window.set_icon(game.texture(project.icon)); + game.camera = world.spawn("scripts/camera2d"); }); }, "Play the game present in this folder."); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index d8906f7..1c246c5 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -582,9 +582,9 @@ JSValue arb2js(cpArbiter *arb) void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit) { - JSValue hh = *hit; - script_call_sym(*fn, 1, &hh); - JS_FreeValue(js, hh); + script_call_sym(*fn, 1, hit); + JS_FreeValue(js, *hit); + JS_FreeValue(js, *fn); } /* TODO: Limitation, cannot handle multiple collision same frame */ @@ -595,6 +595,7 @@ int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go) if (!JS_IsUndefined(go->cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.begin, &go->cbs.bhit)) { YughSpam("Added begin for %p", &go->cbs.begin); + JS_DupValue(js, go->cbs.begin); go->cbs.bhit = arb2js(arb); } diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index cd65a94..5a9246c 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -714,8 +714,6 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, make_texture, 1), }; -JSC_CCALL(render_normal, opengl_rendermode(LIT)) -JSC_CCALL(render_wireframe, opengl_rendermode(WIREFRAME)) JSC_CCALL(render_grid, draw_grid(js2number(argv[0]), js2number(argv[1]), js2color(argv[2]));) JSC_CCALL(render_point, draw_cppoint(js2vec2(argv[0]), js2number(argv[1]), js2color(argv[2]))) JSC_CCALL(render_circle, draw_circle(js2vec2(argv[0]), js2number(argv[1]), js2number(argv[2]), js2color(argv[3]), -1);) @@ -743,16 +741,10 @@ JSC_CCALL(render_end_pass, sprite_flush(); ) JSC_SCALL(render_text_size, ret = bb2js(text_bb(str, js2number(argv[1]), js2number(argv[2]), 1))) -JSC_CCALL(render_world2screen, return vec22js(world2screen(js2vec2(argv[0])))) -JSC_CCALL(render_screen2world, return vec22js(screen2world(js2vec2(argv[0])))) JSC_CCALL(render_set_camera, useproj = projection) JSC_CCALL(render_set_window, useproj = hudproj) static const JSCFunctionListEntry js_render_funcs[] = { - MIST_FUNC_DEF(render,world2screen,1), - MIST_FUNC_DEF(render,screen2world,1), - MIST_FUNC_DEF(render, normal, 0), - MIST_FUNC_DEF(render, wireframe, 0), MIST_FUNC_DEF(render, grid, 3), MIST_FUNC_DEF(render, point, 3), MIST_FUNC_DEF(render, circle, 3), @@ -873,11 +865,21 @@ static const JSCFunctionListEntry js_input_funcs[] = { JSC_CCALL(prosperon_emitters_step, emitters_step(js2number(argv[0]))) JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0]))) JSC_CCALL(prosperon_window_render, openglRender(&mainwin, js2gameobject(argv[0]), js2number(argv[1]))) +JSC_CCALL(prosperon_guid, + uint8_t bytes[16]; + for (int i = 0; i < 16; i++) bytes[i] = rand()%256; + char uuid[37]; + snprintf(uuid, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]); + return str2js(uuid); +) static const JSCFunctionListEntry js_prosperon_funcs[] = { MIST_FUNC_DEF(prosperon, emitters_step, 1), MIST_FUNC_DEF(prosperon, phys2d_step, 1), - MIST_FUNC_DEF(prosperon, window_render, 0) + MIST_FUNC_DEF(prosperon, window_render, 0), + MIST_FUNC_DEF(prosperon, guid, 0), }; JSC_CCALL(time_now, @@ -1085,18 +1087,50 @@ static void ray_query_fn(cpShape *shape, float t, cpVect n, float a, JSValue *cb number2js(a) }; script_call_sym(*cb, 3, argv); - for (int i = 0; i < 3; i++) - JS_FreeValue(js, argv[i]); + for (int i = 0; i < 3; i++) JS_FreeValue(js, argv[i]); } JSC_CCALL(physics_ray_query, cpSpaceSegmentQuery(space, js2vec2(argv[0]).cp, js2vec2(argv[1]).cp, js2number(argv[2]), allfilter, ray_query_fn, &argv[3]); ); +static void point_query_fn(cpShape *shape, float dist, cpVect point, JSValue *cb) +{ + JSValue argv[3] = { + JS_DupValue(js, shape2go(shape)->ref), + vec22js((HMM_Vec2)point), + number2js(dist) + }; + script_call_sym(*cb, 3, argv); + for (int i = 0; i < 3; i++) JS_FreeValue(js, argv[i]); +} + +JSC_CCALL(physics_point_query, + cpSpacePointQuery(space, js2vec2(argv[0]).cp, js2number(argv[1]), allfilter, point_query_fn, &argv[2]); +); + +JSValue pointinfo2js(cpPointQueryInfo info) +{ + JSValue o = JS_NewObject(js); + JS_SetPropertyStr(js, o, "distance", number2js(info.distance)); + JS_SetPropertyStr(js, o, "point", vec22js((HMM_Vec2)info.point)); + JS_SetPropertyStr(js, o, "entity", JS_DupValue(js, shape2go(info.shape)->ref)); + return o; +} + +JSC_CCALL(physics_point_query_nearest, + cpPointQueryInfo info; + cpShape *sh = cpSpacePointQueryNearest(space, js2vec2(argv[0]).cp, js2number(argv[1]), allfilter, &info); + if (!sh) return JS_UNDEFINED; + return pointinfo2js(info); +) + static const JSCFunctionListEntry js_physics_funcs[] = { MIST_FUNC_DEF(physics, sgscale, 2), MIST_FUNC_DEF(physics, set_cat_mask, 2), MIST_FUNC_DEF(physics, pos_query, 2), + MIST_FUNC_DEF(physics, point_query, 3), + MIST_FUNC_DEF(physics, point_query_nearest, 3), MIST_FUNC_DEF(physics, ray_query, 2), MIST_FUNC_DEF(physics, box_query, 2), MIST_FUNC_DEF(physics, shape_query, 1), @@ -1200,7 +1234,13 @@ static const JSCFunctionListEntry js_window_funcs[] = { MIST_FUNC_DEF(window, set_icon, 1) }; -JSC_GETSET_BODY(pos, Position, cvec2) +JSValue js_gameobject_set_pos(JSContext *js, JSValue this, JSValue val) { + gameobject *go = js2gameobject(this); + cpBodySetPosition(go->body, js2vec2(val).cp); + if (go->phys == CP_BODY_TYPE_STATIC) + cpSpaceReindexShapesForBody(space, go->body); +} +JSValue js_gameobject_get_pos(JSContext *js, JSValue this) { return vec22js((HMM_Vec2)cpBodyGetPosition(js2gameobject(this)->body)); } JSValue js_gameobject_set_angle (JSContext *js, JSValue this, JSValue val) { cpBodySetAngle(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); } JSValue js_gameobject_get_angle (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngle(js2gameobject(this)->body)); } JSC_GETSET_BODY(velocity, Velocity, cvec2) diff --git a/source/engine/render.c b/source/engine/render.c index 54f29c1..7dd2bd0 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -121,18 +121,13 @@ void capture_screen(int x, int y, int w, int h, const char *path) #include "HandmadeMath.h" -int renderMode = LIT; - struct rgba editorClearColor = {35,60,92,255}; -void opengl_rendermode(enum RenderMode r) { - renderMode = r; -} - sg_pass_action pass_action = {0}; static struct { sg_pass_action pass_action; + sg_pass pass; sg_pipeline pipe; sg_shader shader; @@ -283,23 +278,6 @@ void render_init() { }); } -HMM_Vec2 world2screen(HMM_Vec2 pos) -{ - pos = HMM_SubV2(pos, campos); - pos = HMM_ScaleV2(pos, 1.0/camzoom); - pos = HMM_AddV2(pos, HMM_ScaleV2(mainwin.size,0.5)); - return pos; -} - -HMM_Vec2 screen2world(HMM_Vec2 pos) -{ - pos = HMM_ScaleV2(pos, 1/mainwin.dpi); - pos = HMM_SubV2(pos, HMM_ScaleV2(mainwin.size, 0.5)); - pos = HMM_ScaleV2(pos, camzoom); - pos = HMM_AddV2(pos, campos); - return pos; -} - HMM_Mat4 projection = {0.f}; HMM_Mat4 hudproj = {0.f}; HMM_Mat4 useproj = {0}; diff --git a/source/engine/sprite.c b/source/engine/sprite.c index cfcd6d0..70d4c2e 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -85,8 +85,9 @@ int sprite_sort(sprite **sa, sprite **sb) if (!goa && !gob) return 0; if (!goa) return -1; if (!gob) return 1; - if (goa->drawlayer == gob->drawlayer) return 0; if (goa->drawlayer > gob->drawlayer) return 1; + if (gob->drawlayer > goa->drawlayer) return -1; + if (*sa > *sb) return 1; return -1; }