Add all files needed for engine into main branch

This commit is contained in:
2023-04-22 21:44:26 +00:00
parent 1e8d76961d
commit 2ab0f33d3f
31 changed files with 6077 additions and 17 deletions

609
source/scripts/base.js Normal file
View File

@@ -0,0 +1,609 @@
/* Prototypes out an object and extends with values */
function clone(proto, binds) {
var c = Object.create(proto);
complete_assign(c, binds);
return c;
};
/* Prototypes out an object and assigns values */
function copy(proto, binds) {
var c = Object.create(proto);
Object.assign(c, binds);
return c;
};
/* OBJECT DEFININTIONS */
Object.defineProperty(Object.prototype, 'getOwnPropertyDescriptors', {
value: function() {
var obj = {};
for (var key in this) {
obj[key] = Object.getOwnPropertyDescriptor(this, key);
}
return obj;
}
});
Object.defineProperty(Object.prototype, 'hasOwn', {
value: function(x) { return this.hasOwnProperty(x); }
});
Object.defineProperty(Object.prototype, 'array', {
value: function() {
var a = [];
for (var key in this)
a.push(this[key]);
return a;
},
});
Object.defineProperty(Object.prototype, 'defn', {
value: function(name, val) {
Object.defineProperty(this, name, { value:val, writable:true, configurable:true });
}
});
Object.defineProperty(Object.prototype, 'nulldef', {
value: function(name, val) {
if (!this.hasOwnProperty(name)) this[name] = val;
}
});
/* defc 'define constant'. Defines a value that is not writable. */
Object.defineProperty(Object.prototype, 'defc', {
value: function(name, val) {
Object.defineProperty(this,name, {
value: val,
writable:false,
enumerable:true,
configurable:false,
});
}
});
Object.defineProperty(Object.prototype, 'deflock', {
value: function(prop) {
Object.defineProperty(this,prop, {configurable:false});
}
});
Object.defineProperty(Object.prototype, 'forEach', {
value: function(fn) {
for (var key in this)
fn(this[key]);
}
});
Object.defineProperty(Object.prototype, 'empty', {
get: function() {
return Object.keys(this).empty;
},
});
Object.defineProperty(Object.prototype, 'nth', {
value: function(x) {
if (this.empty || x >= Object.keys(this).length) return null;
return this[Object.keys(this)[x]];
},
});
Object.defineProperty(Object.prototype, 'findIndex', {
value: function(x) {
var i = 0;
for (var key in this) {
if (this[key] === x) return i;
i++;
}
return -1;
}
});
/* STRING DEFS */
Object.defineProperty(String.prototype, 'next', {
value: function(char, from) {
if (!Array.isArray(char))
char = [char];
if (from > this.length-1)
return -1;
else if (!from)
from = 0;
var find = this.slice(from).search(char[0]);
if (find === -1)
return -1;
else
return from + find;
var i = 0;
var c = this.charAt(from+i);
while (!char.includes(c)) {
i++;
if (from+i >this.length-1) return -1;
c = this.charAt(from+i);
}
return from+i;
}
});
Object.defineProperty(String.prototype, 'prev', {
value: function(char, from, count) {
if (from > this.length-1)
return -1;
else if (!from)
from = this.length-1;
if (!count) count = 0;
var find = this.slice(0,from).lastIndexOf(char);
while (count > 1) {
find = this.slice(0,find).lastIndexOf(char);
count--;
}
if (find === -1)
return 0;
else
return find;
}
});
Object.defineProperty(String.prototype, 'shift', {
value: function(n) {
if (n === 0) return this.slice();
if (n > 0)
return this.slice(n);
if (n < 0)
return this.slice(0, this.length+n);
}
});
/* ARRAY DEFS */
Object.defineProperty(Array.prototype, 'copy', {
value: function() {
var c = [];
this.forEach(function(x, i) {
c[i] = deep_copy(x);
});
return c;
}
});
Object.defineProperty(Array.prototype, 'rotate', {
value: function(a) {
return Vector.rotate(this, a);
}
});
Object.defineProperty(Array.prototype, '$add', {
value: function(b) {
for (var i = 0; i < this.length; i++) {
this[i] += b[i];
}
}});
function setelem(n) {
return {
get: function() { return this[n]; },
set: function(x) { this[n] = x; }
}
};
function arrsetelem(str, n)
{
Object.defineProperty(Array.prototype, str, setelem(n));
}
Object.defineProperty(Array.prototype, 'x', setelem(0));
Object.defineProperty(Array.prototype, 'y', setelem(1));
Object.defineProperty(Array.prototype, 'z', setelem(2));
Object.defineProperty(Array.prototype, 'w', setelem(3));
arrsetelem('r', 0);
arrsetelem('g', 1);
arrsetelem('b', 2);
arrsetelem('a', 3);
Object.defineProperty(Array.prototype, 'add', {
value: function(b) {
var c = [];
for (var i = 0; i < this.length; i++) { c[i] = this[i] + b[i]; }
return c;
}});
Object.defineProperty(Array.prototype, 'newfirst', {
value: function(i) {
var c = this.slice();
if (i >= c.length) return c;
do {
c.push(c.shift());
i--;
} while (i > 0);
return c;
}
});
Object.defineProperty(Array.prototype, 'doubleup', {
value: function(n) {
var c = [];
this.forEach(function(x) {
for (var i = 0; i < n; i++)
c.push(x);
});
return c;
}
});
Object.defineProperty(Array.prototype, 'sub', {
value: function(b) {
var c = [];
for (var i = 0; i < this.length; i++) { c[i] = this[i] - b[i]; }
return c;
}});
Object.defineProperty(Array.prototype, 'apply', {
value: function(fn) {
this.forEach(function(x) { x[fn].apply(x); });
}
});
Object.defineProperty(Array.prototype, 'scale', {
value: function(s) {
return this.map(function(x) { return x*s; });
}});
Object.defineProperty(Array.prototype, 'equal', {
value: function(b) {
if (this.length !== b.length) return false;
if (b == null) return false;
if (this === b) return true;
return JSON.stringify(this) === JSON.stringify(b);
for (var i = 0; i < this.length; i++) {
if (!this[i] === b[i])
return false;
}
return true;
}});
function add(x,y) { return x+y; };
function mult(x,y) { return x*y; };
Object.defineProperty(Array.prototype, 'mapc', {
value: function(fn, arr) {
return this.map(function(x, i) {
return fn(x, arr[i]);
});
}
});
Object.defineProperty(Array.prototype, 'remove', {
value: function(b) {
var idx = this.indexOf(b);
if (idx === -1) return false;
this.splice(idx, 1);
return true;
}});
Object.defineProperty(Array.prototype, 'set', {
value: function(b) {
if (this.length !== b.length) return;
b.forEach(function(val, i) { this[i] = val; }, this);
}
});
Object.defineProperty(Array.prototype, 'flat', {
value: function() {
return [].concat.apply([],this);
}
});
Object.defineProperty(Array.prototype, 'any', {
value: function(fn) {
var ev = this.every(function(x) {
return !fn(x);
});
return !ev;
}
});
/* Return true if array contains x */
/*Object.defineProperty(Array.prototype, 'includes', {
value: function(x) {
return this.some(e => e === x);
}});
*/
Object.defineProperty(Array.prototype, 'empty', {
get: function() { return this.length === 0; },
});
Object.defineProperty(Array.prototype, 'push_unique', {
value: function(x) {
if (!this.includes(x)) this.push(x);
}});
Object.defineProperty(Array.prototype, 'unique', {
value: function() {
var c = [];
this.forEach(function(x) { c.push_unique(x); });
return c;
}
});
Object.defineProperty(Array.prototype, 'findIndex', {
value: function(fn) {
var idx = -1;
this.every(function(x, i) {
if (fn(x)) {
idx = i;
return false;
}
return true;
});
return idx;
}});
Object.defineProperty(Array.prototype, 'find', {
value: function(fn) {
var ret;
this.every(function(x) {
if (fn(x)) {
ret = x;
return false;
}
return true;
});
return ret;
}});
Object.defineProperty(Array.prototype, 'last', {
get: function() { return this[this.length-1]; },
});
Object.defineProperty(Array.prototype, 'at', {
value: function(x) {
return x < 0 ? this[this.length+x] : this[x];
}});
Object.defineProperty(Array.prototype, 'wrapped', {
value: function(x) {
var c = this.slice(0, this.length);
for (var i = 0; i < x; i++)
c.push(this[i]);
return c;
}});
Object.defineProperty(Array.prototype, 'wrap_idx', {
value: function(x) {
while (x >= this.length) {
x -= this.length;
}
return x;
}
});
Object.defineProperty(Array.prototype, 'mirrored', {
value: function(x) {
var c = this.slice(0);
if (c.length <= 1) return c;
for (var i = c.length-2; i >= 0; i--)
c.push(c[i]);
return c;
}
});
/* MATH EXTENSIONS */
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; }
Math.lerp = function (s, f, dt) {
return s + (Math.clamp(dt, 0, 1) * (f - s));
};
Math.snap = function(val, grid) {
if (!grid || grid === 1) return Math.round(val);
var rem = val%grid;
var d = val - rem;
var i = Math.round(rem/grid)*grid;
return d+i;
}
Math.angledist = function (a1, a2) {
var dist = a2 - a1;
var wrap = dist >= 0 ? dist+360 : dist-360;
wrap %= 360;
if (Math.abs(dist) < Math.abs(wrap))
return dist;
return wrap;
};
Math.deg2rad = function(deg) { return deg * 0.0174533; }
Math.rad2deg = function(rad) { return rad / 0.0174533; }
/* BOUNDINGBOXES */
function cwh2bb(c, wh) {
return {
t: c.y+wh.y/2,
b: c.y-wh.y/2,
l: c.x-wh.x/2,
r: c.x+wh.x/2
};
};
function points2bb(points) {
var b= {t:0,b:0,l:0,r:0};
points.forEach(function(x) {
if (x.y > b.t) b.t = x.y;
if (x.y < b.b) b.b = x.y;
if (x.x > b.r) b.r = x.x;
if (x.x < b.l) b.l = x.x;
});
return b;
};
function bb2cwh(bb) {
if (!bb) return undefined;
var cwh = {};
var w = bb.r - bb.l;
var h = bb.t - bb.b;
cwh.wh = [w, h];
cwh.c = [bb.l + w/2, bb.b + h/2];
return cwh;
};
function bb_expand(oldbb, x) {
if (!oldbb || !x) return;
var bb = {};
Object.assign(bb, oldbb);
if (bb.t < x.t) bb.t = x.t;
if (bb.r < x.r) bb.r = x.r;
if (bb.b > x.b) bb.b = x.b;
if (bb.l > x.l) bb.l = x.l;
return bb;
};
function bb_draw(bb, color) {
if (!bb) return;
var draw = bb2cwh(bb);
draw.wh[0] /= editor.camera.zoom;
draw.wh[1] /= editor.camera.zoom;
Debug.box(world2screen(draw.c), draw.wh, color);
};
function bb_from_objects(objs) {
var bb = objs[0].boundingbox;
objs.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox); });
return bb;
};
/* VECTORS */
var Vector = {
x: 0,
y: 0,
length(v) {
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
return Math.sqrt(sum);
},
norm(v) {
var len = Vector.length(v);
return [v.x/len, v.y/len];
},
make(x, y) {
var vec = Object.create(this, {x:x, y:y});
},
project(a, b) {
return cmd(85, a, b);
},
dot(a, b) {
},
random() {
var vec = [Math.random()-0.5, Math.random()-0.5];
return Vector.norm(vec);
},
angle(v) {
return Math.atan2(v.y, v.x);
},
rotate(v,angle) {
var r = Vector.length(v);
var p = Vector.angle(v) + angle;
return [r*Math.cos(p), r*Math.sin(p)];
},
equal(v1, v2, tol) {
if (!tol)
return v1.equal(v2);
var eql = true;
var c = v1.sub(v2);
c.forEach(function(x) {
if (!eql) return;
if (Math.abs(x) > tol)
eql = false;
});
return eql;
},
};
/* POINT ASSISTANCE */
function points2cm(points)
{
var x = 0;
var y = 0;
var n = points.length;
points.forEach(function(p) {
x = x + p[0];
y = y + p[1];
});
return [x/n,y/n];
};
function sortpointsccw(points)
{
var cm = points2cm(points);
var cmpoints = points.map(function(x) { return x.sub(cm); });
var ccw = cmpoints.sort(function(a,b) {
aatan = Math.atan2(a.y, a.x);
batan = Math.atan2(b.y, b.x);
return aatan - batan;
});
return ccw.map(function(x) { return x.add(cm); });
}

