Add files via upload

This commit is contained in:
Haiyong
2021-09-30 11:09:59 +08:00
committed by GitHub
parent 5482fd3f72
commit c8f4d62707
24 changed files with 6772 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
@import url(https://fonts.googleapis.com/css?family=Open+Sans:800);
#world {
background: #ebe5e7;
position:absolute;
width:100%;
height:100%;
overflow:hidden;
}
#instructions{
position:absolute;
width:100%;
top:50%;
margin: auto;
margin-top:120px;
font-family:'Open Sans', sans-serif;
color:#653f4c;
font-size:.9em;
text-transform: uppercase;
text-align : center;
user-select: none;
}
.lightInstructions {
color:#993f4c;
font-size:.8em;
}
#credits{
position:absolute;
width:100%;
margin: auto;
bottom:0;
margin-bottom:20px;
font-family:'Open Sans', sans-serif;
color:#b297a2;
font-size:0.7em;
text-transform: uppercase;
text-align : center;
}
#credits a {
color:#b297a2;
}
#credits .society6 {
color:#993f4c;
}

View File

@@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>海拥 | 爱吹风的小狮子</title>
<link rel="icon" type="image/x-icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<div id="world"></div>
<div id="instructions">按住并拖动以产生风<br/><span class="lightInstructions">小狮子一定会很舒服</span></div>
<div id="credits">
<div class="made-with-love">
Made with
<i></i> by
<a target="_blank" href="http://haiyong.site/index">海拥</a>
</div>
<p>Copyright © <a href="http://haiyong.site/moyu">摸鱼小游戏</a></p>
</div>
<link rel="stylesheet" href="css/style.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js"></script>
<script src="js/script.js"></script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,717 @@
//THREEJS RELATED VARIABLES
var scene,
camera,
controls,
fieldOfView,
aspectRatio,
nearPlane,
farPlane,
shadowLight,
backLight,
light,
renderer,
container;
//SCENE
var floor, lion, fan,
isBlowing = false;
//SCREEN VARIABLES
var HEIGHT,
WIDTH,
windowHalfX,
windowHalfY,
mousePos = {x:0,y:0};
dist = 0;
//INIT THREE JS, SCREEN AND MOUSE EVENTS
function init(){
scene = new THREE.Scene();
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
aspectRatio = WIDTH / HEIGHT;
fieldOfView = 60;
nearPlane = 1;
farPlane = 2000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane);
camera.position.z = 800;
camera.position.y = 0;
camera.lookAt(new THREE.Vector3(0,0,0));
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMapEnabled = true;
container = document.getElementById('world');
container.appendChild(renderer.domElement);
windowHalfX = WIDTH / 2;
windowHalfY = HEIGHT / 2;
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', handleMouseMove, false);
document.addEventListener('mousedown', handleMouseDown, false);
document.addEventListener('mouseup', handleMouseUp, false);
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchend', handleTouchEnd, false);
document.addEventListener('touchmove',handleTouchMove, false);
/*
controls = new THREE.OrbitControls( camera, renderer.domElement);
//*/
}
function onWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
windowHalfX = WIDTH / 2;
windowHalfY = HEIGHT / 2;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
function handleMouseMove(event) {
mousePos = {x:event.clientX, y:event.clientY};
}
function handleMouseDown(event) {
isBlowing = true;
}
function handleMouseUp(event) {
isBlowing = false;
}
function handleTouchStart(event) {
if (event.touches.length > 1) {
event.preventDefault();
mousePos = {x:event.touches[0].pageX, y:event.touches[0].pageY};
isBlowing = true;
}
}
function handleTouchEnd(event) {
//mousePos = {x:windowHalfX, y:windowHalfY};
isBlowing = false;
}
function handleTouchMove(event) {
if (event.touches.length == 1) {
event.preventDefault();
mousePos = {x:event.touches[0].pageX, y:event.touches[0].pageY};
isBlowing = true;
}
}
function createLights() {
light = new THREE.HemisphereLight(0xffffff, 0xffffff, .5)
shadowLight = new THREE.DirectionalLight(0xffffff, .8);
shadowLight.position.set(200, 200, 200);
shadowLight.castShadow = true;
shadowLight.shadowDarkness = .2;
backLight = new THREE.DirectionalLight(0xffffff, .4);
backLight.position.set(-100, 200, 50);
backLight.shadowDarkness = .1;
backLight.castShadow = true;
scene.add(backLight);
scene.add(light);
scene.add(shadowLight);
}
function createFloor(){
floor = new THREE.Mesh(new THREE.PlaneBufferGeometry(1000,500), new THREE.MeshBasicMaterial({color: 0xebe5e7}));
floor.rotation.x = -Math.PI/2;
floor.position.y = -100;
floor.receiveShadow = true;
scene.add(floor);
}
function createLion(){
lion = new Lion();
scene.add(lion.threegroup);
}
function createFan(){
fan = new Fan();
fan.threegroup.position.z = 350;
scene.add(fan.threegroup);
}
Fan = function(){
this.isBlowing = false;
this.speed = 0;
this.acc =0;
this.redMat = new THREE.MeshLambertMaterial ({
color: 0xad3525,
shading:THREE.FlatShading
});
this.greyMat = new THREE.MeshLambertMaterial ({
color: 0x653f4c,
shading:THREE.FlatShading
});
this.yellowMat = new THREE.MeshLambertMaterial ({
color: 0xfdd276,
shading:THREE.FlatShading
});
var coreGeom = new THREE.BoxGeometry(10,10,20);
var sphereGeom = new THREE.BoxGeometry(10, 10, 3);
var propGeom = new THREE.BoxGeometry(10,30,2);
propGeom.applyMatrix( new THREE.Matrix4().makeTranslation( 0,25,0) );
this.core = new THREE.Mesh(coreGeom,this.greyMat);
// propellers
var prop1 = new THREE.Mesh(propGeom, this.redMat);
prop1.position.z = 15;
var prop2 = prop1.clone();
prop2.rotation.z = Math.PI/2;
var prop3 = prop1.clone();
prop3.rotation.z = Math.PI;
var prop4 = prop1.clone();
prop4.rotation.z = -Math.PI/2;
this.sphere = new THREE.Mesh(sphereGeom, this.yellowMat);
this.sphere.position.z = 15;
this.propeller = new THREE.Group();
this.propeller.add(prop1);
this.propeller.add(prop2);
this.propeller.add(prop3);
this.propeller.add(prop4);
this.threegroup = new THREE.Group();
this.threegroup.add(this.core);
this.threegroup.add(this.propeller);
this.threegroup.add(this.sphere);
}
Fan.prototype.update = function(xTarget, yTarget){
this.threegroup.lookAt(new THREE.Vector3(0,80,60));
this.tPosX = rule3(xTarget, -200, 200, -250, 250);
this.tPosY = rule3(yTarget, -200, 200, 250, -250);
this.threegroup.position.x += (this.tPosX - this.threegroup.position.x) /10;
this.threegroup.position.y += (this.tPosY - this.threegroup.position.y) /10;
this.targetSpeed = (this.isBlowing) ? .3 : .01;
if (this.isBlowing && this.speed < .5){
this.acc +=.001;
this.speed += this.acc;
}else if (!this.isBlowing){
this.acc = 0;
this.speed *= .98;
}
this.propeller.rotation.z += this.speed;
}
Lion = function(){
this.windTime = 0;
this.bodyInitPositions = [];
this.maneParts = [];
this.threegroup = new THREE.Group();
this.yellowMat = new THREE.MeshLambertMaterial ({
color: 0xfdd276,
shading:THREE.FlatShading
});
this.redMat = new THREE.MeshLambertMaterial ({
color: 0xad3525,
shading:THREE.FlatShading
});
this.pinkMat = new THREE.MeshLambertMaterial ({
color: 0xe55d2b,
shading:THREE.FlatShading
});
this.whiteMat = new THREE.MeshLambertMaterial ({
color: 0xffffff,
shading:THREE.FlatShading
});
this.purpleMat = new THREE.MeshLambertMaterial ({
color: 0x451954,
shading:THREE.FlatShading
});
this.greyMat = new THREE.MeshLambertMaterial ({
color: 0x653f4c,
shading:THREE.FlatShading
});
this.blackMat = new THREE.MeshLambertMaterial ({
color: 0x302925,
shading:THREE.FlatShading
});
var bodyGeom = new THREE.CylinderGeometry(30,80, 140, 4);
var maneGeom = new THREE.BoxGeometry(40,40,15);
var faceGeom = new THREE.BoxGeometry(80,80,80);
var spotGeom = new THREE.BoxGeometry(4,4,4);
var mustacheGeom = new THREE.BoxGeometry(30,2,1);
mustacheGeom.applyMatrix( new THREE.Matrix4().makeTranslation( 15, 0, 0 ) );
var earGeom = new THREE.BoxGeometry(20,20,20);
var noseGeom = new THREE.BoxGeometry(40,40,20);
var eyeGeom = new THREE.BoxGeometry(5,30,30);
var irisGeom = new THREE.BoxGeometry(4,10,10);
var mouthGeom = new THREE.BoxGeometry(20,20,10);
var smileGeom = new THREE.TorusGeometry( 12, 4, 2, 10, Math.PI );
var lipsGeom = new THREE.BoxGeometry(40,15,20);
var kneeGeom = new THREE.BoxGeometry(25, 80, 80);
kneeGeom.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 50, 0 ) );
var footGeom = new THREE.BoxGeometry(40, 20, 20);
// body
this.body = new THREE.Mesh(bodyGeom, this.yellowMat);
this.body.position.z = -60;
this.body.position.y = -30;
this.bodyVertices = [0,1,2,3,4,10];
for (var i=0;i<this.bodyVertices.length; i++){
var tv = this.body.geometry.vertices[this.bodyVertices[i]];
tv.z =70;
//tv.x = 0;
this.bodyInitPositions.push({x:tv.x, y:tv.y, z:tv.z});
}
// knee
this.leftKnee = new THREE.Mesh(kneeGeom, this.yellowMat);
this.leftKnee.position.x = 65;
this.leftKnee.position.z = -20;
this.leftKnee.position.y = -110;
this.leftKnee.rotation.z = -.3;
this.rightKnee = new THREE.Mesh(kneeGeom, this.yellowMat);
this.rightKnee.position.x = -65;
this.rightKnee.position.z = -20;
this.rightKnee.position.y = -110;
this.rightKnee.rotation.z = .3;
// feet
this.backLeftFoot = new THREE.Mesh(footGeom, this.yellowMat);
this.backLeftFoot.position.z = 30;
this.backLeftFoot.position.x = 75;
this.backLeftFoot.position.y = -90;
this.backRightFoot = new THREE.Mesh(footGeom, this.yellowMat);
this.backRightFoot.position.z = 30;
this.backRightFoot.position.x = -75;
this.backRightFoot.position.y = -90;
this.frontRightFoot = new THREE.Mesh(footGeom, this.yellowMat);
this.frontRightFoot.position.z = 40;
this.frontRightFoot.position.x = -22;
this.frontRightFoot.position.y = -90;
this.frontLeftFoot = new THREE.Mesh(footGeom, this.yellowMat);
this.frontLeftFoot.position.z = 40;
this.frontLeftFoot.position.x = 22;
this.frontLeftFoot.position.y = -90;
// mane
this.mane = new THREE.Group();
for (var j=0; j<4; j++){
for (var k=0; k<4; k++){
var manePart = new THREE.Mesh(maneGeom, this.redMat);
manePart.position.x = (j*40)-60;
manePart.position.y = (k*40)-60;
var amp;
var zOffset;
var periodOffset = Math.random()*Math.PI*2;
var angleOffsetY, angleOffsetX;
var angleAmpY, angleAmpX;
var xInit, yInit;
if ((j==0 && k==0) || (j==0 && k==3) || (j==3 && k==0) || (j==3 && k==3)){
amp = -10-Math.floor(Math.random()*5);
zOffset = -5;
}else if (j==0 || k ==0 || j==3 || k==3){
amp = -5-Math.floor(Math.random()*5);
zOffset = 0;
}else{
amp = 0;
zOffset = 0;
}
this.maneParts.push({mesh:manePart, amp:amp, zOffset:zOffset, periodOffset:periodOffset, xInit:manePart.position.x, yInit:manePart.position.y});
this.mane.add(manePart);
}
}
this.mane.position.y = -10;
this.mane.position.z = 80;
//this.mane.rotation.z = Math.PI/4;
// face
this.face = new THREE.Mesh(faceGeom, this.yellowMat);
this.face.position.z = 135;
// Mustaches
this.mustaches = [];
this.mustache1 = new THREE.Mesh(mustacheGeom, this.greyMat);
this.mustache1.position.x = 30;
this.mustache1.position.y = -5;
this.mustache1.position.z = 175;
this.mustache2 = this.mustache1.clone();
this.mustache2.position.x = 35;
this.mustache2.position.y = -12;
this.mustache3 = this.mustache1.clone();
this.mustache3.position.y = -19;
this.mustache3.position.x = 30;
this.mustache4 = this.mustache1.clone();
this.mustache4.rotation.z = Math.PI;
this.mustache4.position.x = -30;
this.mustache5 = new THREE.Mesh(mustacheGeom, this.blackMat);
this.mustache5 = this.mustache2.clone();
this.mustache5.rotation.z = Math.PI;
this.mustache5.position.x = -35;
this.mustache6 = new THREE.Mesh(mustacheGeom, this.blackMat);
this.mustache6 = this.mustache3.clone();
this.mustache6.rotation.z = Math.PI;
this.mustache6.position.x = -30;
this.mustaches.push(this.mustache1);
this.mustaches.push(this.mustache2);
this.mustaches.push(this.mustache3);
this.mustaches.push(this.mustache4);
this.mustaches.push(this.mustache5);
this.mustaches.push(this.mustache6);
// spots
this.spot1 = new THREE.Mesh(spotGeom, this.redMat);
this.spot1.position.x = 39;
this.spot1.position.z = 150;
this.spot2 = this.spot1.clone();
this.spot2.position.z = 160;
this.spot2.position.y = -10;
this.spot3 = this.spot1.clone();
this.spot3.position.z = 140;
this.spot3.position.y = -15;
this.spot4 = this.spot1.clone();
this.spot4.position.z = 150;
this.spot4.position.y = -20;
this.spot5 = this.spot1.clone();
this.spot5.position.x = -39;
this.spot6 = this.spot2.clone();
this.spot6.position.x = -39;
this.spot7 = this.spot3.clone();
this.spot7.position.x = -39;
this.spot8 = this.spot4.clone();
this.spot8.position.x = -39;
// eyes
this.leftEye = new THREE.Mesh(eyeGeom, this.whiteMat);
this.leftEye.position.x = 40;
this.leftEye.position.z = 120;
this.leftEye.position.y = 25;
this.rightEye = new THREE.Mesh(eyeGeom, this.whiteMat);
this.rightEye.position.x = -40;
this.rightEye.position.z = 120;
this.rightEye.position.y = 25;
// iris
this.leftIris = new THREE.Mesh(irisGeom, this.purpleMat);
this.leftIris.position.x = 42;
this.leftIris.position.z = 120;
this.leftIris.position.y = 25;
this.rightIris = new THREE.Mesh(irisGeom, this.purpleMat);
this.rightIris.position.x = -42;
this.rightIris.position.z = 120;
this.rightIris.position.y = 25;
// mouth
this.mouth = new THREE.Mesh(mouthGeom, this.blackMat);
this.mouth.position.z = 171;
this.mouth.position.y = -30;
this.mouth.scale.set(.5,.5,1);
// smile
this.smile = new THREE.Mesh(smileGeom, this.greyMat);
this.smile.position.z = 173;
this.smile.position.y = -15;
this.smile.rotation.z = -Math.PI;
// lips
this.lips = new THREE.Mesh(lipsGeom, this.yellowMat);
this.lips.position.z = 165;
this.lips.position.y = -45;
// ear
this.rightEar = new THREE.Mesh(earGeom, this.yellowMat);
this.rightEar.position.x = -50;
this.rightEar.position.y = 50;
this.rightEar.position.z = 105;
this.leftEar = new THREE.Mesh(earGeom, this.yellowMat);
this.leftEar.position.x = 50;
this.leftEar.position.y = 50;
this.leftEar.position.z = 105;
// nose
this.nose = new THREE.Mesh(noseGeom, this.greyMat);
this.nose.position.z = 170;
this.nose.position.y = 25;
// head
this.head = new THREE.Group();
this.head.add(this.face);
this.head.add(this.mane);
this.head.add(this.rightEar);
this.head.add(this.leftEar);
this.head.add(this.nose);
this.head.add(this.leftEye);
this.head.add(this.rightEye);
this.head.add(this.leftIris);
this.head.add(this.rightIris);
this.head.add(this.mouth);
this.head.add(this.smile);
this.head.add(this.lips);
this.head.add(this.spot1);
this.head.add(this.spot2);
this.head.add(this.spot3);
this.head.add(this.spot4);
this.head.add(this.spot5);
this.head.add(this.spot6);
this.head.add(this.spot7);
this.head.add(this.spot8);
this.head.add(this.mustache1);
this.head.add(this.mustache2);
this.head.add(this.mustache3);
this.head.add(this.mustache4);
this.head.add(this.mustache5);
this.head.add(this.mustache6);
this.head.position.y = 60;
this.threegroup.add(this.body);
this.threegroup.add(this.head);
this.threegroup.add(this.leftKnee);
this.threegroup.add(this.rightKnee);
this.threegroup.add(this.backLeftFoot);
this.threegroup.add(this.backRightFoot);
this.threegroup.add(this.frontRightFoot);
this.threegroup.add(this.frontLeftFoot);
this.threegroup.traverse( function ( object ) {
if ( object instanceof THREE.Mesh ) {
object.castShadow = true;
object.receiveShadow = true;
}
} );
}
Lion.prototype.updateBody = function(speed){
this.head.rotation.y += (this.tHeagRotY - this.head.rotation.y) / speed;
this.head.rotation.x += (this.tHeadRotX - this.head.rotation.x) / speed;
this.head.position.x += (this.tHeadPosX-this.head.position.x) / speed;
this.head.position.y += (this.tHeadPosY-this.head.position.y) / speed;
this.head.position.z += (this.tHeadPosZ-this.head.position.z) / speed;
this.leftEye.scale.y += (this.tEyeScale - this.leftEye.scale.y) / (speed*2);
this.rightEye.scale.y = this.leftEye.scale.y;
this.leftIris.scale.y += (this.tIrisYScale - this.leftIris.scale.y) / (speed*2);
this.rightIris.scale.y = this.leftIris.scale.y;
this.leftIris.scale.z += (this.tIrisZScale - this.leftIris.scale.z) / (speed*2);
this.rightIris.scale.z = this.leftIris.scale.z;
this.leftIris.position.y += (this.tIrisPosY - this.leftIris.position.y) / speed;
this.rightIris.position.y = this.leftIris.position.y;
this.leftIris.position.z += (this.tLeftIrisPosZ - this.leftIris.position.z) / speed;
this.rightIris.position.z += (this.tRightIrisPosZ - this.rightIris.position.z) / speed;
this.rightKnee.rotation.z += (this.tRightKneeRotZ - this.rightKnee.rotation.z) / speed;
this.leftKnee.rotation.z += (this.tLeftKneeRotZ - this.leftKnee.rotation.z) / speed;
this.lips.position.x += (this.tLipsPosX - this.lips.position.x) / speed;
this.lips.position.y += (this.tLipsPosY - this.lips.position.y) / speed;
this.smile.position.x += (this.tSmilePosX - this.smile.position.x) / speed;
this.mouth.position.z += (this.tMouthPosZ - this.mouth.position.z) / speed;
this.smile.position.z += (this.tSmilePosZ - this.smile.position.z) / speed;
this.smile.position.y += (this.tSmilePosY - this.smile.position.y) / speed;
this.smile.rotation.z += (this.tSmileRotZ - this.smile.rotation.z) / speed;
}
Lion.prototype.look = function(xTarget, yTarget){
this.tHeagRotY = rule3(xTarget, -200, 200, -Math.PI/4, Math.PI/4);
this.tHeadRotX = rule3(yTarget, -200,200, -Math.PI/4, Math.PI/4);
this.tHeadPosX = rule3(xTarget, -200, 200, 70,-70);
this.tHeadPosY = rule3(yTarget, -140, 260, 20, 100);
this.tHeadPosZ = 0;
this.tEyeScale = 1;
this.tIrisYScale = 1;
this.tIrisZScale = 1;
this.tIrisPosY = rule3(yTarget, -200,200, 35,15);
this.tLeftIrisPosZ = rule3(xTarget, -200, 200, 130, 110);
this.tRightIrisPosZ = rule3(xTarget, -200, 200, 110, 130);
this.tLipsPosX = 0;
this.tLipsPosY = -45;
this.tSmilePosX = 0;
this.tMouthPosZ = 174;
this.tSmilePosZ = 173;
this.tSmilePosY = -15;
this.tSmileRotZ = -Math.PI;
this.tRightKneeRotZ = rule3(xTarget, -200, 200, .3-Math.PI/8, .3+Math.PI/8);
this.tLeftKneeRotZ = rule3(xTarget, -200, 200, -.3-Math.PI/8, -.3+Math.PI/8)
this.updateBody(10);
this.mane.rotation.y = 0;
this.mane.rotation.x = 0;
for (var i=0; i<this.maneParts.length; i++){
var m = this.maneParts[i].mesh;
m.position.z = 0;
m.rotation.y = 0;
}
for (var i=0; i<this.mustaches.length; i++){
var m = this.mustaches[i];
m.rotation.y = 0;
}
for (var i=0; i<this.bodyVertices.length; i++){
var tvInit = this.bodyInitPositions[i];
var tv = this.body.geometry.vertices[this.bodyVertices[i]];
tv.x = tvInit.x + this.head.position.x;
}
this.body.geometry.verticesNeedUpdate = true;
}
Lion.prototype.cool = function(xTarget, yTarget){
this.tHeagRotY = rule3(xTarget, -200, 200, Math.PI/4, -Math.PI/4);
this.tHeadRotX = rule3(yTarget, -200,200, Math.PI/4, -Math.PI/4);
this.tHeadPosX = rule3(xTarget, -200, 200, -70,70);
this.tHeadPosY = rule3(yTarget, -140, 260, 100, 20);
this.tHeadPosZ = 100;
this.tEyeScale = 0.1;
this.tIrisYScale = 0.1;
this.tIrisZScale = 3;
this.tIrisPosY = 20;
this.tLeftIrisPosZ = 120;
this.tRightIrisPosZ = 120;
this.tLipsPosX = rule3(xTarget, -200, 200, -15,15);
this.tLipsPosY = rule3(yTarget, -200, 200, -45,-40);
this.tMouthPosZ = 168;
this.tSmilePosX = rule3(xTarget, -200, 200, -15,15);
this.tSmilePosY = rule3(yTarget, -200, 200, -20,-8);
this.tSmilePosZ = 176;
this.tSmileRotZ = rule3(xTarget, -200, 200, -Math.PI-.3, -Math.PI+.3);
this.tRightKneeRotZ = rule3(xTarget, -200, 200, .3+Math.PI/8, .3-Math.PI/8);
this.tLeftKneeRotZ = rule3(xTarget, -200, 200, -.3+Math.PI/8, -.3-Math.PI/8);
this.updateBody(10);
this.mane.rotation.y = -.8*this.head.rotation.y;
this.mane.rotation.x = -.8*this.head.rotation.x;
var dt = 20000 / (xTarget*xTarget+yTarget*yTarget);
dt = Math.max(Math.min(dt,1), .5);
this.windTime += dt;
for (var i=0; i<this.maneParts.length; i++){
var m = this.maneParts[i].mesh;
var amp = this.maneParts[i].amp;
var zOffset = this.maneParts[i].zOffset;
var periodOffset = this.maneParts[i].periodOffset;
m.position.z = zOffset + Math.cos(this.windTime+periodOffset)*amp*dt*2;
}
this.leftEar.rotation.x = Math.cos(this.windTime)*Math.PI/16*dt;
this.rightEar.rotation.x = -Math.cos(this.windTime)*Math.PI/16*dt;
for (var i=0; i<this.mustaches.length; i++){
var m = this.mustaches[i];
var amp = (i<3) ? -Math.PI/8 : Math.PI/8;
m.rotation.y = amp + Math.cos(this.windTime + i)*dt*amp;
};
for (var i=0; i<this.bodyVertices.length; i++){
var tvInit = this.bodyInitPositions[i];
var tv = this.body.geometry.vertices[this.bodyVertices[i]];
tv.x = tvInit.x + this.head.position.x;
}
this.body.geometry.verticesNeedUpdate = true;
}
function loop(){
render();
var xTarget = (mousePos.x-windowHalfX);
var yTarget= (mousePos.y-windowHalfY);
fan.isBlowing = isBlowing;
fan.update(xTarget, yTarget);
if(isBlowing) {
lion.cool(xTarget, yTarget);
}else{
lion.look(xTarget, yTarget);
}
requestAnimationFrame(loop);
}
function render(){
if (controls) controls.update();
renderer.render(scene, camera);
}
init();
createLights();
createFloor();
createLion();
createFan();
loop();
function clamp(v,min, max){
return Math.min(Math.max(v, min), max);
}
function rule3(v,vmin,vmax,tmin, tmax){
var nv = Math.max(Math.min(v,vmax), vmin);
var dv = vmax-vmin;
var pc = (nv-vmin)/dv;
var dt = tmax-tmin;
var tv = tmin + (pc*dt);
return tv;
}

