create new entities in editor

This commit is contained in:
John Alanbrook 2024-03-01 17:45:06 +00:00
parent 1e432346ff
commit 1e9b5f6341
8 changed files with 169 additions and 69 deletions

View file

@ -4,6 +4,16 @@ this.view2world = function(pos) { return cmd(137,pos); };
this.world2view = function(pos) { return cmd(136,pos); }; this.world2view = function(pos) { return cmd(136,pos); };
this.realzoom = function() { return cmd(135); }; this.realzoom = function() { return cmd(135); };
this.right = function()
{
return this.pos.x + (Window.width/2);
}
this.left = function()
{
return this.pos.x - (Window.width/2);
}
this.mixin({ this.mixin({
get zoom() { get zoom() {
var z = Game.native.y / Window.dimensions.y; var z = Game.native.y / Window.dimensions.y;

View file

@ -817,8 +817,8 @@ component.circle2d.impl = Object.mix({
set offset(x) { cmd_circle2d(1,this.id,x); }, set offset(x) { cmd_circle2d(1,this.id,x); },
get offset() { return cmd_circle2d(3,this.id); }, get offset() { return cmd_circle2d(3,this.id); },
get pos() { return this.offset; }, get pos() { return cmd_circle2d(3,this.id); },
set pos(x) { this.offset = x; }, set pos(x) { cmd_circle2d(1,this.id,x); },
}, collider2d.impl); }, collider2d.impl);

View file

@ -99,7 +99,7 @@ var Gizmos = {
}, },
}; };
Object.assign(profile, { Object.assign(performance, {
tick_now() { return cmd(127); }, tick_now() { return cmd(127); },
ns(ticks) { return cmd(128, ticks); }, ns(ticks) { return cmd(128, ticks); },
us(ticks) { return cmd(129, ticks); }, us(ticks) { return cmd(129, ticks); },
@ -123,34 +123,43 @@ Object.assign(profile, {
cpu(fn, times, q) { cpu(fn, times, q) {
times ??= 1; times ??= 1;
q ??= "unnamed"; q ??= "unnamed";
var start = profile.tick_now(); var start = performance.tick_now();
for (var i = 0; i < times; i++) for (var i = 0; i < times; i++)
fn(); fn();
var elapsed = profile.tick_now() - start; var elapsed = performance.tick_now() - start;
var avgt = profile.best_t(elapsed/times); var avgt = performance.best_t(elapsed/times);
var totalt = profile.best_t(elapsed); var totalt = performance.best_t(elapsed);
console.say(`profile [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`); console.say(`performance [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`);
}, },
get fps() { return sys_cmd(8); }, get fps() { return sys_cmd(8); },
measure(fn, str) {
str ??= 'unnamed';
var start = performance.tick_now();
fn();
var elapsed = performance.tick_now()-start;
elapsed = performance.best_t(elapsed);
say(`performance [${str}]: ${elapsed.time.toFixed(3)} ${elapsed.unit}`);
},
}); });
profile.test = { performance.test = {
barecall() { profile(0); }, barecall() { performance(0); },
unpack_num(n) { profile(1,n); }, unpack_num(n) { performance(1,n); },
unpack_array(n) { profile(2,n); }, unpack_array(n) { performance(2,n); },
pack_num() { profile(3); }, pack_num() { performance(3); },
pack_string() { profile(6); }, pack_string() { performance(6); },
unpack_string(s) { profile(4,s); }, unpack_string(s) { performance(4,s); },
unpack_32farr(a) { profile(5,a); }, unpack_32farr(a) { performance(5,a); },
call_fn_n(fn1, n) { profile(7,fn1,n,fn2); }, call_fn_n(fn1, n) { performance(7,fn1,n,fn2); },
}; };
profile.test.call_fn_n.doc = "Calls fn1 n times, and then fn2."; performance.test.call_fn_n.doc = "Calls fn1 n times, and then fn2.";
profile.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`; performance.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`;
/* These controls are available during editing, and during play of debug builds */ /* These controls are available during editing, and during play of debug builds */
var DebugControls = {}; var DebugControls = {};
@ -347,4 +356,6 @@ Debug.api.print_doc = function(name)
return { return {
Debug, Debug,
Time, Time,
Gizmos,
performance
} }

View file

@ -521,8 +521,8 @@ var editor = {
lvl_history: [], lvl_history: [],
load(file) { load(urstr) {
var obj = editor.edit_level.spawn(Object.access(ur, file)); var obj = editor.edit_level.spawn(urstr);
obj.set_worldpos(Mouse.worldpos); obj.set_worldpos(Mouse.worldpos);
this.selectlist = [obj]; this.selectlist = [obj];
}, },
@ -537,12 +537,41 @@ var editor = {
/* Checking to save an entity as a subtype. */ /* Checking to save an entity as a subtype. */
/* sub is the name of the (sub)type; obj is the object to save it as */ /* sub is the name of the (sub)type; obj is the object to save it as */
/* if saving subtype of 'empty', it appears on the top level */
saveas_check(sub, obj) { saveas_check(sub, obj) {
return; if (!sub) {
if (!sub) return; console.warn(`Cannot save an object to an empty ur.`);
obj ??= editor.selectlist[0]; return;
}
// var curur = prototypes.get_ur(sub);
if (!obj) {
console.warn(`Specify an obejct to save.`);
return;
}
if (obj.ur === 'empty') {
/* make a new type path */
if (Object.access(ur,sub)) {
console.warn(`Ur named ${sub} already exists.`);
return;
}
var file = `${sub}.json`;
io.slurpwrite(file, json.encode(obj.json_obj(),null,1));
ur[sub] = {
name: sub,
data: file,
proto: json.decode(json.encode(obj))
}
obj.ur = sub;
return;
} else if (!sub.startswith(obj.ur)) {
console.warn(`Cannot make an ur of type ${sub} from an object with the ur ${obj.ur}`);
return;
}
var curur = Object.access(ur,sub);
if (curur) { if (curur) {
notifypanel.action = editor.saveas; notifypanel.action = editor.saveas;
@ -572,16 +601,32 @@ var editor = {
}, },
} }
editor.new_object = function()
{
var obj = editor.edit_level.spawn();
obj.set_worldpos(Mouse.worldpos);
this.selectlist = [obj];
return obj;
}
editor.new_object.doc = "Create an empty object.";
editor.new_from_img = function(path)
{
var o = editor.new_object();
o.add_component(component.sprite).path = path;
return o;
}
editor.inputs = {}; editor.inputs = {};
editor.inputs.drop = function(str) { editor.inputs.drop = function(str) {
str = str.slice(os.cwd().length+1);
if (!Resources.is_image(str)) { if (!Resources.is_image(str)) {
console.warn("NOT AN IMAGE"); console.warn("NOT AN IMAGE");
return; return;
} }
if (this.selectlist.length === 0) { if (this.selectlist.length === 0)
return editor.new_from_img(str);
}
if (this.sel_comp?.comp === 'sprite') { if (this.sel_comp?.comp === 'sprite') {
this.sel_comp.path = str; this.sel_comp.path = str;
@ -821,20 +866,35 @@ editor.inputs['C-s'] = function() {
} else if (editor.selectlist.length === 1) } else if (editor.selectlist.length === 1)
saveobj = editor.selectlist[0]; saveobj = editor.selectlist[0];
// saveobj.check_dirty(); saveobj.check_dirty();
// if (!saveobj._ed.dirty) return; if (!saveobj._ed.dirty) {
console.warn(`Object ${saveobj.full_path()} does not need saved.`);
return;
}
var savejs = saveobj.json_obj(); var savejs = saveobj.json_obj();
Object.merge(saveobj.__proto__, savejs); var tur = saveobj.get_ur();
if (savejs.objects) saveobj.__proto__.objects = savejs.objects; if (!tur) {
// var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json"; console.warn(`Can't save object because it has no ur.`);
path = "CHANGETHIS"; return;
}
if (!tur.data) {
io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1));
tur.data = tur.text.set_ext(".json");
}
else {
var oldjs = json.decode(io.slurp(tur.data));
Object.merge(oldjs, savejs);
io.slurpwrite(tur.data, json.encode(oldjs,null,1));
}
io.slurpwrite(path, JSON.stringify(saveobj.__proto__,null,1)); Object.merge(tur.proto, savejs);
console.warn(`Wrote to file ${path}`); saveobj.check_dirty();
Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); // Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
return;
Game.all_objects(function(x) { Game.all_objects(function(x) {
if (typeof x !== 'object') return; if (typeof x !== 'object') return;
if (!('_ed' in x)) return; if (!('_ed' in x)) return;
@ -847,7 +907,12 @@ editor.inputs['C-s'].doc = "Save selected.";
editor.inputs['C-S'] = function() { editor.inputs['C-S'] = function() {
if (editor.selectlist.length !== 1) return; if (editor.selectlist.length !== 1) return;
saveaspanel.stem = this.selectlist[0].ur; if (this.selectlist[0].ur !== 'empty')
saveaspanel.stem = this.selectlist[0].ur + ".";
else
saveaspanel.stem = "";
saveaspanel.obj = this.selectlist[0];
editor.openpanel(saveaspanel); editor.openpanel(saveaspanel);
}; };
editor.inputs['C-S'].doc = "Save selected as."; editor.inputs['C-S'].doc = "Save selected as.";
@ -864,11 +929,7 @@ editor.inputs.t.doc = "Lock selected objects to make them non selectable.";
editor.inputs['M-t'] = function() { editor.edit_level.objects.forEach(function(x) { x._ed.selectable = true; }); }; editor.inputs['M-t'] = function() { editor.edit_level.objects.forEach(function(x) { x._ed.selectable = true; }); };
editor.inputs['M-t'].doc = "Unlock all objects in current level."; editor.inputs['M-t'].doc = "Unlock all objects in current level.";
editor.inputs['C-n'] = function() { editor.inputs['C-n'] = editor.new_object;
console.warn(`Spawning a new object on ${editor.edit_level.toString()}`);
editor.edit_level.spawn();
};
editor.inputs['C-n'].doc = "Create an empty object.";
editor.inputs['C-o'] = function() { editor.inputs['C-o'] = function() {
editor.openpanel(openlevelpanel); editor.openpanel(openlevelpanel);
@ -1823,13 +1884,17 @@ var openlevelpanel = Object.copy(inputpanel, {
}, },
}); });
/* Should set stem to the ur path folloed by a '.' before opening */
var saveaspanel = Object.copy(inputpanel, { var saveaspanel = Object.copy(inputpanel, {
get title() { return `save level as: ${this.stem}.`; }, get title() {
var full = this.stem ? this.stem : "";
return `save level as: ${full}.`;
},
action() { action() {
var savename = ""; var saveur = this.value;
if (this.stem) savename += this.stem + "."; if (this.stem) saveur = this.stem + saveur;
editor.saveas_check(savename + this.value, this.obj); editor.saveas_check(saveur, this.obj);
}, },
}); });

View file

@ -236,7 +236,7 @@ Register.add_cb(10, "draw");
register(9, console.stack, this); register(9, console.stack, this);
Register.gamepad_playermap[0] = player[0]; Register.gamepad_playermap[0] = Player.players[0];
var Event = { var Event = {
events: {}, events: {},
@ -418,5 +418,3 @@ Game.view_camera = function(cam)
Window.title(`Prosperon v${prosperon.version}`); Window.title(`Prosperon v${prosperon.version}`);
Window.width = 1280; Window.width = 1280;
Window.height = 720; Window.height = 720;

View file

@ -150,10 +150,9 @@ var gameobject = {
return undefined; return undefined;
}, },
check_dirty() { check_dirty() {
// TODO: IMPLEMENT
return;
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
var lur = ur[this.master.ur]; var lur = ur[this.master.ur];
if (!lur) return; if (!lur) return;
var lur = lur.objects[this.toString()]; var lur = lur.objects[this.toString()];
@ -306,6 +305,11 @@ var gameobject = {
worldangle() { return Math.rad2turn(q_body(2,this.body)); }, worldangle() { return Math.rad2turn(q_body(2,this.body)); },
sworldangle(x) { set_body(0,this.body,Math.turn2rad(x)); }, sworldangle(x) { set_body(0,this.body,Math.turn2rad(x)); },
get_ur() {
// if (this.ur === 'empty') return undefined;
return Object.access(ur,this.ur);
},
/* spawn an entity /* spawn an entity
text can be: text can be:
the file path of a script the file path of a script
@ -319,7 +323,7 @@ var gameobject = {
text = text.name; text = text.name;
if (typeof text === 'undefined') if (typeof text === 'undefined')
ent.ur = "new"; ent.ur = "empty";
else if (typeof text !== 'string') { else if (typeof text !== 'string') {
console.error(`Must pass in an ur type or a string to make an entity.`); console.error(`Must pass in an ur type or a string to make an entity.`);
return; return;
@ -352,11 +356,15 @@ var gameobject = {
cmd(113, ent.body, ent); // set the internal obj reference to this obj cmd(113, ent.body, ent); // set the internal obj reference to this obj
Object.hide(ent, 'ur','body', 'components', 'objects', '_ed', 'timers', 'master'); Object.hide(ent, 'ur', 'body', 'components', 'objects', '_ed', 'timers', 'master');
if (ent.ur === 'empty') {
if (!ur.empty.proto) ur.empty.proto = json.decode(json.encode(ent));
return ent;
}
if (ent.ur === 'script') if (ent.ur === 'script')
eval_env(io.slurp(text), ent, ent.ur); eval_env(io.slurp(text), ent, ent.ur);
else if (ent.ur !== 'new') else
apply_ur(ent.ur, ent); apply_ur(ent.ur, ent);
for (var [prop,p] of Object.entries(ent)) { for (var [prop,p] of Object.entries(ent)) {
@ -369,16 +377,18 @@ var gameobject = {
ent.components[prop] = ent[prop]; ent.components[prop] = ent[prop];
}; };
check_registers(ent); check_registers(ent);
if (typeof ent.load === 'function') ent.load(); if (typeof ent.load === 'function') ent.load();
if (typeof ent.start === 'function') ent.start(); if (Game.playing())
if (typeof ent.start === 'function') ent.start();
var mur = Object.access(ur,ent.ur); var mur = ent.get_ur();
if (mur && !mur.proto) if (mur && !mur.proto)
mur.proto = json.decode(json.encode(ent)); mur.proto = json.decode(json.encode(ent));
ent.sync();
if (!Object.empty(ent.objects)) { if (!Object.empty(ent.objects)) {
var o = ent.objects; var o = ent.objects;
delete ent.objects; delete ent.objects;
@ -412,13 +422,13 @@ var gameobject = {
var str = name.replaceAll('.', '_'); var str = name.replaceAll('.', '_');
var n = 1; var n = 1;
var t = str; var t = str;
while (t in list) { while (list.indexOf(t) !== -1) {
t = str + n; t = str + n;
n++; n++;
} }
return t; return t;
}; };
var name = unique_name(Object.keys(parent.objects), this.ur); var name = unique_name(Object.keys(parent.objects), this.ur);
parent.objects[name] = this; parent.objects[name] = this;
@ -531,7 +541,7 @@ var gameobject = {
/* The unique components of this object. Its diff. */ /* The unique components of this object. Its diff. */
json_obj() { json_obj() {
var u = Object.access(ur,this.ur); var u = this.get_ur();
if (!u) return {}; if (!u) return {};
var proto = u.proto; var proto = u.proto;
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.
@ -566,7 +576,7 @@ var gameobject = {
}, },
proto() { proto() {
var u = Object.access(ur,this.ur); var u = this.get_ur();
if (!u) return {}; if (!u) return {};
return u.proto; return u.proto;
}, },
@ -733,7 +743,10 @@ gameobject.doc = {
rotary_limit: 'Limit the angle relative to the to body between min and max.', rotary_limit: 'Limit the angle relative to the to body between min and max.',
ratchet: 'Like a socket wrench, relative to to. ratch is the distance between clicks.', ratchet: 'Like a socket wrench, relative to to. ratch is the distance between clicks.',
gear: 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.', gear: 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.',
motor: 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.' motor: 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.',
layer: 'Bitmask for collision layers.',
draw_layer: 'Layer for drawing. Higher numbers draw above lower ones.',
warp_layer: 'Bitmask for selecting what warps should affect this entity.',
}; };
var resavi = function(ur, path) var resavi = function(ur, path)
@ -848,6 +861,10 @@ for (var file of io.glob("**.json")) {
topur.data = file; topur.data = file;
} }
ur.empty = {
name: "empty"
};
return { return {
gameobject, gameobject,
ur ur

View file

@ -82,7 +82,6 @@ void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
cpShapeFilter filter; cpShapeFilter filter;
filter.group = (cpCollisionType)go; filter.group = (cpCollisionType)go;
filter.categories = 1<<go->layer | editor_cat; filter.categories = 1<<go->layer | editor_cat;
// filter.mask = CP_ALL_CATEGORIES;
filter.mask = category_masks[go->layer] | editor_cat; filter.mask = category_masks[go->layer] | editor_cat;
// filter.mask = CP_ALL_CATEGORIES; // filter.mask = CP_ALL_CATEGORIES;
cpShapeSetFilter(shape, filter); cpShapeSetFilter(shape, filter);

View file

@ -2153,12 +2153,12 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst
const char *STRTEST = "TEST STRING"; const char *STRTEST = "TEST STRING";
JSValue duk_profile_js2num(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) JSValue duk_performance_js2num(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{ {
} }
JSValue duk_profile(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) JSValue duk_performance(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{ {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
switch(cmd) { switch(cmd) {
@ -2249,7 +2249,7 @@ void ffi_load() {
DUK_FUNC(inflate_cpv, 3) DUK_FUNC(inflate_cpv, 3)
DUK_FUNC(profile, 2) DUK_FUNC(performance, 2)
JS_FreeValue(js,globalThis); JS_FreeValue(js,globalThis);