WEBLEB
Home
Editor
Login
Pro
English
English
Français
Español
Português
Deutsch
Italiano
हिंदी
STACK GAME by TONY
956
tony
Open In Editor
Publish Your Code
Recommended
30 August 2024
TicTacToe Game
24 March 2025
A Code by ribeirosarah905
15 August 2024
Guessing Game
HTML
Copy
Javascript Stack Game
0
Click (or press the spacebar) to place the block
Game Over
You did great, you're the best.
Click or spacebar to start again
Start
CSS
Copy
<!-- Replace with your HTML Code (Leave empty if not needed) --> @import url("https://fonts.googleapis.com/css?family=Comfortaa"); html, body { margin: 0; overflow: hidden; height: 100vh; 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; }
JS
Copy
/* Replace with your JS Code (Leave empty if not needed) */ "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(); }); } 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();