diff --git a/Games/Tower_Block_Game/README.md b/Games/Tower_Block_Game/README.md new file mode 100644 index 0000000000..d3e8dcc7a9 --- /dev/null +++ b/Games/Tower_Block_Game/README.md @@ -0,0 +1,46 @@ +# **Tower Block Game** + +--- + +
+ +## **Description 📃** + +- The Tower Block Game is an engaging and fun stacking game where players aim to stack blocks as high as possible without missing. The game uses 3D graphics and smooth animations to create an immersive experience. + +## **Functionalities 🎮** + +- Start a new game by clicking the "Start" button or pressing the spacebar. +- Stack blocks by clicking or pressing the spacebar. +- The game ends if a block is missed. +- View your current score during the game. +- Restart the game after it ends by clicking or pressing the spacebar. + +
+ +## **How to play? 🕹ī¸** + +1. Open the game in your web browser. +2. Click the "Start" button or press the spacebar to begin. +3. As the block moves, click or press the spacebar to place it. +4. Try to align the blocks as closely as possible. +5. The game ends if a block is missed. +6. Click or press the spacebar to restart the game. + +
+ +## **Screenshots 📸** +
+ +![Tower_Block_Game](https://github.com/Saipradyumnagoud/GameZone/assets/143107589/955917b4-98e7-43c9-833d-96683546d58a) + + + +
+ +## **Working video 📹** + +https://github.com/Saipradyumnagoud/GameZone/assets/143107589/e0a6612d-2917-42a8-8a10-f1fbeddbf4ea + + + diff --git a/Games/Tower_Block_Game/index.html b/Games/Tower_Block_Game/index.html new file mode 100644 index 0000000000..6d78781f2a --- /dev/null +++ b/Games/Tower_Block_Game/index.html @@ -0,0 +1,28 @@ + + + + + + Tower Block 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
+
+
+
+ + + + + diff --git a/Games/Tower_Block_Game/script.js b/Games/Tower_Block_Game/script.js new file mode 100644 index 0000000000..008fcb2986 --- /dev/null +++ b/Games/Tower_Block_Game/script.js @@ -0,0 +1,310 @@ + +console.clear(); +var Stage = /** @class */ (function () { + function Stage() { + // container + var _this = this; + 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 + var aspect = window.innerWidth / window.innerHeight; + var 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', function () { return _this.onResize(); }); + this.onResize(); + } + Stage.prototype.setCamera = function (y, speed) { + if (speed === void 0) { 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 }); + }; + Stage.prototype.onResize = function () { + var 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(); + }; + return Stage; +}()); +var Block = /** @class */ (function () { + function Block(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 { + var 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 + var 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; + } + } + Block.prototype.reverseDirection = function () { + this.direction = this.direction > 0 ? this.speed : Math.abs(this.speed); + }; + Block.prototype.place = function () { + this.state = this.STATES.STOPPED; + var overlap = this.targetBlock.dimension[this.workingDimension] - Math.abs(this.position[this.workingPlane] - this.targetBlock.position[this.workingPlane]); + var 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) { + var choppedDimensions = { width: this.dimension.width, height: this.dimension.height, depth: this.dimension.depth }; + choppedDimensions[this.workingDimension] -= overlap; + this.dimension[this.workingDimension] = overlap; + var 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)); + var placedMesh = new THREE.Mesh(placedGeometry, this.material); + var 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)); + var choppedMesh = new THREE.Mesh(choppedGeometry, this.material); + var 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; + }; + Block.prototype.tick = function () { + if (this.state == this.STATES.ACTIVE) { + var 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]; + } + }; + return Block; +}()); +var Game = /** @class */ (function () { + function Game() { + var _this = this; + 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', function (e) { + if (e.keyCode == 32) + _this.onAction(); + }); + document.addEventListener('click', function (e) { + _this.onAction(); + }); + document.addEventListener('touchstart', function (e) { + e.preventDefault(); + _this.onAction(); + // ?? this triggers after click on android so you + // insta-lose, will figure it out later. + }); + } + Game.prototype.updateState = function (newState) { + for (var key in this.STATES) + this.mainContainer.classList.remove(this.STATES[key]); + this.mainContainer.classList.add(newState); + this.state = newState; + }; + Game.prototype.onAction = function () { + switch (this.state) { + case this.STATES.READY: + this.startGame(); + break; + case this.STATES.PLAYING: + this.placeBlock(); + break; + case this.STATES.ENDED: + this.restartGame(); + break; + } + }; + Game.prototype.startGame = function () { + if (this.state != this.STATES.PLAYING) { + this.scoreContainer.innerHTML = '0'; + this.updateState(this.STATES.PLAYING); + this.addBlock(); + } + }; + Game.prototype.restartGame = function () { + var _this = this; + this.updateState(this.STATES.RESETTING); + var oldBlocks = this.placedBlocks.children; + var removeSpeed = 0.2; + var delayAmount = 0.02; + var _loop_1 = function (i) { + TweenLite.to(oldBlocks[i].scale, removeSpeed, { x: 0, y: 0, z: 0, delay: (oldBlocks.length - i) * delayAmount, ease: Power1.easeIn, onComplete: function () { return _this.placedBlocks.remove(oldBlocks[i]); } }); + TweenLite.to(oldBlocks[i].rotation, removeSpeed, { y: 0.5, delay: (oldBlocks.length - i) * delayAmount, ease: Power1.easeIn }); + }; + for (var i = 0; i < oldBlocks.length; i++) { + _loop_1(i); + } + var cameraMoveSpeed = removeSpeed * 2 + (oldBlocks.length * delayAmount); + this.stage.setCamera(2, cameraMoveSpeed); + var countdown = { value: this.blocks.length - 1 }; + TweenLite.to(countdown, cameraMoveSpeed, { value: 0, onUpdate: function () { _this.scoreContainer.innerHTML = String(Math.round(countdown.value)); } }); + this.blocks = this.blocks.slice(0, 1); + setTimeout(function () { + _this.startGame(); + }, cameraMoveSpeed * 1000); + }; + Game.prototype.placeBlock = function () { + var _this = this; + var currentBlock = this.blocks[this.blocks.length - 1]; + var newBlocks = currentBlock.place(); + this.newBlocks.remove(currentBlock.mesh); + if (newBlocks.placed) + this.placedBlocks.add(newBlocks.placed); + if (newBlocks.chopped) { + this.choppedBlocks.add(newBlocks.chopped); + var positionParams = { y: '-=30', ease: Power1.easeIn, onComplete: function () { return _this.choppedBlocks.remove(newBlocks.chopped); } }; + var rotateRandomness = 10; + var 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(); + }; + Game.prototype.addBlock = function () { + var 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); + var 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'); + }; + Game.prototype.endGame = function () { + this.updateState(this.STATES.ENDED); + }; + Game.prototype.tick = function () { + var _this = this; + this.blocks[this.blocks.length - 1].tick(); + this.stage.render(); + requestAnimationFrame(function () { _this.tick(); }); + }; + return Game; +}()); +var game = new Game(); diff --git a/Games/Tower_Block_Game/styles.css b/Games/Tower_Block_Game/styles.css new file mode 100644 index 0000000000..713a97096d --- /dev/null +++ b/Games/Tower_Block_Game/styles.css @@ -0,0 +1,143 @@ +@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; + -webkit-transition: -webkit-transform 0.5s ease; + transition: -webkit-transform 0.5s ease; + transition: transform 0.5s ease; + transition: transform 0.5s ease, -webkit-transform 0.5s ease; + color: #333344; + -webkit-transform: translatey(-200px) scale(1); + 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: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +#container .game-over * { + -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease; + opacity: 0; + -webkit-transform: translatey(-50px); + 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: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: distribute; + justify-content: space-around; +} +#container .game-ready #start-button { + -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease; + opacity: 0; + -webkit-transform: translatey(-50px); + 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; + -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, -webkit-transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease; + transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease; + opacity: 0; +} +#container #instructions.hide { + opacity: 0 !important; +} +#container.playing #score, #container.resetting #score { + -webkit-transform: translatey(0px) scale(1); + transform: translatey(0px) scale(1); +} +#container.playing #instructions { + opacity: 1; +} +#container.ready .game-ready #start-button { + opacity: 1; + -webkit-transform: translatey(0); + transform: translatey(0); +} +#container.ended #score { + -webkit-transform: translatey(6vh) scale(1.5); + transform: translatey(6vh) scale(1.5); +} +#container.ended .game-over * { + opacity: 1; + -webkit-transform: translatey(0); + transform: translatey(0); +} +#container.ended .game-over p { + -webkit-transition-delay: 0.3s; + transition-delay: 0.3s; +} \ No newline at end of file diff --git a/README.md b/README.md index 7d6dabf257..18847fffd0 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ This repository also provides one such platforms where contributers come over an | [Intellect Quest](https://github.com/Will2Jacks/GameZoneForked/tree/Task/Games/Intellect_Quest) | | [Taash_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Taash_Game) | | [Number_Guessing_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Number_Guessing_Game) | +| [Tower_Block_Game](https://github.com/Saipradyumnagoud/GameZone/tree/main/Games/Tower_Block_Game) | | [Modulo_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Modulo_Game) | @@ -405,6 +406,5 @@ Terms and conditions for use, reproduction and distribution are under the [Apach
- -

Back to top

+

Back to top

diff --git a/assets/images/Tower_Block_Game.png b/assets/images/Tower_Block_Game.png new file mode 100644 index 0000000000..4681a2dd40 Binary files /dev/null and b/assets/images/Tower_Block_Game.png differ