View File

@@ -0,0 +1,652 @@
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block
}
body {
line-height: 1
}
ol,
ul {
list-style: none
}
blockquote,
q {
quotes: none
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none
}
table {
border-collapse: collapse;
border-spacing: 0
}
@charset "UTF-8";
@import url("https://fonts.googleapis.com/css?family=Arvo");
* {
box-sizing: border-box;
}
a {
color: #1B9AAA;
text-decoration: none;
border-bottom: 1px solid currentColor;
}
a:hover {
color: #14727e;
}
a:focus,
a:active {
color: #0d4a52;
}
body,
html {
position: relative;
width: 100%;
height: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
font-family: "Arvo", Helvetica, sans-serif;
font-family: 12px;
color: #555;
background: #F8FFE5;
}
strong {
font-weight: bold;
}
p {
line-height: 1.6;
font-size: 16px;
}
@media screen and (max-width:400px) {
.haiyong{
font-size: 12px;
}
}
.inspired {
margin-top: 1em;
font-size: 0.9rem;
color: #9a9a95;
}
header {
color: #F8FFE5;
text-align: center;
}
header span {
display: inline-block;
box-sizing: border-box;
width: 4rem;
height: 4rem;
line-height: 4rem;
margin: 0 0.4rem;
background: #FFC43D;
}
@media screen and (max-width:440px) {
header span {
width: 3rem;
height: 3rem;
line-height: 3rem;
}
}
@media screen and (max-width:375px) {
header span {
width: 2.5rem;
height: 2.5rem;
line-height: 2.5rem;
}
}
header span:nth-of-type(2) {
background: #EF476F;
}
header span:nth-of-type(3) {
background: #1B9AAA;
}
header span:nth-of-type(4) {
background: #06D6A0;
}
h1 {
font-size: 2.2rem;
}
.directions {
padding: 2rem;
border-top: 1px solid #9a9a95;
border-bottom: 1px solid #9a9a95;
}
@media screen and (max-width:440px) {
.directions{
padding: 1rem;
}
}
.container {
margin: 0 auto;
padding-bottom: 3.5rem;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
width: 100%;
max-width: 550px;
text-align: center;
}
header .container {
padding: 0;
padding: 2rem 4rem;
max-width: 900px;
}
@media screen and (max-width:440px) {
header .container {
padding: 1rem 2rem;
}
}
.scores {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.score-container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin: 0.8rem;
font-size: 1.2rem;
line-height: 1;
color: #555;
}
.score-container.best-score {
color: #9a9a95;
}
.score {
margin-left: 1rem;
position: relative;
font-weight: bold;
font-size: 1.5rem;
vertical-align: middle;
text-align: right;
}
.game {
position: relative;
margin: 0 auto;
background: #9a9a95;
padding: 7px;
display: inline-block;
border-radius: 3px;
box-sizing: border-box;
}
.tile-container {
border-radius: 6px;
position: relative;
width: 270px;
height: 270px;
}
.tile,
.background {
display: block;
color: #F8FFE5;
position: absolute;
width: 67.5px;
height: 67.5px;
box-sizing: border-box;
text-align: center;
}
.background {
z-index: 1;
text-align: center;
border: 5px solid #9a9a95;
background-color: #F8FFE5;
}
.tile {
opacity: 0;
z-index: 2;
background: #FFC43D;
color: #F8FFE5;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
font-size: 1.8rem;
align-items: center;
-webkit-transition: 110ms ease-in-out;
transition: 110ms ease-in-out;
border-radius: 3px;
border: 7px solid #9a9a95;
box-sizing: border-box;
}
.tile--4 {
background: #EF476F;
color: #F8FFE5;
}
.tile--8 {
background: #1B9AAA;
color: #F8FFE5;
}
.tile--16 {
background: #06D6A0;
color: #F8FFE5;
}
.tile--32 {
background: #f37694;
color: #F8FFE5;
}
.tile--64 {
background: #22c2d6;
color: #F8FFE5;
}
.tile--128 {
background: #17f8be;
color: #F8FFE5;
}
.tile--256 {
background: #ffd470;
color: #F8FFE5;
}
.tile--512 {
background: #eb184a;
color: #F8FFE5;
}
.tile--1024 {
background: #14727e;
color: #F8FFE5;
}
.tile--2048 {
background: #05a47b;
color: #F8FFE5;
}
.tile--pop {
-webkit-animation: pop 0.3s ease-in-out;
animation: pop 0.3s ease-in-out;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.tile--shrink {
-webkit-animation: shrink 0.5s ease-in-out;
animation: shrink 0.5s ease-in-out;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.add {
position: absolute;
opacity: 0;
left: 120%;
top: 0;
font-size: 1rem;
color: #1B9AAA;
}
.add.active {
-webkit-animation: add 0.8s ease-in-out;
animation: add 0.8s ease-in-out;
}
@-webkit-keyframes add {
0% {
opacity: 1;
top: 0;
}
100% {
opacity: 0;
top: -100%;
}
}
@keyframes add {
0% {
opacity: 1;
top: 0;
}
100% {
opacity: 0;
top: -100%;
}
}
@-webkit-keyframes pop {
0% {
-webkit-transform: scale(0.5);
transform: scale(0.5);
opacity: 0;
}
90% {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: 1;
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
}
@keyframes pop {
0% {
-webkit-transform: scale(0.5);
transform: scale(0.5);
opacity: 0;
}
90% {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: 1;
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
}
@-webkit-keyframes shrink {
0% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
100% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
opacity: 0.9;
}
}
@keyframes shrink {
0% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
100% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
opacity: 0.9;
}
}
.end {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background: rgba(85, 85, 85, 0.9);
color: white;
font-size: 2rem;
-webkit-transition: opacity 0.3s ease-in-out;
transition: opacity 0.3s ease-in-out;
}
.end btn {
margin-top: 1rem;
}
.end.active {
opacity: 1;
z-index: 1000;
}
.monkey {
font-size: 3rem;
margin: 1rem 0;
}
.btn {
font-family: inherit;
font-size: 1rem;
border: none;
background: #1B9AAA;
letter-spacing: 1px;
color: white;
font-weight: 300;
padding: 0.9em 1.5em;
border-radius: 3px;
border: 1px solid transparent;
cursor: pointer;
}
.btn:hover {
background-color: #14727e;
}
.btn:active {
background-color: #0d4a52;
}
.btn:focus {
box-shadow: 0 0 10px #0d4a52 inset;
outline: none;
}
.not-recommended {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin-top: 0.8rem;
}
.not-recommended *+* {
margin-left: 10px;
}
.not-recommended__item+.not-recommended__annotation:before {
font-size: 30px;
content: "😐";
}
.not-recommended__item:hover+.not-recommended__annotation:before {
content: "😟";
}
.not-recommended__item:focus+.not-recommended__annotation:before {
content: "😄";
}
.not-recommended__item:active+.not-recommended__annotation:before {
content: "😨";
}
footer {
background-color: #158ca5;
bottom: 0;
box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.5);
color: white;
display: flex;
justify-content: space-around;
left: 0;
padding: 15px;
position: fixed;
right: 0;
}
footer a {
color: white;
}
footer .center {
justify-content: center;
}

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=0">
<title>海拥 | 2048</title>
<meta name="keywords" content="游戏" />
<meta name="description" content="游戏 | 2048小游戏;立志打造一个拥有100个小游戏的摸鱼网站。Made By Haiyong技术支持——海拥" />
<meta name="author" content="海拥(http://haiyong.site/game)" />
<meta name="copyright" content="海拥(http://haiyong.site/game)" />
<link rel="icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg" sizes="192x192" />
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<header>
<div class="container">
<h1><span>2</span><span>0</span><span>4</span><span>8</span></h1>
<p class="inspired">by the 原2048的灵感</p>
</div>
</header>
<div class="container">
<div class="directions">
<p id="haiyong" class="haiyong"><strong>如何玩:</strong> 使用鼠标方向键键移动数字方块。相邻的两个方块数字相同,它们可合并成一个!</p>
</div>
<div class="scores">
<div class="score-container best-score">
历史最高
<div class="score">
<div id="bestScore">0</div>
</div>
</div>
<div class="score-container">
分数:
<div class="score">
<div id="score">0</div>
<div class="add" id="add"></div>
</div>
</div>
</div>
<div class="game">
<div id="tile-container" class="tile-container"></div>
<div class="end" id="end">游戏结束<div class="monkey">🙈</div><button class="btn not-recommended__item js-restart-btn"
id="try-again">再试一次</button></div>
</div>
<div class="not-recommended">
<button class="btn not-recommended__item js-restart-btn" id="restart">重新启动游戏</button>
<span class="not-recommended__annotation"></span>
</div>
<footer>
<span class="author">Created by <a href="http://haiyong.site/index">Haiyong</a></span>
<span class="center">2048</span>
<span class="opposite">友链:<a href="https://www.captainai.net/haiyong">人工智能学习</a></span>
</footer>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -0,0 +1,453 @@
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var game = null;
var bestScore = 0;
var scoreDiv = document.getElementById('score');
var bestScoreDiv = document.getElementById('bestScore');
var addDiv = document.getElementById('add');
var endDiv = document.getElementById('end');
var size = 4;
var nextId = 1;
var score = 0;
function initGame() {
game = Array(size * size).fill(null); // 4 x 4 grid, represented as an array
initBestScore();
}
function initBestScore() {
bestScore = localStorage.getItem('bestScore') || 0;
bestScoreDiv.innerHTML = bestScore;
}
function updateDOM(before, after) {
var newElements = getNewElementsDOM(before, after);
var existingElements = getExistingElementsDOM(before, after);
var mergedTiles = getMergedTiles(after);
removeElements(mergedTiles);
drawGame(newElements, true);
drawGame(existingElements);
}
function removeElements(mergedTiles) {
for (var _iterator = mergedTiles, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var tile = _ref;
var _loop = function _loop() {
if (_isArray2) {
if (_i2 >= _iterator2.length) return 'break';
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) return 'break';
_ref2 = _i2.value;
}
var id = _ref2;
var currentElm = document.getElementById(id);
positionTile(tile, currentElm);
currentElm.classList.add('tile--shrink');
setTimeout(function () {
currentElm.remove();
}, 100);
};
for (var _iterator2 = tile.mergedIds, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
var _ret = _loop();
if (_ret === 'break') break;
}
}
}
function getMergedTiles(after) {
return after.filter(function (tile) {
return tile && tile.mergedIds;
});
}
function getNewElementsDOM(before, after) {
var beforeIds = before.filter(function (tile) {
return tile;
}).map(function (tile) {
return tile.id;
});
var newElements = after.filter(function (tile) {
return tile && beforeIds.indexOf(tile.id) === -1;
});
return newElements;
}
function getExistingElementsDOM(before, after) {
var beforeIds = before.filter(function (tile) {
return tile;
}).map(function (tile) {
return tile.id;
});
var existingElements = after.filter(function (tile) {
return tile && beforeIds.indexOf(tile.id) !== -1;
});
return existingElements;
}
function drawBackground() {
var tileContainer = document.getElementById('tile-container');
tileContainer.innerHTML = '';
for (var i = 0; i < game.length; i++) {
var tile = game[i];
var tileDiv = document.createElement('div');
var x = i % size;
var y = Math.floor(i / size);
tileDiv.style.top = y * 67.5 + 'px';
tileDiv.style.left = x * 67.5 + 'px';
tileDiv.classList.add("background");
tileContainer.appendChild(tileDiv);
}
}
function positionTile(tile, elm) {
var x = tile.index % size;
var y = Math.floor(tile.index / size);
elm.style.top = y * 67.5 + 'px';
elm.style.left = x * 67.5 + 'px';
}
function drawGame(tiles, isNew) {
var tileContainer = document.getElementById('tile-container');
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile) {
if (isNew) {
(function () {
var tileDiv = document.createElement('div');
positionTile(tile, tileDiv);
tileDiv.classList.add('tile', 'tile--' + tile.value);
tileDiv.id = tile.id;
setTimeout(function () {
tileDiv.classList.add("tile--pop");
}, tile.mergedIds ? 1 : 150);
tileDiv.innerHTML = '<p>' + tile.value + '</p>';
tileContainer.appendChild(tileDiv);
})();
} else {
var currentElement = document.getElementById(tile.id);
positionTile(tile, currentElement);
}
}
}
}
function gameOver() {
if (game.filter(function (number) {
return number === null;
}).length === 0) {
var sameNeighbors = game.find(function (tile, i) {
var isRightSame = game[i + 1] && (i + 1) % 4 !== 0 ? tile.value === game[i + 1].value : false;
var isDownSame = game[i + 4] ? tile.value === game[i + 4].value : false;
if (isRightSame || isDownSame) {
return true;
}
return false;
});
return !sameNeighbors;
}
}
function generateNewNumber() {
// 0.9 probability of 2, 0.1 probability of 4
var p = Math.random() * 100;
return p <= 90 ? 2 : 4;
}
function addRandomNumber() {
// Adds either a 2 or a 4 to an empty position in the game array
var emptyCells = game.map(function (_, index) {
return index;
}).filter(function (index) {
return game[index] === null;
});
if (emptyCells.length === 0) {
return;
}
var newPos = emptyCells[Math.floor(Math.random() * emptyCells.length)];
var newObj = {
id: nextId++,
index: newPos,
value: generateNewNumber()
};
game.splice(newPos, 1, newObj);
}
function getIndexForPoint(x, y) {
return y * size + x;
}
function reflectGrid(grid) {
var reflectedGame = Array(size * size).fill(0);
for (var row = 0; row < size; row++) {
for (var col = 0; col < size; col++) {
var index1 = getIndexForPoint(col, row);
var index2 = getIndexForPoint(size - col - 1, row);
reflectedGame[index1] = grid[index2];
}
}
return reflectedGame;
}
function rotateLeft90Deg(grid) {
var rotatedGame = Array(size * size).fill(0);
for (var row = 0; row < size; row++) {
for (var col = 0; col < size; col++) {
var index1 = getIndexForPoint(col, row);
var index2 = getIndexForPoint(size - 1 - row, col);
rotatedGame[index1] = grid[index2];
}
}
return rotatedGame;
}
function rotateRight90Deg(grid) {
var rotatedGame = Array(size * size).fill(0);
for (var row = 0; row < size; row++) {
for (var col = 0; col < size; col++) {
var index1 = getIndexForPoint(col, row);
var index2 = getIndexForPoint(row, size - 1 - col);
rotatedGame[index1] = grid[index2];
}
}
return rotatedGame;
}
/*
For any cell whose neighbor to the right is empty, move that cell
to the right. For any cell whose neighbor to the right is equal
to the same value, combine the values together (e.g. 2+2 = 4)
*/
function shiftGameRight(gameGrid) {
// reflect game grid
var reflectedGame = reflectGrid(gameGrid);
// shift left
reflectedGame = shiftGameLeft(reflectedGame);
// reflect back
return reflectGrid(reflectedGame);
}
function shiftGameLeft(gameGrid) {
var newGameState = [];
var totalAdd = 0;
// for rows
for (var i = 0; i < size; i++) {
// for columns
var firstPos = 4 * i;
var lastPos = size + 4 * i;
var currentRow = gameGrid.slice(firstPos, lastPos);
var filteredRow = currentRow.filter(function (row) {
return row;
});
for (var _iterator3 = filteredRow, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref3 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref3 = _i3.value;
}
var row = _ref3;
delete row.mergedIds;
}
for (var j = 0; j < filteredRow.length - 1; j++) {
if (filteredRow[j].value === filteredRow[j + 1].value) {
var sum = filteredRow[j].value * 2;
filteredRow[j] = {
id: nextId++,
mergedIds: [filteredRow[j].id, filteredRow[j + 1].id],
value: sum
};
filteredRow.splice(j + 1, 1);
score += sum;
totalAdd += sum;
}
}
while (filteredRow.length < size) {
filteredRow.push(null);
};
newGameState = [].concat(newGameState, filteredRow);
}
if (totalAdd > 0) {
scoreDiv.innerHTML = score;
addDiv.innerHTML = '+' + totalAdd;
addDiv.classList.add('active');
setTimeout(function () {
addDiv.classList.remove("active");
}, 800);
if (score > bestScore) {
localStorage.setItem('bestScore', score);
initBestScore();
}
}
return newGameState;
}
function shiftGameUp(gameGrid) {
var rotatedGame = rotateLeft90Deg(gameGrid);
rotatedGame = shiftGameLeft(rotatedGame);
return rotateRight90Deg(rotatedGame);
}
function shiftGameDown(gameGrid) {
var rotatedGame = rotateRight90Deg(gameGrid);
rotatedGame = shiftGameLeft(rotatedGame);
return rotateLeft90Deg(rotatedGame);
}
var buttons = document.querySelectorAll(".js-restart-btn");
var length = buttons.length;
for (var i = 0; i < length; i++) {
if (document.addEventListener) {
buttons[i].addEventListener("click", function () {
newGameStart();
});
} else {
buttons[i].attachEvent("onclick", function () {
newGameStart();
});
};
};
document.addEventListener("keydown", handleKeypress);
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function handleTouchStart(evt) {
xDown = evt.touches[0].clientX;
yDown = evt.touches[0].clientY;
};
function handleTouchMove(evt) {
var prevGame = [].concat(game);
if (!xDown || !yDown) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if (Math.abs(xDiff) > Math.abs(yDiff)) {
if (xDiff > 0) {
game = shiftGameLeft(game);
} else {
game = shiftGameRight(game);
}
} else {
if (yDiff > 0) {
game = shiftGameUp(game);
} else {
game = shiftGameDown(game);
}
}
game = game.map(function (tile, index) {
if (tile) {
return _extends({}, tile, {
index: index
});
} else {
return null;
}
});
addRandomNumber();
updateDOM(prevGame, game);
if (gameOver()) {
setTimeout(function () {
endDiv.classList.add('active');
}, 800);
return;
}
xDown = null;
yDown = null;
};
function handleKeypress(evt) {
var modifiers = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
var whichKey = event.which;
var prevGame = [].concat(game);
if (!modifiers) {
event.preventDefault();
switch (whichKey) {
case 37:
game = shiftGameLeft(game);
break;
case 38:
game = shiftGameUp(game);
break;
case 39:
game = shiftGameRight(game);
break;
case 40:
game = shiftGameDown(game);
break;
}
game = game.map(function (tile, index) {
if (tile) {
return _extends({}, tile, {
index: index
});
} else {
return null;
}
});
addRandomNumber();
updateDOM(prevGame, game);
if (gameOver()) {
setTimeout(function () {
endDiv.classList.add('active');
}, 800);
return;
}
}
}
function newGameStart() {
document.getElementById('tile-container').innerHTML = '';
endDiv.classList.remove('active');
score = 0;
scoreDiv.innerHTML = score;
initGame();
drawBackground();
var previousGame = [].concat(game);
addRandomNumber();
addRandomNumber();
updateDOM(previousGame, game);
}
newGameStart();

