Separate entity from rigidbody
This commit is contained in:
parent
e86e126894
commit
79e4772f93
|
@ -177,7 +177,7 @@ Object.mixin(os.sprite(true), {
|
||||||
height() { return this.dimensions().y; },
|
height() { return this.dimensions().y; },
|
||||||
});
|
});
|
||||||
globalThis.allsprites = {};
|
globalThis.allsprites = {};
|
||||||
os.sprite(true).make = function(go)
|
os.sprite().make = function(go)
|
||||||
{
|
{
|
||||||
var sp = os.sprite();
|
var sp = os.sprite();
|
||||||
sp.go = go;
|
sp.go = go;
|
||||||
|
|
|
@ -344,7 +344,7 @@ var editor = {
|
||||||
root = root ? root + "." : root;
|
root = root ? root + "." : root;
|
||||||
Object.entries(obj.objects).forEach(function(x) {
|
Object.entries(obj.objects).forEach(function(x) {
|
||||||
var p = root + x[0];
|
var p = root + x[0];
|
||||||
render.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
render.text(p, x[1].this2screen(), 1, editor.color_depths[depth]);
|
||||||
editor.draw_objects_names(x[1], p, depth+1);
|
editor.draw_objects_names(x[1], p, depth+1);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -402,7 +402,7 @@ var editor = {
|
||||||
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.this2screen(),3,Color.blue);
|
||||||
|
|
||||||
var thiso = editor.get_this();
|
var thiso = editor.get_this();
|
||||||
var clvl = thiso;
|
var clvl = thiso;
|
||||||
|
@ -447,16 +447,16 @@ var editor = {
|
||||||
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||||
|
|
||||||
this.selectlist.forEach(function(x) {
|
this.selectlist.forEach(function(x) {
|
||||||
render.text(x.urstr(), x.screenpos().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
render.text(x.urstr(), x.this2screen().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
||||||
render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos());
|
render.text(x.pos.map(function(x) { return Math.round(x); }), x.this2screen());
|
||||||
render.cross(x.screenpos(), 10, Color.blue);
|
render.cross(x.this2screen(), 10, Color.blue);
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.entries(thiso.objects).forEach(function(x) {
|
Object.entries(thiso.objects).forEach(function(x) {
|
||||||
var p = x[1].namestr();
|
var p = x[1].namestr();
|
||||||
render.text(p, x[1].screenpos().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
render.text(p, x[1].this2screen().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
||||||
render.point(x[1].screenpos(),5,Color.blue.alpha(0.3));
|
render.point(x[1].this2screen(),5,Color.blue.alpha(0.3));
|
||||||
render.point(x[1].screenpos(), 1, Color.red);
|
render.point(x[1].this2screen(), 1, Color.red);
|
||||||
});
|
});
|
||||||
|
|
||||||
var mg = physics.pos_query(input.mouse.worldpos());
|
var mg = physics.pos_query(input.mouse.worldpos());
|
||||||
|
@ -474,7 +474,7 @@ var editor = {
|
||||||
for (var key in this.selectlist[0].components) {
|
for (var key in this.selectlist[0].components) {
|
||||||
var selected = this.sel_comp === this.selectlist[0].components[key];
|
var selected = this.sel_comp === this.selectlist[0].components[key];
|
||||||
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
||||||
render.text(str, this.selectlist[0].screenpos().add([0,-render.font.linegap*(i++)]));
|
render.text(str, this.selectlist[0].this2screen().add([0,-render.font.linegap*(i++)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.sel_comp) {
|
if (this.sel_comp) {
|
||||||
|
@ -879,7 +879,7 @@ editor.inputs['C-s'] = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var savejs = saveobj.json_obj();
|
var savejs = saveobj.json_obj();
|
||||||
var tur = saveobj.get_ur();
|
var tur = saveobj.ur;
|
||||||
if (!tur) {
|
if (!tur) {
|
||||||
console.warn(`Can't save object because it has no ur.`);
|
console.warn(`Can't save object because it has no ur.`);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -289,7 +289,6 @@ game.engine_start = function(s) {
|
||||||
gggstart(function() {
|
gggstart(function() {
|
||||||
global.mixin("scripts/sound.js");
|
global.mixin("scripts/sound.js");
|
||||||
world_start();
|
world_start();
|
||||||
go_init();
|
|
||||||
window.set_icon(os.make_texture("icons/moon.gif"))
|
window.set_icon(os.make_texture("icons/moon.gif"))
|
||||||
Object.readonly(window.__proto__, 'vsync');
|
Object.readonly(window.__proto__, 'vsync');
|
||||||
Object.readonly(window.__proto__, 'enable_dragndrop');
|
Object.readonly(window.__proto__, 'enable_dragndrop');
|
||||||
|
@ -330,9 +329,9 @@ function process()
|
||||||
}
|
}
|
||||||
var st = profile.now();
|
var st = profile.now();
|
||||||
if (!game.camera)
|
if (!game.camera)
|
||||||
prosperon.window_render(world, 1);
|
prosperon.window_render(world.transform, 1);
|
||||||
else
|
else
|
||||||
prosperon.window_render(game.camera, game.camera.zoom);
|
prosperon.window_render(game.camera.transform, game.camera.zoom);
|
||||||
|
|
||||||
render.set_camera();
|
render.set_camera();
|
||||||
|
|
||||||
|
@ -627,7 +626,8 @@ global.mixin("scripts/actor");
|
||||||
global.mixin("scripts/entity");
|
global.mixin("scripts/entity");
|
||||||
|
|
||||||
function world_start() {
|
function world_start() {
|
||||||
globalThis.world = os.make_gameobject();
|
globalThis.world = Object.create(entity);
|
||||||
|
world.transform = os.make_transform2d();
|
||||||
world.objects = {};
|
world.objects = {};
|
||||||
world.toString = function() { return "world"; };
|
world.toString = function() { return "world"; };
|
||||||
world.ur = "world";
|
world.ur = "world";
|
||||||
|
|
|
@ -12,7 +12,18 @@ function obj_unique_name(name, obj) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameobject = {
|
function unique_name(list, name = "new_object") {
|
||||||
|
var str = name.replaceAll('.', '_');
|
||||||
|
var n = 1;
|
||||||
|
var t = str;
|
||||||
|
while (list.indexOf(t) !== -1) {
|
||||||
|
t = str + n;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
var entity = {
|
||||||
get_comp_by_name(name) {
|
get_comp_by_name(name) {
|
||||||
var comps = [];
|
var comps = [];
|
||||||
for (var c of Object.values(this.components))
|
for (var c of Object.values(this.components))
|
||||||
|
@ -22,79 +33,6 @@ var gameobject = {
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
check_dirty() {
|
|
||||||
this._ed.urdiff = this.json_obj();
|
|
||||||
this._ed.dirty = !Object.empty(this._ed.urdiff);
|
|
||||||
return; // TODO: IMPLEMENT
|
|
||||||
var lur = this.master.ur;
|
|
||||||
if (!lur) return;
|
|
||||||
var lur = lur.objects[this.toString()];
|
|
||||||
var d = ediff(this._ed.urdiff, lur);
|
|
||||||
if (!d || Object.empty(d))
|
|
||||||
this._ed.inst = true;
|
|
||||||
else
|
|
||||||
this._ed.inst = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
namestr() {
|
|
||||||
var s = this.toString();
|
|
||||||
if (this._ed?.dirty)
|
|
||||||
if (this._ed.inst) s += "#";
|
|
||||||
else s += "*";
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
|
|
||||||
urstr() {
|
|
||||||
var str = this.ur.name;
|
|
||||||
if (this._ed.dirty) str = "*" + str;
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
|
|
||||||
full_path() {
|
|
||||||
return this.path_from(world);
|
|
||||||
},
|
|
||||||
/* pin this object to the to object */
|
|
||||||
pin(to) {
|
|
||||||
var p = joint.pin(this,to);
|
|
||||||
},
|
|
||||||
slide(to, a = [0,0], b = [0,0], min = 0, max = 50) {
|
|
||||||
var p = joint.slide(this, to, a, b, min, max);
|
|
||||||
p.max_force = 500;
|
|
||||||
p.break();
|
|
||||||
},
|
|
||||||
pivot(to, piv = this.pos) {
|
|
||||||
var p = joint.pivot(this, to, piv);
|
|
||||||
},
|
|
||||||
/* groove is on to, from local points a and b, anchored to this at local anchor */
|
|
||||||
groove(to, a, b, anchor = [0,0]) {
|
|
||||||
var p = joint.groove(to, this, a, b, anchor);
|
|
||||||
},
|
|
||||||
damped_spring(to, length = Vector.length(this.pos,to.pos), stiffness = 1, damping = 1) {
|
|
||||||
var dc = 2 * Math.sqrt(stiffness * this.mass);
|
|
||||||
var p = joint.damped_spring(this, to, [0, 0], [0, 0], stiffness, damping * dc);
|
|
||||||
},
|
|
||||||
damped_rotary_spring(to, angle = 0, stiffness = 1, damping = 1) {
|
|
||||||
/* calculate actual damping value from the damping ratio */
|
|
||||||
/* damping = 1 is critical */
|
|
||||||
var dc = 2 * Math.sqrt(stiffness * this.get_moi()); /* critical damping number */
|
|
||||||
/* zeta = actual/critical */
|
|
||||||
var p = joint.damped_rotary(this, to, angle, stiffness, damping * dc);
|
|
||||||
},
|
|
||||||
rotary_limit(to, min, max) {
|
|
||||||
var p = joint.rotary(this, to, Math.turn2rad(min), Math.turn2rad(max));
|
|
||||||
},
|
|
||||||
ratchet(to, ratch) {
|
|
||||||
var phase = this.angle - to.angle;
|
|
||||||
var p = joint.ratchet(this, to, phase, Math.turn2rad(ratch));
|
|
||||||
},
|
|
||||||
gear(to, ratio = 1, phase = 0) {
|
|
||||||
var phase = this.angle - to.angle;
|
|
||||||
var p = joint.gear(this, to, phase, ratio);
|
|
||||||
},
|
|
||||||
motor(to, rate) {
|
|
||||||
var p = joint.motor(this, to, rate);
|
|
||||||
},
|
|
||||||
|
|
||||||
path_from(o) {
|
path_from(o) {
|
||||||
var p = this.toString();
|
var p = this.toString();
|
||||||
var c = this.master;
|
var c = this.master;
|
||||||
|
@ -106,6 +44,8 @@ var gameobject = {
|
||||||
return p;
|
return p;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
full_path() { return this.path_from(world); },
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
for (var k in this.objects) {
|
for (var k in this.objects) {
|
||||||
this.objects[k].kill();
|
this.objects[k].kill();
|
||||||
|
@ -113,6 +53,11 @@ var gameobject = {
|
||||||
this.objects = {};
|
this.objects = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sync() {
|
||||||
|
this.components.forEach(function(x) { x.sync?.(); });
|
||||||
|
this.objects.forEach(function(x) { x.sync(); });
|
||||||
|
},
|
||||||
|
|
||||||
delay(fn, seconds) {
|
delay(fn, seconds) {
|
||||||
var timers = this.timers;
|
var timers = this.timers;
|
||||||
var stop = function() {
|
var stop = function() {
|
||||||
|
@ -145,110 +90,60 @@ var gameobject = {
|
||||||
|
|
||||||
cry(file) { return audio.cry(file); },
|
cry(file) { return audio.cry(file); },
|
||||||
|
|
||||||
set pos(x) { this.set_pos(x); },
|
get pos() { return this.transform.pos; },
|
||||||
get pos() { return this.rpos; },
|
set pos(x) { this.transform.pos = x; },
|
||||||
set angle(x) { this.set_angle(x); },
|
get angle() { return this.transform.angle; },
|
||||||
get angle() { return this.rangle; },
|
set angle(x) { this.transform.angle = x; },
|
||||||
set scale(x) { this.set_scale(x); },
|
get scale() { return this.transform.scale; },
|
||||||
get scale() { return this.rscale; },
|
set scale(x) { this.transform.scale = x; },
|
||||||
|
|
||||||
set_pos(x, relative = world) {
|
move(vec) { this.pos = this.pos.add(vec); },
|
||||||
var newpos = relative.this2world(x);
|
rotate(x) { this.angle += x; },
|
||||||
var move = newpos.sub(this.pos);
|
|
||||||
this.rpos = newpos;
|
|
||||||
this.objects.forEach(x => x.move(move));
|
|
||||||
},
|
|
||||||
|
|
||||||
set_angle(x, relative = world) {
|
|
||||||
var newangle = relative.angle + x;
|
|
||||||
var diff = newangle - this.angle;
|
|
||||||
this.rangle = newangle;
|
|
||||||
this.objects.forEach(obj => {
|
|
||||||
obj.rotate(diff);
|
|
||||||
obj.set_pos(Vector.rotate(obj.get_pos(obj.master), diff), obj.master);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
set_scale(x, relative = world) {
|
|
||||||
if (typeof x === 'number') x = [x,x,x];
|
|
||||||
var newscale = relative.scale.map((s,i) => x[i]*s);
|
|
||||||
var pct = this.scale.map((s,i) => newscale[i]/s);
|
|
||||||
this.rscale = newscale;
|
|
||||||
this.objects.forEach(obj => {
|
|
||||||
obj.grow(pct);
|
|
||||||
obj.set_pos(obj.get_pos(obj.master).map((x,i) => x*pct[i]), obj.master);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
get_pos(relative = world) {
|
|
||||||
if (relative === world) return this.pos;
|
|
||||||
return relative.world2this(this.pos);
|
|
||||||
//return this.pos.sub(relative.pos);
|
|
||||||
},
|
|
||||||
|
|
||||||
get_angle(relative = world) {
|
|
||||||
if (relative === world) return this.angle;
|
|
||||||
return this.angle - relative.angle;
|
|
||||||
},
|
|
||||||
|
|
||||||
get_scale(relative = world) {
|
|
||||||
if (relative === world) return this.scale;
|
|
||||||
var masterscale = relative.scale;
|
|
||||||
return this.scale.map((x,i) => x/masterscale[i]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Moving, rotating, scaling functions, world relative */
|
|
||||||
move(vec) { this.set_pos(this.pos.add(vec)); },
|
|
||||||
rotate(x) { this.set_angle(this.angle + x); },
|
|
||||||
grow(vec) {
|
grow(vec) {
|
||||||
if (typeof vec === 'number') vec = [vec,vec,vec];
|
if (typeof vec === 'number') vec = [vec,vec];
|
||||||
this.set_scale(this.scale.map((x, i) => x * vec[i]));
|
this.scale = this.scale.map((x,i) => x*vec[i]);
|
||||||
},
|
},
|
||||||
|
|
||||||
screenpos() { return game.camera.world2view(this.pos); },
|
/* Reparent 'this' to be 'parent's child */
|
||||||
|
reparent(parent) {
|
||||||
|
assert(parent, `Tried to reparent ${this.toString()} to nothing.`);
|
||||||
|
console.spam(`parenting ${this.toString()} to ${parent.toString()}`);
|
||||||
|
if (this.master === parent) {
|
||||||
|
console.warn("not reparenting ...");
|
||||||
|
console.warn(`${this.master} is the same as ${parent}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
get_ur() { return this.ur; },
|
var name = unique_name(Object.keys(parent), this.name);
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
this.master?.remove_obj(this);
|
||||||
|
this.master = parent;
|
||||||
|
parent.objects[this.guid] = this;
|
||||||
|
parent[name] = this;
|
||||||
|
Object.hide(parent, name);
|
||||||
|
},
|
||||||
|
|
||||||
|
remove_obj(obj) {
|
||||||
|
delete this.objects[obj.guid];
|
||||||
|
delete this[obj.name];
|
||||||
|
Object.unhide(this, obj.name);
|
||||||
|
},
|
||||||
|
|
||||||
/* spawn an entity
|
|
||||||
text can be:
|
|
||||||
the file path of a script
|
|
||||||
an ur object
|
|
||||||
nothing
|
|
||||||
*/
|
|
||||||
spawn(text, config, callback) {
|
spawn(text, config, callback) {
|
||||||
var st = profile.now();
|
var st = profile.now();
|
||||||
var ent = os.make_gameobject();
|
var ent = Object.create(entity);
|
||||||
|
ent.transform = os.make_transform2d();
|
||||||
|
|
||||||
ent.guid = prosperon.guid();
|
ent.guid = prosperon.guid();
|
||||||
|
|
||||||
ent.components = {};
|
ent.components = {};
|
||||||
ent.objects = {};
|
ent.objects = {};
|
||||||
ent.timers = [];
|
ent.timers = [];
|
||||||
|
|
||||||
Object.mixin(ent, {
|
if (!text)
|
||||||
set category(n) {
|
ent.ur = emptyur;
|
||||||
if (n === 0) {
|
else if (typeof text === 'object' && text) {// assume it's an ur
|
||||||
this.categories = n;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cat = (1 << (n-1));
|
|
||||||
this.categories = cat;
|
|
||||||
},
|
|
||||||
get category() {
|
|
||||||
if (this.categories === 0) return 0;
|
|
||||||
var pos = 0;
|
|
||||||
var num = this.categories;
|
|
||||||
while (num > 0) {
|
|
||||||
if (num & 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
num >>>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos+1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof text === 'object' && text) {// assume it's an ur
|
|
||||||
ent.ur = text;
|
ent.ur = text;
|
||||||
text = ent.ur.text;
|
text = ent.ur.text;
|
||||||
config = [ent.ur.data, config].filter(x => x).flat();
|
config = [ent.ur.data, config].filter(x => x).flat();
|
||||||
|
@ -294,7 +189,7 @@ var gameobject = {
|
||||||
if (sim.playing())
|
if (sim.playing())
|
||||||
if (typeof ent.start === 'function') ent.start();
|
if (typeof ent.start === 'function') ent.start();
|
||||||
|
|
||||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master', 'categories');
|
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master');
|
||||||
|
|
||||||
ent._ed = {
|
ent._ed = {
|
||||||
selectable: true,
|
selectable: true,
|
||||||
|
@ -324,6 +219,7 @@ var gameobject = {
|
||||||
|
|
||||||
if (callback) callback(ent);
|
if (callback) callback(ent);
|
||||||
|
|
||||||
|
|
||||||
ent.ur.fresh ??= json.decode(json.encode(ent));
|
ent.ur.fresh ??= json.decode(json.encode(ent));
|
||||||
ent.ur.fresh.objects = {};
|
ent.ur.fresh.objects = {};
|
||||||
for (var i in ent.objects)
|
for (var i in ent.objects)
|
||||||
|
@ -333,60 +229,17 @@ var gameobject = {
|
||||||
return ent;
|
return ent;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Reparent 'this' to be 'parent's child */
|
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
||||||
reparent(parent) {
|
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
||||||
assert(parent, `Tried to reparent ${this.toString()} to nothing.`);
|
|
||||||
console.spam(`parenting ${this.toString()} to ${parent.toString()}`);
|
|
||||||
if (this.master === parent) {
|
|
||||||
console.warn("not reparenting ...");
|
|
||||||
console.warn(`${this.master} is the same as ${parent}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.master?.remove_obj(this);
|
|
||||||
|
|
||||||
this.master = parent;
|
|
||||||
|
|
||||||
function unique_name(list, name = "new_object") {
|
|
||||||
var str = name.replaceAll('.', '_');
|
|
||||||
var n = 1;
|
|
||||||
var t = str;
|
|
||||||
while (list.indexOf(t) !== -1) {
|
|
||||||
t = str + n;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
|
|
||||||
var name = unique_name(Object.keys(parent.objects), this.ur.name);
|
|
||||||
|
|
||||||
parent.objects[name] = this;
|
|
||||||
parent[name] = this;
|
|
||||||
Object.hide(parent, name);
|
|
||||||
this.toString = function() { return name; };
|
|
||||||
},
|
|
||||||
|
|
||||||
remove_obj(obj) {
|
|
||||||
delete this.objects[obj.toString()];
|
|
||||||
delete this[obj.toString()];
|
|
||||||
Object.unhide(this, obj.toString());
|
|
||||||
},
|
|
||||||
|
|
||||||
components: {},
|
|
||||||
objects: {},
|
|
||||||
master: undefined,
|
|
||||||
|
|
||||||
this2screen(pos) { return game.camera.world2view(this.this2world(pos)); },
|
this2screen(pos) { return game.camera.world2view(this.this2world(pos)); },
|
||||||
screen2this(pos) { return this.world2this(game.camera.view2world(pos)); },
|
screen2this(pos) { return this.world2this(game.camera.view2world(pos)); },
|
||||||
|
|
||||||
in_air() { return this.in_air(); },
|
/* Make a unique object the same as its prototype */
|
||||||
|
revert() { Object.merge(this, this.ur.fresh); },
|
||||||
hide() { this.components.forEach(x => x.hide?.());
|
|
||||||
this.objects.forEach(x => x.hide?.()); },
|
|
||||||
|
|
||||||
show() { this.components.forEach(function(x) { x.show?.(); });
|
|
||||||
this.objects.forEach(function(x) { x.show?.(); }); },
|
|
||||||
|
|
||||||
|
name: "new_object",
|
||||||
|
toString() { return this.name; },
|
||||||
width() {
|
width() {
|
||||||
var bb = this.boundingbox();
|
var bb = this.boundingbox();
|
||||||
return bb.r - bb.l;
|
return bb.r - bb.l;
|
||||||
|
@ -397,19 +250,11 @@ var gameobject = {
|
||||||
return bb.t - bb.b;
|
return bb.t - bb.b;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Make a unique object the same as its prototype */
|
|
||||||
revert() { Object.merge(this, this.ur.fresh); },
|
|
||||||
|
|
||||||
toString() { return "new_object"; },
|
|
||||||
|
|
||||||
flipx() { return this.scale.x < 0; },
|
flipx() { return this.scale.x < 0; },
|
||||||
flipy() { return this.scale.y < 0; },
|
flipy() { return this.scale.y < 0; },
|
||||||
|
|
||||||
mirror(plane) { this.scale = Vector.reflect(this.scale, plane); },
|
mirror(plane) { this.scale = Vector.reflect(this.scale, plane); },
|
||||||
|
|
||||||
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
|
||||||
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
|
||||||
|
|
||||||
/* Bounding box of the object in world dimensions */
|
/* Bounding box of the object in world dimensions */
|
||||||
boundingbox() {
|
boundingbox() {
|
||||||
var boxes = [];
|
var boxes = [];
|
||||||
|
@ -476,21 +321,6 @@ var gameobject = {
|
||||||
return t;
|
return t;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Velocity and angular velocity of the object */
|
|
||||||
phys_obj() {
|
|
||||||
var phys = {};
|
|
||||||
phys.velocity = this.velocity;
|
|
||||||
phys.angularvelocity = this.angularvelocity;
|
|
||||||
return phys;
|
|
||||||
},
|
|
||||||
|
|
||||||
phys_mat() {
|
|
||||||
return {
|
|
||||||
friction: this.friction,
|
|
||||||
elasticity: this.elasticity
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
dup(diff) {
|
dup(diff) {
|
||||||
var n = this.master.spawn(this.ur);
|
var n = this.master.spawn(this.ur);
|
||||||
Object.totalmerge(n, this.transform());
|
Object.totalmerge(n, this.transform());
|
||||||
|
@ -532,10 +362,6 @@ var gameobject = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
up() { return [0, 1].rotate(this.angle); },
|
|
||||||
down() { return [0, -1].rotate(this.angle); },
|
|
||||||
right() { return [1, 0].rotate(this.angle); },
|
|
||||||
left() { return [-1, 0].rotate(this.angle); },
|
|
||||||
|
|
||||||
make_objs(objs) {
|
make_objs(objs) {
|
||||||
for (var prop in objs) {
|
for (var prop in objs) {
|
||||||
|
@ -575,19 +401,159 @@ var gameobject = {
|
||||||
Object.assign(this[name], data);
|
Object.assign(this[name], data);
|
||||||
return this[name];
|
return this[name];
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var gameobject = {
|
||||||
|
check_dirty() {
|
||||||
|
this._ed.urdiff = this.json_obj();
|
||||||
|
this._ed.dirty = !Object.empty(this._ed.urdiff);
|
||||||
|
return; // TODO: IMPLEMENT
|
||||||
|
var lur = this.master.ur;
|
||||||
|
if (!lur) return;
|
||||||
|
var lur = lur.objects[this.toString()];
|
||||||
|
var d = ediff(this._ed.urdiff, lur);
|
||||||
|
if (!d || Object.empty(d))
|
||||||
|
this._ed.inst = true;
|
||||||
|
else
|
||||||
|
this._ed.inst = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
namestr() {
|
||||||
|
var s = this.toString();
|
||||||
|
if (this._ed?.dirty)
|
||||||
|
if (this._ed.inst) s += "#";
|
||||||
|
else s += "*";
|
||||||
|
return s;
|
||||||
|
},
|
||||||
|
|
||||||
|
urstr() {
|
||||||
|
var str = this.ur.name;
|
||||||
|
if (this._ed.dirty) str = "*" + str;
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* pin this object to the to object */
|
||||||
|
pin(to) {
|
||||||
|
var p = joint.pin(this,to);
|
||||||
|
},
|
||||||
|
slide(to, a = [0,0], b = [0,0], min = 0, max = 50) {
|
||||||
|
var p = joint.slide(this, to, a, b, min, max);
|
||||||
|
p.max_force = 500;
|
||||||
|
p.break();
|
||||||
|
},
|
||||||
|
pivot(to, piv = this.pos) {
|
||||||
|
var p = joint.pivot(this, to, piv);
|
||||||
|
},
|
||||||
|
/* groove is on to, from local points a and b, anchored to this at local anchor */
|
||||||
|
groove(to, a, b, anchor = [0,0]) {
|
||||||
|
var p = joint.groove(to, this, a, b, anchor);
|
||||||
|
},
|
||||||
|
damped_spring(to, length = Vector.length(this.pos,to.pos), stiffness = 1, damping = 1) {
|
||||||
|
var dc = 2 * Math.sqrt(stiffness * this.mass);
|
||||||
|
var p = joint.damped_spring(this, to, [0, 0], [0, 0], stiffness, damping * dc);
|
||||||
|
},
|
||||||
|
damped_rotary_spring(to, angle = 0, stiffness = 1, damping = 1) {
|
||||||
|
/* calculate actual damping value from the damping ratio */
|
||||||
|
/* damping = 1 is critical */
|
||||||
|
var dc = 2 * Math.sqrt(stiffness * this.get_moi()); /* critical damping number */
|
||||||
|
/* zeta = actual/critical */
|
||||||
|
var p = joint.damped_rotary(this, to, angle, stiffness, damping * dc);
|
||||||
|
},
|
||||||
|
rotary_limit(to, min, max) {
|
||||||
|
var p = joint.rotary(this, to, Math.turn2rad(min), Math.turn2rad(max));
|
||||||
|
},
|
||||||
|
ratchet(to, ratch) {
|
||||||
|
var phase = this.angle - to.angle;
|
||||||
|
var p = joint.ratchet(this, to, phase, Math.turn2rad(ratch));
|
||||||
|
},
|
||||||
|
gear(to, ratio = 1, phase = 0) {
|
||||||
|
var phase = this.angle - to.angle;
|
||||||
|
var p = joint.gear(this, to, phase, ratio);
|
||||||
|
},
|
||||||
|
motor(to, rate) {
|
||||||
|
var p = joint.motor(this, to, rate);
|
||||||
|
},
|
||||||
|
|
||||||
|
set_pos(x, relative = world) {
|
||||||
|
var newpos = relative.this2world(x);
|
||||||
|
var move = newpos.sub(this.pos);
|
||||||
|
this.rpos = newpos;
|
||||||
|
this.objects.forEach(x => x.move(move));
|
||||||
|
},
|
||||||
|
|
||||||
|
set_angle(x, relative = world) {
|
||||||
|
var newangle = relative.angle + x;
|
||||||
|
var diff = newangle - this.angle;
|
||||||
|
this.rangle = newangle;
|
||||||
|
this.objects.forEach(obj => {
|
||||||
|
obj.rotate(diff);
|
||||||
|
obj.set_pos(Vector.rotate(obj.get_pos(obj.master), diff), obj.master);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
set_scale(x, relative = world) {
|
||||||
|
if (typeof x === 'number') x = [x,x,x];
|
||||||
|
var newscale = relative.scale.map((s,i) => x[i]*s);
|
||||||
|
var pct = this.scale.map((s,i) => newscale[i]/s);
|
||||||
|
this.rscale = newscale;
|
||||||
|
this.objects.forEach(obj => {
|
||||||
|
obj.grow(pct);
|
||||||
|
obj.set_pos(obj.get_pos(obj.master).map((x,i) => x*pct[i]), obj.master);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_pos(relative = world) {
|
||||||
|
if (relative === world) return this.pos;
|
||||||
|
return relative.world2this(this.pos);
|
||||||
|
//return this.pos.sub(relative.pos);
|
||||||
|
},
|
||||||
|
|
||||||
|
get_angle(relative = world) {
|
||||||
|
if (relative === world) return this.angle;
|
||||||
|
return this.angle - relative.angle;
|
||||||
|
},
|
||||||
|
|
||||||
|
get_scale(relative = world) {
|
||||||
|
if (relative === world) return this.scale;
|
||||||
|
var masterscale = relative.scale;
|
||||||
|
return this.scale.map((x,i) => x/masterscale[i]);
|
||||||
|
},
|
||||||
|
|
||||||
|
in_air() { return this.in_air(); },
|
||||||
|
|
||||||
|
/* Velocity and angular velocity of the object */
|
||||||
|
phys_obj() {
|
||||||
|
var phys = {};
|
||||||
|
phys.velocity = this.velocity;
|
||||||
|
phys.angularvelocity = this.angularvelocity;
|
||||||
|
return phys;
|
||||||
|
},
|
||||||
|
|
||||||
|
set category(n) {
|
||||||
|
if (n === 0) {
|
||||||
|
this.categories = n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cat = (1 << (n-1));
|
||||||
|
this.categories = cat;
|
||||||
|
},
|
||||||
|
get category() {
|
||||||
|
if (this.categories === 0) return 0;
|
||||||
|
var pos = 0;
|
||||||
|
var num = this.categories;
|
||||||
|
while (num > 0) {
|
||||||
|
if (num & 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
num >>>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function go_init() {
|
return pos+1;
|
||||||
var gop = os.make_gameobject().__proto__;
|
|
||||||
Object.mixin(gop, gameobject);
|
|
||||||
gop.sync = function() {
|
|
||||||
this.selfsync();
|
|
||||||
this.components.forEach(function(x) { x.sync?.(); });
|
|
||||||
this.objects.forEach(function(x) { x.sync?.(); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
|
entity.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
|
||||||
|
|
||||||
gameobject.doc = {
|
gameobject.doc = {
|
||||||
doc: "All objects in the game created through spawning have these attributes.",
|
doc: "All objects in the game created through spawning have these attributes.",
|
||||||
|
@ -695,8 +661,18 @@ function apply_ur(u, ent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var emptyur = {
|
||||||
|
name: "empty"
|
||||||
|
}
|
||||||
|
|
||||||
var getur = function(text, data)
|
var getur = function(text, data)
|
||||||
{
|
{
|
||||||
|
if (!text && !data) {
|
||||||
|
console.info('empty ur');
|
||||||
|
return {
|
||||||
|
name: "empty"
|
||||||
|
};
|
||||||
|
}
|
||||||
var urstr = text + "+" + data;
|
var urstr = text + "+" + data;
|
||||||
if (!ur[urstr]) {
|
if (!ur[urstr]) {
|
||||||
ur[urstr] = {
|
ur[urstr] = {
|
||||||
|
@ -784,4 +760,4 @@ game.ur.save = function(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { go_init }
|
return { entity }
|
|
@ -84,8 +84,6 @@ void model_free(model *m);
|
||||||
|
|
||||||
void model_draw_go(model *m, gameobject *go, gameobject *cam);
|
void model_draw_go(model *m, gameobject *go, gameobject *cam);
|
||||||
|
|
||||||
void model_init();
|
|
||||||
|
|
||||||
material *material_make();
|
material *material_make();
|
||||||
void material_free(material *mat);
|
void material_free(material *mat);
|
||||||
|
|
||||||
|
|
|
@ -204,9 +204,3 @@ HMM_Vec3 go_pos3d(gameobject *go)
|
||||||
HMM_Vec2 pos2d = go_pos(go);
|
HMM_Vec2 pos2d = go_pos(go);
|
||||||
return (HMM_Vec3){pos2d.x, pos2d.y, go->drawlayer};
|
return (HMM_Vec3){pos2d.x, pos2d.y, go->drawlayer};
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameobject_draw_debug(gameobject *go) {
|
|
||||||
if (!go || !go->body) return;
|
|
||||||
|
|
||||||
cpBodyEachShape(go->body, body_draw_shapes_dbg, NULL);
|
|
||||||
}
|
|
||||||
|
|
|
@ -779,7 +779,21 @@ JSC_CCALL(render_setuniproj,
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(render_setunim4,
|
JSC_CCALL(render_setunim4,
|
||||||
HMM_Mat4 m = transform2d2mat4(js2transform2d(argv[2]));
|
HMM_Mat4 m = MAT1;
|
||||||
|
if (JS_IsArray(js, argv[2])) {
|
||||||
|
JSValue arr = argv[2];
|
||||||
|
int n = js_arrlen(arr);
|
||||||
|
if (n == 1)
|
||||||
|
m = transform2d2mat4(js2transform2d(js_getpropidx(arr,0)));
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
HMM_Mat4 p = transform2d2mat4(js2transform2d(js_getpropidx(arr, i)));
|
||||||
|
m = HMM_MulM4(p,m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
m = transform2d2mat4(js2transform2d(argv[2]));
|
||||||
|
|
||||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -920,7 +934,7 @@ static const JSCFunctionListEntry js_input_funcs[] = {
|
||||||
|
|
||||||
JSC_CCALL(prosperon_emitters_step, emitters_step(js2number(argv[0])))
|
JSC_CCALL(prosperon_emitters_step, emitters_step(js2number(argv[0])))
|
||||||
JSC_CCALL(prosperon_phys2d_step, phys2d_update(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_window_render, openglRender(&mainwin, js2transform2d(argv[0]), js2number(argv[1])))
|
||||||
JSC_CCALL(prosperon_guid,
|
JSC_CCALL(prosperon_guid,
|
||||||
uint8_t bytes[16];
|
uint8_t bytes[16];
|
||||||
for (int i = 0; i < 16; i++) bytes[i] = rand()%256;
|
for (int i = 0; i < 16; i++) bytes[i] = rand()%256;
|
||||||
|
@ -1089,8 +1103,6 @@ static const JSCFunctionListEntry js_io_funcs[] = {
|
||||||
MIST_FUNC_DEF(io, mod,1)
|
MIST_FUNC_DEF(io, mod,1)
|
||||||
};
|
};
|
||||||
|
|
||||||
JSC_CCALL(debug_draw_gameobject, gameobject_draw_debug(js2gameobject(argv[0]));)
|
|
||||||
|
|
||||||
JSC_GETSET_GLOBAL(disabled_color, color)
|
JSC_GETSET_GLOBAL(disabled_color, color)
|
||||||
JSC_GETSET_GLOBAL(sleep_color, color)
|
JSC_GETSET_GLOBAL(sleep_color, color)
|
||||||
JSC_GETSET_GLOBAL(dynamic_color, color)
|
JSC_GETSET_GLOBAL(dynamic_color, color)
|
||||||
|
@ -1098,7 +1110,6 @@ JSC_GETSET_GLOBAL(kinematic_color, color)
|
||||||
JSC_GETSET_GLOBAL(static_color, color)
|
JSC_GETSET_GLOBAL(static_color, color)
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_debug_funcs[] = {
|
static const JSCFunctionListEntry js_debug_funcs[] = {
|
||||||
MIST_FUNC_DEF(debug, draw_gameobject, 1),
|
|
||||||
CGETSET_ADD(global, disabled_color),
|
CGETSET_ADD(global, disabled_color),
|
||||||
CGETSET_ADD(global, sleep_color),
|
CGETSET_ADD(global, sleep_color),
|
||||||
CGETSET_ADD(global, dynamic_color),
|
CGETSET_ADD(global, dynamic_color),
|
||||||
|
@ -1716,7 +1727,16 @@ JSC_SCALL(os_make_texture,
|
||||||
JSC_CCALL(os_make_font, return font2js(MakeFont(js2str(argv[0]), js2number(argv[1]))))
|
JSC_CCALL(os_make_font, return font2js(MakeFont(js2str(argv[0]), js2number(argv[1]))))
|
||||||
|
|
||||||
JSC_CCALL(os_make_transform2d,
|
JSC_CCALL(os_make_transform2d,
|
||||||
|
if (JS_IsUndefined(argv[0]))
|
||||||
return transform2d2js(make_transform2d());
|
return transform2d2js(make_transform2d());
|
||||||
|
|
||||||
|
int n = js2number(argv[0]);
|
||||||
|
transform2d *t = calloc(sizeof(transform2d), n);
|
||||||
|
JSValue arr = JS_NewArray(js);
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
js_setprop_num(arr, i, transform2d2js(t+i));
|
||||||
|
|
||||||
|
return arr;
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_SCALL(os_system, return number2js(system(str)); )
|
JSC_SCALL(os_system, return number2js(system(str)); )
|
||||||
|
@ -1742,7 +1762,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||||
MIST_FUNC_DEF(os, make_texture, 1),
|
MIST_FUNC_DEF(os, make_texture, 1),
|
||||||
MIST_FUNC_DEF(os, make_font, 2),
|
MIST_FUNC_DEF(os, make_font, 2),
|
||||||
MIST_FUNC_DEF(os, make_model, 1),
|
MIST_FUNC_DEF(os, make_model, 1),
|
||||||
MIST_FUNC_DEF(os, make_transform2d, 0),
|
MIST_FUNC_DEF(os, make_transform2d, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "steam.h"
|
#include "steam.h"
|
||||||
|
|
|
@ -258,8 +258,6 @@ void render_init() {
|
||||||
font_init();
|
font_init();
|
||||||
debugdraw_init();
|
debugdraw_init();
|
||||||
|
|
||||||
model_init();
|
|
||||||
|
|
||||||
sg_color c = (sg_color){0,0,0,1};
|
sg_color c = (sg_color){0,0,0,1};
|
||||||
pass_action = (sg_pass_action){
|
pass_action = (sg_pass_action){
|
||||||
.colors[0] = {.load_action = SG_LOADACTION_CLEAR, .clear_value = c},
|
.colors[0] = {.load_action = SG_LOADACTION_CLEAR, .clear_value = c},
|
||||||
|
@ -337,7 +335,7 @@ HMM_Mat4 useproj = {0};
|
||||||
#define MODE_EXPAND 4
|
#define MODE_EXPAND 4
|
||||||
#define MODE_FULL 5
|
#define MODE_FULL 5
|
||||||
|
|
||||||
void openglRender(struct window *window, gameobject *cam, float zoom) {
|
void openglRender(struct window *window, transform2d *cam, float zoom) {
|
||||||
sg_swapchain sch = sglue_swapchain();
|
sg_swapchain sch = sglue_swapchain();
|
||||||
sg_begin_pass(&(sg_pass){
|
sg_begin_pass(&(sg_pass){
|
||||||
.action = pass_action,
|
.action = pass_action,
|
||||||
|
@ -372,7 +370,7 @@ void openglRender(struct window *window, gameobject *cam, float zoom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2D projection
|
// 2D projection
|
||||||
campos = go_pos(cam);
|
campos = cam->pos;
|
||||||
camzoom = zoom;
|
camzoom = zoom;
|
||||||
|
|
||||||
projection = HMM_Orthographic_RH_NO(
|
projection = HMM_Orthographic_RH_NO(
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "sokol/sokol_gfx.h"
|
#include "sokol/sokol_gfx.h"
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
#include "gameobject.h"
|
#include "gameobject.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
#define RGBA_MAX 255
|
#define RGBA_MAX 255
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ void render_init();
|
||||||
extern HMM_Vec2 campos;
|
extern HMM_Vec2 campos;
|
||||||
extern float camzoom;
|
extern float camzoom;
|
||||||
|
|
||||||
void openglRender(struct window *window, gameobject *cam, float zoom);
|
void openglRender(struct window *window, transform2d *cam, float zoom);
|
||||||
void opengl_rendermode(enum RenderMode r);
|
void opengl_rendermode(enum RenderMode r);
|
||||||
|
|
||||||
void openglInit3d(struct window *window);
|
void openglInit3d(struct window *window);
|
||||||
|
|
Loading…
Reference in a new issue