many fixes to editor

This commit is contained in:
John Alanbrook 2024-04-04 17:28:11 -05:00
parent 32268fc25d
commit 403771d7f8
17 changed files with 183 additions and 120 deletions

View file

@ -216,6 +216,15 @@ The ur[fn::A German prefix meaning primitive, original, or earliest.] system is
When prosperon starts, it searches for urs by name. Any file ending in ".jso" or ".json" will be interpereted as an ur, with same named jso and json being applied as (text, config) for an ur. A jso or json alone also constitute an ur. When prosperon starts, it searches for urs by name. Any file ending in ".jso" or ".json" will be interpereted as an ur, with same named jso and json being applied as (text, config) for an ur. A jso or json alone also constitute an ur.
An ur can also be defined by a json file. If an ur is found, it takes predecent over auto generated urs. The json of an ur looks like this:
| field | description |
|----|----|
| text | Path to a script file, or array of script files, to apply to the object |
| data | Path to a json file, or array of json files, to apply to the object |
Any ur file with this sort of json creates an ur which can be created in the game. A file named "box.ur" will be ingested and be available as "ur.box". When saving differences, it creates a json file with the same name as an ur (in this case, "box.json").
#+begin_scholium #+begin_scholium
Create an ur from the *hello* files above, and then spawn it. Create an ur from the *hello* files above, and then spawn it.
#+begin_src #+begin_src
@ -225,6 +234,10 @@ Primum.spawn(ur.hello);
When creating an actor from source files, all of its setup must take place. In this example, the setup happens during *ur.create*, and spawning is simply a matter of prototyping it. When creating an actor from source files, all of its setup must take place. In this example, the setup happens during *ur.create*, and spawning is simply a matter of prototyping it.
#+end_scholium #+end_scholium
This method allows high composability of game objects.
If an entity is created without an ur, is ur is defined as its given text and data. It cannot be saved. It must be given a new ur name.
Each ur has the following fields. Each ur has the following fields.
| field | description | | field | description |

View file

@ -882,6 +882,11 @@ Object.defineProperty(String.prototype, 'uc', { value: function() { return this.
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }}); Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
/* ARRAY DEFS */ /* ARRAY DEFS */
Object.defineProperty(Array.prototype, 'aspect', {
value: function() {
return this.x/this.y;
}
});
Object.defineProperty(Array.prototype, 'copy', { Object.defineProperty(Array.prototype, 'copy', {
value: function() { value: function() {
var c = []; var c = [];

View file

@ -1,20 +1,35 @@
this.phys = physics.kinematic; this.phys = physics.kinematic;
this.dir_view2world = function(dir) { return dir.scale(this.zoom); }; this.dir_view2world = function(dir) { return dir.scale(this.zoom); };
this.view2world = function(pos) { this.view2world = function(pos) {
pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]); var useren = window.rendersize.scale(this.zoom);
pos = pos.sub(window.rendersize.scale(0.5)); if (window.mode === window.modetypes.stretch) {
pos = pos.scale(this.zoom); pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]);
pos = pos.add(this.pos); pos = pos.sub(window.rendersize.scale(0.5));
pos = pos.scale(this.zoom);
pos = pos.add(this.pos);
}
if (window.mode === window.modetypes.full) {
pos = pos.sub(window.size.scale(0.5));
pos = pos.scale(this.zoom);
pos = pos.add(this.pos);
}
return pos; return pos;
}; };
this.world2view = function(pos) { this.world2view = function(pos) {
pos = pos.sub(this.pos); if (window.mode === window.modetypes.stretch) {
pos = pos.scale(1.0/this.zoom); pos = pos.sub(this.pos);
pos = pos.add(window.rendersize.scale(0.5)); pos = pos.scale(1.0/this.zoom);
pos = pos.add(window.rendersize.scale(0.5));
}
if (window.mode === window.modetypes.full) {
pos = pos.sub(this.pos);
pos = pos.scale(1/this.zoom);
pos = pos.add(window.size.scale(0.5));
}
return pos; return pos;
}; };
this.screenright = function() { return this.view2world(window.size).x; } this.screenright = function() { return this.view2world(window.size).x; }
this.screenleft = function() { return this.pos.x - (window.rendersize.x/2); } this.screenleft = function() { return this.view2world([0,0]).x; }
this.zoom = 1; this.zoom = 1;

View file

@ -425,7 +425,7 @@ component.polygon2d = Object.copy(collider2d, {
gizmo() { gizmo() {
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green)); this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green));
this.points.forEach((x,i)=>render.coordinate(this.gameobject.this2screen(x), i)); this.points.forEach((x,i)=>render.coordinate(this.gameobject.this2screen(x)));
}, },
pick(pos) { pick(pos) {
@ -589,11 +589,11 @@ component.edge2d = Object.copy(collider2d, {
this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x))); this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x)));
} else { } else {
for (var i = 0; i < this.points.length; i += 3) for (var i = 0; i < this.points.length; i += 3)
render.coordinate(this.gameobject.this2screen(this.points[i]), i, Color.teal); render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.teal);
for (var i = 1; i < this.points.length; i+=3) { for (var i = 1; i < this.points.length; i+=3) {
render.coordinate(this.gameobject.this2screen(this.points[i]), i, Color.green); render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.green);
render.coordinate(this.gameobject.this2screen(this.points[i+1]), i+1, Color.green); render.coordinate(this.gameobject.this2screen(this.points[i+1]), 1, Color.green);
render.line([this.gameobject.this2screen(this.points[i-1]), this.gameobject.this2screen(this.points[i])], Color.yellow); render.line([this.gameobject.this2screen(this.points[i-1]), this.gameobject.this2screen(this.points[i])], Color.yellow);
render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], Color.yellow); render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], Color.yellow);
} }
@ -707,7 +707,6 @@ component.edge2d.impl = Object.mix(collider2d.impl, {
var bucket = component.edge2d; var bucket = component.edge2d;
bucket.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises."; bucket.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises.";
bucket.inputs = {}; bucket.inputs = {};
//bucket.inputs.post = function() { this.sync(); };
bucket.inputs.h = function() { this.hollow = !this.hollow; }; bucket.inputs.h = function() { this.hollow = !this.hollow; };
bucket.inputs.h.doc = "Toggle hollow."; bucket.inputs.h.doc = "Toggle hollow.";

View file

@ -42,7 +42,7 @@ function ediff(from,to)
var diff = ediff(from[key], to[key]); var diff = ediff(from[key], to[key]);
if (diff && !Object.empty(diff)) if (diff && !Object.empty(diff))
ret[key] = Object.values(ediff(v,[])); ret[key] = Object.values(ediff(v,[]));
return; return;
} }

