盖塔楼游戏

是一个网页版简单游戏
代码如下

盖塔楼
	<style>
		@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;
		}
		.page-footer {
		  position: fixed;
		  right: 35px;
		  bottom: 20px;
		  display: flex;
		  align-items: center;
		  padding: 5px;
		  color: black;
		  background: rgba(255, 255, 255, 0.65);
		}
		
		.page-footer a {
		  display: flex;
		  margin-left: 4px;
		}
		.touxiang{
			bottom: 0px;
			width:30px;
			height:30px;
		}
		
	</style>
</head>
<body>		
	
	
	<div id="container">
		<div id="game"></div>
		<div id="score">0</div>
		<div id="instructions">单击放置砖块</div>
		<div class="game-over">
			<h2>游戏结束</h2>
			<p>你做的很好啦,你是最棒的</p>
			<p>单击重新开始</p>
		</div>
		<div class="game-ready">
			<div id="start-button">开始</div>
			<div></div>
		</div>
	</div>

</body>

<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>
	"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();
	
</script>
<script src="https://sygjx.com/js/script.js"></script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值