View File

@@ -0,0 +1,657 @@
var component = {
toString() {
if ('gameobject' in this)
return this.name + " on " + this.gameobject;
else
return this.name;
},
name: "component",
component: true,
set enabled(x) { },
get enabled() { },
enable() { this.enabled = true; },
disable() { this.enabled = false; },
make(go) { },
kill() { Log.info("Kill not created for this component yet"); },
gui() { },
gizmo() { },
prepare_center() {},
finish_center() {},
clone(spec) {
return clone(this, spec);
},
};
var sprite = clone(component, {
name: "sprite",
path: "",
_pos: [0, 0],
get layer() {
if (!this.gameobject)
return 0;
else
return this.gameobject.draw_layer;
},
get pos() { return this._pos; },
set pos(x) {
this._pos = x;
this.sync();
},
get boundingbox() {
if (!this.gameobject) return null;
var dim = cmd(64, this.path);
dim = dim.scale(this.gameobject.scale);
var realpos = this.pos.copy();
realpos.x *= dim.x;
realpos.y *= dim.y;
realpos.x += (dim.x/2);
realpos.y += (dim.y/2);
return cwh2bb(realpos, dim);
},
set asset(x) {
if (!x) return;
if (!x.endsWith(".png")) {
Log.error("Can't set texture to a non image.");
return;
}
this.path = x;
Log.info("path is now " + x);
this.sync();
},
_enabled: true,
set enabled(x) { this._enabled = x; cmd(20, this.id, x); },
get enabled() { return this._enabled; return cmd(21, this.id); },
get visible() { return this.enabled; },
set visible(x) { this.enabled = x; },
_angle: 0,
get angle() { return this._angle; },
set angle(x) {
this._angle = x;
sync();
},
make(go) {
var sprite = clone(this);
Object.defineProperty(sprite, 'id', {value:make_sprite(go,this.path,this.pos)});
sprite.sync();
return sprite;
},
rect: {s0:0, s1: 1, t0: 0, t1: 1},
sync() {
if (!this.hasOwn('id')) return;
cmd(60, this.id, this.layer);
cmd(37, this.id, this.pos);
cmd(12, this.id, this.path, this.rect);
},
load_img(img) {
cmd(12, this.id, img);
},
kill() {
cmd(9, this.id);
},
});
/* Container to play sprites and anim2ds */
var char2d = clone(sprite, {
clone(anims) {
var char = clone(this);
char.anims = anims;
return char;
},
name: "char 2d",
frame2rect(frames, frame) {
var rect = {s0:0,s1:1,t0:0,t1:1};
var frameslice = 1/frames;
rect.s0 = frameslice*frame;
rect.s1 = frameslice*(frame+1);
return rect;
},
make(go) {
var char = clone(this);
char.curplaying = char.anims.array()[0];
Object.defineProperty(char, 'id', {value:make_sprite(go,this.path,this.pos)});
char.frame = 0;
char.timer = timer.make(char.advance, 1/char.curplaying.fps, char);
char.timer.loop = true;
char.rect = char.frame2rect(char.curplaying.frames, char.frame);
char.setsprite();
return char;
},
frame: 0,
play(name) {
if (!(name in this.anims)) {
Log.info("Can't find an animation named " + name);
return;
}
if (this.curplaying === this.anims[name]) return;
this.curplaying = this.anims[name];
this.timer.time = 1/this.curplaying.fps;
this.timer.start();
this.frame = 0;
this.setsprite();
},
setsprite() {
this.path = this.curplaying.path;
this.rect = this.frame2rect(this.curplaying.frames, this.frame);
cmd(12, this.id, this.path, this.rect);
},
advance() {
this.frame = (this.frame + 1) % this.curplaying.frames;
this.setsprite();
},
devance() {
this.frame = (this.frame - 1);
if (this.frame === -1) this.frame = this.curplaying.frames-1;
this.setsprite();
},
pause() {
this.timer.pause();
},
stop() {
this.frame = 0;
this.timer.stop();
this.setsprite();
},
kill() {
this.timer.kill();
cmd(9, this.id);
},
});
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
var collider2d = clone(component, {
name: "collider 2d",
_sensor: false,
set sensor(x) {
this._sensor = x;
if (this.shape)
cmd(18, this.shape, x);
},
get sensor() { return this._sensor; },
input_s_pressed() {
if (!Keys.alt()) return;
this.sensor = !this.sensor;
},
input_t_pressed() {
if (!Keys.alt()) return;
this.enabled = !this.enabled;
},
coll_sync() {
cmd(18, this.shape, this.sensor);
},
_enabled: true,
set enabled(x) {this._enabled = x; if (this.id) cmd(22, this.id, x); },
get enabled() { return this._enabled; },
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
register_hit(fn, obj) {
register_collide(1, fn, obj, this.gameobject.body, this.shape);
},
});
var polygon2d = clone(collider2d, {
name: "polygon 2d",
points: [],
help: "Ctrl-click Add a point\nShift-click Remove a point",
clone(spec) {
var obj = Object.create(this);
obj.points = this.points.copy();
Object.assign(obj, spec);
return obj;
},
make(go) {
var poly = Object.create(this);
Object.assign(poly, make_poly2d(go, this.points));
Object.defineProperty(poly, 'id', {enumerable:false});
Object.defineProperty(poly, 'shape', {enumerable:false});
return poly;
},
get boundingbox() {
if (!this.gameobject) return null;
var scaledpoints = [];
this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this);
return points2bb(scaledpoints);
},
input_f10_pressed() {
this.points = sortpointsccw(this.points);
},
sync() {
if (!this.id) return;
cmd_poly2d(0, this.id, this.spoints);
this.coll_sync();
},
input_b_pressed() {
if (!Keys.ctrl()) return;
this.points = this.spoints;
this.mirrorx = false;
this.mirrory = false;
},
get spoints() {
var spoints = this.points.slice();
if (this.mirrorx) {
spoints.forEach(function(x) {
var newpoint = x.slice();
newpoint.x = -newpoint.x;
spoints.push(newpoint);
});
}
if (this.mirrory) {
spoints.forEach(function(x) {
var newpoint = x.slice();
newpoint.y = -newpoint.y;
spoints.push(newpoint);
});
}
return spoints;
},
gizmo() {
if (!this.hasOwn('points')) this.points = this.__proto__.points.copy();
this.spoints.forEach(function(x) {
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
}, this);
this.points.forEach(function(x, i) {
Debug.numbered_point(this.gameobject.this2world(x), i);
}, this);
this.sync();
},
input_lmouse_pressed() {
if (Keys.ctrl()) {
this.points.push(this.gameobject.world2this(Mouse.worldpos));
} else if (Keys.shift()) {
var idx = grab_from_points(screen2world(Mouse.pos), this.points.map(this.gameobject.this2world,this.gameobject), 25);
if (idx === -1) return;
this.points.splice(idx, 1);
}
},
pick(pos) {
return Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
},
query() {
return cmd(80, this.shape);
},
mirrorx: false,
mirrory: false,
input_m_pressed() {
if (Keys.ctrl())
this.mirrory = !this.mirrory;
else
this.mirrorx = !this.mirrorx;
},
});
var bucket = clone(collider2d, {
name: "bucket",
help: "Ctrl-click Add a point\nShift-click Remove a point\n+,- Increase/decrease spline segs\nCtrl-+,- Inc/dec spline degrees\nCtrl-b,v Inc/dec spline thickness",
clone(spec) {
var obj = Object.create(this);
obj.cpoints = this.cpoints.copy();
dainty_assign(obj, spec);
return obj;
},
cpoints:[],
degrees:2,
dimensions:2,
/* open: 0
clamped: 1
beziers: 2
looped: 3
*/
type: 3,
get boundingbox() {
if (!this.gameobject) return null;
var scaledpoints = [];
this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this);
return points2bb(scaledpoints);
},
mirrorx: false,
mirrory: false,
input_m_pressed() {
if (Keys.ctrl()) {
this.mirrory = !this.mirrory;
} else {
this.mirrorx = !this.mirrorx;
}
this.sync();
},
hollow: false,
input_h_pressed() {
this.hollow = !this.hollow;
},
get spoints() {
var spoints = this.cpoints.slice();
if (this.mirrorx) {
for (var i = spoints.length-1; i >= 0; i--) {
var newpoint = spoints[i].slice();
newpoint.x = -newpoint.x;
spoints.push(newpoint);
}
}
if (this.mirrory) {
for (var i = spoints.length-1; i >= 0; i--) {
var newpoint = spoints[i].slice();
newpoint.y = -newpoint.y;
spoints.push(newpoint);
}
}
return spoints;
if (this.hollow) {
var hpoints = [];
var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt);
inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); });
inflatep[1].forEach(function(x) { hpoints.push(x); });
return hpoints;
}
return spoints;
},
hollowt: 0,
input_g_pressed() {
if (!Keys.ctrl()) return;
this.hollowt--;
if (this.hollowt < 0) this.hollowt = 0;
},
input_f_pressed() {
if (!Keys.ctrl()) return;
this.hollowt++;
},
sample(n) {
var spoints = this.spoints;
this.degrees = Math.clamp(this.degrees, 1, spoints.length-1);
if (spoints.length === 2)
return spoints;
if (spoints.length < 2)
return [];
if (this.degrees < 2) {
if (this.type === 3)
return spoints.wrapped(1);
return spoints;
}
/*
order = degrees+1
knots = spoints.length + order
assert knots%order != 0
*/
if (this.type === 3)
return spline_cmd(0, this.degrees, this.dimensions, 0, spoints.wrapped(this.degrees), n);
return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n);
},
samples: 10,
points:[],
make(go) {
var edge = Object.create(this);
Object.assign(edge, make_edge2d(go, this.points, this.thickness));
Object.defineProperty(edge, 'id', {enumerable:false});
Object.defineProperty(edge, 'shape', {enumerable:false});
edge.defn('points', []);
// Object.defineProperty(edge, 'points', {enumerable:false});
edge.sync();
return edge;
},
sync() {
if (!this.gameobject) return;
this.points = this.sample(this.samples);
cmd_edge2d(0, this.id, this.points);
cmd_edge2d(1, this.id, this._thickness * this.gameobject.scale);
this.coll_sync();
},
gizmo() {
if (!this.hasOwn('cpoints')) this.cpoints = this.__proto__.cpoints.copy();
this.spoints.forEach(function(x) {
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
}, this);
this.cpoints.forEach(function(x, i) {
Debug.numbered_point(this.gameobject.this2world(x), i);
}, this);
this.sync();
},
_thickness:0, /* Number of pixels out the edge is */
get thickness() { return this._thickness; },
set thickness(x) {
this._thickness = Math.max(x, 0);
cmd_edge2d(1, this.id, this._thickness);
},
input_v_pressrep() {
if (!Keys.alt()) return;
this.thickness--;
},
input_b_pressrep() {
if (Keys.alt()) {
this.thickness++;
} else if (Keys.ctrl()) {
this.cpoints = this.spoints;
this.mirrorx = false;
this.mirrory = false;
}
},
finish_center(change) {
this.cpoints = this.cpoints.map(function(x) { return x.sub(change); });
this.sync();
},
input_plus_pressrep() {
if (Keys.ctrl())
this.degrees++;
else
this.samples += 1;
},
input_minus_pressrep() {
if (Keys.ctrl())
this.degrees--;
else {
this.samples -= 1;
if (this.samples < 1) this.samples = 1;
}
},
input_r_pressed() {
if (!Keys.ctrl()) return;
this.cpoints = this.cpoints.reverse();
},
input_l_pressed() {
if (!Keys.ctrl()) return;
this.type = 3;
},
input_c_pressed() {
if (!Keys.ctrl()) return;
this.type = 1;
},
input_o_pressed() {
if (!Keys.ctrl()) return;
this.type = 0;
},
input_lmouse_pressed() {
if (Keys.ctrl()) {
if (Keys.alt()) {
var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(this.gameobject.world2this,this.gameobject), 25);
if (idx === -1) return;
this.cpoints = this.cpoints.newfirst(idx);
return;
}
var idx = 0;
if (this.cpoints.length >= 2) {
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 1000);
if (idx === -1) return;
}
if (idx === this.cpoints.length)
this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos)));
else
this.cpoints.splice(idx, 0, this.gameobject.world2this(screen2world(Mouse.pos)));
return;
} else if (Keys.shift()) {
var idx = grab_from_points(screen2world(Mouse.pos), this.cpoints.map(function(x) {return x.add(this.gameobject.pos); }, this), 25);
if (idx === -1) return;
this.cpoints.splice(idx, 1);
}
},
pick(pos) { return Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints); },
input_lbracket_pressrep() {
var np = [];
this.cpoints.forEach(function(c) {
np.push(Vector.rotate(c, Math.deg2rad(-1)));
});
this.cpoints = np;
},
input_rbracket_pressrep() {
var np = [];
this.cpoints.forEach(function(c) {
np.push(Vector.rotate(c, Math.deg2rad(1)));
});
this.cpoints = np;
},
});
var circle2d = clone(collider2d, {
name: "circle 2d",
get radius() {
return this.rradius;
},
rradius: 10,
set radius(x) {
this.rradius = x;
cmd_circle2d(0, this.id, this.rradius);
},
get boundingbox() {
if (!this.gameobject) return null;
var radius = this.radius*2*this.gameobject.scale;
return cwh2bb(this.offset.scale(this.gameobject.scale), [radius, radius]);
},
get scale() { return this.radius; },
set scale(x) { this.radius = x; },
ofset: [0,0],
get offset() { return this.ofset; },
set offset(x) { this.ofset = x; cmd_circle2d(1, this.id, this.ofset); },
get pos() { return this.ofset; },
set pos(x) { this.offset = x; },
make(go) {
var circle = clone(this);
var circ = make_circle2d(go, circle.radius, circle.offset);
Object.assign(circle, circ);
Object.defineProperty(circle, 'id', {enumerable:false});
Object.defineProperty(circle, 'shape', {enumerable:false});
return circle;
},
gui() {
Nuke.newline();
Nuke.label("circle2d");
this.radius = Nuke.pprop("Radius", this.radius);
this.offset = Nuke.pprop("offset", this.offset);
},
sync() {
cmd_circle2d(0, this.id, this.rradius);
cmd_circle2d(-1, this.id);
this.coll_sync();
},
});

