2023-04-22 16:44:26 -05:00
|
|
|
var component = {
|
2023-09-20 17:58:18 -05:00
|
|
|
components: [],
|
2023-04-22 16:44:26 -05:00
|
|
|
toString() {
|
|
|
|
if ('gameobject' in this)
|
|
|
|
return this.name + " on " + this.gameobject;
|
|
|
|
else
|
|
|
|
return this.name;
|
|
|
|
},
|
|
|
|
name: "component",
|
|
|
|
component: true,
|
2023-05-27 07:01:17 -05:00
|
|
|
enabled: true,
|
2023-04-22 16:44:26 -05:00
|
|
|
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() {},
|
2023-09-20 17:58:18 -05:00
|
|
|
extend(spec) {
|
|
|
|
return Object.copy(this, spec);
|
2023-04-22 16:44:26 -05:00
|
|
|
},
|
2023-09-26 17:07:51 -05:00
|
|
|
|
|
|
|
/* Given a relative path, return the full path */
|
|
|
|
resani(path) {
|
|
|
|
if (!this.gameobject) return path;
|
|
|
|
if (path[0] === '/') return path.slice(1);
|
|
|
|
var res = this.gameobject.ur.toString();
|
|
|
|
res = res.replaceAll('.', '/');
|
|
|
|
var restry = res + "/" + path;
|
|
|
|
while (!IO.exists(restry)) {
|
|
|
|
res = res.updir() + "/";
|
|
|
|
if (res === "/")
|
|
|
|
return path;
|
|
|
|
|
|
|
|
restry = res + path;
|
|
|
|
}
|
|
|
|
return restry;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* Given the full path, return the most relative path */
|
|
|
|
resavi(path) {
|
|
|
|
if (!this.gameobject) return path;
|
|
|
|
if (path[0] === '/') return path;
|
|
|
|
|
|
|
|
var res = this.gameobject.ur.toString();
|
|
|
|
res = res.replaceAll('.', '/');
|
|
|
|
if (!path.startsWith(res))
|
|
|
|
return path;
|
|
|
|
|
|
|
|
return path.replace(res, "").slice(1);
|
|
|
|
},
|
2023-04-22 16:44:26 -05:00
|
|
|
};
|
|
|
|
|
2023-09-21 12:50:39 -05:00
|
|
|
component.sprite = {
|
|
|
|
pos:[0,0],
|
|
|
|
color:[1,1,1],
|
|
|
|
layer:0,
|
|
|
|
enabled:true,
|
2023-09-26 17:07:51 -05:00
|
|
|
path: "",
|
2023-09-21 12:50:39 -05:00
|
|
|
toString() { return "sprite"; },
|
|
|
|
make(go) {
|
|
|
|
var nsprite = Object.create(component.sprite.maker);
|
2023-09-25 16:34:48 -05:00
|
|
|
nsprite.gameobject = go;
|
|
|
|
Object.assign(nsprite, make_sprite(go.body));
|
2023-09-21 12:50:39 -05:00
|
|
|
nsprite.ur = this;
|
|
|
|
return nsprite;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
component.sprite.maker = Object.copy(component, {
|
2023-09-26 17:07:51 -05:00
|
|
|
set path(x) {
|
|
|
|
x = this.resani(x);
|
|
|
|
cmd(12,this.id,x,this.rect);
|
|
|
|
},
|
|
|
|
get path() {
|
2023-09-29 13:16:59 -05:00
|
|
|
return this.resavi(cmd(116,this.id));
|
2023-09-26 17:07:51 -05:00
|
|
|
},
|
2023-05-25 21:55:55 -05:00
|
|
|
get visible() { return this.enabled; },
|
|
|
|
set visible(x) { this.enabled = x; },
|
2023-09-21 12:50:39 -05:00
|
|
|
asset(str) { this.path = str; },
|
2023-05-29 10:47:30 -05:00
|
|
|
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
2023-09-20 17:58:18 -05:00
|
|
|
get enabled() { return cmd(114,this.id); },
|
|
|
|
set enabled(x) { cmd(20,this.id,x); },
|
|
|
|
set color(x) { cmd(96,this.id,x); },
|
|
|
|
get color() {return undefined; },
|
|
|
|
get pos() { return cmd(111, this.id); },
|
|
|
|
set pos(x) { cmd(37,this.id,x); },
|
|
|
|
set layer(x) { cmd(60, this.id, x); },
|
|
|
|
get layer() { return undefined; },
|
|
|
|
|
|
|
|
boundingbox() {
|
2023-09-21 12:50:39 -05:00
|
|
|
return cwh2bb([0,0],[0,0]);
|
2023-09-20 17:58:18 -05:00
|
|
|
var dim = this.dimensions();
|
|
|
|
dim = dim.scale(this.gameobject.scale);
|
|
|
|
var realpos = this.pos.copy();
|
|
|
|
realpos.x = realpos.x * dim.x + (dim.x/2);
|
|
|
|
realpos.y = realpos.y * dim.y + (dim.y/2);
|
|
|
|
return cwh2bb(realpos,dim);
|
|
|
|
},
|
|
|
|
|
|
|
|
kill() { cmd(9,this.id); },
|
2023-09-14 17:37:04 -05:00
|
|
|
dimensions() { return cmd(64,this.path); },
|
|
|
|
width() { return cmd(64,this.path).x; },
|
|
|
|
height() { return cmd(64,this.path).y; },
|
2023-04-22 16:44:26 -05:00
|
|
|
});
|
|
|
|
|
2023-09-23 12:35:02 -05:00
|
|
|
Object.freeze(sprite);
|
|
|
|
|
2023-09-21 12:50:39 -05:00
|
|
|
var sprite = component.sprite.maker;
|
2023-09-20 13:33:11 -05:00
|
|
|
|
2023-09-13 16:49:22 -05:00
|
|
|
sprite.inputs = {};
|
|
|
|
sprite.inputs.kp9 = function() { this.pos = [0,0]; };
|
|
|
|
sprite.inputs.kp8 = function() { this.pos = [-0.5, 0]; };
|
|
|
|
sprite.inputs.kp7 = function() { this.pos = [-1,0]; };
|
|
|
|
sprite.inputs.kp6 = function() { this.pos = [0,-0.5]; };
|
|
|
|
sprite.inputs.kp5 = function() { this.pos = [-0.5,-0.5]; };
|
|
|
|
sprite.inputs.kp4 = function() { this.pos = [-1,-0.5]; };
|
|
|
|
sprite.inputs.kp3 = function() { this.pos = [0, -1]; };
|
|
|
|
sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; };
|
|
|
|
sprite.inputs.kp1 = function() { this.pos = [-1,-1]; };
|
2023-09-23 12:35:02 -05:00
|
|
|
Object.seal(sprite);
|
2023-09-13 16:49:22 -05:00
|
|
|
|
2023-09-25 08:21:02 -05:00
|
|
|
var aseframeset2anim = function(frameset, meta)
|
|
|
|
{
|
|
|
|
var anim = {};
|
|
|
|
anim.frames = [];
|
|
|
|
anim.path = meta.image;
|
|
|
|
var dim = meta.size;
|
|
|
|
|
|
|
|
var ase_make_frame = function(ase_frame,i) {
|
|
|
|
var f = ase_frame.frame;
|
|
|
|
var frame = {};
|
|
|
|
frame.rect = {
|
|
|
|
s0: f.x/dim.w,
|
|
|
|
s1: (f.x+f.w)/dim.w,
|
|
|
|
t0: f.y/dim.h,
|
|
|
|
t1: (f.y+f.h)/dim.h
|
|
|
|
};
|
|
|
|
frame.time = ase_frame.duration / 1000;
|
|
|
|
anim.frames.push(frame);
|
|
|
|
};
|
|
|
|
|
|
|
|
frameset.forEach(ase_make_frame);
|
2023-09-25 16:34:48 -05:00
|
|
|
anim.dim = [frameset[0].sourceSize.x, frameset[0].sourceSize.y];
|
2023-09-25 08:21:02 -05:00
|
|
|
anim.loop = true;
|
|
|
|
return anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
var ase2anim = function(ase)
|
|
|
|
{
|
|
|
|
var json = IO.slurp(ase);
|
|
|
|
json = JSON.parse(json);
|
|
|
|
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
|
|
|
|
return aseframeset2anim(json.frames, json.meta);
|
|
|
|
}
|
|
|
|
|
|
|
|
var ase2anims = function(ase)
|
|
|
|
{
|
|
|
|
var json = IO.slurp(ase);
|
|
|
|
json = JSON.parse(json);
|
|
|
|
var anims = {};
|
|
|
|
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
|
|
|
|
for (var tag of json.meta.frameTags)
|
|
|
|
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), json.meta);
|
|
|
|
|
|
|
|
return anims;
|
|
|
|
}
|
|
|
|
|
2023-09-24 11:26:44 -05:00
|
|
|
var gif2anim = function(gif)
|
|
|
|
{
|
|
|
|
var anim = {};
|
|
|
|
anim.frames = [];
|
|
|
|
anim.path = gif;
|
|
|
|
var frames = cmd(139,gif);
|
|
|
|
var yslice = 1/frames;
|
|
|
|
for (var f = 0; f < frames; f++) {
|
|
|
|
var frame = {};
|
|
|
|
frame.rect = {
|
|
|
|
s0: 0,
|
|
|
|
s1: 1,
|
|
|
|
t0: yslice*f,
|
|
|
|
t1: yslice*(f+1)
|
|
|
|
};
|
|
|
|
frame.time = 0.05;
|
|
|
|
anim.frames.push(frame);
|
|
|
|
}
|
|
|
|
anim.loop = true;
|
2023-09-25 16:34:48 -05:00
|
|
|
var dim = cmd(64,gif);
|
|
|
|
dim.y /= frames;
|
|
|
|
anim.dim = dim;
|
2023-09-24 11:26:44 -05:00
|
|
|
return anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
var strip2anim = function(strip)
|
|
|
|
{
|
|
|
|
var anim = {};
|
|
|
|
anim.frames = [];
|
|
|
|
anim.path = strip;
|
|
|
|
var frames = 8;
|
|
|
|
var xslice = 1/frames;
|
|
|
|
for (var f = 0; f < frames; f++) {
|
|
|
|
var frame = {};
|
|
|
|
frame.rect = {s0:xslice*f, s1: slice*(f+1), t0:0, t1:1};
|
|
|
|
frame.time = 0.05;
|
|
|
|
anim.frames.push(frame);
|
|
|
|
}
|
2023-09-25 16:34:48 -05:00
|
|
|
anim.dim = cmd(64,strip);
|
|
|
|
anim.dim.x /= frames;
|
2023-09-24 11:26:44 -05:00
|
|
|
return anim;
|
|
|
|
}
|
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
/* Container to play sprites and anim2ds */
|
2023-09-20 17:58:18 -05:00
|
|
|
component.char2d = Object.copy(sprite, {
|
2023-09-23 12:35:02 -05:00
|
|
|
get enabled() { return cmd(114,this.id); },
|
|
|
|
set enabled(x) { cmd(20,this.id,x); },
|
|
|
|
set color(x) { cmd(96,this.id,x); },
|
|
|
|
get pos() { return cmd(111, this.id); },
|
|
|
|
set pos(x) { cmd(37,this.id,x); },
|
|
|
|
set layer(x) { cmd(60, this.id, x); },
|
|
|
|
get layer() { return this.gameobject.draw_layer; },
|
2023-09-24 11:26:44 -05:00
|
|
|
|
|
|
|
boundingbox() {
|
2023-09-25 16:34:48 -05:00
|
|
|
var dim = this.curplaying.dim.slice();
|
2023-09-24 11:26:44 -05:00
|
|
|
dim = dim.scale(this.gameobject.scale);
|
2023-09-25 16:34:48 -05:00
|
|
|
var realpos = this.pos.slice();
|
|
|
|
realpos.x = realpos.x * dim.x + (dim.x/2);
|
|
|
|
realpos.y = realpos.y * dim.y + (dim.y/2);
|
2023-09-24 11:26:44 -05:00
|
|
|
return cwh2bb(realpos,dim);
|
|
|
|
},
|
|
|
|
|
|
|
|
sync() {
|
|
|
|
if (this.path)
|
|
|
|
cmd(12,this.id,this.path,this.rect);
|
|
|
|
},
|
|
|
|
|
|
|
|
kill() { cmd(9,this.id); },
|
2023-09-23 12:35:02 -05:00
|
|
|
ur: {
|
|
|
|
|
|
|
|
},
|
2023-09-24 11:26:44 -05:00
|
|
|
|
2023-09-23 12:35:02 -05:00
|
|
|
make(go) {
|
|
|
|
var char = Object.create(this);
|
2023-09-25 16:34:48 -05:00
|
|
|
char.gameobject = go;
|
|
|
|
Object.assign(char, make_sprite(go.body));
|
2023-04-22 16:44:26 -05:00
|
|
|
char.frame = 0;
|
2023-09-24 11:26:44 -05:00
|
|
|
char.timer = timer.make(char.advance.bind(char), 1);
|
2023-04-22 16:44:26 -05:00
|
|
|
char.timer.loop = true;
|
|
|
|
return char;
|
|
|
|
},
|
|
|
|
|
|
|
|
frame: 0,
|
|
|
|
|
|
|
|
play(name) {
|
2023-09-24 11:26:44 -05:00
|
|
|
if (!(name in this)) {
|
2023-04-22 16:44:26 -05:00
|
|
|
Log.info("Can't find an animation named " + name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-24 11:26:44 -05:00
|
|
|
if (this.curplaying === this[name]) {
|
2023-04-28 12:49:18 -05:00
|
|
|
this.timer.start();
|
|
|
|
return;
|
|
|
|
}
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-09-24 11:26:44 -05:00
|
|
|
this.curplaying = this[name];
|
2023-04-22 16:44:26 -05:00
|
|
|
this.frame = 0;
|
2023-09-24 11:26:44 -05:00
|
|
|
this.timer.time = this.curplaying.frames[this.frame].time;
|
|
|
|
this.timer.start();
|
2023-04-22 16:44:26 -05:00
|
|
|
this.setsprite();
|
|
|
|
},
|
|
|
|
|
|
|
|
setsprite() {
|
2023-09-24 11:26:44 -05:00
|
|
|
cmd(12, this.id, this.curplaying.path, this.curplaying.frames[this.frame].rect);
|
2023-04-22 16:44:26 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
advance() {
|
2023-09-24 11:26:44 -05:00
|
|
|
this.frame = (this.frame + 1) % this.curplaying.frames.length;
|
2023-04-22 16:44:26 -05:00
|
|
|
this.setsprite();
|
2023-04-28 12:49:18 -05:00
|
|
|
|
|
|
|
if (this.frame === 0 && !this.curplaying.loop)
|
|
|
|
this.timer.pause();
|
2023-04-22 16:44:26 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
devance() {
|
|
|
|
this.frame = (this.frame - 1);
|
|
|
|
if (this.frame === -1) this.frame = this.curplaying.frames-1;
|
|
|
|
this.setsprite();
|
|
|
|
},
|
2023-04-28 12:49:18 -05:00
|
|
|
|
|
|
|
setframe(frame) {
|
|
|
|
this.frame = frame;
|
|
|
|
this.setsprite();
|
|
|
|
},
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
pause() {
|
|
|
|
this.timer.pause();
|
|
|
|
},
|
|
|
|
|
|
|
|
stop() {
|
2023-04-28 12:49:18 -05:00
|
|
|
this.setframe(0);
|
2023-04-22 16:44:26 -05:00
|
|
|
this.timer.stop();
|
|
|
|
},
|
|
|
|
|
|
|
|
kill() {
|
|
|
|
this.timer.kill();
|
|
|
|
cmd(9, this.id);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-05-27 07:01:17 -05:00
|
|
|
/* Returns points specifying this geometry, with ccw */
|
|
|
|
var Geometry = {
|
|
|
|
box(w, h) {
|
|
|
|
w /= 2;
|
|
|
|
h /= 2;
|
|
|
|
|
|
|
|
var points = [
|
|
|
|
[w,h],
|
|
|
|
[-w,h],
|
|
|
|
[-w,-h],
|
|
|
|
[w,-h]
|
|
|
|
];
|
|
|
|
|
|
|
|
return points;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
|
2023-09-20 17:58:18 -05:00
|
|
|
var collider2d = Object.copy(component, {
|
2023-04-22 16:44:26 -05:00
|
|
|
name: "collider 2d",
|
2023-05-25 21:55:55 -05:00
|
|
|
sensor: false,
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
},
|
2023-09-20 13:33:11 -05:00
|
|
|
/* set sensor(x) { cmd(18,this.shape,x); },
|
2023-05-27 07:01:17 -05:00
|
|
|
get sensor() { return cmd(21,this.shape); },
|
|
|
|
set enabled(x) { cmd(22,this.shape,x); },
|
2023-08-24 16:22:52 -05:00
|
|
|
get enabled() { return cmd(23,this.shape); }
|
2023-09-20 13:33:11 -05:00
|
|
|
*/
|
2023-04-22 16:44:26 -05:00
|
|
|
});
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
collider2d.inputs = {};
|
|
|
|
collider2d.inputs['M-s'] = function() { this.sensor = !this.sensor; }
|
|
|
|
collider2d.inputs['M-s'].doc = "Toggle if this collider is a sensor.";
|
|
|
|
|
|
|
|
collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; }
|
|
|
|
collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled.";
|
|
|
|
|
2023-09-20 17:58:18 -05:00
|
|
|
component.polygon2d = Object.copy(collider2d, {
|
2023-09-23 12:35:02 -05:00
|
|
|
sync() {
|
|
|
|
cmd_poly2d(0, this.id, this.spoints);
|
|
|
|
},
|
|
|
|
|
|
|
|
boundingbox() {
|
|
|
|
return points2bb(this.spoints);
|
|
|
|
},
|
2023-05-25 21:55:55 -05:00
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
make(go) {
|
|
|
|
var poly = Object.create(this);
|
2023-09-25 16:34:48 -05:00
|
|
|
poly.gameobject = go;
|
2023-09-27 17:40:04 -05:00
|
|
|
poly.points = [];
|
2023-09-27 09:37:20 -05:00
|
|
|
poly.flipx = false;
|
|
|
|
poly.flipy = false;
|
|
|
|
Object.assign(poly, make_poly2d(go.body, poly.points));
|
2023-04-22 16:44:26 -05:00
|
|
|
return poly;
|
|
|
|
},
|
2023-05-25 21:55:55 -05:00
|
|
|
|
2023-05-27 07:01:17 -05:00
|
|
|
/* EDITOR */
|
2023-04-22 16:44:26 -05:00
|
|
|
get spoints() {
|
|
|
|
var spoints = this.points.slice();
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
if (this.flipx) {
|
2023-04-22 16:44:26 -05:00
|
|
|
spoints.forEach(function(x) {
|
|
|
|
var newpoint = x.slice();
|
|
|
|
newpoint.x = -newpoint.x;
|
|
|
|
spoints.push(newpoint);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
if (this.flipy) {
|
2023-04-22 16:44:26 -05:00
|
|
|
spoints.forEach(function(x) {
|
|
|
|
var newpoint = x.slice();
|
|
|
|
newpoint.y = -newpoint.y;
|
|
|
|
spoints.push(newpoint);
|
|
|
|
});
|
|
|
|
}
|
2023-05-27 07:01:17 -05:00
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
return spoints;
|
|
|
|
},
|
|
|
|
|
|
|
|
gizmo() {
|
|
|
|
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);
|
|
|
|
},
|
|
|
|
|
|
|
|
pick(pos) {
|
2023-09-27 12:36:32 -05:00
|
|
|
var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
|
|
|
|
if (p) {
|
|
|
|
return {
|
|
|
|
set pos(n) {
|
|
|
|
p.x = n.x;
|
|
|
|
p.y = n.y;
|
|
|
|
},
|
|
|
|
get pos() { return p; },
|
|
|
|
sync: this.sync.bind(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return undefined;
|
2023-04-22 16:44:26 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
query() {
|
|
|
|
return cmd(80, this.shape);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-09-20 17:58:18 -05:00
|
|
|
var polygon2d = component.polygon2d;
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
polygon2d.inputs = {};
|
2023-09-13 16:49:22 -05:00
|
|
|
polygon2d.inputs.post = function() { this.sync(); };
|
2023-08-25 01:30:39 -05:00
|
|
|
polygon2d.inputs.f10 = function() {
|
|
|
|
this.points = sortpointsccw(this.points);
|
|
|
|
};
|
|
|
|
polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
|
|
|
|
|
|
|
|
polygon2d.inputs['C-lm'] = function() {
|
|
|
|
this.points.push(this.gameobject.world2this(Mouse.worldpos));
|
|
|
|
};
|
|
|
|
polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse.";
|
|
|
|
|
|
|
|
polygon2d.inputs['S-lm'] = function() {
|
2023-09-13 16:49:22 -05:00
|
|
|
var idx = grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25);
|
2023-08-25 01:30:39 -05:00
|
|
|
if (idx === -1) return;
|
|
|
|
this.points.splice(idx, 1);
|
|
|
|
};
|
|
|
|
polygon2d.inputs['S-lm'].doc = "Remove point under mouse.";
|
|
|
|
|
|
|
|
polygon2d.inputs['C-b'] = function() {
|
|
|
|
this.points = this.spoints;
|
|
|
|
this.flipx = false;
|
|
|
|
this.flipy = false;
|
|
|
|
};
|
|
|
|
polygon2d.inputs['C-b'].doc = "Freeze mirroring in place.";
|
|
|
|
|
2023-09-20 17:58:18 -05:00
|
|
|
Object.freeze(polygon2d);
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
component.edge2d = Object.copy(collider2d, {
|
2023-04-22 16:44:26 -05:00
|
|
|
degrees:2,
|
|
|
|
dimensions:2,
|
|
|
|
/* open: 0
|
|
|
|
clamped: 1
|
|
|
|
beziers: 2
|
|
|
|
looped: 3
|
|
|
|
*/
|
|
|
|
type: 3,
|
2023-06-28 11:35:41 -05:00
|
|
|
typeid: {
|
|
|
|
open: 0,
|
|
|
|
clamped: 1,
|
|
|
|
beziers: 2,
|
|
|
|
looped: 3
|
|
|
|
},
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
flipx: false,
|
|
|
|
flipy: false,
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
hollow: false,
|
2023-05-27 07:01:17 -05:00
|
|
|
hollowt: 0,
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
get spoints() {
|
|
|
|
var spoints = this.cpoints.slice();
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
if (this.flipx) {
|
2023-04-22 16:44:26 -05:00
|
|
|
for (var i = spoints.length-1; i >= 0; i--) {
|
|
|
|
var newpoint = spoints[i].slice();
|
|
|
|
newpoint.x = -newpoint.x;
|
|
|
|
spoints.push(newpoint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
if (this.flipy) {
|
2023-04-22 16:44:26 -05:00
|
|
|
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 = [];
|
2023-05-27 07:01:17 -05:00
|
|
|
var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt);
|
|
|
|
inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); });
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
inflatep[1].forEach(function(x) { hpoints.push(x); });
|
|
|
|
return hpoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
return spoints;
|
|
|
|
},
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
if (this.type === typeid.this.looped)
|
2023-04-22 16:44:26 -05:00
|
|
|
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);
|
2023-09-27 17:40:04 -05:00
|
|
|
},
|
|
|
|
set thickness(x) {
|
|
|
|
cmd_edge2d(1,this.id,x);
|
|
|
|
},
|
|
|
|
|
|
|
|
get thickness() { return cmd(112,this.id); },
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
samples: 10,
|
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
boundingbox() {
|
|
|
|
return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
|
|
|
|
},
|
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
make(go) {
|
|
|
|
var edge = Object.create(this);
|
2023-09-25 16:34:48 -05:00
|
|
|
edge.gameobject = go;
|
2023-09-27 17:40:04 -05:00
|
|
|
edge.cpoints = [];
|
|
|
|
edge.points = [];
|
|
|
|
Object.assign(edge, make_edge2d(go.body, edge.points, 0));
|
|
|
|
edge.thickness = 0;
|
2023-04-22 16:44:26 -05:00
|
|
|
return edge;
|
|
|
|
},
|
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
sync() {
|
|
|
|
var sensor = this.sensor;
|
|
|
|
this.points = this.sample(this.samples);
|
|
|
|
cmd_edge2d(0,this.id,this.points);
|
|
|
|
this.sensor = sensor;
|
|
|
|
},
|
|
|
|
|
2023-05-27 07:01:17 -05:00
|
|
|
/* EDITOR */
|
2023-04-22 16:44:26 -05:00
|
|
|
gizmo() {
|
|
|
|
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);
|
|
|
|
},
|
2023-05-27 07:01:17 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
finish_center(change) {
|
|
|
|
this.cpoints = this.cpoints.map(function(x) { return x.sub(change); });
|
2023-05-27 07:01:17 -05:00
|
|
|
},
|
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
pick(pos) {
|
|
|
|
var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints);
|
|
|
|
if (p) return {
|
|
|
|
set pos(n) { p.x = n.x; p.y = n.y; },
|
|
|
|
get pos() { return p; },
|
|
|
|
sync: this.sync.bind(this),
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
},
|
2023-08-25 01:30:39 -05:00
|
|
|
});
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-09-27 17:40:04 -05:00
|
|
|
var bucket = component.edge2d;
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs = {};
|
|
|
|
bucket.inputs.h = function() { this.hollow = !this.hollow; };
|
|
|
|
bucket.inputs.h.doc = "Toggle hollow.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-g'] = function() {
|
|
|
|
this.hollowt--;
|
|
|
|
if (this.hollowt < 0) this.hollowt = 0;
|
|
|
|
};
|
|
|
|
bucket.inputs['C-g'].doc = "Thin the hollow thickness.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-f'] = function() { this.hollowt++; };
|
|
|
|
bucket.inputs['C-f'].doc = "Increase the hollow thickness.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['M-v'] = function() { this.thickness--; };
|
|
|
|
bucket.inputs['M-v'].doc = "Decrease spline thickness.";
|
|
|
|
bucket.inputs['M-v'].rep = true;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-b'] = function() {
|
|
|
|
this.cpoints = this.spoints;
|
|
|
|
this.flipx = false;
|
|
|
|
this.flipy = false;
|
|
|
|
};
|
|
|
|
bucket.inputs['C-b'].doc = "Freeze mirroring,";
|
|
|
|
bucket.inputs['M-b'] = function() { this.thickness++; };
|
|
|
|
bucket.inputs['M-b'].doc = "Increase spline thickness.";
|
|
|
|
bucket.inputs['M-b'].rep = true;
|
|
|
|
|
|
|
|
bucket.inputs['C-plus'] = function() { this.degrees++; };
|
|
|
|
bucket.inputs['C-plus'].doc = "Increase the degrees of this spline.";
|
|
|
|
bucket.inputs['C-plus'].rep = true;
|
|
|
|
|
|
|
|
bucket.inputs.plus = function() { this.samples++; };
|
|
|
|
bucket.inputs.plus.doc = "Increase the number of samples of this spline.";
|
|
|
|
bucket.inputs.plus.rep = true;
|
|
|
|
|
|
|
|
bucket.inputs.minus = function() {
|
|
|
|
this.samples--;
|
|
|
|
if (this.samples < 1) this.samples = 1;
|
|
|
|
};
|
|
|
|
bucket.inputs.minus.doc = "Decrease the number of samples on this spline.";
|
|
|
|
bucket.inputs.minus.rep = true;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-minus'] = function() { this.degrees--; };
|
|
|
|
bucket.inputs['C-minus'].doc = "Decrease the number of degrees of this spline.";
|
|
|
|
bucket.inputs['C-minus'].rep = true;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-r'] = function() { this.cpoints = this.cpoints.reverse(); };
|
|
|
|
bucket.inputs['C-r'].doc = "Reverse the order of the spline's points.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-l'] = function() { this.type = 3; };
|
|
|
|
bucket.inputs['C-l'].doc = "Set type of spline to clamped.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-c'] = function() { this.type = 1; };
|
|
|
|
bucket.inputs['C-c'].doc = "Set type of spline to closed.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-o'] = function() { this.type = 0; };
|
|
|
|
bucket.inputs['C-o'].doc = "Set spline to open.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-M-lm'] = function() {
|
|
|
|
var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(this.gameobject.world2this,this.gameobject), 25);
|
|
|
|
if (idx === -1) return;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
this.cpoints = this.cpoints.newfirst(idx);
|
|
|
|
};
|
|
|
|
bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['C-lm'] = function() {
|
|
|
|
var idx = 0;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
if (this.cpoints.length >= 2) {
|
|
|
|
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 1000);
|
|
|
|
if (idx === -1) return;
|
|
|
|
}
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
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)));
|
|
|
|
};
|
|
|
|
bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs['S-lm'] = function() {
|
|
|
|
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;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
this.cpoints.splice(idx, 1);
|
|
|
|
};
|
|
|
|
bucket.inputs['S-lm'].doc = "Remove point from the spline.";
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
bucket.inputs.lb = function() {
|
|
|
|
var np = [];
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
this.cpoints.forEach(function(c) {
|
|
|
|
np.push(Vector.rotate(c, Math.deg2rad(-1)));
|
|
|
|
});
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-08-25 01:30:39 -05:00
|
|
|
this.cpoints = np;
|
|
|
|
};
|
|
|
|
bucket.inputs.lb.doc = "Rotate the points CCW.";
|
|
|
|
bucket.inputs.lb.rep = true;
|
|
|
|
|
|
|
|
bucket.inputs.rb = function() {
|
|
|
|
var np = [];
|
|
|
|
|
|
|
|
this.cpoints.forEach(function(c) {
|
|
|
|
np.push(Vector.rotate(c, Math.deg2rad(1)));
|
|
|
|
});
|
|
|
|
|
|
|
|
this.cpoints = np;
|
|
|
|
};
|
|
|
|
bucket.inputs.rb.doc = "Rotate the points CW.";
|
|
|
|
bucket.inputs.rb.rep = true;
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-09-20 17:58:18 -05:00
|
|
|
component.circle2d = Object.copy(collider2d, {
|
2023-09-20 13:33:11 -05:00
|
|
|
set radius(x) { cmd_circle2d(0,this.id,x); },
|
|
|
|
get radius() { return cmd_circle2d(2,this.id); },
|
2023-04-22 16:44:26 -05:00
|
|
|
|
2023-09-23 12:35:02 -05:00
|
|
|
set scale(x) { this.radius = x; },
|
|
|
|
get scale() { return this.radius; },
|
|
|
|
|
2023-09-20 13:33:11 -05:00
|
|
|
set offset(x) { cmd_circle2d(1,this.id,x); },
|
|
|
|
get offset() { return cmd_circle2d(3,this.id); },
|
|
|
|
|
|
|
|
boundingbox() {
|
|
|
|
var diameter = this.radius*2*this.gameobject.scale;
|
|
|
|
return cwh2bb(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]);
|
|
|
|
},
|
2023-04-22 16:44:26 -05:00
|
|
|
|
|
|
|
make(go) {
|
2023-09-20 13:33:11 -05:00
|
|
|
var circle = Object.create(this);
|
2023-09-25 16:34:48 -05:00
|
|
|
circle.gameobject = go;
|
2023-09-27 09:37:20 -05:00
|
|
|
Object.assign(circle, make_circle2d(go.body));
|
2023-09-26 17:07:51 -05:00
|
|
|
|
2023-04-22 16:44:26 -05:00
|
|
|
return circle;
|
|
|
|
},
|
|
|
|
|
|
|
|
gui() {
|
|
|
|
Nuke.newline();
|
|
|
|
Nuke.label("circle2d");
|
|
|
|
this.radius = Nuke.pprop("Radius", this.radius);
|
|
|
|
this.offset = Nuke.pprop("offset", this.offset);
|
|
|
|
},
|
2023-05-01 20:58:10 -05:00
|
|
|
|
2023-09-20 17:58:18 -05:00
|
|
|
ur: {
|
|
|
|
radius:10,
|
|
|
|
offset:[0,0],
|
2023-09-21 08:38:23 -05:00
|
|
|
toString() { return "circle2d"; },
|
2023-09-20 17:58:18 -05:00
|
|
|
},
|
|
|
|
});
|
2023-05-01 20:58:10 -05:00
|
|
|
|
|
|
|
/* ASSETS */
|
|
|
|
|
|
|
|
var Texture = {
|
|
|
|
mipmaps(path, x) {
|
|
|
|
cmd(94, path, x);
|
|
|
|
},
|
|
|
|
|
|
|
|
sprite(path, x) {
|
|
|
|
cmd(95, path, x);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
var Resources = {
|
|
|
|
load(path) {
|
|
|
|
if (path in this)
|
|
|
|
return this[path];
|
|
|
|
|
|
|
|
var src = {};
|
|
|
|
this[path] = src;
|
|
|
|
src.path = path;
|
|
|
|
|
|
|
|
if (!IO.exists(`${path}.asset`))
|
|
|
|
return this[path];
|
|
|
|
|
|
|
|
var data = JSON.parse(IO.slurp(`${path}.asset`));
|
|
|
|
Object.assign(src,data);
|
|
|
|
return this[path];
|
|
|
|
|
|
|
|
},
|
|
|
|
};
|