View file

@ -3,7 +3,6 @@
selectable selectable
*/ */
window.mode = window.modetypes.full;
game.loadurs(); game.loadurs();
console.info(`window size: ${window.size}, render size: ${window.rendersize}`); console.info(`window size: ${window.size}, render size: ${window.rendersize}`);
@ -11,6 +10,8 @@ console.info(`window size: ${window.size}, render size: ${window.rendersize}`);
player[0].control(debug); player[0].control(debug);
Register.gui.register(debug.draw, debug); Register.gui.register(debug.draw, debug);
var show_frame = true;
var editor = { var editor = {
toString() { return "editor"; }, toString() { return "editor"; },
grid_size: 100, grid_size: 100,
@ -38,8 +39,7 @@ var editor = {
return this.do_select(go); return this.do_select(go);
}, },
/* Tries to select id */ do_select(obj) { /* select an object, if it is selectable given the current editor state */
do_select(obj) {
if (!obj) return; if (!obj) return;
if (!obj._ed.selectable) return undefined; if (!obj._ed.selectable) return undefined;
@ -394,13 +394,16 @@ var editor = {
gui() { gui() {
/* Clean out killed objects */ /* Clean out killed objects */
if (show_frame)
render.line(shape.box(window.rendersize.x, window.rendersize.y).wrapped(1).map(p => game.camera.world2view(p)), Color.yellow);
render.text([0,0], game.camera.world2view([0,0])); render.text([0,0], game.camera.world2view([0,0]));
render.text("WORKING LAYER: " + this.working_layer, [0,520]); render.text("WORKING LAYER: " + this.working_layer, [0,520]);
render.text("MODE: " + this.edit_mode, [0,500]); render.text("MODE: " + this.edit_mode, [0,500]);
if (this.comp_info && this.sel_comp) if (this.comp_info && this.sel_comp)
render.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1); render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
render.cross(editor.edit_level.screenpos(),3,Color.blue); render.cross(editor.edit_level.screenpos(),3,Color.blue);
@ -530,7 +533,6 @@ var editor = {
var obj = editor.edit_level.spawn(mur); var obj = editor.edit_level.spawn(mur);
obj.set_worldpos(input.mouse.worldpos()); obj.set_worldpos(input.mouse.worldpos());
this.selectlist = [obj]; this.selectlist = [obj];
console.warn(`made something and now the selected objects is ${this.selectlist.length} long.`);
}, },
load_prev() { load_prev() {
@ -567,7 +569,7 @@ var editor = {
ur[sub] = { ur[sub] = {
name: sub, name: sub,
data: file, data: file,
proto: json.decode(json.encode(obj)) fresh: json.decode(json.encode(obj))
} }
obj.ur = sub; obj.ur = sub;
@ -667,7 +669,8 @@ editor.inputs.f9 = function() { os.capture( "capture.bmp", 0, 0, 500, 500); }
editor.inputs.release_post = function() { editor.inputs.release_post = function() {
editor.snapshot(); editor.snapshot();
editor.edit_level.check_dirty();
editor.selectlist?.forEach(x => x.check_dirty());
/* snap all objects to be pixel perfect */ /* snap all objects to be pixel perfect */
game.all_objects(o => o.pos = o.pos.map(x => Math.round(x)), editor.edit_level); game.all_objects(o => o.pos = o.pos.map(x => Math.round(x)), editor.edit_level);
@ -765,11 +768,11 @@ editor.inputs.m = function() {
}; };
editor.inputs.m.doc = "Mirror selected objects on the X axis."; editor.inputs.m.doc = "Mirror selected objects on the X axis.";
editor.inputs.q = function() { editor.comp_info = !editor.comp_info; }; editor.inputs.q = function() { editor.comp_info = !editor.comp_info; };
editor.inputs.q.doc = "Toggle help for the selected component."; editor.inputs.q.doc = "Toggle help for the selected component.";
editor.inputs.f = function() { editor.inputs.f = function() {
return;
if (editor.selectlist.length === 0) return; if (editor.selectlist.length === 0) return;
var bb = editor.selectlist[0].boundingbox(); var bb = editor.selectlist[0].boundingbox();
editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox()); }); editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox()); });
@ -787,6 +790,7 @@ editor.inputs['C-f'] = function() {
editor.inputs['C-f'].doc = "Tunnel into the selected level object to edit it."; editor.inputs['C-f'].doc = "Tunnel into the selected level object to edit it.";
editor.inputs['C-F'] = function() { editor.inputs['C-F'] = function() {
console.info("PRESSED C-F");
if (editor.edit_level.master === world) return; if (editor.edit_level.master === world) return;
editor.edit_level = editor.edit_level.master; editor.edit_level = editor.edit_level.master;
@ -901,14 +905,13 @@ editor.inputs['C-s'] = function() {
if (!tur.data) { if (!tur.data) {
io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1)); io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1));
tur.data = tur.text.set_ext(".json"); tur.data = tur.text.set_ext(".json");
} } else {
else {
var oldjs = json.decode(io.slurp(tur.data)); var oldjs = json.decode(io.slurp(tur.data));
Object.merge(oldjs, savejs); Object.merge(oldjs, savejs);
io.slurpwrite(tur.data, json.encode(oldjs,null,1)); io.slurpwrite(tur.data, json.encode(oldjs,null,1));
} }
Object.merge(tur.proto, savejs); Object.merge(tur.fresh, savejs);
saveobj.check_dirty(); saveobj.check_dirty();
// Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); // Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
@ -1484,6 +1487,7 @@ var inputpanel = {
}; };
inputpanel.inputs = {}; inputpanel.inputs = {};
inputpanel.inputs.block = true;
inputpanel.inputs.post = function() { this.keycb(); } inputpanel.inputs.post = function() { this.keycb(); }

View file

@ -241,7 +241,7 @@ global.mixin("scripts/render");
global.mixin("scripts/debug"); global.mixin("scripts/debug");
var frame_t = profile.secs(profile.now()); var frame_t = profile.secs(profile.now());
var phys_step = 1/60; var phys_step = 1/240;
var sim = {}; var sim = {};
sim.mode = "play"; sim.mode = "play";
@ -280,14 +280,14 @@ function process()
prosperon.update(dt*game.timescale); prosperon.update(dt*game.timescale);
if (sim.mode === "step") if (sim.mode === "step")
sim.pause(); sim.pause();
}
physlag += dt;
physlag += dt;
while (physlag > phys_step) {
while (physlag > phys_step) { physlag -= phys_step;
physlag -= phys_step; prosperon.phys2d_step(phys_step*game.timescale);
prosperon.phys2d_step(phys_step*game.timescale); prosperon.physupdate(phys_step*game.timescale);
prosperon.physupdate(phys_step*game.timescale); }
} }
if (!game.camera) if (!game.camera)
@ -312,15 +312,15 @@ function process()
game.timescale = 1; 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, startobj) { game.all_objects = function(fn, startobj) {
startobj ??= world; startobj ??= world;
var eachobj = function(obj,fn)
{
fn(obj);
for (var o in obj.objects)
eachobj(obj.objects[o],fn);
}
eachobj(startobj,fn); eachobj(startobj,fn);
}; };
@ -529,11 +529,13 @@ var Event = {
}, },
}; };
// window.rendersize is the resolution the game renders at
// window.size is the physical size of the window on the desktop
window.modetypes = { window.modetypes = {
stretch: 0, // stretch to fill window stretch: 0, // stretch render to fill window
keep: 1, // keep exact dimensions keep: 1, // keep render exact dimensions, with no stretching
width: 2, // keep width width: 2, // keep render at width
height: 3, // keep height height: 3, // keep render at height
expand: 4, // expand width or height expand: 4, // expand width or height
full: 5 // expand out beyond window full: 5 // expand out beyond window
}; };
@ -546,8 +548,6 @@ global.mixin("scripts/spline");
global.mixin("scripts/components"); global.mixin("scripts/components");
window.doc = {}; window.doc = {};
window.doc.width = "Width of the game window.";
window.doc.height = "Height of the game window.";
window.doc.dimensions = "Window width and height packaged in an array [width,height]"; window.doc.dimensions = "Window width and height packaged in an array [width,height]";
window.doc.title = "Name in the title bar of the window."; window.doc.title = "Name in the title bar of the window.";
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width."; window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
@ -557,7 +557,6 @@ global.mixin("scripts/entity");
function world_start() { function world_start() {
globalThis.world = os.make_gameobject(); globalThis.world = os.make_gameobject();
world.setref(world);
world.objects = {}; world.objects = {};
world.toString = function() { return "world"; }; world.toString = function() { return "world"; };
world.ur = "world"; world.ur = "world";

View file

@ -10,8 +10,6 @@ function obj_unique_name(name, obj) {
return n; return n;
} }
var urcache = {};
var gameobject_impl = { var gameobject_impl = {
get pos() { get pos() {
assert(this.master, `Entity ${this.toString()} has no master.`); assert(this.master, `Entity ${this.toString()} has no master.`);
@ -74,7 +72,7 @@ var gameobject = {
this._ed.urdiff = this.json_obj(); this._ed.urdiff = this.json_obj();
this._ed.dirty = !Object.empty(this._ed.urdiff); this._ed.dirty = !Object.empty(this._ed.urdiff);
return; // TODO: IMPLEMENT return; // TODO: IMPLEMENT
var lur = ur[this.master.ur]; var lur = this.master.ur;
if (!lur) return; if (!lur) return;
var lur = lur.objects[this.toString()]; var lur = lur.objects[this.toString()];
var d = ediff(this._ed.urdiff, lur); var d = ediff(this._ed.urdiff, lur);
@ -93,8 +91,9 @@ var gameobject = {
}, },
urstr() { urstr() {
if (this._ed.dirty) return "*" + this.ur; var str = this.ur.name;
return this.ur; if (this._ed.dirty) str = "*" + str;
return str;
}, },
full_path() { full_path() {
@ -213,11 +212,7 @@ var gameobject = {
}, },
cry(file) { cry(file) {
this.crying = audio.play(file, audio.bus.sfx); return audio.cry(file);
var killfn = () => { this.crying = undefined;
console.warn("killed"); }
this.crying.hook = killfn;
return killfn;
}, },
gscale() { return this.scale; }, gscale() { return this.scale; },
@ -239,7 +234,7 @@ var gameobject = {
worldangle() { return this.angle; }, worldangle() { return this.angle; },
sworldangle(x) { this.angle = x; }, sworldangle(x) { this.angle = x; },
get_ur() { return urcache[this.ur]; }, get_ur() { return this.ur; },
/* spawn an entity /* spawn an entity
text can be: text can be:
@ -250,24 +245,33 @@ var gameobject = {
spawn(text, config, callback) { spawn(text, config, callback) {
var ent = os.make_gameobject(); var ent = os.make_gameobject();
ent.guid = prosperon.guid(); ent.guid = prosperon.guid();
ent.setref(ent);
ent.components = {}; ent.components = {};
ent.objects = {}; ent.objects = {};
ent.timers = []; ent.timers = [];
if (typeof text === 'object' && text) // assume it's an ur if (typeof text === 'object' && text) // assume it's an ur
{ ent.ur = text;
config = text.data; else
ent.ur = text.name; ent.ur = getur(text, config);
text = text.text;
} text = ent.ur.text;
config = [ent.ur.data, config];
if (text)
use(text, ent); if (typeof text === 'string')
if (config) use(text, ent);
Object.assign(ent, json.decode(io.slurp(config))); else if (Array.isArray(text))
text.forEach(path => use(path,ent));
if (typeof config === 'string')
Object.assign(ent, json.decode(Resources.replstrs(config)));
else if (Array.isArray(config))
config.forEach(function(path) {
if (typeof path === 'string')
Object.assign(ent, json.decode(Resources.replstrs(path)));
else if (typeof path === 'object')
Object.assign(ent,path);
});
ent.ur ??= text + "+" + config;
ent.reparent(this); ent.reparent(this);
for (var [prop, p] of Object.entries(ent)) { for (var [prop, p] of Object.entries(ent)) {
@ -296,8 +300,7 @@ var gameobject = {
selectable: true, selectable: true,
dirty: false, dirty: false,
inst: false, inst: false,
urdiff: {}, urdiff: {}
fresh: json.decode(json.encode(ent)),
}; };
Object.hide(ent, '_ed'); Object.hide(ent, '_ed');
@ -308,12 +311,10 @@ var gameobject = {
var o = ent.objects; var o = ent.objects;
delete ent.objects; delete ent.objects;
for (var i in o) { for (var i in o) {
console.info(`MAKING ${i}`); var newur = o[i].ur;
var n = ent.spawn(ur[o[i].ur]);
ent.rename_obj(n.toString(), i);
delete o[i].ur; delete o[i].ur;
Object.assign(n, o[i]); var n = ent.spawn(ur[newur], o[i]);
n.sync(); ent.rename_obj(n.toString(), i);
} }
} }
@ -321,6 +322,8 @@ var gameobject = {
if (callback) callback(ent); if (callback) callback(ent);
ent.ur.fresh ??= json.decode(json.encode(ent));
return ent; return ent;
}, },
@ -349,7 +352,7 @@ var gameobject = {
return t; return t;
}; };
var name = unique_name(Object.keys(parent.objects), this.ur); var name = unique_name(Object.keys(parent.objects), this.ur.name);
parent.objects[name] = this; parent.objects[name] = this;
parent[name] = this; parent[name] = this;
@ -446,7 +449,7 @@ var gameobject = {
/* The unique components of this object. Its diff. */ /* The unique components of this object. Its diff. */
json_obj() { json_obj() {
var fresh = this._ed.fresh; var fresh = this.ur.fresh;
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components. var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
var d = ediff(thiso, fresh); var d = ediff(thiso, fresh);
@ -473,7 +476,7 @@ var gameobject = {
/* The object needed to store an object as an instance of a master */ /* The object needed to store an object as an instance of a master */
instance_obj() { instance_obj() {
var t = this.transform(); var t = this.transform();
t.ur = this.ur; t.ur = this.ur.name;
return t; return t;
}, },
@ -484,7 +487,7 @@ var gameobject = {
t.angle = Math.places(this.angle, 4); t.angle = Math.places(this.angle, 4);
if (t.angle === 0) delete t.angle; if (t.angle === 0) delete t.angle;
t.scale = this.scale; t.scale = this.scale;
t.scale = t.scale.map((x, i) => x / this._ed.fresh.scale[i]); t.scale = t.scale.map((x, i) => x / this.ur.fresh.scale[i]);
t.scale = t.scale.map(x => Math.places(x, 3)); t.scale = t.scale.map(x => Math.places(x, 3));
if (t.scale.every(x => x === 1)) delete t.scale; if (t.scale.every(x => x === 1)) delete t.scale;
return t; return t;
@ -499,7 +502,7 @@ var gameobject = {
}, },
dup(diff) { dup(diff) {
var n = this.master.spawn(this.__proto__); var n = this.master.spawn(this.ur);
Object.totalmerge(n, this.instance_obj()); Object.totalmerge(n, this.instance_obj());
return n; return n;
}, },
@ -592,9 +595,8 @@ var gameobject = {
function go_init() { function go_init() {
var gop = os.make_gameobject().__proto__; var gop = os.make_gameobject().__proto__;
Object.mixin(gop, gameobject); Object.mixin(gop, gameobject);
var gsync = gop.sync;
gop.sync = function() { gop.sync = function() {
gsync.call(this); this.selfsync();
this.components.forEach(function(x) { x.sync?.(); }); this.components.forEach(function(x) { x.sync?.(); });
this.objects.forEach(function(x) { x.sync?.(); }); this.objects.forEach(function(x) { x.sync?.(); });
} }
@ -734,10 +736,33 @@ function file2fqn(file) {
return ur[fqn]; return ur[fqn];
} }
var getur = function(text, data)
{
var urstr = text + "+" + data;
if (!ur[urstr]) {
ur[urstr] = {
name: urstr,
text: text,
data: data
}
}
return ur[urstr];
}
game.loadurs = function() { game.loadurs = function() {
ur = {}; ur = {};
ur._list = []; ur._list = [];
/* FIND ALL URS IN A PROJECT */ /* FIND ALL URS IN A PROJECT */
for (var file of io.glob("**.ur")) {
var urname = file.name();
if (ur[urname]) {
console.warn(`Tried to make another ur with the name ${urname} from ${file}, but it already exists.`);
continue;
}
var urjson = json.decode(io.slurp(file));
urjson.name = urname;
ur[urname] = urjson;
}
for (var file of io.glob("**.jso")) { for (var file of io.glob("**.jso")) {
if (file[0] === '.' || file[0] === '_') continue; if (file[0] === '.' || file[0] === '_') continue;
var topur = file2fqn(file); var topur = file2fqn(file);

View file

@ -309,8 +309,8 @@ var Player = {
switch (state) { switch (state) {
case 'released': case 'released':
pawn.inputs.release_post?.call(pawn); pawn.inputs.release_post?.call(pawn);
break; break;
} }
if (!pawn.inputs.fallthru) return; if (!pawn.inputs.fallthru) return;

View file

@ -1,4 +1,5 @@
var audio = {}; var audio = {};
var cries = {};
audio.samplerate = dspsound.samplerate(); audio.samplerate = dspsound.samplerate();
audio.play = function(file,bus) { audio.play = function(file,bus) {
@ -10,6 +11,7 @@ audio.play = function(file,bus) {
} }
var src = audio.dsp.source(file); var src = audio.dsp.source(file);
src.plugin(bus); src.plugin(bus);
src.guid = prosperon.guid();
return src; return src;
} }
audio.bus = {}; audio.bus = {};
@ -17,15 +19,24 @@ audio.bus.master = dspsound.master();
audio.dsp = {}; audio.dsp = {};
audio.dsp = dspsound; audio.dsp = dspsound;
var cries = [];
audio.cry = function(file) audio.cry = function(file)
{ {
var player = audio.play(file); var player = audio.play(file);
cries.push(player); player.guid = prosperon.guid();
var hook = function() { console.warn("ENDED SOUND!!!!"); cries.remove(player); player = undefined; hook = undefined;} cries[player.guid] = player;
player.hook = hook; player.ended = function() { delete cries[player.guid]; player = undefined; }
return player.ended;
} }
var killer = Register.appupdate.register(function() {
for (var i in cries) {
var cry = cries[i];
if (!cry.ended) continue;
if (cry.frame < cry.lastframe || cry.frame === cry.lastframe) cry.ended();
cry.lastframe = cry.frame;
}
});
var song; var song;
audio.music = function(file, fade) { audio.music = function(file, fade) {

View file

@ -192,10 +192,14 @@ Cmdline.register_order("edit", function() {
} }
window.size = [1280, 720]; window.size = [1280, 720];
window.mode = window.modetypes.full;
sim.pause();
game.engine_start(function() { game.engine_start(function() {
global.mixin("scripts/editor.js"); global.mixin("scripts/editor.js");
use("editorconfig.js"); use("editorconfig.js");
use("config.js");
editor.enter_editor(); editor.enter_editor();
}); });
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?"); }, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");

View file

@ -530,7 +530,6 @@ int shape_get_sensor(struct phys2d_shape *shape) {
if (!shape->shape) { if (!shape->shape) {
struct phys2d_edge *edge = shape->data; struct phys2d_edge *edge = shape->data;
if (arrlen(edge->shapes) > 0) return cpShapeGetSensor(edge->shapes[0]); if (arrlen(edge->shapes) > 0) return cpShapeGetSensor(edge->shapes[0]);
YughWarn("Attempted to get the sensor of an edge with no shapes. It has %d points.", arrlen(edge->points));
return 0; return 0;
} }

View file

@ -50,15 +50,15 @@ void font_init() {
.shader = fontshader, .shader = fontshader,
.layout = { .layout = {
.attrs = { .attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* verts */ [0].format = SG_VERTEXFORMAT_FLOAT2, /* verts */
[0].buffer_index = 1, [0].buffer_index = 1,
[1].format = SG_VERTEXFORMAT_FLOAT2, /* pos */ [1].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[2].format = SG_VERTEXFORMAT_FLOAT2, /* width and height */ [2].format = SG_VERTEXFORMAT_FLOAT2, /* width and height */
[3].format = SG_VERTEXFORMAT_USHORT2N, /* uv pos */ [3].format = SG_VERTEXFORMAT_USHORT2N, /* uv pos */
[4].format = SG_VERTEXFORMAT_USHORT2N, /* uv width and height */ [4].format = SG_VERTEXFORMAT_USHORT2N, /* uv width and height */
[5].format = SG_VERTEXFORMAT_UBYTE4N, /* color */ [5].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
}, },
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE .buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE
}, },
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP, .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.colors[0].blend = blend_trans, .colors[0].blend = blend_trans,
@ -244,7 +244,7 @@ void text_flush(HMM_Mat4 *proj) {
} }
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) { void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) {
if (curchar+1 >= max_chars) if (curchar-10 >= max_chars)
return; return;
struct rgba colorbox = {0,0,0,255}; struct rgba colorbox = {0,0,0,255};
@ -395,15 +395,15 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
} }
while (wordstart < line) { while (wordstart < line) {
if (*wordstart == '\e') if (*wordstart == '\e')
wordstart = esc_color(wordstart, &usecolor, color); wordstart = esc_color(wordstart, &usecolor, color);
sdrawCharacter(font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255}); sdrawCharacter(font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor); sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
cursor.X += font->Characters[*wordstart].Advance * tracking * scale; cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
wordstart++; wordstart++;
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor); check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
} }
} }
} }

View file

@ -61,10 +61,6 @@ const char *js2str(JSValue v) {
return JS_ToCString(js, v); return JS_ToCString(js, v);
} }
/* support functions for these macros when they involve a JSValue */
JSValue js2JSValue(JSValue v) { return v; }
JSValue JSValue2js(JSValue v) { return v; }
QJSCLASS(gameobject) QJSCLASS(gameobject)
QJSCLASS(emitter) QJSCLASS(emitter)
QJSCLASS(dsp_node) QJSCLASS(dsp_node)
@ -1082,14 +1078,12 @@ static const JSCFunctionListEntry js_dsp_node_funcs[] = {
JSC_GETSET(sound, loop, boolean) JSC_GETSET(sound, loop, boolean)
JSC_GETSET(sound, timescale, number) JSC_GETSET(sound, timescale, number)
JSC_GETSET(sound, frame, number) JSC_GETSET(sound, frame, number)
JSC_GETSET_HOOK(sound, hook)
JSC_CCALL(sound_frames, return number2js(js2sound(this)->data->frames)) JSC_CCALL(sound_frames, return number2js(js2sound(this)->data->frames))
static const JSCFunctionListEntry js_sound_funcs[] = { static const JSCFunctionListEntry js_sound_funcs[] = {
CGETSET_ADD(sound, loop), CGETSET_ADD(sound, loop),
CGETSET_ADD(sound, timescale), CGETSET_ADD(sound, timescale),
CGETSET_ADD(sound, frame), CGETSET_ADD(sound, frame),
CGETSET_ADD(sound, hook),
MIST_FUNC_DEF(sound, frames, 0), MIST_FUNC_DEF(sound, frames, 0),
}; };
@ -1164,8 +1158,7 @@ JSC_GETSET(gameobject, maxvelocity, number)
JSC_GETSET(gameobject, maxangularvelocity, number) JSC_GETSET(gameobject, maxangularvelocity, number)
JSC_GETSET(gameobject, warp_filter, bitmask) JSC_GETSET(gameobject, warp_filter, bitmask)
JSC_GETSET(gameobject, drawlayer, number) JSC_GETSET(gameobject, drawlayer, number)
JSC_CCALL(gameobject_setref, js2gameobject(this)->ref = argv[0]); JSC_CCALL(gameobject_selfsync, gameobject_apply(js2gameobject(this)))
JSC_CCALL(gameobject_sync, gameobject_apply(js2gameobject(this)))
JSC_CCALL(gameobject_in_air, return boolean2js(phys2d_in_air(js2gameobject(this)->body))) JSC_CCALL(gameobject_in_air, return boolean2js(phys2d_in_air(js2gameobject(this)->body)))
JSC_CCALL(gameobject_world2this, return vec22js(world2go(js2gameobject(this), js2vec2(argv[0])))) JSC_CCALL(gameobject_world2this, return vec22js(world2go(js2gameobject(this), js2vec2(argv[0]))))
JSC_CCALL(gameobject_this2world, return vec22js(go2world(js2gameobject(this), js2vec2(argv[0])))) JSC_CCALL(gameobject_this2world, return vec22js(go2world(js2gameobject(this), js2vec2(argv[0]))))
@ -1200,8 +1193,7 @@ static const JSCFunctionListEntry js_gameobject_funcs[] = {
MIST_FUNC_DEF(gameobject, this2world, 1), MIST_FUNC_DEF(gameobject, this2world, 1),
MIST_FUNC_DEF(gameobject, dir_world2this, 1), MIST_FUNC_DEF(gameobject, dir_world2this, 1),
MIST_FUNC_DEF(gameobject, dir_this2world, 1), MIST_FUNC_DEF(gameobject, dir_this2world, 1),
MIST_FUNC_DEF(gameobject,setref,1), MIST_FUNC_DEF(gameobject, selfsync, 0),
MIST_FUNC_DEF(gameobject, sync, 0),
}; };
JSC_CCALL(joint_pin, return constraint2js(constraint_make(cpPinJointNew(js2gameobject(argv[0])->body, js2gameobject(argv[1])->body, cpvzero,cpvzero)))) JSC_CCALL(joint_pin, return constraint2js(constraint_make(cpPinJointNew(js2gameobject(argv[0])->body, js2gameobject(argv[1])->body, cpvzero,cpvzero))))
@ -1454,6 +1446,7 @@ JSC_CCALL(os_sprite,
JSC_CCALL(os_make_gameobject, JSC_CCALL(os_make_gameobject,
ret = gameobject2js(MakeGameobject()); ret = gameobject2js(MakeGameobject());
JS_SetPropertyFunctionList(js, ret, js_gameobject_funcs, countof(js_gameobject_funcs)); JS_SetPropertyFunctionList(js, ret, js_gameobject_funcs, countof(js_gameobject_funcs));
js2gameobject(ret)->ref = ret;
return ret; return ret;
) )
JSC_CCALL(os_make_circle2d, JSC_CCALL(os_make_circle2d,

View file

@ -278,13 +278,11 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
if(end) { if(end) {
if (s->loop) if (s->loop)
s->frame = 0; s->frame = 0;
script_call_sym(s->hook,0,NULL);
} }
} }
void free_source(struct sound *s) void free_source(struct sound *s)
{ {
JS_FreeValue(js, s->hook);
src_delete(s->src); src_delete(s->src);
free(s); free(s);
} }
@ -305,7 +303,6 @@ struct dsp_node *dsp_source(const char *path)
self->loop = false; self->loop = false;
self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self); self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self);
self->timescale = 1; self->timescale = 1;
self->hook = JS_UNDEFINED;
dsp_node *n = make_node(self, sound_fillbuf, free_source); dsp_node *n = make_node(self, sound_fillbuf, free_source);
return n; return n;
} }

View file

@ -17,7 +17,6 @@ typedef struct sound {
int loop; int loop;
float timescale; float timescale;
SRC_STATE *src; SRC_STATE *src;
JSValue hook;
} sound; } sound;
/* Represents a sound file source, fulled loaded*/ /* Represents a sound file source, fulled loaded*/

View file

@ -112,7 +112,7 @@ void quickjs_set_dumpout(FILE *f)
//#define DUMP_READ_OBJECT //#define DUMP_READ_OBJECT
#ifdef DUMP #ifdef DUMP
#define DUMP_FREE //#define DUMP_FREE
#define DUMP_MEM #define DUMP_MEM
#define DUMP_CLOSURE #define DUMP_CLOSURE
#define DUMP_GC #define DUMP_GC