2020-03-25 03:47:04 +00:00
|
|
|
import { Select } from "../Applet/Init";
|
2019-12-14 23:11:00 +00:00
|
|
|
import { KeyControl } from "../Applet/Keyboard";
|
|
|
|
import { Loop } from "../Applet/Loop";
|
2020-02-16 04:38:54 +00:00
|
|
|
import { DrawSet, Layer } from "../Applet/Render";
|
2019-12-14 23:11:00 +00:00
|
|
|
import { FindCollisions } from "./Collision";
|
2020-04-04 22:52:25 +00:00
|
|
|
import {
|
|
|
|
CollisionClass,
|
|
|
|
ComponentSchema,
|
|
|
|
Data,
|
|
|
|
Location,
|
|
|
|
PolygonComponent,
|
|
|
|
RenderBounds,
|
|
|
|
} from "./Components";
|
|
|
|
import {
|
|
|
|
Component,
|
|
|
|
copySparse,
|
|
|
|
Create,
|
|
|
|
EntityState,
|
|
|
|
Join,
|
|
|
|
Liveness,
|
|
|
|
Lookup,
|
|
|
|
Remove,
|
|
|
|
StateForSchema,
|
|
|
|
Store,
|
|
|
|
} from "./Data";
|
2019-12-14 23:11:00 +00:00
|
|
|
import { DumbMotion } from "./Location";
|
|
|
|
import { RunRenderBounds } from "./Renderers";
|
|
|
|
|
2020-04-04 22:52:25 +00:00
|
|
|
class Generic<T> extends Component<T> {
|
|
|
|
constructor(from: T) {
|
|
|
|
super(from);
|
|
|
|
Object.assign(this, from);
|
|
|
|
}
|
|
|
|
clone(): Generic<T> & T {
|
|
|
|
return new Generic<T>(this as unknown as T) as Generic<T> & T;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function generic<T>(from: T): Component<T> & T {
|
|
|
|
return new Generic<T>(from) as Component<T> & T;
|
|
|
|
}
|
|
|
|
|
2020-01-16 03:49:52 +00:00
|
|
|
interface Apple {}
|
|
|
|
interface Banana {
|
2019-12-14 23:11:00 +00:00
|
|
|
peeled: boolean
|
|
|
|
}
|
2020-01-16 03:49:52 +00:00
|
|
|
interface Carrot {
|
2019-12-14 23:11:00 +00:00
|
|
|
cronch: number
|
|
|
|
}
|
|
|
|
|
2020-04-04 22:52:25 +00:00
|
|
|
interface TestSchema extends ComponentSchema {
|
|
|
|
apple: Apple;
|
|
|
|
banana: Banana;
|
|
|
|
carrot: Carrot;
|
|
|
|
}
|
|
|
|
|
|
|
|
class TestData extends Data implements StateForSchema<TestSchema> {
|
|
|
|
apple: Store<Generic<Apple>>;
|
|
|
|
banana: Store<Generic<Banana>>;
|
|
|
|
carrot: Store<Generic<Carrot>>;
|
|
|
|
constructor(from: Partial<TestData>) {
|
|
|
|
super(from);
|
|
|
|
this.apple = copySparse(from.apple);
|
|
|
|
this.banana = copySparse(from.banana);
|
|
|
|
this.carrot = copySparse(from.carrot);
|
|
|
|
}
|
|
|
|
clone(): TestData {
|
|
|
|
return new TestData(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeTestData(): TestData {
|
|
|
|
return new TestData({
|
|
|
|
entity: [
|
|
|
|
new EntityState({generation: 5, alive: Liveness.ALIVE}),
|
|
|
|
new EntityState({generation: 5, alive: Liveness.DEAD}),
|
|
|
|
new EntityState({generation: 5, alive: Liveness.ALIVE}),
|
|
|
|
new EntityState({generation: 5, alive: Liveness.ALIVE}),
|
|
|
|
new EntityState({generation: 5, alive: Liveness.INACTIVE}),
|
|
|
|
new EntityState({generation: 5, alive: Liveness.ALIVE}),
|
|
|
|
],
|
|
|
|
apple: [
|
|
|
|
generic({generation: 5}),
|
|
|
|
generic({generation: 5}),
|
|
|
|
generic({generation: -1}),
|
|
|
|
generic({generation: -1}),
|
|
|
|
generic({generation: 5}),
|
|
|
|
generic({generation: 5}),
|
|
|
|
],
|
|
|
|
banana: {
|
|
|
|
3: generic({generation: 5, peeled: false}),
|
|
|
|
4: generic({generation: 5, peeled: true}),
|
|
|
|
},
|
|
|
|
carrot: {
|
|
|
|
0: generic({generation: 5, cronch: 1}),
|
|
|
|
1: generic({generation: 5, cronch: 1}),
|
|
|
|
2: generic({generation: 4, cronch: 10}),
|
|
|
|
3: generic({generation: 5, cronch: 1}),
|
|
|
|
},
|
|
|
|
});
|
2019-12-14 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 03:47:04 +00:00
|
|
|
class EcsJoinTest {
|
2019-12-14 23:11:00 +00:00
|
|
|
constructor(pre: HTMLElement) {
|
2020-04-04 22:52:25 +00:00
|
|
|
const data = new TestData({
|
|
|
|
|
|
|
|
});
|
2019-12-14 23:11:00 +00:00
|
|
|
pre.innerText = JSON.stringify({
|
|
|
|
"apples": Join(data, "apple"),
|
|
|
|
"bananas": Join(data, "banana"),
|
|
|
|
"carrots": Join(data, "carrot"),
|
|
|
|
"apples+carrots": Join(data, "apple", "carrot"),
|
|
|
|
}, null, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 03:47:04 +00:00
|
|
|
class EcsLookupTest {
|
2019-12-14 23:11:00 +00:00
|
|
|
constructor(pre: HTMLElement) {
|
2020-04-04 22:52:25 +00:00
|
|
|
const data = makeTestData();
|
2020-01-16 06:54:43 +00:00
|
|
|
const applesMaybeCarrots = Join(data, "apple", "id").map(([apple, id]) => ({
|
2019-12-14 23:11:00 +00:00
|
|
|
apple,
|
|
|
|
maybeCarrot: Lookup(data, id, "carrot")[0]
|
|
|
|
}));
|
|
|
|
pre.innerText = JSON.stringify(applesMaybeCarrots, null, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 03:47:04 +00:00
|
|
|
class EcsRemoveTest {
|
2019-12-14 23:11:00 +00:00
|
|
|
constructor(pre: HTMLElement) {
|
2020-04-04 22:52:25 +00:00
|
|
|
const data = makeTestData();
|
2020-01-16 06:54:43 +00:00
|
|
|
const beforeDelete = Join(data, "apple", "carrot", "id",);
|
2019-12-14 23:11:00 +00:00
|
|
|
Remove(data, [0, 5]);
|
2020-01-16 06:54:43 +00:00
|
|
|
const afterDelete = Join(data, "apple", "carrot", "id");
|
2019-12-14 23:11:00 +00:00
|
|
|
pre.innerText = JSON.stringify({
|
|
|
|
beforeDelete,
|
|
|
|
afterDelete
|
|
|
|
}, null, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 03:47:04 +00:00
|
|
|
class EcsCreateTest {
|
2019-12-14 23:11:00 +00:00
|
|
|
constructor(pre: HTMLElement) {
|
2020-04-04 22:52:25 +00:00
|
|
|
const data = makeTestData();
|
2020-01-16 06:54:43 +00:00
|
|
|
const beforeCreate = Join(data, "apple", "banana", "carrot", "id");
|
2019-12-14 23:11:00 +00:00
|
|
|
const createdId = Create(data, {
|
2020-04-04 22:52:25 +00:00
|
|
|
apple: generic({}),
|
|
|
|
banana: generic({peeled: false}),
|
|
|
|
carrot: generic({cronch: 11})
|
2019-12-14 23:11:00 +00:00
|
|
|
});
|
2020-01-16 06:54:43 +00:00
|
|
|
const afterCreate = Join(data, "apple", "banana", "carrot", "id");
|
2019-12-14 23:11:00 +00:00
|
|
|
pre.innerText = JSON.stringify({
|
|
|
|
beforeCreate,
|
|
|
|
afterCreate,
|
|
|
|
createdId
|
|
|
|
}, null, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 03:47:04 +00:00
|
|
|
class LoopTest {
|
2020-04-04 22:52:25 +00:00
|
|
|
data = new Data({});
|
2019-12-14 23:11:00 +00:00
|
|
|
|
|
|
|
constructor(public canvas: HTMLCanvasElement, cx: CanvasRenderingContext2D, keys: KeyControl) {
|
|
|
|
const drawSet = new DrawSet();
|
|
|
|
|
2020-01-19 06:24:29 +00:00
|
|
|
// spinner box
|
|
|
|
Create(this.data, {
|
2019-12-14 23:11:00 +00:00
|
|
|
location: new Location({
|
|
|
|
X: 200,
|
|
|
|
Y: 200,
|
|
|
|
VAngle: Math.PI
|
|
|
|
}),
|
2020-04-04 22:52:25 +00:00
|
|
|
bounds: new PolygonComponent({points: [-50, 50, -60, 250, 60, 250, 50, 50]}),
|
|
|
|
collisionTargetClass: new CollisionClass({ name: "block"}),
|
|
|
|
renderBounds: new RenderBounds({color: "#0a0", layer: 0}),
|
2019-12-14 23:11:00 +00:00
|
|
|
});
|
|
|
|
|
2020-01-19 06:24:29 +00:00
|
|
|
// triangles
|
|
|
|
[0, 1, 2, 3, 4, 5].forEach(angle => Create(this.data, {
|
2019-12-14 23:11:00 +00:00
|
|
|
location: new Location({
|
|
|
|
X: 200,
|
|
|
|
Y: 200,
|
2020-01-19 06:24:29 +00:00
|
|
|
Angle: angle,
|
2019-12-14 23:11:00 +00:00
|
|
|
VAngle: -Math.PI/10
|
|
|
|
}),
|
2020-04-04 22:52:25 +00:00
|
|
|
bounds: new PolygonComponent({points: [70, 0, 55, 40, 85, 40]}),
|
|
|
|
collisionSourceClass: new CollisionClass({ name: "tri"}),
|
|
|
|
renderBounds: new RenderBounds({
|
|
|
|
color: "#d40",
|
|
|
|
layer: 0,
|
|
|
|
})
|
2020-01-19 06:24:29 +00:00
|
|
|
}));
|
2019-12-14 23:11:00 +00:00
|
|
|
|
|
|
|
const loop = new Loop(30,
|
|
|
|
interval => {
|
|
|
|
DumbMotion(this.data, interval);
|
|
|
|
|
2020-01-19 06:24:29 +00:00
|
|
|
Join(this.data, "collisionSourceClass", "renderBounds").forEach(([collisionSourceClass, renderBounds]) => {
|
|
|
|
if(collisionSourceClass.name === "tri") {
|
|
|
|
renderBounds.color = "#d40";
|
|
|
|
}
|
|
|
|
});
|
2019-12-14 23:11:00 +00:00
|
|
|
|
2020-01-19 06:24:29 +00:00
|
|
|
FindCollisions(this.data, 500, (className, sourceId, _targetId) => {
|
2019-12-14 23:11:00 +00:00
|
|
|
switch(className) {
|
|
|
|
case "tri>block":
|
|
|
|
const [debug] = Lookup(this.data, sourceId, "renderBounds");
|
|
|
|
if(debug) debug.color = "#0ff";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
dt => {
|
|
|
|
cx.fillStyle = "#848";
|
|
|
|
cx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
RunRenderBounds(this.data, drawSet);
|
|
|
|
drawSet.draw(cx, dt);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
loop.start();
|
|
|
|
|
|
|
|
keys.setHandler({
|
|
|
|
press: key => {
|
|
|
|
if(key == "a") loop.start();
|
|
|
|
else if(key == "b") loop.stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2020-03-25 03:47:04 +00:00
|
|
|
|
|
|
|
export function BindTests(): void {
|
|
|
|
Select("#EcsJoinTest").forEach(e => new EcsJoinTest(e));
|
|
|
|
Select("#EcsLookupTest").forEach(e => new EcsLookupTest(e));
|
|
|
|
Select("#EcsRemoveTest").forEach(e => new EcsRemoveTest(e));
|
|
|
|
Select("#EcsCreateTest").forEach(e => new EcsCreateTest(e));
|
|
|
|
Select("#RenderTest").forEachCanvas((c, cx, keys) => new LoopTest(c, cx, keys));
|
|
|
|
}
|