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.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({
get zoom() {
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); },
get offset() { return cmd_circle2d(3,this.id); },
get pos() { return this.offset; },
set pos(x) { this.offset = x; },
get pos() { return cmd_circle2d(3,this.id); },
set pos(x) { cmd_circle2d(1,this.id,x); },
}, collider2d.impl);

View file

@ -99,7 +99,7 @@ var Gizmos = {
},
};
Object.assign(profile, {
Object.assign(performance, {
tick_now() { return cmd(127); },
ns(ticks) { return cmd(128, ticks); },
us(ticks) { return cmd(129, ticks); },
@ -123,34 +123,43 @@ Object.assign(profile, {
cpu(fn, times, q) {
times ??= 1;
q ??= "unnamed";
var start = profile.tick_now();
var start = performance.tick_now();
for (var i = 0; i < times; i++)
fn();
var elapsed = profile.tick_now() - start;
var avgt = profile.best_t(elapsed/times);
var totalt = profile.best_t(elapsed);
var elapsed = performance.tick_now() - start;
var avgt = performance.best_t(elapsed/times);
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); },
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 = {
barecall() { profile(0); },
unpack_num(n) { profile(1,n); },
unpack_array(n) { profile(2,n); },
pack_num() { profile(3); },
pack_string() { profile(6); },
unpack_string(s) { profile(4,s); },
unpack_32farr(a) { profile(5,a); },
call_fn_n(fn1, n) { profile(7,fn1,n,fn2); },
performance.test = {
barecall() { performance(0); },
unpack_num(n) { performance(1,n); },
unpack_array(n) { performance(2,n); },
pack_num() { performance(3); },
pack_string() { performance(6); },
unpack_string(s) { performance(4,s); },
unpack_32farr(a) { performance(5,a); },
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 */
var DebugControls = {};
@ -347,4 +356,6 @@ Debug.api.print_doc = function(name)
return {
Debug,
Time,
Gizmos,
performance
}

View file

@ -521,8 +521,8 @@ var editor = {
lvl_history: [],
load(file) {
var obj = editor.edit_level.spawn(Object.access(ur, file));
load(urstr) {
var obj = editor.edit_level.spawn(urstr);
obj.set_worldpos(Mouse.worldpos);
this.selectlist = [obj];
},
@ -537,12 +537,41 @@ var editor = {
/* Checking to save an entity as a subtype. */
/* 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) {
return;
if (!sub) return;
obj ??= editor.selectlist[0];
// var curur = prototypes.get_ur(sub);
if (!sub) {
console.warn(`Cannot save an object to an empty ur.`);
return;
}
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) {
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.drop = function(str) {
str = str.slice(os.cwd().length+1);
if (!Resources.is_image(str)) {
console.warn("NOT AN IMAGE");
return;
}
if (this.selectlist.length === 0) {
}
if (this.selectlist.length === 0)
return editor.new_from_img(str);
if (this.sel_comp?.comp === 'sprite') {
this.sel_comp.path = str;
@ -821,20 +866,35 @@ editor.inputs['C-s'] = function() {
} else if (editor.selectlist.length === 1)
saveobj = editor.selectlist[0];
// saveobj.check_dirty();
// if (!saveobj._ed.dirty) return;
saveobj.check_dirty();
if (!saveobj._ed.dirty) {
console.warn(`Object ${saveobj.full_path()} does not need saved.`);
return;
}
var savejs = saveobj.json_obj();
Object.merge(saveobj.__proto__, savejs);
if (savejs.objects) saveobj.__proto__.objects = savejs.objects;
// var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json";
path = "CHANGETHIS";
var tur = saveobj.get_ur();
if (!tur) {
console.warn(`Can't save object because it has no ur.`);
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));
console.warn(`Wrote to file ${path}`);
Object.merge(tur.proto, savejs);
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) {
if (typeof x !== 'object') return;
if (!('_ed' in x)) return;
@ -847,7 +907,12 @@ editor.inputs['C-s'].doc = "Save selected.";
editor.inputs['C-S'] = function() {
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.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'].doc = "Unlock all objects in current level.";
editor.inputs['C-n'] = function() {
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-n'] = editor.new_object;
editor.inputs['C-o'] = function() {
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, {
get title() { return `save level as: ${this.stem}.`; },
get title() {
var full = this.stem ? this.stem : "";
return `save level as: ${full}.`;
},
action() {
var savename = "";
if (this.stem) savename += this.stem + ".";
editor.saveas_check(savename + this.value, this.obj);
var saveur = this.value;
if (this.stem) saveur = this.stem + saveur;
editor.saveas_check(saveur, this.obj);
},
});

View file

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

View file

@ -150,10 +150,9 @@ var gameobject = {
return undefined;
},
check_dirty() {
// TODO: IMPLEMENT
return;
this._ed.urdiff = this.json_obj();
this._ed.dirty = !Object.empty(this._ed.urdiff);
return; // TODO: IMPLEMENT
var lur = ur[this.master.ur];
if (!lur) return;
var lur = lur.objects[this.toString()];
@ -306,6 +305,11 @@ var gameobject = {
worldangle() { return Math.rad2turn(q_body(2,this.body)); },
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
text can be:
the file path of a script
@ -319,7 +323,7 @@ var gameobject = {
text = text.name;
if (typeof text === 'undefined')
ent.ur = "new";
ent.ur = "empty";
else if (typeof text !== 'string') {
console.error(`Must pass in an ur type or a string to make an entity.`);
return;
@ -352,11 +356,15 @@ var gameobject = {
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')
eval_env(io.slurp(text), ent, ent.ur);
else if (ent.ur !== 'new')
else
apply_ur(ent.ur, ent);
for (var [prop,p] of Object.entries(ent)) {
@ -369,16 +377,18 @@ var gameobject = {
ent.components[prop] = ent[prop];
};
check_registers(ent);
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)
mur.proto = json.decode(json.encode(ent));
ent.sync();
if (!Object.empty(ent.objects)) {
var o = ent.objects;
delete ent.objects;
@ -412,13 +422,13 @@ var gameobject = {
var str = name.replaceAll('.', '_');
var n = 1;
var t = str;
while (t in list) {
while (list.indexOf(t) !== -1) {
t = str + n;
n++;
}
return t;
};
var name = unique_name(Object.keys(parent.objects), this.ur);
parent.objects[name] = this;
@ -531,7 +541,7 @@ var gameobject = {
/* The unique components of this object. Its diff. */
json_obj() {
var u = Object.access(ur,this.ur);
var u = this.get_ur();
if (!u) return {};
var proto = u.proto;
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
@ -566,7 +576,7 @@ var gameobject = {
},
proto() {
var u = Object.access(ur,this.ur);
var u = this.get_ur();
if (!u) return {};
return u.proto;
},
@ -733,7 +743,10 @@ gameobject.doc = {
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.',
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)
@ -848,6 +861,10 @@ for (var file of io.glob("**.json")) {
topur.data = file;
}
ur.empty = {
name: "empty"
};
return {
gameobject,
ur

View file

@ -82,7 +82,6 @@ void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
cpShapeFilter filter;
filter.group = (cpCollisionType)go;
filter.categories = 1<<go->layer | editor_cat;
// filter.mask = CP_ALL_CATEGORIES;
filter.mask = category_masks[go->layer] | editor_cat;
// filter.mask = CP_ALL_CATEGORIES;
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";
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]);
switch(cmd) {
@ -2249,7 +2249,7 @@ void ffi_load() {
DUK_FUNC(inflate_cpv, 3)
DUK_FUNC(profile, 2)
DUK_FUNC(performance, 2)
JS_FreeValue(js,globalThis);