207
source/scripts/debug.js Normal file
View File

@@ -0,0 +1,207 @@
var Gizmos = {
pick_gameobject_points(worldpos, gameobject, points) {
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
if (idx === -1) return null;
return points[idx];
},
};
var Debug = {
draw_grid(width, span) {
cmd(47, width, span);
},
point(pos, size, color) {
color = color ? color : Color.blue;
cmd(51, pos, size,color);
},
arrow(start, end, color, capsize) {
color = color ? color : Color.red;
if (!capsize)
capsize = 4;
cmd(81, start, end, color, capsize);
},
box(pos, wh, color) {
color = color ? color : Color.white;
cmd(53, pos, wh, color);
},
numbered_point(pos, n) {
Debug.point(world2screen(pos), 3);
gui_text(n, world2screen(pos).add([0,4]), 1);
},
phys_drawing: false,
draw_phys(on) {
this.phys_drawing = on;
cmd(4, this.phys_drawing);
},
draw_obj_phys(obj) {
cmd(82, obj.body);
},
register_call(fn, obj) {
register_debug(fn,obj);
},
print_callstack() {
for (var i = -3;; i--) {
var t = Duktape.act(i);
if (!t) break;
var file = t.function ? t.function.fileName : "";
var line = t.lineNumber;
Log.info(file + ":" + line);
}
},
line(points, color, type) {
if (!type)
type = 0;
if (!color)
color = Color.white;
switch (type) {
case 0:
cmd(83, points, color);
}
},
};
var Gizmos = {
pick_gameobject_points(worldpos, gameobject, points) {
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
if (idx === -1) return null;
return points[idx];
},
};
var Nuke = {
newline(cols) { nuke(3, cols ? cols : 1); },
newrow(height) { nuke(13,height); },
wins: {},
curwin:"",
prop(str, v) {
var ret = nuke(2, str, v);
if (Number.isFinite(ret)) return ret;
return 0;
},
treeid: 0,
tree(str) { var on = nuke(11, str, this.treeid); this.treeid++; return on; },
tree_pop() { nuke(12);},
prop_num(str, num) { return nuke(2, str, num, -1e10, 1e10, 0.01); },
prop_bool(str, val) { return nuke(4, str, val); },
checkbox(val) { return nuke(4,"",val); },
label(str) { nuke(5, str); },
textbox(str) { return nuke(7, str); },
scrolltext(str) { nuke(14,str); },
defaultrect: { x:10, y:10, w:400, h:600 },
window(name) {
this.curwin = name;
var rect;
if (name in this.wins)
rect = this.wins[name];
else
rect = { x:10, y:10, w:400, h:600 };
nuke(0, name, rect);
},
button(name) { return nuke(6, name); },
radio(name, val, cmp) { return nuke(9, name, val, cmp); },
img(path) { nuke(8, path); },
end() {
this.wins[this.curwin] = nuke(10);
this.treeid = 0;
nuke(1);
},
pprop(str, p, nonew) {
switch(typeof p) {
case 'number':
if (!nonew) Nuke.newline();
return Nuke.prop_num(str, p);
break;
case 'boolean':
if (!nonew) Nuke.newline();
return Nuke.prop_bool(str, p);
case 'object':
if (Array.isArray(p)) {
var arr = [];
Nuke.newline(p.length+1);
Nuke.label(str);
arr[0] = Nuke.pprop("#x", p[0], true);
arr[1] = Nuke.pprop("#y", p[1], true);
return arr;
} else {
if (!nonew)Nuke.newline(2);
Nuke.label(str);
Nuke.label(p);
}
break;
case 'string':
if (!nonew) Nuke.newline();
Nuke.label(str);
return Nuke.textbox(p);
default:
if (!nonew) Nuke.newline(2);
Nuke.label(str);
Nuke.label(p);
}
},
};
Object.defineProperty(Nuke, "curwin", {enumerable:false});
Object.defineProperty(Nuke, "defaultrect", {enumerable:false});
var Log = {
print(msg, lvl) {
var lg;
if (typeof msg === 'object') {
lg = JSON.stringify(msg, null, 2);
} else {
lg = msg;
}
var stack = (new Error()).stack;
var n = stack.next('\n',0)+1;
n = stack.next('\n', n)+1;
var nnn = stack.slice(n);
var fmatch = nnn.match(/\(.*\:/);
var file = fmatch ? fmatch[0].shift(1).shift(-1) : "nofile";
var lmatch = nnn.match(/\:\d*\)/);
var line = lmatch ? lmatch[0].shift(1).shift(-1) : "0";
yughlog(lvl, lg, file, line);
},
info(msg) {
this.print(msg, 0);
},
warn(msg) {
this.print(msg, 1);
},
error(msg) {
this.print(msg, 2);
},
};

