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); } } }