@ -1,133 +0,0 @@ |
|||
import fish1 from "./images/fish1.png"; |
|||
import fish2 from "./images/fish2.png"; |
|||
import fish3 from "./images/fish3.png"; |
|||
import fish4 from "./images/fish4.png"; |
|||
import fish5 from "./images/fish5.png"; |
|||
import fish6 from "./images/fish6.png"; |
|||
import fish7 from "./images/fish7.png"; |
|||
import fish8 from "./images/fish8.png"; |
|||
import fish9 from "./images/fish9.png"; |
|||
import fish10 from "./images/fish10.png"; |
|||
import shark1 from "./images/shark1.png"; |
|||
import shark2 from "./images/shark2.png"; |
|||
import cannon1 from "./images/cannon1.png"; |
|||
export const fishFrames = { |
|||
fish1: { |
|||
url: fish1, |
|||
swim: { start: 0, end: 3 }, |
|||
capture: { start: 4, end: 8 }, |
|||
size: [54, 22], |
|||
offsets: [2, 2], |
|||
frameWidth: 55, |
|||
frameHeight: 37, |
|||
}, |
|||
fish2: { |
|||
url: fish2, |
|||
swim: { start: 0, end: 3 }, |
|||
capture: { start: 4, end: 8 }, |
|||
size: [70, 35], |
|||
offsets: [10, 5], |
|||
frameWidth: 78, |
|||
frameHeight: 64, |
|||
}, |
|||
fish3: { |
|||
url: fish3, |
|||
swim: { start: 0, end: 3 }, |
|||
capture: { start: 4, end: 8 }, |
|||
size: [65, 36], |
|||
offsets: [5, 0], |
|||
frameWidth: 72, |
|||
frameHeight: 56, |
|||
}, |
|||
fish4: { |
|||
url: fish4, |
|||
swim: { start: 0, end: 3 }, |
|||
capture: { start: 4, end: 8 }, |
|||
size: [75, 36], |
|||
offsets: [3, -2], |
|||
frameWidth: 77, |
|||
frameHeight: 59, |
|||
}, |
|||
fish5: { |
|||
url: fish5, |
|||
swim: { start: 0, end: 3 }, |
|||
capture: { start: 4, end: 8 }, |
|||
size: [85, 70], |
|||
offsets: [15, 18], |
|||
frameWidth: 107, |
|||
frameHeight: 122, |
|||
}, |
|||
fish6: { |
|||
url: fish6, |
|||
swim: { start: 0, end: 8 }, |
|||
capture: { start: 8, end: 12 }, |
|||
size: [90, 60], |
|||
offsets: [15, 0], |
|||
frameWidth: 105, |
|||
frameHeight: 79, |
|||
}, |
|||
fish7: { |
|||
url: fish7, |
|||
swim: { start: 0, end: 6 }, |
|||
capture: { start: 6, end: 10 }, |
|||
size: [70, 75], |
|||
offsets: [15, 2], |
|||
frameWidth: 92, |
|||
frameHeight: 151, |
|||
}, |
|||
fish8: { |
|||
url: fish8, |
|||
swim: { start: 0, end: 7 }, |
|||
capture: { start: 7, end: 12 }, |
|||
size: [80, 85], |
|||
offsets: [40, 3], |
|||
frameWidth: 174, |
|||
frameHeight: 126, |
|||
}, |
|||
fish9: { |
|||
url: fish9, |
|||
swim: { start: 0, end: 7 }, |
|||
capture: { start: 7, end: 12 }, |
|||
size: [100, 120], |
|||
offsets: [60, 15], |
|||
frameWidth: 166, |
|||
frameHeight: 183, |
|||
}, |
|||
fish10: { |
|||
url: fish10, |
|||
swim: { start: 0, end: 5 }, |
|||
capture: { start: 5, end: 10 }, |
|||
size: [140, 100], |
|||
offsets: [20, 22], |
|||
frameWidth: 178, |
|||
frameHeight: 187, |
|||
}, |
|||
shark1: { |
|||
url: shark1, |
|||
swim: { start: 0, end: 7 }, |
|||
capture: { start: 7, end: 12 }, |
|||
size: [450, 150], |
|||
offsets: [60, 50], |
|||
frameWidth: 509, |
|||
frameHeight: 270, |
|||
}, |
|||
shark2: { |
|||
url: shark2, |
|||
swim: { start: 0, end: 7 }, |
|||
capture: { start: 7, end: 12 }, |
|||
size: [450, 150], |
|||
offsets: [60, 60], |
|||
frameWidth: 516, |
|||
frameHeight: 273, |
|||
}, |
|||
}; |
|||
export const cannonsFrames = { |
|||
cannon1: { |
|||
url: cannon1, |
|||
anims: { start: 0, end: 5 }, |
|||
size: [37, 60], |
|||
offsets: [37 / 2, 0], |
|||
frameWidth: 74, |
|||
frameHeight: 74, |
|||
}, |
|||
}; |
|||
|
Before Width: | Height: | Size: 1.1 MiB |
@ -1,59 +0,0 @@ |
|||
{"frames": { |
|||
|
|||
"bottom-bar.png": |
|||
{ |
|||
"frame": {"x":0,"y":0,"w":765,"h":72}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":765,"h":72}, |
|||
"sourceSize": {"w":765,"h":72} |
|||
}, |
|||
"cannon_minus.png": |
|||
{ |
|||
"frame": {"x":132,"y":72,"w":44,"h":31}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":44,"h":31}, |
|||
"sourceSize": {"w":44,"h":31} |
|||
}, |
|||
"cannon_minus_down.png": |
|||
{ |
|||
"frame": {"x":88,"y":72,"w":44,"h":31}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":44,"h":31}, |
|||
"sourceSize": {"w":44,"h":31} |
|||
}, |
|||
"cannon_plus.png": |
|||
{ |
|||
"frame": {"x":44,"y":72,"w":44,"h":31}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":44,"h":31}, |
|||
"sourceSize": {"w":44,"h":31} |
|||
}, |
|||
"cannon_plus_down.png": |
|||
{ |
|||
"frame": {"x":0,"y":72,"w":44,"h":31}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":44,"h":31}, |
|||
"sourceSize": {"w":44,"h":31} |
|||
}, |
|||
"energy-bar.png": |
|||
{ |
|||
"frame": {"x":0,"y":103,"w":213,"h":19}, |
|||
"rotated": false, |
|||
"trimmed": false, |
|||
"spriteSourceSize": {"x":0,"y":0,"w":213,"h":19}, |
|||
"sourceSize": {"w":213,"h":19} |
|||
} |
|||
}, |
|||
"meta": { |
|||
"app": "http://www.texturepacker.com", |
|||
"version": "1.0", |
|||
"image": "bottom.png", |
|||
"format": "RGBA8888", |
|||
"size": {"w":765,"h":122} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 382 KiB |
@ -1,35 +0,0 @@ |
|||
import Phaser from "phaser"; |
|||
import Scene from "./scene"; |
|||
const launch = ({ containerId, onLose }) => { |
|||
const container = document.getElementById(containerId); |
|||
const width = container.clientWidth; |
|||
const height = container.clientHeight; |
|||
const game = new Phaser.Game({ |
|||
type: Phaser.CANVAS, |
|||
width, |
|||
height, |
|||
parent: containerId, |
|||
physics: { |
|||
default: "arcade", |
|||
arcade: { |
|||
debug: true, |
|||
}, |
|||
}, |
|||
scale: { |
|||
mode: Phaser.Scale.FIT, |
|||
autoCenter: Phaser.Scale.CENTER_BOTH, |
|||
parent: containerId, |
|||
width: 1080, |
|||
height: 1080, |
|||
}, |
|||
scene: Scene, |
|||
}); |
|||
Object.assign(game, { |
|||
onLose, |
|||
restart() { |
|||
this.scene.scenes[0].scene.start("scene"); |
|||
}, |
|||
}); |
|||
return game; |
|||
}; |
|||
export default launch; |
|||
@ -1,179 +0,0 @@ |
|||
import Phaser from "phaser"; |
|||
import bg from "./images/bg.png"; |
|||
import bottom from "./images/bottom.png"; |
|||
import bottomMap from "./images/bottom.json"; |
|||
import { fishFrames, cannonsFrames } from "./assets"; |
|||
|
|||
export default class Scene extends Phaser.Scene { |
|||
constructor() { |
|||
super({ |
|||
key: "scene", |
|||
}); |
|||
} |
|||
|
|||
preload() { |
|||
this.load.image("bg", bg); |
|||
this.load.atlas("bottom", bottom, bottomMap); |
|||
Object.entries(fishFrames).forEach( |
|||
([k, { url, frameWidth, frameHeight }]) => { |
|||
this.load.spritesheet(k, url, { frameWidth, frameHeight }); |
|||
} |
|||
); |
|||
Object.entries(cannonsFrames).forEach( |
|||
([k, { url, frameWidth, frameHeight }]) => { |
|||
this.load.spritesheet(k, url, { frameWidth, frameHeight }); |
|||
} |
|||
); |
|||
} |
|||
get cannon() { |
|||
return this.cannons[this.cannonIndex]; |
|||
} |
|||
create() { |
|||
this.layout(); |
|||
this.addListeners(); |
|||
this.animateFishes(); |
|||
this.animateCannons(); |
|||
this.addCannon(); |
|||
this.addFish(); |
|||
} |
|||
animateCannons() { |
|||
Object.entries(cannonsFrames).forEach(([k, { anims }]) => { |
|||
this.anims.create({ |
|||
key: `${k}_fire`, |
|||
frames: this.anims.generateFrameNumbers(k, anims), |
|||
frameRate: 10, |
|||
repeat: 0, |
|||
}); |
|||
}); |
|||
} |
|||
animateFishes() { |
|||
Object.entries(fishFrames).forEach(([k, { swim, capture }]) => { |
|||
this.anims.create({ |
|||
key: `${k}_swim`, |
|||
frames: this.anims.generateFrameNumbers(k, swim), |
|||
frameRate: 10, |
|||
repeat: -1, |
|||
}); |
|||
this.anims.create({ |
|||
key: `${k}_capture`, |
|||
frames: this.anims.generateFrameNumbers(k, capture), |
|||
frameRate: 10, |
|||
repeat: -1, |
|||
}); |
|||
}); |
|||
} |
|||
layout() { |
|||
this.addBg(); |
|||
this.addBottomBar(); |
|||
} |
|||
addListeners() { |
|||
this.input.on( |
|||
"gameobjectdown", |
|||
(_, obj) => { |
|||
switch (obj.name) { |
|||
case "minus": |
|||
obj.setFrame("cannon_minus_down.png"); |
|||
break; |
|||
case "plus": |
|||
obj.setFrame("cannon_plus_down.png"); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
}, |
|||
this |
|||
); |
|||
this.input.on( |
|||
"gameobjectup", |
|||
(pointer, obj) => { |
|||
switch (obj.name) { |
|||
case "minus": |
|||
obj.setFrame("cannon_minus.png"); |
|||
break; |
|||
case "plus": |
|||
obj.setFrame("cannon_plus.png"); |
|||
break; |
|||
case "bg": |
|||
const theta = Math.atan2( |
|||
this.game.config.height - pointer.y, |
|||
this.game.config.width / 2 - pointer.x |
|||
); |
|||
this.cannon.setRotation(theta - Math.PI / 2); |
|||
this.cannon.anims.play(`${this.cannon.name}_fire`, true); |
|||
default: |
|||
break; |
|||
} |
|||
}, |
|||
this |
|||
); |
|||
} |
|||
addBg() { |
|||
const bg = this.add.image(0, 0, "bg"); |
|||
bg.name = "bg"; |
|||
bg.setOrigin(0); |
|||
bg.displayWidth = this.game.config.width; |
|||
bg.displayHeight = this.game.config.height; |
|||
bg.setInteractive(); |
|||
} |
|||
addBottomBar() { |
|||
const bottomBar = this.add.image( |
|||
this.game.config.width / 2, |
|||
this.game.config.height - 45, |
|||
"bottom", |
|||
"bottom-bar.png" |
|||
); |
|||
bottomBar.displayWidth = 958; |
|||
bottomBar.displayHeight = 90; |
|||
const minus = this.add.image( |
|||
this.game.config.width / 2 - 40, |
|||
this.game.config.height - 50, |
|||
"bottom", |
|||
"cannon_minus.png" |
|||
); |
|||
minus.name = "minus"; |
|||
minus.setOrigin(0); |
|||
minus.displayWidth = 55; |
|||
minus.displayHeight = 38; |
|||
minus.setInteractive(); |
|||
const plus = this.add.image( |
|||
this.game.config.width / 2 + 95, |
|||
this.game.config.height - 50, |
|||
"bottom", |
|||
"cannon_plus.png" |
|||
); |
|||
plus.name = "plus"; |
|||
plus.setOrigin(0); |
|||
plus.displayWidth = 55; |
|||
plus.displayHeight = 38; |
|||
plus.setInteractive(); |
|||
} |
|||
addFish() { |
|||
Object.entries(fishFrames).forEach(([k, { size, offsets }]) => { |
|||
const fish = this.physics.add.sprite( |
|||
(Math.random() * this.game.config.width) / 2 + |
|||
this.game.config.width / 4, |
|||
(Math.random() * this.game.config.width) / 2 + |
|||
this.game.config.width / 4, |
|||
"fish1" |
|||
); |
|||
fish.body.setSize(...size); |
|||
fish.body.setOffset(...offsets); |
|||
fish.anims.play(`${k}_swim`, true); |
|||
}); |
|||
} |
|||
addCannon() { |
|||
this.cannonIndex = 0; |
|||
const [k, { size, offsets }] = Object.entries(cannonsFrames)[ |
|||
this.cannonIndex |
|||
]; |
|||
const cannon = this.physics.add.sprite( |
|||
this.game.config.width / 2 + 55, |
|||
this.game.config.height - 50, |
|||
k |
|||
); |
|||
cannon.body.setSize(...size); |
|||
cannon.body.setOffset(...offsets); |
|||
cannon.name = k; |
|||
this.cannon = cannon; |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
import flipper from "./flipper/game"; |
|||
import snake from "./snake/snake"; |
|||
import water from "./water/game"; |
|||
let h5games = { flipper, snake, water }; |
|||
export default h5games; |
|||
@ -1,184 +0,0 @@ |
|||
@charset "UTF-8"; |
|||
|
|||
html,body { |
|||
position: relative; |
|||
width: 100%; |
|||
max-width: 540px; |
|||
height: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
background-color: #ece060; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.snake-game { |
|||
position: relative; |
|||
width: 100%; |
|||
height: auto; |
|||
} |
|||
|
|||
.snake-game canvas { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: auto; |
|||
} |
|||
|
|||
.snake-controller { |
|||
position: absolute; |
|||
top: 60%; |
|||
left: 0; |
|||
width: 100%; |
|||
} |
|||
|
|||
.snake-switch { |
|||
position: absolute; |
|||
width: 50px; |
|||
height: 53px; |
|||
background: url(../images/switch@2x.png) 0 0 no-repeat; |
|||
background-size: 100% 100%; |
|||
top: 160px; |
|||
right: 30px; |
|||
border: 0 none; |
|||
appearance: none; |
|||
-webkit-appearance: none; |
|||
outline: 0; |
|||
} |
|||
|
|||
.snake-trigger { |
|||
position: absolute; |
|||
width: 50px; |
|||
height: 50px; |
|||
background: url(../images/pause@2x.png) 0 0 no-repeat; |
|||
background-size: 100% 100%; |
|||
top: 160px; |
|||
left: 30px; |
|||
border: 0 none; |
|||
appearance: none; |
|||
-webkit-appearance: none; |
|||
outline: 0; |
|||
} |
|||
.snake-trigger:checked { |
|||
background-image: url(../images/play@2x.png); |
|||
} |
|||
|
|||
.snake-direction { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 0; |
|||
width: 160px; |
|||
height: 160px; |
|||
margin-left: -80px; |
|||
border: 2px solid #414042; |
|||
background-color: #414042; |
|||
border-radius: 100%; |
|||
overflow: hidden; |
|||
transform: rotateZ(45deg); |
|||
-webkit-transform: rotateZ(45deg); |
|||
} |
|||
|
|||
.snake-up, .snake-right, .snake-down, .snake-left { |
|||
position: absolute; |
|||
width: 80px; |
|||
height: 80px; |
|||
background-color: #ddd; |
|||
} |
|||
|
|||
.snake-up::after, |
|||
.snake-right::after, |
|||
.snake-down::after, |
|||
.snake-left::after { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 40px; |
|||
top: 40px; |
|||
width: 10px; |
|||
height: 10px; |
|||
border-width: 2px 0 0 2px; |
|||
border-color: #414042; |
|||
border-style: solid; |
|||
transform-origin: left top; |
|||
-webkit-transform-origin: left top; |
|||
} |
|||
|
|||
.snake-up { |
|||
top: -1px; |
|||
left: -1px; |
|||
} |
|||
|
|||
.snake-right { |
|||
top: -1px; |
|||
right: -1px; |
|||
} |
|||
.snake-right::after { |
|||
transform: rotate(90deg); |
|||
-webkit-transform: rotate(90deg); |
|||
} |
|||
|
|||
.snake-down { |
|||
bottom: -1px; |
|||
right: -1px; |
|||
} |
|||
|
|||
.snake-down::after { |
|||
transform: rotate(180deg); |
|||
-webkit-transform: rotate(180deg); |
|||
} |
|||
|
|||
.snake-left { |
|||
bottom: -1px; |
|||
left: -1px; |
|||
} |
|||
|
|||
.snake-left::after { |
|||
transform: rotate(270deg); |
|||
-webkit-transform: rotate(270deg); |
|||
} |
|||
|
|||
.snake-direction.up .snake-up, |
|||
.snake-direction.right .snake-right, |
|||
.snake-direction.down .snake-down, |
|||
.snake-direction.left .snake-left |
|||
{ |
|||
background-color: rgba(188, 188, 188, .7); |
|||
} |
|||
|
|||
.snake-timer { |
|||
position: absolute; |
|||
top: 172px; |
|||
right: 0; |
|||
left: 0; |
|||
margin: 0 auto; |
|||
width: 200px; |
|||
text-align: center; |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.snake-speed { |
|||
position: absolute; |
|||
top: 206px; |
|||
right: 0; |
|||
left: 0; |
|||
margin: 0 auto; |
|||
width: 120px; |
|||
height: 4px; |
|||
border-radius: 2px; |
|||
background-color: #ffeeee; |
|||
box-shadow: inset 1px 1px 3px -1px rgba(0, 0, 0, .3); |
|||
} |
|||
|
|||
.snake-speed-thumb { |
|||
position: absolute; |
|||
top: -3px; |
|||
left: 50%; |
|||
width: 10px; |
|||
height: 10px; |
|||
border-radius: 100%; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, .3); |
|||
background-color: #fff; |
|||
} |
|||
|
|||
|
|||
|
|||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 997 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 42 KiB |
@ -0,0 +1,59 @@ |
|||
import Waterful from "./waterful"; |
|||
import "./water.css"; |
|||
export default class Game { |
|||
constructor({ containerId, onWon, onLose }) { |
|||
const waterful = new Waterful(); |
|||
const container = document.getElementById(containerId); |
|||
const containerWH = container.clientWidth; |
|||
const bg = document.createElement("div"); |
|||
bg.style.transform = `scale(${containerWH / 2160})`; |
|||
bg.className = "bg"; |
|||
["left", "right"].forEach((name) => { |
|||
const button = document.createElement("div"); |
|||
button.className = "button " + name; |
|||
bg.appendChild(button); |
|||
}); |
|||
container.appendChild(bg); |
|||
const meta = document.createElement("div"); |
|||
meta.className = "meta"; |
|||
bg.appendChild(meta); |
|||
this.loaded = false; |
|||
this.options = { |
|||
container: bg, |
|||
red: 6, |
|||
yellow: 6, |
|||
green: 6, |
|||
score: { |
|||
left: [], |
|||
right: [], |
|||
}, |
|||
callbacks: { |
|||
score(score) { |
|||
console.log("score: ", score, score.total); |
|||
}, |
|||
end(score) { |
|||
onWon(score.total); |
|||
}, |
|||
step(step) { |
|||
if (step === 0) onLose(); |
|||
meta.textContent = `剩余 ${step} 次机会`; |
|||
}, |
|||
}, |
|||
}; |
|||
waterful.preload().then(() => { |
|||
this.loaded = true; |
|||
waterful.init(this.options); |
|||
}); |
|||
this.waterful = waterful; |
|||
} |
|||
dispose() {} |
|||
restart() { |
|||
this.loaded && this.waterful.restart(this.options); |
|||
} |
|||
pause() { |
|||
this.loaded && this.waterful.pause(); |
|||
} |
|||
resume() { |
|||
this.loaded && this.waterful.resume(); |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,183 @@ |
|||
import createjs from "./createjs-2015.11.26.combined"; |
|||
import Matter from "matter-js"; |
|||
function rule(t, e) { |
|||
return !!( |
|||
[0, 1, 2, 3, 4, 5, 6].includes(t) && |
|||
((e %= 180), |
|||
e < 0 && (e += 180), |
|||
(e >= 0 && e <= 65) || (e >= 115 && e <= 180)) |
|||
); |
|||
} |
|||
function segmentsIntr(t, e, i, r) { |
|||
var n = (t.x - i.x) * (e.y - i.y) - (t.y - i.y) * (e.x - i.x), |
|||
s = (t.x - r.x) * (e.y - r.y) - (t.y - r.y) * (e.x - r.x); |
|||
if (n * s >= 0) return !1; |
|||
var a = (i.x - t.x) * (r.y - t.y) - (i.y - t.y) * (r.x - t.x), |
|||
o = a + n - s; |
|||
return !(a * o >= 0); |
|||
} |
|||
function stopUnusual(t, e, i, r) { |
|||
var n = 1e-4; |
|||
return Math.abs(t) <= n && Math.abs(e) <= n; |
|||
} |
|||
export default class Ring { |
|||
constructor(x, y, r, id, waterful) { |
|||
this.active = true; |
|||
this.color = id.replace("ring_", ""); |
|||
this.r = r; |
|||
const sprite = new createjs.SpriteSheet({ |
|||
images: [waterful._queue.getResult(id)], |
|||
frames: { width: 62, height: 62 }, |
|||
animations: { |
|||
normal: { |
|||
frames: [ |
|||
0, |
|||
1, |
|||
2, |
|||
3, |
|||
4, |
|||
5, |
|||
6, |
|||
7, |
|||
8, |
|||
9, |
|||
10, |
|||
11, |
|||
10, |
|||
9, |
|||
8, |
|||
7, |
|||
6, |
|||
5, |
|||
4, |
|||
3, |
|||
2, |
|||
1, |
|||
0, |
|||
], |
|||
speed: 0.3, |
|||
}, |
|||
prepare: { |
|||
frames: [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0], |
|||
speed: 0.1, |
|||
}, |
|||
}, |
|||
}); |
|||
this.texture = new createjs.Sprite(sprite, "normal"); |
|||
const bounds = this.texture.getBounds(); |
|||
this.texture.regX = bounds.width / 2; |
|||
this.texture.regY = bounds.height / 2; |
|||
this.texture.stop(); |
|||
this.texture.x = x; |
|||
this.texture.y = y; |
|||
this.texture.scaleX = (r * 2) / bounds.width; |
|||
this.texture.scaleY = (r * 2) / bounds.height; |
|||
this.texture.on("animationend", function (e) { |
|||
var target = e.currentTarget; |
|||
target.y < 528 |
|||
? e.target.gotoAndPlay("prepare") |
|||
: e.target.gotoAndPlay("normal"); |
|||
}); |
|||
this.body = Matter.Bodies.circle(this.texture.x, this.texture.y, r, { |
|||
frictionAir: 0.02, |
|||
restitution: 0.15, |
|||
}); |
|||
} |
|||
update(waterful) { |
|||
const { texture, body, r } = this; |
|||
const { x, y, rotation } = texture; |
|||
const { position, angle, velocity } = body; |
|||
const innerRadius = texture.scaleX * 16; |
|||
const startPoint = { |
|||
x: x - innerRadius * Math.cos(rotation * (Math.PI / 180)), |
|||
y: y - innerRadius * Math.sin(rotation * (Math.PI / 180)), |
|||
}; |
|||
const endPoint = { |
|||
x: x + innerRadius * Math.cos(-rotation * (Math.PI / 180)), |
|||
y: y + innerRadius * Math.sin(rotation * (Math.PI / 180)), |
|||
}; |
|||
const m = { x: 616, y: 264 }; |
|||
const n = { x: 616, y: 700 }; |
|||
const u = { x: 1196, y: 264 }; |
|||
const v = { x: 1196, y: 700 }; |
|||
if ( |
|||
segmentsIntr(startPoint, endPoint, m, n) && |
|||
this.afterCollision(waterful, "left") |
|||
) |
|||
return; |
|||
if ( |
|||
segmentsIntr(startPoint, endPoint, u, v) && |
|||
this.afterCollision(waterful, "right") |
|||
) |
|||
return; |
|||
const x1 = Math.round(x); |
|||
const x2 = Math.round(position.x); |
|||
const y1 = Math.round(y); |
|||
const y2 = Math.round(position.y); |
|||
if (x1 !== x2 || y1 !== y2) { |
|||
texture.paused && texture.play(); |
|||
texture.rotation = (180 * angle) / Math.PI; |
|||
} else { |
|||
!texture.paused && texture.stop(); |
|||
} |
|||
if (stopUnusual(velocity.x, velocity.y, x1, y1)) { |
|||
var factor = 1; |
|||
if (x1 < 206 || (x1 > 400 && x1 < 455)) { |
|||
factor = -1; |
|||
} |
|||
Matter.Body.applyForce( |
|||
body, |
|||
{ x: position.x, y: position.y }, |
|||
{ x: 0.05 * factor, y: 0 } |
|||
); |
|||
} |
|||
texture.x = body.position.x; |
|||
texture.y = body.position.y; |
|||
} |
|||
afterCollision(waterful, dir) { |
|||
const { texture } = this; |
|||
const { currentFrame, rotation } = texture; |
|||
const followRule = rule(currentFrame, rotation); |
|||
if ( |
|||
!followRule || |
|||
waterful._score[dir].length > 8 || |
|||
this.body.velocity.y <= 0 |
|||
) |
|||
return false; |
|||
const scores = waterful._score[dir].length; |
|||
createjs.Tween.get(this.texture) |
|||
.to({ y: 666 - 30 * scores }, (666 - 30 * scores) / 0.21) |
|||
.call(function () { |
|||
waterful._staticRings.push(this); |
|||
}); |
|||
Matter.World.remove(waterful._engine.world, this.body); |
|||
this.body = null; |
|||
this.active = false; |
|||
this.update = () => { |
|||
const { texture } = this; |
|||
const { currentFrame } = texture; |
|||
var t = this.texture, |
|||
e = t.currentFrame; |
|||
if (0 === currentFrame) texture.gotoAndStop(0); |
|||
else { |
|||
if (!this.frameCounter) this.frameCounter = 5; |
|||
texture.gotoAndStop(--texture.currentFrame); |
|||
this.frameCounter--; |
|||
if (texture.x < 582) ++texture.x; |
|||
if (texture.x > 660 && texture.x < 660 + 80) --texture.x; |
|||
if (texture.x > 1242) --texture.x; |
|||
if (texture.x > 1162 && texture.x < 1206) ++texture.x; |
|||
} |
|||
|
|||
let angle = Math.round(texture.rotation) % 180; |
|||
angle < 0 && (angle += 180); |
|||
angle > 0 && angle <= 90 |
|||
? (texture.rotation = angle - 1) |
|||
: angle > 90 && angle < 180 |
|||
? (texture.rotation = angle + 1) |
|||
: 0 === currentFrame && (this.update = function () {}); |
|||
}; |
|||
waterful.score(dir, this.color); |
|||
return true; |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
.bg { |
|||
position: relative; |
|||
width: 2160px; |
|||
height: 2160px; |
|||
transform-origin: top left; |
|||
background-image: url(./bg.jpg); |
|||
background-size: cover; |
|||
} |
|||
@font-face { |
|||
font-family: "game"; |
|||
src: url("./font.ttf") format("truetype"); |
|||
} |
|||
|
|||
.bg .watercanvas { |
|||
position: absolute; |
|||
left: 144px; |
|||
top: 383px; |
|||
width: 1868px; |
|||
height: 1075px; |
|||
} |
|||
.bg .button { |
|||
position: absolute; |
|||
bottom: 112px; |
|||
width: 540px; |
|||
height: 383px; |
|||
} |
|||
.bg .button.left { |
|||
left: 230px; |
|||
} |
|||
.bg .button.right { |
|||
right: 230px; |
|||
} |
|||
.bg .meta { |
|||
position: absolute; |
|||
text-align: center; |
|||
top: 1873px; |
|||
left: 837px; |
|||
right: 837px; |
|||
height: 117px; |
|||
line-height: 117px; |
|||
font-size: 52px; |
|||
color: #fff; |
|||
font-family: "game"; |
|||
} |
|||
@ -0,0 +1,378 @@ |
|||
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 (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 (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); |
|||
} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 15 KiB |