View File

@@ -0,0 +1,5 @@
*{margin:0px;padding:0px; font-family: "微软雅黑";}
html,iframe,body{height:100%}
.none{display:none !important}
@media screen and (max-width: 640px){#mobileFrame{display:none !important;}}
#hidemobile{font-size: 14px;font-weight: bold;border: 1px solid silver;position: absolute;right: 20px;top: 8px;width: 15px;height: 15px;text-align: center;padding: 0;line-height: 15px;border-radius: 15px;cursor:pointer;}

View File

@@ -0,0 +1,24 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<title>海拥 | 飞机躲避障碍</title>
<link rel="icon" type="image/x-icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg"/>
<link rel="stylesheet" href="css/style.css">
<script src="js/script.js"></script>
</head>
<body>
<iframe src="https://www.jsdaima.com/Uploads/js/201804/1523085687/index.html" frameborder="0" width="100%" height="100%"></iframe>
</body>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</html>

View File

@@ -0,0 +1,7 @@
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();

View File

@@ -0,0 +1,54 @@
html,
body {
height: 100%;
margin: 0;
}
body {
font-family: Arial, Verdana, sans-serif;
cursor: grab;
display: flex;
justify-content: center;
align-items: center;
color: white;
background-color: #1e1a33;
}
div,
i {
user-select: none;
pointer-events: none;
}
i {
position: fixed;
color: white;
top: -10%;
z-index: 9999;
animation-name: snowflakes-fall, snowflakes-shake;
animation-duration: 10s, 3s;
animation-timing-function: linear, ease-in-out;
animation-iteration-count: infinite, infinite;
animation-play-state: running, running;
}
@keyframes snowflakes-fall {
0% {
top: -10%;
}
100% {
top: 100%;
}
}
@keyframes snowflakes-shake {
0% {
transform: translateX(0px);
}
50% {
transform: translateX(80px);
}
100% {
transform: translateX(0px);
}
}

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>海拥 | 圣诞老人过桥</title>
<link rel="icon" type="image/x-icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg"/>
<link rel="stylesheet" href="https://demo.mycodes.net/html5/guoxuanya/css/style.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script src="js/script.js"></script>
<script type="module">
import { quotes } from "http://haiyong.site/wp-includes/js/quotes.js";
let randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
console.log(
`%c✨ ${randomQuote}`,
"font-size:20px; background:#FFF; color:#581845;padding:10px; border: 3px solid #581845;border-radius:10px;"
);</script>
<div style="text-align:center;">
</div>
</body>
</html>

View File

@@ -0,0 +1,655 @@
let status = "waiting";
let lastTimestamp;
let santaX;
let santaY;
let sceneOffset;
let score = 0;
let platforms = [];
let sticks = [];
let trees = [];
let clouds = [];
const config = {
canvasWidth: 375,
canvasHeight: 375,
platformHeight: 100,
santaDistanceFromEdge: 10,
paddingX: 100,
perfectAreaSize: 10,
backgroundSpeedMultiplier: 0.2,
speed: 4,
santaWidth: 17,
santaHeight: 30
};
const colours = {
lightBg: "#62AFB9",
medBg: "#182757",
darkBg: "#0D5B66",
lightHill: "#E9E9E9",
medHill: "#34A65F",
darkHill: "#07133A",
platform: "#9B4546",
platformTop: "#620E0E",
em: "#CC231E",
skin: "#CF6D60"
};
const hills = [
{
baseHeight: 120,
amplitude: 20,
stretch: 0.5,
colour: colours.lightHill
},
{
baseHeight: 100,
amplitude: 10,
stretch: 1,
colour: colours.medHill
},
{
baseHeight: 70,
amplitude: 20,
stretch: 0.5,
colour: colours.darkHill
}
];
const scoreElement = createElementStyle(
"div",
`position:absolute;top:1.5em;font-size:5em;font-weight:900;text-shadow:${addShadow(
colours.darkHill,
7
)}`
);
const canvas = createElementStyle("canvas");
const introductionElement = createElementStyle(
"div",
`font-size:1.2em;position:absolute;text-align:center;transition:opacity 2s;width:250px`,
"按住任意位置以伸出杆子,确定好他的长度,否则圣诞老人会掉下来"
);
const perfectElement = createElementStyle(
"div",
"position:absolute;opacity:0;transition:opacity 2s",
"双倍分数"
);
const restartButton = createElementStyle(
"button",
`width:120px;height:120px;position:absolute;border-radius:50%;color:white;background-color:${colours.em};border:none;font-weight:700;font-size:1.2em;display:none;cursor:pointer`,
"重新开始"
);
for (let i = 0; i <= 30; i++) {
createElementStyle(
"i",
`font-size: ${3 * Math.random()}em;left: ${
100 * Math.random()
}%; animation-delay: ${10 * Math.random()}s, ${2 * Math.random()}s`,
"."
);
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
Array.prototype.last = function () {
return this[this.length - 1];
};
Math.sinus = function (degree) {
return Math.sin((degree / 180) * Math.PI);
};
window.addEventListener("keydown", function (event) {
if (event.key == " ") {
event.preventDefault();
resetGame();
return;
}
});
["mousedown", "touchstart"].forEach(function (evt) {
window.addEventListener(evt, function (event) {
if (status == "waiting") {
lastTimestamp = undefined;
introductionElement.style.opacity = 0;
status = "stretching";
window.requestAnimationFrame(animate);
}
});
});
["mouseup", "touchend"].forEach(function (evt) {
window.addEventListener(evt, function (event) {
if (status == "stretching") {
status = "turning";
}
});
});
window.addEventListener("resize", function (event) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
draw();
});
restartButton.addEventListener("click", function (event) {
event.preventDefault();
resetGame();
restartButton.style.display = "none";
});
window.requestAnimationFrame(animate);
resetGame();
function resetGame() {
status = "waiting";
lastTimestamp = undefined;
sceneOffset = 0;
score = 0;
introductionElement.style.opacity = 1;
perfectElement.style.opacity = 0;
restartButton.style.display = "none";
scoreElement.innerText = score;
platforms = [{ x: 50, w: 50 }];
santaX = platforms[0].x + platforms[0].w - config.santaDistanceFromEdge;
santaY = 0;
sticks = [{ x: platforms[0].x + platforms[0].w, length: 0, rotation: 0 }];
trees = [];
clouds = [];
for (let i = 0; i <= 20; i++) {
if (i <= 3) generatePlatform();
generateTree();
generateCloud();
}
draw();
}
function generateCloud() {
const minimumGap = 60;
const maximumGap = 300;
const lastCloud = clouds[clouds.length - 1];
let furthestX = lastCloud ? lastCloud.x : 0;
const x =
furthestX +
minimumGap +
Math.floor(Math.random() * (maximumGap - minimumGap));
const y =
minimumGap +
Math.floor(Math.random() * (maximumGap - minimumGap)) -
window.innerHeight / 1.2;
const w = Math.floor(Math.random() * 15 + 15);
clouds.push({ x, y, w });
}
function generateTree() {
const minimumGap = 30;
const maximumGap = 150;
const lastTree = trees[trees.length - 1];
let furthestX = lastTree ? lastTree.x : 0;
const x =
furthestX +
minimumGap +
Math.floor(Math.random() * (maximumGap - minimumGap));
const treeColors = [colours.lightHill, colours.medBg, colours.medHill];
const color = treeColors[Math.floor(Math.random() * 3)];
trees.push({ x, color });
}
function generatePlatform() {
const minimumGap = 40;
const maximumGap = 200;
const minimumWidth = 20;
const maximumWidth = 100;
const lastPlatform = platforms[platforms.length - 1];
let furthestX = lastPlatform.x + lastPlatform.w;
const x =
furthestX +
minimumGap +
Math.floor(Math.random() * (maximumGap - minimumGap));
const w =
minimumWidth + Math.floor(Math.random() * (maximumWidth - minimumWidth));
platforms.push({ x, w });
}
function animate(timestamp) {
if (!lastTimestamp) {
lastTimestamp = timestamp;
window.requestAnimationFrame(animate);
return;
}
switch (status) {
case "waiting":
return;
case "stretching": {
sticks.last().length += (timestamp - lastTimestamp) / config.speed;
break;
}
case "turning": {
sticks.last().rotation += (timestamp - lastTimestamp) / config.speed;
if (sticks.last().rotation > 90) {
sticks.last().rotation = 90;
const [nextPlatform, perfectHit] = thePlatformTheStickHits();
if (nextPlatform) {
score += perfectHit ? 2 : 1;
scoreElement.innerText = score;
if (perfectHit) {
perfectElement.style.opacity = 1;
setTimeout(() => (perfectElement.style.opacity = 0), 1000);
}
generatePlatform();
generateTree();
generateTree();
generateCloud();
generateCloud();
}
status = "walking";
}
break;
}
case "walking": {
santaX += (timestamp - lastTimestamp) / config.speed;
const [nextPlatform] = thePlatformTheStickHits();
if (nextPlatform) {
const maxSantaX =
nextPlatform.x + nextPlatform.w - config.santaDistanceFromEdge;
if (santaX > maxSantaX) {
santaX = maxSantaX;
status = "transitioning";
}
} else {
const maxSantaX =
sticks.last().x + sticks.last().length + config.santaWidth;
if (santaX > maxSantaX) {
santaX = maxSantaX;
status = "falling";
}
}
break;
}
case "transitioning": {
sceneOffset += (timestamp - lastTimestamp) / (config.speed / 2);
const [nextPlatform] = thePlatformTheStickHits();
if (sceneOffset > nextPlatform.x + nextPlatform.w - config.paddingX) {
sticks.push({
x: nextPlatform.x + nextPlatform.w,
length: 0,
rotation: 0
});
status = "waiting";
}
break;
}
case "falling": {
if (sticks.last().rotation < 180)
sticks.last().rotation += (timestamp - lastTimestamp) / config.speed;
santaY += (timestamp - lastTimestamp) / (config.speed / 2);
const maxSantaY =
config.platformHeight +
100 +
(window.innerHeight - config.canvasHeight) / 2;
if (santaY > maxSantaY) {
restartButton.style.display = "block";
return;
}
break;
}
default:
throw Error("Wrong status");
}
draw();
window.requestAnimationFrame(animate);
lastTimestamp = timestamp;
}
function thePlatformTheStickHits() {
if (sticks.last().rotation != 90)
throw Error(`Stick is ${sticks.last().rotation}°`);
const stickFarX = sticks.last().x + sticks.last().length;
const platformTheStickHits = platforms.find(
(platform) => platform.x < stickFarX && stickFarX < platform.x + platform.w
);
if (
platformTheStickHits &&
platformTheStickHits.x +
platformTheStickHits.w / 2 -
config.perfectAreaSize / 2 <
stickFarX &&
stickFarX <
platformTheStickHits.x +
platformTheStickHits.w / 2 +
config.perfectAreaSize / 2
)
return [platformTheStickHits, true];
return [platformTheStickHits, false];
}
function draw() {
ctx.save();
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
drawBackground();
ctx.translate(
(window.innerWidth - config.canvasWidth) / 2 - sceneOffset,
(window.innerHeight - config.canvasHeight) / 2
);
drawPlatforms();
drawSanta();
drawSticks();
ctx.restore();
}
function drawPlatforms() {
platforms.forEach(({ x, w }) => {
let newX = x + 3;
let newW = w - 6;
let platformHeight =
config.platformHeight + (window.innerHeight - config.canvasHeight) / 2;
ctx.fillStyle = colours.platform;
ctx.fillRect(
newX,
config.canvasHeight - config.platformHeight,
newW,
platformHeight
);
for (let i = 1; i <= platformHeight / 10; ++i) {
let yGap = config.canvasHeight - config.platformHeight + i * 10;
ctx.moveTo(newX, yGap);
ctx.lineTo(newX + newW, yGap);
let xGap = i % 2 ? 0 : 10;
for (let j = 1; j < newW / 30; ++j) {
let x = j * 20 + xGap;
ctx.moveTo(newX + x, yGap);
ctx.lineTo(newX + x, yGap + 10);
}
ctx.strokeStyle = colours.platformTop;
ctx.stroke();
}
ctx.fillStyle = colours.platformTop;
ctx.fillRect(x, config.canvasHeight - config.platformHeight, w, 10);
if (sticks.last().x < x) {
ctx.fillStyle = "white";
ctx.fillRect(
x + w / 2 - config.perfectAreaSize / 2,
config.canvasHeight - config.platformHeight,
config.perfectAreaSize,
config.perfectAreaSize
);
}
});
}
function drawSanta() {
ctx.save();
ctx.fillStyle = "red";
ctx.translate(
santaX - config.santaWidth / 2,
santaY +
config.canvasHeight -
config.platformHeight -
config.santaHeight / 2
);
ctx.fillRect(
-config.santaWidth / 2,
-config.santaHeight / 2,
config.santaWidth,
config.santaHeight - 4
);
const legDistance = 5;
ctx.beginPath();
ctx.arc(legDistance, 11.5, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.beginPath();
ctx.arc(-legDistance, 11.5, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = colours.skin;
ctx.arc(5, -7, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "white";
ctx.arc(7, -2, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "red";
ctx.moveTo(-8, -13.5);
ctx.lineTo(-15, -3.5);
ctx.lineTo(-5, -7);
ctx.fill();
ctx.fillStyle = "white";
ctx.fillRect(-config.santaWidth / 2, -12, config.santaWidth, 3);
ctx.fillStyle = "black";
ctx.fillRect(-config.santaWidth / 2, 2, config.santaWidth, 2);
ctx.fillStyle = "white";
ctx.fillRect(-config.santaWidth / 2, 4, config.santaWidth, 4.5);
ctx.beginPath();
ctx.fillStyle = "white";
ctx.arc(-17, -2, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.restore();
}
function drawSticks() {
sticks.forEach((stick) => {
ctx.save();
ctx.translate(stick.x, config.canvasHeight - config.platformHeight);
ctx.rotate((Math.PI / 180) * stick.rotation);
ctx.beginPath();
ctx.lineWidth = 4;
ctx.moveTo(0, 0);
ctx.lineTo(0, -stick.length);
ctx.strokeStyle = ctx.createPattern(createCandyPattern(), "repeat");
ctx.stroke();
ctx.restore();
});
}
function drawBackground() {
var gradient = ctx.createRadialGradient(
window.innerWidth / 2,
window.innerHeight / 2,
0,
window.innerHeight / 2,
window.innerWidth / 2,
window.innerWidth
);
gradient.addColorStop(0, colours.lightBg);
gradient.addColorStop(1, colours.darkBg);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, window.innerWidth, window.innerHeight);
hills.forEach((hill) =>
drawHill(hill.baseHeight, hill.amplitude, hill.stretch, hill.colour)
);
trees.forEach((tree) => drawTree(tree.x, tree.color));
clouds.forEach((cloud) => drawCloud(cloud.x, cloud.y, cloud.w));
}
function drawHill(baseHeight, amplitude, stretch, color) {
ctx.beginPath();
ctx.moveTo(0, window.innerHeight);
ctx.lineTo(0, getHillY(0, baseHeight, amplitude, stretch));
for (let i = 0; i < window.innerWidth; i++) {
ctx.lineTo(i, getHillY(i, baseHeight, amplitude, stretch));
}
ctx.lineTo(window.innerWidth, window.innerHeight);
ctx.fillStyle = color;
ctx.fill();
}
function drawTree(x, color) {
ctx.save();
ctx.translate(
(-sceneOffset * config.backgroundSpeedMultiplier + x) * hills[1].stretch,
getTreeY(x, hills[1].baseHeight, hills[1].amplitude)
);
const treeTrunkHeight = 15;
const treeTrunkWidth = 10;
const treeCrownHeight = 60;
const treeCrownWidth = 30;
// Draw trunk
ctx.fillStyle = colours.darkHill;
ctx.fillRect(
-treeTrunkWidth / 2,
-treeTrunkHeight,
treeTrunkWidth,
treeTrunkHeight
);
// Draw crown
ctx.beginPath();
ctx.moveTo(-treeCrownWidth / 2, -treeTrunkHeight * 3);
ctx.lineTo(0, -(treeTrunkHeight + treeCrownHeight));
ctx.lineTo(treeCrownWidth / 2, -treeTrunkHeight * 3);
ctx.moveTo(-treeCrownWidth / 2, -treeTrunkHeight * 2);
ctx.lineTo(0, -(treeTrunkHeight / 2 + treeCrownHeight));
ctx.lineTo(treeCrownWidth / 2, -treeTrunkHeight * 2);
ctx.moveTo(-treeCrownWidth / 2, -treeTrunkHeight);
ctx.lineTo(0, -(treeTrunkHeight + treeCrownHeight / 2));
ctx.lineTo(treeCrownWidth / 2, -treeTrunkHeight);
ctx.fillStyle = color;
ctx.fill();
ctx.restore();
}
function drawCloud(x, y, width) {
ctx.save();
ctx.translate(
(-sceneOffset * config.backgroundSpeedMultiplier + x) * hills[1].stretch,
getTreeY(x, hills[1].baseHeight, hills[1].amplitude)
);
height = width * 1.5;
ctx.beginPath();
ctx.arc(x, y, width, Math.PI * 0.5, Math.PI * 1.5);
ctx.arc(x + height, y - width, height, Math.PI * 1, Math.PI * 2);
ctx.arc(x + height * 2, y - width, height, Math.PI * 1.2, Math.PI);
ctx.arc(x + width * 3, y, width, Math.PI * 1.5, Math.PI * 0.5);
ctx.moveTo(x + width * 3, y + width);
ctx.lineTo(x, y + width);
ctx.fillStyle = "rgba(255, 255, 255, .3)";
ctx.fill();
ctx.restore();
}
function createCandyPattern() {
const patternCanvas = document.createElement("canvas");
const pctx = patternCanvas.getContext("2d");
const max = 15;
let i = 0;
let x = 0;
let z = 90;
while (i < max) {
pctx.beginPath();
pctx.moveTo(0, x);
pctx.lineTo(0, z);
pctx.lineWidth = 24;
pctx.strokeStyle = "red";
pctx.stroke();
pctx.beginPath();
pctx.moveTo(0, x + 24);
pctx.lineTo(0, z + 24);
pctx.lineWidth = 24;
pctx.strokeStyle = "white";
pctx.stroke();
x += 48;
z += 48;
i++;
}
return patternCanvas;
}
function getHillY(windowX, baseHeight, amplitude, stretch) {
const sineBaseY = window.innerHeight - baseHeight;
return (
Math.sinus(
(sceneOffset * config.backgroundSpeedMultiplier + windowX) * stretch
) *
amplitude +
sineBaseY
);
}
function getTreeY(x, baseHeight, amplitude) {
const sineBaseY = window.innerHeight - baseHeight;
return Math.sinus(x) * amplitude + sineBaseY;
}
function createElementStyle(element, cssStyles = null, inner = null) {
const g = document.createElement(element);
if (cssStyles) g.style.cssText = cssStyles;
if (inner) g.innerHTML = inner;
document.body.appendChild(g);
return g;
}
function addShadow(colour, depth) {
let shadow = "";
for (let i = 0; i <= depth; i++) {
shadow += `${i}px ${i}px 0 ${colour}`;
shadow += i < depth ? ", " : "";
}
return shadow;
}

View File

@@ -0,0 +1,267 @@
body {
margin: 0;
background-color: #000;
background-image: radial-gradient(ellipse at top, #335476 0.0%, #31506e 11.1%, #304b67 22.2%, #2f4760 33.3%, #2d4359 44.4%, #2c3f51 55.6%, #2a3a4a 66.7%, #293643 77.8%, #28323d 88.9%, #262e36 100.0%);
height: 100vh;
overflow: hidden;
font-family: monospace;
font-weight: bold;
letter-spacing: 0.06em;
color: rgba(255, 255, 255, 0.75);
}
#c {
display: block;
touch-action: none;
transform: translateZ(0);
}
/*/////////////////////
// HUD //
/////////////////////*/
.hud__score,
.pause-btn {
position: fixed;
font-size: calc(14px + 2vw + 1vh);
}
.hud__score {
top: 0.65em;
left: 0.65em;
pointer-events: none;
user-select: none;
}
.cube-count-lbl {
font-size: 0.46em;
}
.pause-btn {
position: fixed;
top: 0;
right: 0;
padding: 0.8em 0.65em;
}
.pause-btn > div {
position: relative;
width: 0.8em;
height: 0.8em;
opacity: 0.75;
}
.pause-btn > div::before,
.pause-btn > div::after {
content: '';
display: block;
width: 34%;
height: 100%;
position: absolute;
background-color: #fff;
}
.pause-btn > div::after {
right: 0;
}
.slowmo {
position: fixed;
bottom: 0;
width: 100%;
pointer-events: none;
opacity: 0;
transition: opacity 0.4s;
will-change: opacity;
}
.slowmo::before {
content: 'SLOW-MO';
display: block;
font-size: calc(8px + 1vw + 0.5vh);
margin-left: 0.5em;
margin-bottom: 8px;
}
.slowmo::after {
content: '';
display: block;
position: fixed;
bottom: 0;
width: 100%;
height: 1.5vh;
background-color: rgba(0, 0, 0, 0.25);
z-index: -1;
}
.slowmo__bar {
height: 1.5vh;
background-color: rgba(255, 255, 255, 0.75);
transform-origin: 0 0;
}
/*/////////////////////
// MENUS //
/////////////////////*/
.menus::before {
content: '';
pointer-events: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000;
opacity: 0;
transition: opacity 0.2s;
transition-timing-function: ease-in;
}
.menus.has-active::before {
opacity: 0.08;
transition-duration: 0.4s;
transition-timing-function: ease-out;
}
.menus.interactive-mode::before {
opacity: 0.02;
}
/* Menu containers */
.menu {
pointer-events: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
user-select: none;
text-align: center;
color: rgba(255, 255, 255, 0.9);
opacity: 0;
visibility: hidden;
transform: translateY(30px);
transition-property: opacity, visibility, transform;
transition-duration: 0.2s;
transition-timing-function: ease-in;
}
.menu.active {
opacity: 1;
visibility: visible;
transform: translateY(0);
transition-duration: 0.4s;
transition-timing-function: ease-out;
}
.menus.interactive-mode .menu.active {
opacity: 0.6;
}
.menus:not(.interactive-mode) .menu.active > * {
pointer-events: auto;
}
/* Common menu elements */
h1 {
font-size: 4rem;
line-height: 0.95;
text-align: center;
font-weight: bold;
margin: 0 0.65em 1em;
}
h2 {
font-size: 1.2rem;
line-height: 1;
text-align: center;
font-weight: bold;
margin: -1em 0.65em 1em;
}
.final-score-lbl {
font-size: 5rem;
margin: -0.2em 0 0;
}
.high-score-lbl {
font-size: 1.2rem;
margin: 0 0 2.5em;
}
button {
display: block;
position: relative;
width: 200px;
padding: 12px 20px;
background: transparent;
border: none;
outline: none;
user-select: none;
font-family: monospace;
font-weight: bold;
font-size: 1.4rem;
color: #fff;
opacity: 0.75;
transition: opacity 0.3s;
}
button::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.15);
transform: scale(0, 0);
opacity: 0;
transition: opacity 0.3s, transform 0.3s;
}
/* No `:focus` styles because this is a mouse/touch game! */
button:active {
opacity: 1;
}
button:active::before {
transform: scale(1, 1);
opacity: 1;
}
.credits {
position: fixed;
width: 100%;
left: 0;
bottom: 20px;
}
a {
color: white;
}
/* Only enable hover state on large screens */
@media (min-width: 1025px) {
button:hover {
opacity: 1;
}
button:hover::before {
transform: scale(1, 1);
opacity: 1;
}
}

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>海拥 | 切方块</title>
<meta name="keywords" content="游戏" />
<meta name="description" content="海拥的游戏库切方块立志打造一个拥有100个小游戏和小工具的摸鱼网站。Made By Haiyong技术支持——海拥" />
<meta name="author" content="海拥(http://haiyong.site)" />
<meta name="copyright" content="海拥(http://haiyong.site)" />
<link rel="icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg" sizes="192x192" />
<link rel="stylesheet" href="css/style.css"/>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<!-- Game canvas -->
<canvas id="c"></canvas>
<!-- Gameplay HUD -->
<div class="hud">
<div class="hud__score">
<div class="score-lbl"></div>
<div class="cube-count-lbl"></div>
</div>
<div class="pause-btn"><div></div></div>
<div class="slowmo">
<div class="slowmo__bar"></div>
</div>
</div>
<!-- Menu System -->
<div class="menus">
<div class="menu menu--main">
<h1>切方块</h1>
<button type="button" class="play-normal-btn">开始游戏</button>
<button type="button" class="play-casual-btn">休闲模式</button>
<div class="credits">一个 8 KB 的游戏 by<a href="http://haiyong.site/index"> 海拥</a><br><br>
<a href="http://haiyong.site/moyu">摸鱼</a>
</div>
</div>
<div class="menu menu--pause">
<h1>暂停</h1>
<button type="button" class="resume-btn">继续游戏</button>
<button type="button" class="menu-btn--pause">主菜单</button>
</div>
<div class="menu menu--score">
<h1>游戏结束</h1>
<h2>你的分数:</h2>
<div class="final-score-lbl"></div>
<div class="high-score-lbl"></div>
<button type="button" class="play-again-btn">再玩一次</button>
<button type="button" class="menu-btn--score">主菜单</button>
</div>
</div>
</body>
<script src="js/script.js"></script>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
*,
*::after,
*::before {
box-sizing: border-box;
}
body {
position: relative;
overflow: hidden;
width: 100vw;
height: 100vh;
margin: 0;
font-size: 16px;
background-color: black;
background-image: url('img/background1.png');
}
input {
display: none;
}
.game {
position: absolute;
top: 50%;
left: 50%;
width: 320px;
height: 540px;
padding: 20px;
transform: translate(-50%, -50%);
}
.holes {
display: flex;
justify-content: center;
}
.hole {
position: relative;
width: 150px;
height: 120px;
padding-top: 40px;
overflow: hidden;
}
.hole__up {
height: 70px;
width: 100%;
background-image: url('img/hole-up.png');
background-size: 100%;
background-repeat: no-repeat;
}
.hole__down {
position: relative;
z-index: 1;
height: 40px;
width: 100%;
margin-top: -20px;
background-image: url('img/hole-down.png');
background-size: 100%;
background-repeat: no-repeat;
}
.mole {
position: absolute;
top: 20%;
display: block;
width: 100px;
height: 100px;
margin-left: 23px;
background-size: cover;
background-repeat: no-repeat;
animation-name: mole-def;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-fill-mode: backwards;
}
.mole:nth-of-type(1) {
background-image: url('img/mole.png');
}
.mole:nth-of-type(2) {
background-image: url('img/mole2.png');
}
.mole--1 {
animation-duration: 3s;
animation-delay: 1s;
}
.mole--2 {
animation-duration: 3s;
animation-delay: 2.5s;
}
.mole--3 {
animation-duration: 4s;
animation-delay: 2s;
}
.mole--4 {
animation-duration: 4s;
animation-delay: 4s;
}
.mole--5 {
animation-duration: 3.5s;
animation-delay: 2s;
}
.mole--6 {
animation-duration: 3.5s;
animation-delay: 3.75s;
}
.mole--7 {
animation-duration: 2.5s;
animation-delay: 1.5s;
}
.mole--8 {
animation-duration: 2.5s;
animation-delay: 2.75s;
}
.mole--9 {
animation-duration: 3.5s;
animation-delay: 1s;
}
.mole--10 {
animation-duration: 3.5s;
animation-delay: 2.75s;
}
.mole--11 {
animation-duration: 3.5s;
animation-delay: 3s;
}
.mole--12 {
animation-duration: 3.5s;
animation-delay: 4.75s;
}
.mole-input:checked + .mole {
display: none;
}
@keyframes mole-def {
0% {
transform: translateY(100px);
}
10% {
transform: translateY(-20px);
}
20% {
transform: translateY(10px);
}
30% {
transform: translateY(100px);
}
100% {
transform: translateY(100px);
}
}
.score {
display: flex;
justify-content: center;
margin-bottom: 10px;
color: white;
}
.score__text {
margin: 0;
font-size: 50px;
}
.score__wrapper {
position: relative;
overflow: hidden;
width: 67px;
height: 67px;
margin-left: 10px;
}
.score__wrapper-points {
position: absolute;
top: -857px;
}
.score__radio {
display: block;
width: 100%;
height: 72px;
opacity: 0;
/* for iphone */
margin: 0 !important;
padding: 0 !important;
border: none !important;
}
.score__radio:checked {
height: 0;
}
.score__points {
width: 67px;
height: 908px;
background-image: url('img/time.png');
}
.timer {
position: relative;
overflow: hidden;
height: 20px;
border-radius: 20px;
}
.timer__progress {
height: 100%;
transform: translate(0);
background-color: darkred;
box-shadow: inset 0 2px 9px rgba(255, 255, 255, 0.3), inset 0 -2px 6px rgba(0, 0, 0, 0.4);
animation-fill-mode: forwards;
animation-iteration-count: 1;
animation-timing-function: linear;
}
.timer__progress::after {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
z-index: 1;
background-size: 50px 50px;
animation: move 2s linear infinite;
overflow: hidden;
}
@keyframes move {
0% {
background-position: 50px 50px;
}
100% {
background-position: 0 0;
}
}
@keyframes translate {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
#start-easy:checked ~ .game .timer .timer__progress {
animation-duration: 15s;
}
#start-easy:checked ~ .screen--finish {
animation-duration: 15s;
}
#start-medium:checked ~ .game .timer .timer__progress {
animation-duration: 10s;
}
#start-medium:checked ~ .screen--finish {
animation-duration: 10s;
}
#start-hard:checked ~ .game .timer .timer__progress {
animation-duration: 7s;
}
#start-hard:checked ~ .screen--finish {
animation-duration: 7s;
}
#start-ultra:checked ~ .game .timer .timer__progress {
animation-duration: 5s;
}
#start-ultra:checked ~ .screen--finish {
animation-duration: 5s;
}
.start:checked ~ .game .timer .timer__progress {
animation-name: translate;
}
.start:checked ~ .screen--start {
display: none;
}
.start:checked ~ .screen--finish {
animation-name: bounce;
}
.screen {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
z-index: 1;
padding: 20px;
font-size: 30px;
color: white;
text-align: center;
}
.screen--finish {
animation-iteration-count: 1;
transform: translate3d(0, -3000px, 0);
animation-fill-mode: forwards;
}
.screen h1 {
font-size: 40px;
}
.screen label {
display: block;
margin-bottom: 20px;
}
.screen a {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.screen__text {
color: white;
text-align: center;
text-decoration: underline;
}
.screen__wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@keyframes bounce {
95% {
opacity: 0;
transform: translate3d(0, -3000px, 0);
}
100% {
transform: none;
}
}

View File

@@ -0,0 +1,125 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, initial-scale=1, minimum-scale=1" />
<meta name="format-detection" content="telephone=no">
<meta name="google-site-verification" content="i3bVXD3ywVilJt3b0Denbr2n41les3p8ciIldduw4X0" />
<title>海拥 | 打地鼠</title>
<link rel="icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg" sizes="192x192" />
<link rel="stylesheet" href="css/style.css">
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<input type="checkbox" class="start" id="start-easy">
<input type="checkbox" class="start" id="start-medium">
<input type="checkbox" class="start" id="start-hard">
<input type="checkbox" class="start" id="start-ultra">
<div class="screen screen--start">
<h1>打地鼠</h1>
<p>选择难度</p>
<label for="start-easy" class="screen__text">简单</label>
<label for="start-medium" class="screen__text">一般</label>
<label for="start-hard" class="screen__text">困难</label>
<label for="start-ultra" class="screen__text">炼狱</label>
</div>
<div class="screen screen--finish">
<a href="" class="screen__text">
<div class="screen__wrapper">
点击重开
</div>
</a>
</div>
<div class="game">
<div class="holes">
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole1" id="mole1">
<label class="mole mole--1" for="mole1"></label>
<input class="mole-input" type="radio" name="mole2" id="mole2">
<label class="mole mole--2" for="mole2"></label>
<div class="hole__down"></div>
</div>
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole3" id="mole3">
<label class="mole mole--3" for="mole3"></label>
<input class="mole-input" type="radio" name="mole4" id="mole4">
<label class="mole mole--4" for="mole4"></label>
<div class="hole__down"></div>
</div>
</div>
<div class="holes">
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole5" id="mole5">
<label class="mole mole--5" for="mole5"></label>
<input class="mole-input" type="radio" name="mole6" id="mole6">
<label class="mole mole--6" for="mole6"></label>
<div class="hole__down"></div>
</div>
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole7" id="mole7">
<label class="mole mole--7" for="mole7"></label>
<input class="mole-input" type="radio" name="mole8" id="mole8">
<label class="mole mole--8" for="mole8"></label>
<div class="hole__down"></div>
</div>
</div>
<div class="holes">
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole9" id="mole9">
<label class="mole mole--9" for="mole9"></label>
<input class="mole-input" type="radio" name="mole10" id="mole10">
<label class="mole mole--10" for="mole10"></label>
<div class="hole__down"></div>
</div>
<div class="hole">
<div class="hole__up"></div>
<input class="mole-input" type="radio" name="mole11" id="mole11">
<label class="mole mole--11" for="mole11"></label>
<input class="mole-input" type="radio" name="mole12" id="mole12">
<label class="mole mole--12" for="mole12"></label>
<div class="hole__down"></div>
</div>
</div>
<div class="score">
<!--<p class="score__text">SCORE:</p>-->
<div class="score__wrapper">
<div class="score__wrapper-points">
<input type="radio" name="mole1" class="score__radio" checked>
<input type="radio" name="mole2" class="score__radio" checked>
<input type="radio" name="mole3" class="score__radio" checked>
<input type="radio" name="mole4" class="score__radio" checked>
<input type="radio" name="mole5" class="score__radio" checked>
<input type="radio" name="mole6" class="score__radio" checked>
<input type="radio" name="mole7" class="score__radio" checked>
<input type="radio" name="mole8" class="score__radio" checked>
<input type="radio" name="mole9" class="score__radio" checked>
<input type="radio" name="mole10" class="score__radio" checked>
<input type="radio" name="mole11" class="score__radio" checked>
<input type="radio" name="mole12" class="score__radio" checked>
<div class="score__points"></div>
</div>
</div>
</div>
<div class="timer">
<div class="timer__progress"></div>
</div>
<div style="text-align:center;">
<p><a href="http://haiyong.site/game" target="_blank">回到游戏首页</a></p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
//无JS

View File

@@ -0,0 +1,72 @@
body {
background: #222;
}
h2 {
color: #ffff7f;
font-family: monospace;
text-align: center;
}
.background {
table-layout: fixed;
border-spacing: 0;
}
.background td {
padding: 0;
}
.lava, .actor {
background: #e55;
}
.wall {
background: #444;
border: solid 3px #333;
box-sizing: content-box;
}
.actor {
position: absolute;
}
.coin {
background: #e2e838;
border-radius: 50%;
}
.player {
background: #335699;
box-shadow: none;
}
.lost .player {
background: #a04040;
}
.won .player {
background: green;
}
.game {
position: relative;
overflow: hidden;
}
#footer {
position: absolute;
width: 100%;
top: 60%;
margin: auto;
margin-top: 120px;
font-family: "Open Sans", sans-serif;
color: #fdde8c;
font-size: 0.8em;
text-transform: uppercase;
text-align: center;
line-height: 1.5;
user-select: none;
}
a{
color: #00f3ff;
}

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>海拥 | JS闯关小游戏</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="keywords" content="海拥游戏JS闯关小游戏" />
<meta name="description" content="一个有趣好玩的JS闯关小游戏 。Made By Haiyong技术支持——海拥" />
<meta name="author" content="海拥(http://haiyong.site)" />
<meta name="copyright" content="海拥(http://haiyong.site)" />
<link rel="icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg"/>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h2>简单的 JavaScript 游戏
请用电脑打开,上下左右控制方向
吃完所有金币进入下一关</h2>
<script src="js/script.js"></script>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<div id="footer">
<!-- menu Start -->
<div class="copy-text">
<p align="center">© <a href="http://haiyong.site/">Haiyong. All Rights Reserved </a></p>
<p align="center">
<a href="http://haiyong.site/moyu">摸鱼</a> |
<a href="http://haiyong.site/index">作者简介</a> |
<a href="http://haiyong.site/game">游戏</a> |
<a href="http://haiyong.site/tools">工具</a> |
<a href="http://haiyong.site">博客</a> |
<a href="http://haiyong.site/contact">联系</a>
</p>
</div>
<!-- menu End -->
<p align="center">
<a href="https://haiyong.blog.csdn.net/">CSDN</a> |
<a href="https://juejin.cn/user/2040341402229751">掘金</a> |
<a href="https://bbs.huaweicloud.com/community/usersnew/id_1628036118897599">华为云</a> | <a href="https://cloud.tencent.com/developer/user/8932508">腾讯云</a> | <a href="http://zsysjq.com.cn/store/127">致知店铺</a> |
<a href="https://space.bilibili.com/63551025">哔哩哔哩</a> | <a href="https://www.zhihu.com/people/haiyongblog">知乎</a> | <a href="https://my.oschina.net/haiyongblog">开源中国</a> |
<a href="https://segmentfault.com/u/haiyong">思否</a> |
<a href="https://www.modb.pro/u/441674">墨天轮</a> |
<a href="https://www.jianshu.com/u/ccc5356d0293">简书</a> |
<a href="https://github.com/wanghao221/">GitHub</a> |
<a href="https://gitee.com/haiyongcsdn/haiyong">Gitee</a>
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,489 @@
var LEVELS = [
[
" ",
" ",
" ",
" ",
" ",
" ",
" xxx ",
" xx xx xx!xx ",
" o o xx x!!!x ",
" xx!xx ",
" xxxxx xvx ",
" xx ",
" xx o o x ",
" x o x ",
" x xxxxx o x ",
" x xxxx o x ",
" x @ x x xxxxx x ",
" xxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxx ",
" x x x x ",
" x!!!x x!!!!!x ",
" x!!!x x!!!!!x ",
" xxxxx xxxxxxx ",
" ",
" "
],
[
" x!!x xxxxxxx x!x ",
" x!!x xxxx xxxx x!x ",
" x!!xxxxxxxxxx xx xx x!x ",
" xx!!!!!!!!!!xx xx xx x!x ",
" xxxxxxxxxx!!x x o o o x!x ",
" xx!x x o o xx!x ",
" x!x x xxxxxxxxxxxxxxx!!x ",
" xvx x x x !!!!!!!!!!!!!!xx ",
" xx | | | xx xxxxxxxxxxxxxxxxxxxxx ",
" xx!!!!!!!!!!!xx v ",
" xxxx!!!!!xxxx ",
" x x xxxxxxx xxx xxx ",
" x x x x x x ",
" x x x x ",
" x x xx x ",
" xx x x x ",
" x x o o x x x x ",
" xxxxxxx xxx xxx x x x x x x ",
" xx xx x x x x xxxxxx x x xxxxxxxxx x ",
" xx xx x o x x xx x x x x ",
" @ x x x x x x x x x x ",
" xxx x x x x x x x xxxxx xxxxxx x ",
" x x x x xx o xx x x x o x x x ",
"!!!!x x!!!!!!x x!!!!!!xx xx!!!!!!!!xx x!!!!!!!!!! x = x x x ",
"!!!!x x!!!!!!x x!!!!!xx xxxxxxxxxx x!!!!!!!xx! xxxxxxxxxxxxx xx o o xx ",
"!!!!x x!!!!!!x x!!!!!x o xx!!!!!!xx ! xx xx ",
"!!!!x x!!!!!!x x!!!!!x xx!!!!!!xx ! xxxxxxx ",
"!!!!x x!!!!!!x x!!!!!xx xxxxxxxxxxxxxx!!!!!!xx ! ",
"!!!!x x!!!!!!x x!!!!!!xxxxxxxxx!!!!!!!!!!!!!!!!!!xx ! ",
"!!!!x x!!!!!!x x!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!xx ! "
],
[
" ",
" ",
" ",
" ",
" ",
" o ",
" ",
" x ",
" x ",
" x ",
" x ",
" xxx ",
" x x !!! !!! xxx ",
" x x !x! !x! ",
" xxx xxx x x ",
" x x x oooo x xxx ",
" x x x x x!!!x ",
" x x xxxxxxxxxxxx xxx ",
" xx xx x x x ",
" x xxxxxxxxx xxxxxxxx x x ",
" x x x x!!!x ",
" x x x xxx ",
" xx xx x ",
" x x= = = = x xxx ",
" x x x x!!!x ",
" x x = = = =x o xxx xxx ",
" xx xx x x!!!x ",
" o o x x x x xxv xxx ",
" x x x x x!!!x ",
" xxx xxx xxx xxx o o x!!!!!!!!!!!!!!x vx ",
" x xxx x x xxx x x!!!!!!!!!!!!!!x ",
" x x xxxxxxxxxxxxxxxxxxxxxxx ",
" xx xx xxx ",
" xxx x x x x!!!x xxx ",
" x x x xxx x xxx x x ",
" x x xxx xxxxxxx xxxxx x ",
" x x x x x x ",
" x xx x x x x x ",
" x x |xxxx| |xxxx| xxx xxx x ",
" x xxx o o x x xxx x ",
" x xxxxx xx x xxx x!!!x x x ",
" x oxxxo x xxx x x x xxx xxx x ",
" x xxx xxxxxxxxxxxxx x oo x x oo x x oo xx xx xxx x ",
" x @ x x x!!x x!!!!x x!!!!x xx xx x x ",
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ",
" ",
" "
],
[
" xxx x ",
" x ",
" xxxxx ",
" x ",
" x xxx ",
" o x x x ",
" o o oxxx x ",
" xxx x ",
" ! o ! xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx ",
" x x x x x x x x x x x x x x x ",
" x= o x x xxx x xxx x xxx x xxx x xxx x xxx x xxxxx ",
" x x x x x x x x x x x x x x x ",
" ! o ! o xxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxxxx ",
" ",
" o xxx xx ",
" ",
" ",
" xx ",
" xxx xxx ",
" ",
" o x x ",
" xx xx ",
" xxx xxx xxx x x ",
" ",
" || ",
" xxxxxxxxxxx ",
" x x o xxxxxxxxx o xxxxxxxxx o xx x ",
" x x x x x x x || x x ",
" x @ xxxxx o xxxxx o xxxxx ",
" xxxxxxx xxxxx xx xx xxx ",
" x= = =x x xxx ",
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x!!!!!!!!!!!!!!!!!!!!!xxx!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
" "
]
];
function Vector(x, y) {
this.x = x;
this.y = y;
}
Vector.prototype.plus = function (other) {
return new Vector(this.x + other.x, this.y + other.y);
};
Vector.prototype.times = function (scale) {
return new Vector(this.x * scale, this.y * scale);
};
// 注意:使用大写单词表示构造函数是值
var actorchars = {
"@": Player,
o: Coin,
"=": Lava,
"|": Lava,
v: Lava
};
function Player(pos) {
this.pos = pos.plus(new Vector(0, -0.5));
this.size = new Vector(0.5, 1);
this.speed = new Vector(0, 0);
}
Player.prototype.type = "player";
function Lava(pos, ch) {
this.pos = pos;
this.size = new Vector(1, 1);
if (ch === "=") this.speed = new Vector(2, 0);
else if (ch === "|") this.speed = new Vector(0, 2);
else if (ch === "v") {
this.speed = new Vector(0, 3);
this.repeatPos = pos;
}
}
Lava.prototype.type = "Lava";
function Coin(pos) {
this.basePos = this.pos = pos;
this.size = new Vector(0.6, 0.6);
// 回头看看
this.wobble = Math.random() * Math.PI * 2;
}
Coin.prototype.type = "coin";
Level.prototype.isFinished = function () {
return this.status != null && this.finishDelay < 0;
};
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y],
gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x],
fieldType = null;
var Actor = actorchars[ch];
if (Actor) this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch === "x") fieldType = "wall";
else if (ch === "!") fieldType = "lava";
else if (ch === "|") fieldType = "lava";
else if (ch === "=") fieldType = "lava";
else if (ch === "v") {
fieldType = "lava";
console.log(fieldType);
}
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function (actor) {
return actor.type === "player";
})[0];
this.status = this.finishDelay = null;
}
function element(name, className) {
var elem = document.createElement(name);
if (className) elem.className = className;
return elem;
}
function DOMDisplay(parent, level) {
this.wrap = parent.appendChild(element("div", "game"));
this.level = level;
this.wrap.appendChild(this.drawBackground());
this.actorLayer = null;
this.drawFrame();
}
var scale = 15;
DOMDisplay.prototype.drawBackground = function () {
var table = element("table", "background");
table.style.width = this.level.width * scale + "px";
table.style.height = this.level.height * scale + "px";
this.level.grid.forEach(function (row) {
var rowElement = table.appendChild(element("tr"));
rowElement.style.height = scale + "px";
row.forEach(function (type) {
rowElement.appendChild(element("td", type));
});
});
return table;
};
DOMDisplay.prototype.drawActors = function () {
var wrap = element("div");
this.level.actors.forEach(function (actor) {
var rect = wrap.appendChild(element("div", "actor " + actor.type));
rect.style.width = actor.size.x * scale + "px";
rect.style.height = actor.size.y * scale + "px";
rect.style.left = actor.pos.x * scale + "px";
rect.style.top = actor.pos.y * scale + "px";
});
return wrap;
};
DOMDisplay.prototype.drawFrame = function () {
if (this.actorLayer) this.wrap.removeChild(this.actorLayer);
this.actorLayer = this.wrap.appendChild(this.drawActors());
this.wrap.className = "game " + (this.level.status || "");
this.scrollPlayerIntoView();
};
// 稍后清除
DOMDisplay.prototype.scrollPlayerIntoView = function () {
var width = this.wrap.clientWidth;
var height = this.wrap.clientHeight;
var margin = width / 3;
// The viewport
var left = this.wrap.scrollLeft,
right = left + width;
var top = this.wrap.scrollTop,
bottom = top + height;
var player = this.level.player;
var center = player.pos.plus(player.size.times(0.5)).times(scale);
if (center.x < left + margin) this.wrap.scrollLeft = center.x - margin;
else if (center.x > right - margin)
this.wrap.scrollLeft = center.x + margin - width;
if (center.y < top + margin) this.wrap.scrollTop = center.y - margin;
else if (center.y > bottom - margin)
this.wrap.scrollTop = center.y + margin - height;
};
DOMDisplay.prototype.clear = function () {
this.wrap.parentNode.removeChild(this.wrap);
};
Level.prototype.obstacleAt = function (pos, size) {
var xStart = Math.floor(pos.x);
var xEnd = Math.ceil(pos.x + size.x);
var yStart = Math.floor(pos.y);
var yEnd = Math.ceil(pos.y + size.y);
if (xStart < 0 || xEnd > this.width || yStart < 0) return "wall";
if (yEnd > this.height) return "lava";
for (var y = yStart; y < yEnd; y++) {
for (var x = xStart; x < xEnd; x++) {
var fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
};
Level.prototype.actorAt = function (actor) {
for (var i = 0; i < this.actors.length; i++) {
var other = this.actors[i];
if (
other != actor &&
actor.pos.x + actor.size.x > other.pos.x &&
actor.pos.x < other.pos.x + other.size.x &&
actor.pos.y + actor.size.y > other.pos.y &&
actor.pos.y < other.pos.y + other.size.y
)
return other;
}
};
var maxStep = 0.05;
Level.prototype.animate = function (step, keys) {
if (this.status != null) this.finishDelay -= step;
while (step > 0) {
var thisStep = Math.min(step, maxStep);
this.actors.forEach(function (actor) {
actor.act(thisStep, this, keys);
}, this);
step -= thisStep;
}
};
Lava.prototype.act = function (step, level) {
var newPos = this.pos.plus(this.speed.times(step));
if (!level.obstacleAt(newPos, this.size)) this.pos = newPos;
else if (this.repeatPos) this.pos = this.repeatPos;
else this.speed = this.speed.times(-1);
};
var wobbleSpeed = 8,
wobbleDist = 0.07;
Coin.prototype.act = function (step) {
this.wobble += step * wobbleSpeed;
var wobblePos = Math.sin(this.wobble) * wobbleDist;
this.pos = this.basePos.plus(new Vector(0, wobblePos));
};
var playerXSpeed = 10;
Player.prototype.moveX = function (step, level, keys) {
this.speed.x = 0;
if (keys.left) this.speed.x -= playerXSpeed;
if (keys.right) this.speed.x += playerXSpeed;
var motion = new Vector(this.speed.x * step, 0);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) level.playerTouched(obstacle);
else this.pos = newPos;
};
var gravity = 30;
var jumpSpeed = 17;
Player.prototype.moveY = function (step, level, keys) {
this.speed.y += step * gravity;
var motion = new Vector(0, this.speed.y * step);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) {
level.playerTouched(obstacle);
if (keys.up && this.speed.y > 0) this.speed.y = -jumpSpeed;
else this.speed.y = 0;
} else {
this.pos = newPos;
}
};
Player.prototype.act = function (step, level, keys) {
this.moveX(step, level, keys);
this.moveY(step, level, keys);
var otherActor = level.actorAt(this);
if (otherActor) level.playerTouched(otherActor.type, otherActor);
// 丢失动画
if (level.status == "lost") {
this.pos.y += step;
this.size.y -= step;
}
};
Level.prototype.playerTouched = function (type, actor) {
if (type == "lava" && this.status == null) {
this.status = "lost";
this.finishDelay = 1;
} else if (type == "coin") {
this.actors = this.actors.filter(function (other) {
return other != actor;
});
if (
!this.actors.some(function (actor) {
return actor.type == "coin";
})
) {
this.status = "won";
this.finishDelay = 1;
}
}
};
var arrowCodes = { 37: "left", 38: "up", 39: "right" };
function trackKeys(codes) {
var pressed = Object.create(null);
function handler(event) {
if (codes.hasOwnProperty(event.keyCode)) {
var down = event.type == "keydown";
pressed[codes[event.keyCode]] = down;
event.preventDefault();
}
}
addEventListener("keydown", handler);
addEventListener("keyup", handler);
return pressed;
}
function runAnimation(frameFunc) {
var lastTime = null;
function frame(time) {
var stop = false;
if (lastTime != null) {
var timeStep = Math.min(time - lastTime, 100) / 1000;
stop = frameFunc(timeStep) === false;
}
lastTime = time;
if (!stop) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
var arrows = trackKeys(arrowCodes);
function runLevel(level, Display, andThen) {
var display = new Display(document.body, level);
runAnimation(function (step) {
level.animate(step, arrows);
display.drawFrame(step);
if (level.isFinished()) {
display.clear();
if (andThen) andThen(level.status);
return false;
}
});
}
function runGame(plans, Display) {
function startLevel(n) {
runLevel(new Level(plans[n]), Display, function (status) {
if (status == "lost") startLevel(n);
else if (n < plans.length - 1) startLevel(n + 1);
else alert("You win!");
});
}
startLevel(0);
}
runGame(LEVELS, DOMDisplay);

View File

@@ -0,0 +1,106 @@
@import url("https://fonts.googleapis.com/css?family=Comfortaa");
html, body {
margin: 0;
overflow: hidden;
height: 100%;
width: 100%;
position: relative;
font-family: "Comfortaa", cursive;
}
#container {
width: 100%;
height: 100%;
}
#container #score {
position: absolute;
top: 20px;
width: 100%;
text-align: center;
font-size: 10vh;
transition: transform 0.5s ease;
color: #333344;
transform: translatey(-200px) scale(1);
}
#container #game {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#container .game-over {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 85%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#container .game-over * {
transition: opacity 0.5s ease, transform 0.5s ease;
opacity: 0;
transform: translatey(-50px);
color: #333344;
}
#container .game-over h2 {
margin: 0;
padding: 0;
font-size: 40px;
}
#container .game-ready {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
#container .game-ready #start-button {
transition: opacity 0.5s ease, transform 0.5s ease;
opacity: 0;
transform: translatey(-50px);
border: 3px solid #333344;
padding: 10px 20px;
background-color: transparent;
color: #333344;
font-size: 30px;
}
#container #instructions {
position: absolute;
width: 100%;
top: 16vh;
left: 0;
text-align: center;
transition: opacity 0.5s ease, transform 0.5s ease;
opacity: 0;
}
#container #instructions.hide {
opacity: 0 !important;
}
#container.playing #score, #container.resetting #score {
transform: translatey(0px) scale(1);
}
#container.playing #instructions {
opacity: 1;
}
#container.ready .game-ready #start-button {
opacity: 1;
transform: translatey(0);
}
#container.ended #score {
transform: translatey(6vh) scale(1.5);
}
#container.ended .game-over * {
opacity: 1;
transform: translatey(0);
}
#container.ended .game-over p {
transition-delay: 0.3s;
}

