You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
11 KiB
380 lines
11 KiB
import createjs from "./createjs-2015.11.26.combined";
|
|
import red from "./red.png";
|
|
import yellow from "./yellow.png";
|
|
import green from "./green.png";
|
|
import bubble from "./bubble.png";
|
|
import flash from "./flash.png";
|
|
import magnet from "./magnet.png";
|
|
import needle from "./needle.png";
|
|
import Matter from "matter-js";
|
|
import Ring from "./ring";
|
|
import "./water.css";
|
|
|
|
const width = 1868;
|
|
const height = 1096;
|
|
const throttle = (t, e) => {
|
|
var i = null;
|
|
return function (r) {
|
|
var n = +new Date();
|
|
if (!(null != i && n - i <= e)) return (i = n), t.apply(this, [r]);
|
|
};
|
|
};
|
|
|
|
const loadImg = (src) =>
|
|
new Promise((resolve) => {
|
|
const img = new Image();
|
|
img.onload = () => resolve(img);
|
|
img.src = src;
|
|
});
|
|
|
|
class Queue {
|
|
constructor() {
|
|
this.map = {};
|
|
}
|
|
async loadManifest(manifest) {
|
|
const imgs = await Promise.all(manifest.map(({ src }) => loadImg(src)));
|
|
manifest.forEach((file, i) => {
|
|
this.map[file.id] = imgs[i];
|
|
});
|
|
}
|
|
getResult(id) {
|
|
return this.map[id];
|
|
}
|
|
}
|
|
|
|
export default class Waterful {
|
|
preload() {
|
|
const queue = new Queue();
|
|
this._queue = queue;
|
|
const manifest = [
|
|
{
|
|
id: "ring_red",
|
|
src: red,
|
|
},
|
|
{
|
|
id: "ring_yellow",
|
|
src: yellow,
|
|
},
|
|
{
|
|
id: "ring_green",
|
|
src: green,
|
|
},
|
|
{
|
|
id: "bubble",
|
|
src: bubble,
|
|
},
|
|
{
|
|
id: "flashAnim",
|
|
src: flash,
|
|
},
|
|
{
|
|
id: "magnetAnim",
|
|
src: magnet,
|
|
},
|
|
{
|
|
id: "needle",
|
|
src: needle,
|
|
},
|
|
];
|
|
|
|
return queue.loadManifest(manifest);
|
|
}
|
|
init(options) {
|
|
this.steps = 100;
|
|
this._options = options;
|
|
this._options.callbacks.step(this.steps);
|
|
this.enlarging = false;
|
|
this.magneting = false;
|
|
this.addForceLeft = false;
|
|
this.addForceRight = false;
|
|
this._score = {
|
|
left: options.score.left || [],
|
|
right: options.score.right || [],
|
|
};
|
|
Object.defineProperty(this._score, "total", {
|
|
get: function () {
|
|
return this.left.length + this.right.length;
|
|
},
|
|
});
|
|
this._idleBubbles = { left: [], right: [] };
|
|
this.totalRings =
|
|
this._score.total + options.red + options.yellow + options.green;
|
|
this.initStage(options.container);
|
|
this.initRings(options);
|
|
this.eventBinding(options.container);
|
|
this.getBubbleLeft = throttle(() => {
|
|
if (this._idleBubbles.left.length) return this._idleBubbles.left.shift();
|
|
const bubble = new createjs.Sprite(
|
|
new createjs.SpriteSheet({
|
|
images: [this._queue.getResult("bubble")],
|
|
frames: { width: 320, height: 480 },
|
|
animations: { run: [0, 14, null, 0.3] },
|
|
})
|
|
);
|
|
bubble.x = 0;
|
|
bubble.y = height / 2;
|
|
bubble.on(
|
|
"animationend",
|
|
function () {
|
|
this._stage.removeChild(bubble), this._idleBubbles.left.push(bubble);
|
|
}.bind(this)
|
|
);
|
|
return bubble;
|
|
}, 300);
|
|
this.getBubbleRight = throttle(() => {
|
|
if (this._idleBubbles.right.length)
|
|
return this._idleBubbles.right.shift();
|
|
var bubble = new createjs.Sprite(
|
|
new createjs.SpriteSheet({
|
|
images: [this._queue.getResult("bubble")],
|
|
frames: { width: 320, height: 480 },
|
|
animations: { run: [0, 14, null, 0.3] },
|
|
})
|
|
);
|
|
|
|
bubble.x = width;
|
|
bubble.y = height / 2;
|
|
bubble.scaleX = -1;
|
|
bubble.on(
|
|
"animationend",
|
|
function () {
|
|
this._stage.removeChild(bubble), this._idleBubbles.right.push(bubble);
|
|
}.bind(this)
|
|
);
|
|
return bubble;
|
|
}, 300);
|
|
}
|
|
initStage(container) {
|
|
const drawNeedle = (game, x) => {
|
|
const sheet = new createjs.SpriteSheet({
|
|
images: [game._queue.getResult("needle")],
|
|
frames: { width: 182, height: 659 },
|
|
});
|
|
const sprite = new createjs.Sprite(sheet);
|
|
sprite.x = x;
|
|
sprite.y = 334;
|
|
return sprite;
|
|
};
|
|
const drawFlash = (game, x) => {
|
|
const sheet = new createjs.SpriteSheet({
|
|
images: [game._queue.getResult("flashAnim")],
|
|
frames: { width: 332, height: 168 },
|
|
animations: { run: { frames: [0, 1, 2, 3, 4], speed: 0.2 } },
|
|
});
|
|
const sprite = new createjs.Sprite(sheet);
|
|
const bounds = sprite.getBounds();
|
|
sprite.regX = bounds.width / 2;
|
|
sprite.regY = bounds.height / 2;
|
|
sprite.x = x;
|
|
sprite.y = 334;
|
|
sprite.scaleX = 3;
|
|
sprite.scaleY = 3;
|
|
sprite.on("animationend", function () {
|
|
game._stage.removeChild(this);
|
|
});
|
|
return sprite;
|
|
};
|
|
const { Engine, World, Bodies, Events } = Matter;
|
|
const engine = (this._engine = Engine.create());
|
|
engine.world.gravity.y = 0.2;
|
|
|
|
World.add(engine.world, [
|
|
Bodies.rectangle(width / 2, 0, width, 1, { isStatic: true }),
|
|
Bodies.rectangle(width / 2, height, width, 1, { isStatic: true }),
|
|
Bodies.rectangle(0, height / 2, 1, height, { isStatic: true }),
|
|
Bodies.rectangle(width, height / 2, 1, height, { isStatic: true }),
|
|
Bodies.rectangle(602, 530, 1, 380, { isStatic: true }),
|
|
Bodies.rectangle(634, 530, 1, 380, { isStatic: true }),
|
|
Bodies.rectangle(1188, 530, 1, 380, { isStatic: true }),
|
|
Bodies.rectangle(1220, 530, 1, 380, { isStatic: true }),
|
|
Bodies.circle(616, 764, 90, { isStatic: true }),
|
|
Bodies.circle(1200, 764, 90, { isStatic: true }),
|
|
Bodies.rectangle(618, 906, 74, 100, { isStatic: true }),
|
|
Bodies.rectangle(1204, 906, 74, 100, { isStatic: true }),
|
|
Bodies.rectangle(618, 340, 32, 1, { isStatic: true, friction: 0 }),
|
|
Bodies.rectangle(1204, 340, 32, 1, { isStatic: true, friction: 0 }),
|
|
]),
|
|
Engine.run(engine),
|
|
Events.on(this._engine, "beforeUpdate", () => {
|
|
let force;
|
|
if (this.addForceLeft || this.addForceRight) {
|
|
if (this.addForceLeft) {
|
|
force = 1;
|
|
this.addForceLeft = false;
|
|
}
|
|
if (this.addForceRight) {
|
|
force = -1;
|
|
this.addForceRight = false;
|
|
}
|
|
this._rings.forEach((ring) => {
|
|
if (ring.active) {
|
|
const { x, y } = ring.body.position;
|
|
|
|
Matter.Body.applyForce(
|
|
ring.body,
|
|
{ x, y },
|
|
{ x: 0.3 * force, y: -0.4 }
|
|
);
|
|
Matter.Body.setAngularVelocity(ring.body, (force * Math.PI) / 24);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
const canvas = document.createElement("canvas");
|
|
canvas.className = "watercanvas";
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
container.appendChild(canvas);
|
|
this._stage = new createjs.Stage(canvas);
|
|
this._needles = {};
|
|
const leftNeedle = (this._needles.left = drawNeedle(this, 524));
|
|
const rightNeedle = (this._needles.right = drawNeedle(this, 1106));
|
|
|
|
this._stage.addChild(leftNeedle, rightNeedle);
|
|
this._flashAnim = {
|
|
left: drawFlash(this, 616),
|
|
right: drawFlash(this, 1204),
|
|
};
|
|
}
|
|
initRings(options) {
|
|
this._rings = [];
|
|
this._staticRings = [];
|
|
this._score.left.forEach((ring, i) => {
|
|
this.addStaticRing(ring, i, "left");
|
|
});
|
|
this._score.right.forEach((ring, i) => {
|
|
this.addStaticRing(ring, i, "right");
|
|
});
|
|
this.addRing("ring_red", options.red);
|
|
this.addRing("ring_yellow", options.yellow);
|
|
this.addRing("ring_green", options.green);
|
|
if (options.priceRing && this._rings[0]) {
|
|
const ring = this._rings[0];
|
|
Matter.Body.setPosition(ring.body, { x: 206, y: 216 }),
|
|
(ring.active = true);
|
|
}
|
|
this._stage.update();
|
|
}
|
|
addStaticRing(t, e, i) {
|
|
var r = new createjs.SpriteSheet({
|
|
images: [waterful._queue.getResult("ring_" + t)],
|
|
frames: { width: 62, height: 62 },
|
|
}),
|
|
n = new createjs.Sprite(r),
|
|
s = n.getBounds();
|
|
(n.regX = s.width / 2),
|
|
(n.regY = s.height / 2),
|
|
(n.x = "left" === i ? 206 : 455),
|
|
(n.y = 380 - 14 * e),
|
|
n.gotoAndStop(0),
|
|
this._stage.addChild(n),
|
|
this._staticRings.push(n);
|
|
}
|
|
addRing(name, max) {
|
|
const getX = () => {
|
|
const x = 1670 * Math.random() + 90;
|
|
return (x > 523 && x < 705) || (x > 1106 && x < 1292) ? getX() : x;
|
|
};
|
|
let bodies = [];
|
|
for (let i = 0; i < max; i++) {
|
|
const x = getX();
|
|
const y = 1200 * Math.random() + 150;
|
|
const ring = new Ring(x, y, 80, name, this);
|
|
this._rings.push(ring);
|
|
this._stage.addChild(ring.texture);
|
|
bodies.push(ring.body);
|
|
}
|
|
Matter.World.add(this._engine.world, bodies);
|
|
}
|
|
eventBinding(container) {
|
|
container.querySelector(".button.left").addEventListener("click", (t) => {
|
|
if (createjs.Ticker.pause) return;
|
|
if (this.steps) {
|
|
this.steps--;
|
|
this._options.callbacks.step(this.steps);
|
|
} else return;
|
|
t.preventDefault(), (this.addForceLeft = true);
|
|
var e = this.getBubbleLeft();
|
|
e && (this._stage.addChild(e), e.gotoAndPlay("run"));
|
|
});
|
|
container.querySelector(".button.right").addEventListener("click", (t) => {
|
|
if (createjs.Ticker.pause) return;
|
|
if (this.steps) {
|
|
this.steps--;
|
|
this._options.callbacks.step(this.steps);
|
|
} else return;
|
|
t.preventDefault(), (this.addForceRight = true);
|
|
var e = this.getBubbleRight(this);
|
|
e && (e && this._stage.addChild(e), e.gotoAndPlay("run"));
|
|
});
|
|
createjs.Ticker.timingMode = createjs.Ticker.RAF;
|
|
createjs.Ticker.setFPS(60);
|
|
createjs.Ticker.addEventListener(
|
|
"tick",
|
|
function (t) {
|
|
if (!t.paused) {
|
|
for (var e = 0; e < this._rings.length; e++)
|
|
this._rings[e].update(this);
|
|
if (this.gamma)
|
|
for (var e = 0; e < this._staticRings.length; e++) {
|
|
if (this.gamma < 0) {
|
|
var i = this._staticRings[e].x - 0.1;
|
|
i < 200 && (i = 200), i > 400 && i < 448 && (i = 448);
|
|
} else if (this.gamma > 0) {
|
|
var i = this._staticRings[e].x + 0.1;
|
|
i > 213 && i < 300 && (i = 213), i > 462 && (i = 462);
|
|
}
|
|
this._staticRings[e].x = i;
|
|
}
|
|
|
|
this._stage.update(t);
|
|
}
|
|
}.bind(this)
|
|
);
|
|
}
|
|
score(t, e) {
|
|
"left" === t
|
|
? this._score.left.push(e)
|
|
: "right" === t && this._score.right.push(e),
|
|
this._stage.addChild(this._flashAnim[t]),
|
|
this._flashAnim[t].gotoAndPlay("run");
|
|
var i = this._options;
|
|
i.callbacks.score(this._score),
|
|
this._score.total === this.totalRings && i.callbacks.end(this._score);
|
|
}
|
|
restart(t) {
|
|
this.steps = 100;
|
|
this._options.callbacks.step(this.steps);
|
|
(this._score = { left: [], right: [] }),
|
|
(this.enlarging = false),
|
|
(this.magneting = false),
|
|
(this.addForceLeft = false),
|
|
(this.addForceRight = false),
|
|
this._rings.forEach(
|
|
function (t) {
|
|
this._stage.removeChild(t.texture),
|
|
t.body && Matter.World.remove(this._engine.world, t.body);
|
|
}.bind(this)
|
|
),
|
|
this._staticRings.forEach(
|
|
function (t) {
|
|
this._stage.removeChild(t);
|
|
}.bind(this)
|
|
),
|
|
this.initRings(t);
|
|
}
|
|
pause() {
|
|
createjs.Ticker.pause = true;
|
|
for (var t = 0; t < this._rings.length; t++) {
|
|
var e = this._rings[t].body;
|
|
e && Matter.Sleeping.set(e, true);
|
|
}
|
|
}
|
|
resume() {
|
|
createjs.Ticker.pause = false;
|
|
for (var t = 0; t < this._rings.length; t++) {
|
|
var e = this._rings[t].body;
|
|
e && Matter.Sleeping.set(e, false);
|
|
}
|
|
}
|
|
}
|
|
|