Skip to content

Commit 0ee5dfb

Browse files
author
Aenosh Rajora
committed
First Commit
0 parents  commit 0ee5dfb

File tree

5 files changed

+445
-0
lines changed

5 files changed

+445
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Stack Game
2+
3+
<h3> Tech Stack Used <img src = "https://media2.giphy.com/media/QssGEmpkyEOhBCb7e1/giphy.gif?cid=ecf05e47a0n3gi1bfqntqmob8g9aid1oyj2wr3ds3mg700bl&rid=giphy.gif" width = 32px> </h3>
4+
<p align="left"> <a href="https://www.w3.org/html/" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/html5/html5-original-wordmark.svg" alt="html5" width="40" height="40"/> </a> <a href="https://www.w3schools.com/css/" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/css3/css3-original-wordmark.svg" alt="css3" width="40" height="40"/> </a> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="javascript" width="40" height="40"/> </a> </p>
5+
6+
### Preview
7+
8+
![](/assets/stack-demoo.gif)
9+
=======
10+

assets/stack-demoo.gif

905 KB
Loading

index.html

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE html>
2+
<html lang="en" >
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>DragonUncaged_Stack_Game</title>
6+
<link rel="stylesheet" href="./style.css">
7+
8+
</head>
9+
<body>
10+
<meta name="viewport" content="width=device-width,user-scalable=no">
11+
12+
<div id="container">
13+
<div id="game"></div>
14+
<div id="score">0</div>
15+
<div id="instructions">Click (or press the spacebar) to place the block</div>
16+
<div class="game-over">
17+
<h2>Game Over</h2>
18+
<p>You did great, you're the best.</p>
19+
<p>Click or spacebar to start again</p>
20+
</div>
21+
<div class="game-ready">
22+
<div id="start-button">Start</div>
23+
<div></div>
24+
</div>
25+
</div>
26+
<!-- partial -->
27+
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js'></script>
28+
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js'></script><script src="./script.js"></script>
29+
30+
</body>
31+
</html>