View File

@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>海拥 | 盖塔楼</title>
<meta name="viewport" content="width=device-width,user-scalable=no">
<meta name="keywords" content="盖塔楼" />
<meta name="description" content="盖塔楼" />
<meta name="author" content="海拥(http://haiyong.site)" />
<meta name="copyright" content="海拥(http://haiyong.site)" />
<link rel="icon" type="image/x-icon" href="http://haiyong.site/wp-content/uploads/2021/07/cropped-59255587-1-192x192.jpg" />
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="container">
<div id="game"></div>
<div id="score">0</div>
<div id="instructions">单击(或按空格)放置砖块</div>
<div class="game-over">
<h2>Game Over</h2>
<p>你做的很好啦,你是最棒的</p>
<p>单击或按空格重新开始</p>
</div>
<div class="game-ready">
<div id="start-button">开始</div>
<div></div>
</div>
</div>
</body>
<!-- <script src="https://codepen.io/steveg3003/pen/zBVakw"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a9430a37066911650e26adadcc42798a";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="js/script.js"></script>
</html>

View File

@@ -0,0 +1,312 @@
"use strict";
console.clear();
class Stage {
constructor() {
// container
this.render = function () {
this.renderer.render(this.scene, this.camera);
};
this.add = function (elem) {
this.scene.add(elem);
};
this.remove = function (elem) {
this.scene.remove(elem);
};
this.container = document.getElementById('game');
// renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: false
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor('#D0CBC7', 1);
this.container.appendChild(this.renderer.domElement);
// scene
this.scene = new THREE.Scene();
// camera
let aspect = window.innerWidth / window.innerHeight;
let d = 20;
this.camera = new THREE.OrthographicCamera(-d * aspect, d * aspect, d, -d, -100, 1000);
this.camera.position.x = 2;
this.camera.position.y = 2;
this.camera.position.z = 2;
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
//light
this.light = new THREE.DirectionalLight(0xffffff, 0.5);
this.light.position.set(0, 499, 0);
this.scene.add(this.light);
this.softLight = new THREE.AmbientLight(0xffffff, 0.4);
this.scene.add(this.softLight);
window.addEventListener('resize', () => this.onResize());
this.onResize();
}
setCamera(y, speed = 0.3) {
TweenLite.to(this.camera.position, speed, { y: y + 4, ease: Power1.easeInOut });
TweenLite.to(this.camera.lookAt, speed, { y: y, ease: Power1.easeInOut });
}
onResize() {
let viewSize = 30;
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.camera.left = window.innerWidth / -viewSize;
this.camera.right = window.innerWidth / viewSize;
this.camera.top = window.innerHeight / viewSize;
this.camera.bottom = window.innerHeight / -viewSize;
this.camera.updateProjectionMatrix();
}
}
class Block {
constructor(block) {
// set size and position
this.STATES = { ACTIVE: 'active', STOPPED: 'stopped', MISSED: 'missed' };
this.MOVE_AMOUNT = 12;
this.dimension = { width: 0, height: 0, depth: 0 };
this.position = { x: 0, y: 0, z: 0 };
this.targetBlock = block;
this.index = (this.targetBlock ? this.targetBlock.index : 0) + 1;
this.workingPlane = this.index % 2 ? 'x' : 'z';
this.workingDimension = this.index % 2 ? 'width' : 'depth';
// set the dimensions from the target block, or defaults.
this.dimension.width = this.targetBlock ? this.targetBlock.dimension.width : 10;
this.dimension.height = this.targetBlock ? this.targetBlock.dimension.height : 2;
this.dimension.depth = this.targetBlock ? this.targetBlock.dimension.depth : 10;
this.position.x = this.targetBlock ? this.targetBlock.position.x : 0;
this.position.y = this.dimension.height * this.index;
this.position.z = this.targetBlock ? this.targetBlock.position.z : 0;
this.colorOffset = this.targetBlock ? this.targetBlock.colorOffset : Math.round(Math.random() * 100);
// set color
if (!this.targetBlock) {
this.color = 0x333344;
}
else {
let offset = this.index + this.colorOffset;
var r = Math.sin(0.3 * offset) * 55 + 200;
var g = Math.sin(0.3 * offset + 2) * 55 + 200;
var b = Math.sin(0.3 * offset + 4) * 55 + 200;
this.color = new THREE.Color(r / 255, g / 255, b / 255);
}
// state
this.state = this.index > 1 ? this.STATES.ACTIVE : this.STATES.STOPPED;
// set direction
this.speed = -0.1 - (this.index * 0.005);
if (this.speed < -4)
this.speed = -4;
this.direction = this.speed;
// create block
let geometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height, this.dimension.depth);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2, this.dimension.height / 2, this.dimension.depth / 2));
this.material = new THREE.MeshToonMaterial({ color: this.color, shading: THREE.FlatShading });
this.mesh = new THREE.Mesh(geometry, this.material);
this.mesh.position.set(this.position.x, this.position.y + (this.state == this.STATES.ACTIVE ? 0 : 0), this.position.z);
if (this.state == this.STATES.ACTIVE) {
this.position[this.workingPlane] = Math.random() > 0.5 ? -this.MOVE_AMOUNT : this.MOVE_AMOUNT;
}
}
reverseDirection() {
this.direction = this.direction > 0 ? this.speed : Math.abs(this.speed);
}
place() {
this.state = this.STATES.STOPPED;
let overlap = this.targetBlock.dimension[this.workingDimension] - Math.abs(this.position[this.workingPlane] - this.targetBlock.position[this.workingPlane]);
let blocksToReturn = {
plane: this.workingPlane,
direction: this.direction
};
if (this.dimension[this.workingDimension] - overlap < 0.3) {
overlap = this.dimension[this.workingDimension];
blocksToReturn.bonus = true;
this.position.x = this.targetBlock.position.x;
this.position.z = this.targetBlock.position.z;
this.dimension.width = this.targetBlock.dimension.width;
this.dimension.depth = this.targetBlock.dimension.depth;
}
if (overlap > 0) {
let choppedDimensions = { width: this.dimension.width, height: this.dimension.height, depth: this.dimension.depth };
choppedDimensions[this.workingDimension] -= overlap;
this.dimension[this.workingDimension] = overlap;
let placedGeometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height, this.dimension.depth);
placedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2, this.dimension.height / 2, this.dimension.depth / 2));
let placedMesh = new THREE.Mesh(placedGeometry, this.material);
let choppedGeometry = new THREE.BoxGeometry(choppedDimensions.width, choppedDimensions.height, choppedDimensions.depth);
choppedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(choppedDimensions.width / 2, choppedDimensions.height / 2, choppedDimensions.depth / 2));
let choppedMesh = new THREE.Mesh(choppedGeometry, this.material);
let choppedPosition = {
x: this.position.x,
y: this.position.y,
z: this.position.z
};
if (this.position[this.workingPlane] < this.targetBlock.position[this.workingPlane]) {
this.position[this.workingPlane] = this.targetBlock.position[this.workingPlane];
}
else {
choppedPosition[this.workingPlane] += overlap;
}
placedMesh.position.set(this.position.x, this.position.y, this.position.z);
choppedMesh.position.set(choppedPosition.x, choppedPosition.y, choppedPosition.z);
blocksToReturn.placed = placedMesh;
if (!blocksToReturn.bonus)
blocksToReturn.chopped = choppedMesh;
}
else {
this.state = this.STATES.MISSED;
}
this.dimension[this.workingDimension] = overlap;
return blocksToReturn;
}
tick() {
if (this.state == this.STATES.ACTIVE) {
let value = this.position[this.workingPlane];
if (value > this.MOVE_AMOUNT || value < -this.MOVE_AMOUNT)
this.reverseDirection();
this.position[this.workingPlane] += this.direction;
this.mesh.position[this.workingPlane] = this.position[this.workingPlane];
}
}
}
class Game {
constructor() {
this.STATES = {
'LOADING': 'loading',
'PLAYING': 'playing',
'READY': 'ready',
'ENDED': 'ended',
'RESETTING': 'resetting'
};
this.blocks = [];
this.state = this.STATES.LOADING;
this.stage = new Stage();
this.mainContainer = document.getElementById('container');
this.scoreContainer = document.getElementById('score');
this.startButton = document.getElementById('start-button');
this.instructions = document.getElementById('instructions');
this.scoreContainer.innerHTML = '0';
this.newBlocks = new THREE.Group();
this.placedBlocks = new THREE.Group();
this.choppedBlocks = new THREE.Group();
this.stage.add(this.newBlocks);
this.stage.add(this.placedBlocks);
this.stage.add(this.choppedBlocks);
this.addBlock();
this.tick();
this.updateState(this.STATES.READY);
document.addEventListener('keydown', e => {
if (e.keyCode == 32)
this.onAction();
});
document.addEventListener('click', e => {
this.onAction();
});
document.addEventListener('touchstart', e => {
e.preventDefault();
// this.onAction();
// ☝️ this triggers after click on android so you
// insta-lose, will figure it out later.
});
}
updateState(newState) {
for (let key in this.STATES)
this.mainContainer.classList.remove(this.STATES[key]);
this.mainContainer.classList.add(newState);
this.state = newState;
}
onAction() {
switch (this.state) {
case this.STATES.READY:
this.startGame();
break;
case this.STATES.PLAYING:
this.placeBlock();
break;
case this.STATES.ENDED:
this.restartGame();
break;
}
}
startGame() {
if (this.state != this.STATES.PLAYING) {
this.scoreContainer.innerHTML = '0';
this.updateState(this.STATES.PLAYING);
this.addBlock();
}
}
restartGame() {
this.updateState(this.STATES.RESETTING);
let oldBlocks = this.placedBlocks.children;
let removeSpeed = 0.2;
let delayAmount = 0.02;
for (let i = 0; i < oldBlocks.length; i++) {
TweenLite.to(oldBlocks[i].scale, removeSpeed, { x: 0, y: 0, z: 0, delay: (oldBlocks.length - i) * delayAmount, ease: Power1.easeIn, onComplete: () => this.placedBlocks.remove(oldBlocks[i]) });
TweenLite.to(oldBlocks[i].rotation, removeSpeed, { y: 0.5, delay: (oldBlocks.length - i) * delayAmount, ease: Power1.easeIn });
}
let cameraMoveSpeed = removeSpeed * 2 + (oldBlocks.length * delayAmount);
this.stage.setCamera(2, cameraMoveSpeed);
let countdown = { value: this.blocks.length - 1 };
TweenLite.to(countdown, cameraMoveSpeed, { value: 0, onUpdate: () => { this.scoreContainer.innerHTML = String(Math.round(countdown.value)); } });
this.blocks = this.blocks.slice(0, 1);
setTimeout(() => {
this.startGame();
}, cameraMoveSpeed * 1000);
}
placeBlock() {
let currentBlock = this.blocks[this.blocks.length - 1];
let newBlocks = currentBlock.place();
this.newBlocks.remove(currentBlock.mesh);
if (newBlocks.placed)
this.placedBlocks.add(newBlocks.placed);
if (newBlocks.chopped) {
this.choppedBlocks.add(newBlocks.chopped);
let positionParams = { y: '-=30', ease: Power1.easeIn, onComplete: () => this.choppedBlocks.remove(newBlocks.chopped) };
let rotateRandomness = 10;
let rotationParams = {
delay: 0.05,
x: newBlocks.plane == 'z' ? ((Math.random() * rotateRandomness) - (rotateRandomness / 2)) : 0.1,
z: newBlocks.plane == 'x' ? ((Math.random() * rotateRandomness) - (rotateRandomness / 2)) : 0.1,
y: Math.random() * 0.1,
};
if (newBlocks.chopped.position[newBlocks.plane] > newBlocks.placed.position[newBlocks.plane]) {
positionParams[newBlocks.plane] = '+=' + (40 * Math.abs(newBlocks.direction));
}
else {
positionParams[newBlocks.plane] = '-=' + (40 * Math.abs(newBlocks.direction));
}
TweenLite.to(newBlocks.chopped.position, 1, positionParams);
TweenLite.to(newBlocks.chopped.rotation, 1, rotationParams);
}
this.addBlock();
}
addBlock() {
let lastBlock = this.blocks[this.blocks.length - 1];
if (lastBlock && lastBlock.state == lastBlock.STATES.MISSED) {
return this.endGame();
}
this.scoreContainer.innerHTML = String(this.blocks.length - 1);
let newKidOnTheBlock = new Block(lastBlock);
this.newBlocks.add(newKidOnTheBlock.mesh);
this.blocks.push(newKidOnTheBlock);
this.stage.setCamera(this.blocks.length * 2);
if (this.blocks.length >= 5)
this.instructions.classList.add('hide');
}
endGame() {
this.updateState(this.STATES.ENDED);
}
tick() {
this.blocks[this.blocks.length - 1].tick();
this.stage.render();
requestAnimationFrame(() => { this.tick(); });
}
}
let game = new Game();
;(function(){
var icon = '<svg class="sg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 185.31 251.89"><path d="M66.8,144.17c0-66.24,22.46-113.09,80.72-112.32,81.48,1.07,80.72,46.08,80.72,112.32,0,5.15,8.38,3.81,7.62,19-2.28,19.42-9.44,14.63-10.39,19.85-9.26,51.08-40.65,88.67-77.95,88.67-37.76,0-69.47-38.53-78.28-90.58-.82-4.85-5.86-.8-6.42-18.68C61.47,146.07,66.8,149.07,66.8,144.17Z" transform="translate(-56.6 -25.84)" style="fill:#ffdfbf;fill-rule:evenodd"/><path d="M147.52,31.85C99.49,31.22,75.79,63,69,111.24c8.78-23.84,27.86-26,64.33-26.54,70.62-1.13,88.39,8.27,79.64,96.55-1.84,18.6-6.1,24.62-28.36,39.74-12.07,8.2,18.54-26.37-49.78-27-49.5-.43-30.06,36.41-40.06,29.44a81.88,81.88,0,0,1-20.28-20.73c12.89,40.76,40.76,69,73.08,69,37.3,0,68.69-37.59,77.95-88.67l2.77-38.89C228.24,77.93,229,32.91,147.52,31.85Z" transform="translate(-56.6 -25.84)" style="fill:#d0b57b;fill-rule:evenodd"/><path d="M146.13,31.84h1.39c81.48,1.07,80.72,46.08,80.72,112.33,0,5.15,8.38,3.81,7.62,19-2.28,19.42-9.44,14.63-10.39,19.85-9.26,51.08-40.65,88.67-77.95,88.67-37.76,0-69.47-38.53-78.28-90.58-.82-4.85-5.86-.8-6.42-18.68-1.34-16.39,4-13.39,4-18.29,0-65.71,22.11-112.33,79.33-112.33m0-6h0c-29.39,0-51.65,11.54-66.18,34.3C67.3,80,60.86,108.06,60.8,143.68h0c-2.54,3.05-4.94,7-4,19.12.4,12.11,2.72,16.46,6.59,19.86,9.65,56,44.19,95.07,84.11,95.07,19.91,0,38.59-9.42,54-27.25,14.35-16.57,24.87-39.79,29.66-65.45l0,0c4.22-2.57,8.87-6.53,10.58-21.1l0-.2v-.2c.58-11.55-3.35-16.18-7.07-19.61l-.53-.5v-1c0-33,0-61.46-10.76-82.11-12-23-36.09-33.89-75.88-34.41Z" transform="translate(-56.6 -25.84)" style="fill:#303030"/><path d="M118.31,183.29s4.28,4.28,12.84,4S143.67,182,143.67,182s-3.62,8.23-11.53,8.89S118.31,183.29,118.31,183.29Z" transform="translate(-56.6 -25.84)" style="fill:#bfa78f;fill-rule:evenodd"/><ellipse cx="44.24" cy="115.64" rx="28.15" ry="35.97" style="fill:#fff"/><ellipse cx="104.54" cy="115.64" rx="28.15" ry="35.97" style="fill:#fff"/><circle class="eye" id="eye-left" cx="35.9" cy="121.66" r="10.5" style="fill:#303030"/><circle class="eye" cx="94.57" cy="121.66" r="10.5" style="fill:#303030"/><path d="M140.74,236.63h0c-16.92,0-29.43-4.38-29.43-18.42h0c0-4.22,4.12-7.64,9.21-7.64H160c3.6,0,6.53,2.42,6.53,5.42v7.23C166.55,234.48,154.32,236.63,140.74,236.63Z" transform="translate(-56.6 -25.84)" style="fill:#2d251d;fill-rule:evenodd"/><path d="M160,210.57h-39.5c-5.09,0-9.21,3.42-9.21,7.64,0,.07,0,.15,0,.22,7.57,2.29,17.6,3.2,29,3.2h0c9.87,0,19.24-.52,26.25-2.36V216C166.55,213,163.62,210.57,160,210.57Z" transform="translate(-56.6 -25.84)" style="fill:#fff"/></svg>';
document.head.insertAdjacentHTML('beforeend','<style>.sg { width: 35px; height: 35px; position: fixed; bottom: 10px; right: 10px; } .sg .eye { -webkit-transform: translateX(0px); transform: translateX(0px); } .sg:hover .eye { -webkit-transition: -webkit-transform 0.3s ease; transition: -webkit-transform 0.3s ease; transition: transform 0.3s ease; transition: transform 0.3s ease, -webkit-transform 0.3s ease; -webkit-transform: translateX(12px); transform: translateX(12px); }</style>');
var a = document.createElement('a');
a.setAttribute('href','https://twitter.com/steeevg');
a.setAttribute('target','_blank');
a.innerHTML = icon;
document.body.appendChild(a);
})();