141
source/scripts/diff.js Normal file
View File

@@ -0,0 +1,141 @@
function deep_copy(from) {
if (typeof from !== 'object')
return from;
if (Array.isArray(from)) {
var c = [];
from.forEach(function(x,i) { c[i] = deep_copy(x); });
return c;
}
var obj = {};
for (var key in from)
obj[key] = deep_copy(from[key]);
return obj;
};
var walk_up_get_prop = function(obj, prop, endobj) {
var props = [];
var cur = obj;
while (cur !== Object.prototype) {
if (cur.hasOwn(prop))
props.push(cur[prop]);
cur = cur.__proto__;
}
return props;
};
function complete_assign(target, source) {
var descriptors = {};
var assigns = {};
if (typeof source === 'undefined') return target;
Object.keys(source).forEach(function (k) {
var desc = Object.getOwnPropertyDescriptor(source, k);
if (desc.value) {
if (typeof desc.value === 'object' && desc.value.hasOwn('value'))
descriptors[k] = desc.value;
else
assigns[k] = desc.value;
} else
descriptors[k] = desc;
});
Object.defineProperties(target, descriptors);
Object.assign(target, assigns);
return target;
};
/* Assigns properties from source to target, only if they exist in target */
function dainty_assign(target, source)
{
for (var key in source) {
if (typeof source[key] === 'function') {
target[key] = source[key];
continue;
}
if (!(key in target)) continue;
if (Array.isArray(target[key]))
target[key] = source[key];
else if (typeof target[key] === 'object')
dainty_assign(target[key], source[key]);
else
target[key] = source[key];
}
};
/* Deeply remove source keys from target, not removing objects */
function unmerge(target, source) {
for (var key in source) {
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
unmerge(target[key], source[key]);
else
delete target[key];
}
};
/* Deeply merge two objects, not clobbering objects on target with objects on source */
function deep_merge(target, source)
{
for (var key in source) {
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
deep_merge(target[key], source[key]);
else
target[key] = source[key];
}
};
function equal(x,y) {
if (typeof x === 'object')
for (var key in x)
return equal(x[key],y[key]);
return x === y;
};
function diffassign(target, from) {
if (from.empty) return;
for (var e in from) {
if (typeof from[e] === 'object') {
if (!target.hasOwnProperty(e))
target[e] = from[e];
else
diffassign(target[e], from[e]);
} else {
if (from[e] === "DELETE") {
delete target[e];
} else {
target[e] = from[e];
}
}
}
};
function diff(from, to) {
var obj = {};
for (var e in to) {
if (typeof to[e] === 'object' && from.hasOwnProperty(e)) {
obj[e] = diff(from[e], to[e]);
if (obj[e].empty)
delete obj[e];
} else {
if (from[e] !== to[e])
obj[e] = to[e];
}
}
for (var e in from) {
if (!to.hasOwnProperty(e))
obj[e] = "DELETE";
}
return obj;
};

2572
source/scripts/editor.js Normal file

File diff suppressed because it is too large Load Diff

1597
source/scripts/engine.js Normal file

File diff suppressed because it is too large Load Diff