script.js

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
"use strict";
2+
console.clear();
3+
class Stage {
4+
constructor() {
5+
// container
6+
this.render = function () {
7+
this.renderer.render(this.scene, this.camera);
8+
};
9+
this.add = function (elem) {
10+
this.scene.add(elem);
11+
};
12+
this.remove = function (elem) {
13+
this.scene.remove(elem);
14+
};
15+
this.container = document.getElementById('game');
16+
// renderer
17+
this.renderer = new THREE.WebGLRenderer({
18+
antialias: true,
19+
alpha: false
20+
});
21+
this.renderer.setSize(window.innerWidth, window.innerHeight);
22+
this.renderer.setClearColor('#D0CBC7', 1);
23+
this.container.appendChild(this.renderer.domElement);
24+
// scene
25+
this.scene = new THREE.Scene();
26+
// camera
27+
let aspect = window.innerWidth / window.innerHeight;
28+
let d = 20;
29+
this.camera = new THREE.OrthographicCamera(-d * aspect, d * aspect, d, -d, -100, 1000);
30+
this.camera.position.x = 2;
31+
this.camera.position.y = 2;
32+
this.camera.position.z = 2;
33+
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
34+
//light
35+
this.light = new THREE.DirectionalLight(0xffffff, 0.5);
36+
this.light.position.set(0, 499, 0);
37+
this.scene.add(this.light);
38+
this.softLight = new THREE.AmbientLight(0xffffff, 0.4);
39+
this.scene.add(this.softLight);
40+
window.addEventListener('resize', () => this.onResize());
41+
this.onResize();
42+
}
43+
setCamera(y, speed = 0.3) {
44+
TweenLite.to(this.camera.position, speed, { y: y + 4, ease: Power1.easeInOut });
45+
TweenLite.to(this.camera.lookAt, speed, { y: y, ease: Power1.easeInOut });
46+
}
47+
onResize() {
48+
let viewSize = 30;
49+
this.renderer.setSize(window.innerWidth, window.innerHeight);
50+
this.camera.left = window.innerWidth / -viewSize;
51+
this.camera.right = window.innerWidth / viewSize;
52+
this.camera.top = window.innerHeight / viewSize;
53+
this.camera.bottom = window.innerHeight / -viewSize;
54+
this.camera.updateProjectionMatrix();
55+
}
56+
}
57+
class Block {
58+
constructor(block) {
59+
// set size and position
60+
this.STATES = { ACTIVE: 'active', STOPPED: 'stopped', MISSED: 'missed' };
61+
this.MOVE_AMOUNT = 12;
62+
this.dimension = { width: 0, height: 0, depth: 0 };
63+
this.position = { x: 0, y: 0, z: 0 };
64+
this.targetBlock = block;
65+
this.index = (this.targetBlock ? this.targetBlock.index : 0) + 1;
66+
this.workingPlane = this.index % 2 ? 'x' : 'z';
67+
this.workingDimension = this.index % 2 ? 'width' : 'depth';
68+
// set the dimensions from the target block, or defaults.
69+
this.dimension.width = this.targetBlock ? this.targetBlock.dimension.width : 10;
70+
this.dimension.height = this.targetBlock ? this.targetBlock.dimension.height : 2;
71+
this.dimension.depth = this.targetBlock ? this.targetBlock.dimension.depth : 10;
72+
this.position.x = this.targetBlock ? this.targetBlock.position.x : 0;
73+
this.position.y = this.dimension.height * this.index;
74+
this.position.z = this.targetBlock ? this.targetBlock.position.z : 0;
75+
this.colorOffset = this.targetBlock ? this.targetBlock.colorOffset : Math.round(Math.random() * 100);
76+
// set color
77+
if (!this.targetBlock) {
78+
this.color = 0x333344;
79+
}
80+
else {
81+
let offset = this.index + this.colorOffset;
82+
var r = Math.sin(0.3 * offset) * 55 + 200;
83+
var g = Math.sin(0.3 * offset + 2) * 55 + 200;
84+
var b = Math.sin(0.3 * offset + 4) * 55 + 200;
85+
this.color = new THREE.Color(r / 255, g / 255, b / 255);
86+
}
87+
// state
88+
this.state = this.index > 1 ? this.STATES.ACTIVE : this.STATES.STOPPED;
89+
// set direction
90+
this.speed = -0.1 - (this.index * 0.005);
91+
if (this.speed < -4)
92+
this.speed = -4;
93+
this.direction = this.speed;
94+
// create block
95+
let geometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height, this.dimension.depth);
96+
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2, this.dimension.height / 2, this.dimension.depth / 2));
97+
this.material = new THREE.MeshToonMaterial({ color: this.color, shading: THREE.FlatShading });
98+
this.mesh = new THREE.Mesh(geometry, this.material);
99+
this.mesh.position.set(this.position.x, this.position.y + (this.state == this.STATES.ACTIVE ? 0 : 0), this.position.z);
100+
if (this.state == this.STATES.ACTIVE) {
101+
this.position[this.workingPlane] = Math.random() > 0.5 ? -this.MOVE_AMOUNT : this.MOVE_AMOUNT;
102+
}
103+
}
104+
reverseDirection() {
105+
this.direction = this.direction > 0 ? this.speed : Math.abs(this.speed);
106+
}
107+
place() {
108+
this.state = this.STATES.STOPPED;
109+
let overlap = this.targetBlock.dimension[this.workingDimension] - Math.abs(this.position[this.workingPlane] - this.targetBlock.position[this.workingPlane]);
110+
let blocksToReturn = {
111+
plane: this.workingPlane,
112+
direction: this.direction
113+
};
114+
if (this.dimension[this.workingDimension] - overlap < 0.3) {
115+
overlap = this.dimension[this.workingDimension];
116+
blocksToReturn.bonus = true;
117+
this.position.x = this.targetBlock.position.x;
118+
this.position.z = this.targetBlock.position.z;
119+
this.dimension.width = this.targetBlock.dimension.width;
120+
this.dimension.depth = this.targetBlock.dimension.depth;
121+
}
122+
if (overlap > 0) {
123+
let choppedDimensions = { width: this.dimension.width, height: this.dimension.height, depth: this.dimension.depth };
124+
choppedDimensions[this.workingDimension] -= overlap;
125+
this.dimension[this.workingDimension] = overlap;
126+
let placedGeometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height, this.dimension.depth);
127+
placedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2, this.dimension.height / 2, this.dimension.depth / 2));
128+
let placedMesh = new THREE.Mesh(placedGeometry, this.material);
129+
let choppedGeometry = new THREE.BoxGeometry(choppedDimensions.width, choppedDimensions.height, choppedDimensions.depth);
130+
choppedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(choppedDimensions.width / 2, choppedDimensions.height / 2, choppedDimensions.depth / 2));
131+
let choppedMesh = new THREE.Mesh(choppedGeometry, this.material);
132+
let choppedPosition = {
133+
x: this.position.x,
134+
y: this.position.y,
135+
z: this.position.z
136+
};
137+
if (this.position[this.workingPlane] < this.targetBlock.position[this.workingPlane]) {
138+
this.position[this.workingPlane] = this.targetBlock.position[this.workingPlane];
139+
}
140+
else {
141+
choppedPosition[this.workingPlane] += overlap;
142+
}
143+
placedMesh.position.set(this.position.x, this.position.y, this.position.z);
144+
choppedMesh.position.set(choppedPosition.x, choppedPosition.y, choppedPosition.z);
145+
blocksToReturn.placed = placedMesh;
146+
if (!blocksToReturn.bonus)
147+
blocksToReturn.chopped = choppedMesh;
148+
}
149+
else {
150+
this.state = this.STATES.MISSED;
151+
}
152+
this.dimension[this.workingDimension] = overlap;
153+
return blocksToReturn;
154+
}
155+
tick() {
156+
if (this.state == this.STATES.ACTIVE) {
157+
let value = this.position[this.workingPlane];
158+
if (value > this.MOVE_AMOUNT || value < -this.MOVE_AMOUNT)
159+
this.reverseDirection();
160+
this.position[this.workingPlane] += this.direction;
161+
this.mesh.position[this.workingPlane] = this.position[this.workingPlane];
162+
}
163+
}
164+
}
165+
class Game {
166+
constructor() {
167+
this.STATES = {
168+
'LOADING': 'loading',
169+
'PLAYING': 'playing',
170+
'READY': 'ready',
171+
'ENDED': 'ended',
172+
'RESETTING': 'resetting'
173+
};
174+
this.blocks = [];
175+
this.state = this.STATES.LOADING;
176+
this.stage = new Stage();
177+
this.mainContainer = document.getElementById('container');
178+
this.scoreContainer = document.getElementById('score');
179+
this.startButton = document.getElementById('start-button');
180+
this.instructions = document.getElementById('instructions');
181+
this.scoreContainer.innerHTML = '0';
182+
this.newBlocks = new THREE.Group();
183+
this.placedBlocks = new THREE.Group();
184+
this.choppedBlocks = new THREE.Group();
185+
this.stage.add(this.newBlocks);
186+
this.stage.add(this.placedBlocks);
187+
this.stage.add(this.choppedBlocks);
188+
this.addBlock();
189+
this.tick();
190+
this.updateState(this.STATES.READY);
191+
document.addEventListener('keydown', e => {
192+
if (e.keyCode == 32)
193+
this.onAction();
194+
});
195+
document.addEventListener('click', e => {
196+
this.onAction();
197+
});
198+
document.addEventListener('touchstart', e => {
199+
e.preventDefault();
200+
// this.onAction();
201+
// this triggers after click on android so you
202+
// insta-lose, will figure it out later.
203+
});
204+
}
205+
updateState(newState) {
206+
for (let key in this.STATES)
207+
this.mainContainer.classList.remove(this.STATES[key]);
208+
this.mainContainer.classList.add(newState);
209+
this.state = newState;
210+
}
211+
onAction() {
212+
switch (this.state) {
213+
case this.STATES.READY:
214+
this.startGame();
215+
break;
216+
case this.STATES.PLAYING:
217+
this.placeBlock();
218+
break;
219+
case this.STATES.ENDED:
220+
this.restartGame();
221+
break;
222+
}
223+
}
224+
startGame() {
225+
if (this.state != this.STATES.PLAYING) {
226+
this.scoreContainer.innerHTML = '0';
227+
this.updateState(this.STATES.PLAYING);
228+
this.addBlock();
229+
}
230+
}
231+
restartGame() {
232+
this.updateState(this.STATES.RESETTING);
233+
let oldBlocks = this.placedBlocks.children;
234+
let removeSpeed = 0.2;
235+
let delayAmount = 0.02;
236+
for (let i = 0; i < oldBlocks.length; i++) {
237+
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]) });
238+
TweenLite.to(oldBlocks[i].rotation, removeSpeed, { y: 0.5, delay: (oldBlocks.length - i) * delayAmount, ease: Power1.easeIn });
239+
}
240+
let cameraMoveSpeed = removeSpeed * 2 + (oldBlocks.length * delayAmount);
241+
this.stage.setCamera(2, cameraMoveSpeed);
242+
let countdown = { value: this.blocks.length - 1 };
243+
TweenLite.to(countdown, cameraMoveSpeed, { value: 0, onUpdate: () => { this.scoreContainer.innerHTML = String(Math.round(countdown.value)); } });
244+
this.blocks = this.blocks.slice(0, 1);
245+
setTimeout(() => {
246+
this.startGame();
247+
}, cameraMoveSpeed * 1000);
248+
}
249+
placeBlock() {
250+
let currentBlock = this.blocks[this.blocks.length - 1];
251+
let newBlocks = currentBlock.place();
252+
this.newBlocks.remove(currentBlock.mesh);
253+
if (newBlocks.placed)
254+
this.placedBlocks.add(newBlocks.placed);
255+
if (newBlocks.chopped) {
256+
this.choppedBlocks.add(newBlocks.chopped);
257+
let positionParams = { y: '-=30', ease: Power1.easeIn, onComplete: () => this.choppedBlocks.remove(newBlocks.chopped) };
258+
let rotateRandomness = 10;
259+
let rotationParams = {
260+
delay: 0.05,
261+
x: newBlocks.plane == 'z' ? ((Math.random() * rotateRandomness) - (rotateRandomness / 2)) : 0.1,
262+
z: newBlocks.plane == 'x' ? ((Math.random() * rotateRandomness) - (rotateRandomness / 2)) : 0.1,
263+
y: Math.random() * 0.1,
264+
};
265+
if (newBlocks.chopped.position[newBlocks.plane] > newBlocks.placed.position[newBlocks.plane]) {
266+
positionParams[newBlocks.plane] = '+=' + (40 * Math.abs(newBlocks.direction));
267+
}
268+
else {
269+
positionParams[newBlocks.plane] = '-=' + (40 * Math.abs(newBlocks.direction));
270+
}
271+
TweenLite.to(newBlocks.chopped.position, 1, positionParams);
272+
TweenLite.to(newBlocks.chopped.rotation, 1, rotationParams);
273+
}
274+
this.addBlock();
275+
}
276+
addBlock() {
277+
let lastBlock = this.blocks[this.blocks.length - 1];
278+
if (lastBlock && lastBlock.state == lastBlock.STATES.MISSED) {
279+
return this.endGame();
280+
}
281+
this.scoreContainer.innerHTML = String(this.blocks.length - 1);
282+
let newKidOnTheBlock = new Block(lastBlock);
283+
this.newBlocks.add(newKidOnTheBlock.mesh);
284+
this.blocks.push(newKidOnTheBlock);
285+
this.stage.setCamera(this.blocks.length * 2);
286+
if (this.blocks.length >= 5)
287+
this.instructions.classList.add('hide');
288+
}
289+
endGame() {
290+
this.updateState(this.STATES.ENDED);
291+
}
292+
tick() {
293+
this.blocks[this.blocks.length - 1].tick();
294+
this.stage.render();
295+
requestAnimationFrame(() => { this.tick(); });
296+
}
297+
}
298+
let game = new Game();

0 commit comments

Comments
 (0)