48 |
49 |
50 |
51 | ${displayTitle}
52 |
53 |
54 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Press SpaceBar to start
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | PAUSED
89 |
90 |
91 |
92 |
93 |
94 |
95 | Press P to resume
96 |
97 |
98 | Press SpaceBar to restart
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | Well Done
110 |
111 |
112 | Time:
113 |
114 |
115 |
116 |
117 |
118 | Press SpaceBar to restart
119 |
120 |
121 |
122 |
123 | `;
124 |
125 | document.body.appendChild(this.textOverlayDisplay);
126 |
127 | this.showCoverOverlay();
128 |
129 | }
130 |
131 |
132 | showCoverOverlay(){
133 |
134 | document.getElementById('cover-overlay').style.display = "block";
135 | document.getElementById('gameview-overlay').style.display = "none";
136 |
137 | }
138 |
139 | showGameViewOverlay(){
140 |
141 |
142 | document.getElementById('cover-overlay').style.display = "none";
143 | document.getElementById('gameview-overlay').style.display = "block";
144 |
145 |
146 | }
147 |
148 |
149 |
150 | showTimerDisplay(){
151 |
152 | document.getElementById('timer-parent').style.display = 'block';
153 |
154 | }
155 |
156 | hideTimerDisplay(){
157 |
158 | document.getElementById('timer-parent').style.display = 'none';
159 |
160 | }
161 |
162 | showGameInstruction(){
163 |
164 | document.getElementById("loader").style.display = "none";
165 | let instruction = "`Instruction`";
166 | instruction += "^1000\nMove the ball to the rotating particles at the end of the board";
167 | instruction += "^2500\nBe careful not to collide with the red bricks, they will delay you";
168 | instruction += "^2500\n\n`Controls`"
169 | instruction += "^1000\nUse mouse movement to tilt board and Key A and D to change viewing angle";
170 |
171 |
172 | //somehow its seems like Typed.js npm modules skips the first string in the strings array
173 | //so an empty string is used to make it behave as expected
174 | var typed = new Typed("#instruction", {
175 |
176 | startDelay: 1000,
177 | strings: ["", instruction],
178 | smartBackspace: true, // Default value
179 | typeSpeed: 10,
180 | showCursor: false,
181 | onStart: ()=>{
182 |
183 | this.isTyping = true;
184 |
185 | },
186 | onComplete: ()=>{
187 |
188 | setTimeout(()=>{
189 |
190 | document.getElementById('startMsg').style.display = 'block';
191 | this.isTyping = false;
192 |
193 | }, 3000)
194 |
195 | }
196 |
197 | });
198 |
199 | typed.start();
200 |
201 | }
202 |
203 | showPauseDisplay(){
204 |
205 | document.getElementById('pause-overlay').style.display = 'block';
206 |
207 | }
208 |
209 |
210 | hidePauseDisplay(){
211 |
212 | document.getElementById('pause-overlay').style.display = 'none';
213 |
214 | }
215 |
216 |
217 | showGameOver(){
218 |
219 |
220 | document.getElementById('cover-overlay').style.display = "none";
221 | document.getElementById('gameview-overlay').style.display = "none";
222 |
223 |
224 | document.getElementById('time-score').innerText = document.getElementById('timer-display').innerText;
225 | document.getElementById('gameover-overlay').style.display = "block";
226 |
227 | }
228 |
229 | hideGameOver(){
230 |
231 | document.getElementById('gameover-overlay').style.display = 'none';
232 |
233 | }
234 |
235 |
236 |
237 |
238 |
239 |
240 | /**
241 | * Update to show the progress of the loading process
242 | *
243 | * @param {any} percentage A normalized value (0 - 1) showing the current load progress (required)
244 | * @param {any} message An optional text to display (optional)
245 | * @memberof TextOverlay
246 | */
247 | updateLoadingDisplay(percentage, message){
248 |
249 | percentage = percentage || 0;
250 |
251 | if(Number.isNaN(Number.parseFloat(percentage))) percentage = 0;
252 | if(percentage > 100) percentage = 100;
253 | if(percentage < 0) percentage = 0;
254 |
255 | if(typeof message !== 'string') message = 'loading...';
256 |
257 | //document.getElementById('progress-display').innerText = percentage + "%";
258 | document.getElementById('progress-text').innerText = message;
259 |
260 | }
261 |
262 | updateTimeDisplay(timeText){
263 |
264 | document.getElementById('timer-display').innerText = timeText;
265 |
266 | }
267 |
268 |
269 |
270 | /**
271 | * Inject the needed css style to the head of the html document
272 | *
273 | * @memberof TextOverlay
274 | */
275 | injectCSS(){
276 |
277 | let css = `
278 | .lds-dual-ring {
279 | display: inline-block;
280 | width: 64px;
281 | height: 64px;
282 | }
283 | .lds-dual-ring:after {
284 | content: " ";
285 | display: block;
286 | width: 46px;
287 | height: 46px;
288 | margin: 1px;
289 | border-radius: 50%;
290 | border: 5px solid #cef;
291 | border-color: #cef transparent #cef transparent;
292 | animation: lds-dual-ring 1.2s linear infinite;
293 | }
294 | @keyframes lds-dual-ring {
295 | 0% {
296 | transform: rotate(0deg);
297 | }
298 | 100% {
299 | transform: rotate(360deg);
300 | }
301 | }
302 |
303 | .grid-display{
304 |
305 |
306 | background-color: #3c3c3c !important;
307 | background-color: rgba(149, 138, 124, 0.5);
308 | background-image: linear-gradient(0deg, transparent 24%, rgba(255, 255, 255, 0.05) 25%, rgba(255, 255, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(255, 255, 255, 0.05) 75%, rgba(255, 255, 255, 0.05) 76%, transparent 77%, transparent), linear-gradient(90deg, transparent 24%, rgba(255, 255, 255, 0.05) 25%, rgba(255, 255, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(255, 255, 255, 0.05) 75%, rgba(255, 255, 255, 0.05) 76%, transparent 77%, transparent);
309 | background-size: 50px 50px;
310 |
311 | }
312 |
313 | #text-overlay{
314 | width: 100%;
315 | height: 100%
316 | }
317 |
318 | #cover-overlay {
319 | position: absolute;
320 | width: 100%;
321 | height: 100%;
322 | }
323 |
324 | #display-title{
325 | width: 500px;
326 | height: 150px;
327 | margin: 0px auto;
328 | font-size: 100px;
329 | font-family: jokerman;
330 | color: #cb785e;
331 | text-shadow: 2px 2px 5px black;
332 | text-align: center;
333 | margin-top: 50px;
334 | }
335 |
336 |
337 |
338 |
339 | #overlay-box{
340 |
341 | width: 100%;
342 | height: 200px;
343 |
344 | display: -webkit-box;
345 | display: -moz-box;
346 | display: box;
347 |
348 | -webkit-box-orient: horizontal;
349 | -moz-box-orient: horizontal;
350 | box-orient: horizontal;
351 |
352 | -webkit-box-pack: center;
353 | -moz-box-pack: center;
354 | box-pack: center;
355 |
356 | -webkit-box-align: center;
357 | -moz-box-align: center;
358 | box-align: center;
359 |
360 | color: #ffffff;
361 | text-align: center;
362 | }
363 |
364 | #progress-display{
365 | font-family: jokerman;
366 | font-size: 30px;
367 | color: #cedeac;
368 | text-shadow: 2px 2px 5px black;
369 | }
370 |
371 | #progress-text{
372 | font-family: "Comic Sans MS";
373 | color: black;
374 | }
375 |
376 | #timer-parent{
377 | position: absolute;
378 | width: 100%;
379 | height: 100%;
380 | margin: 0px auto;
381 | text-align: right;
382 | font-family: jokerman;
383 | color: #cb785e;
384 | text-shadow: 2px 2px 2px #8a6161
385 | }
386 |
387 | #timer-display{
388 | font-size: 20px
389 | }
390 |
391 | #pause-overlay {
392 | position: absolute;
393 | width: 100%;
394 | height: 100%;
395 | background-color: rgba(59, 60, 60, 0.9);
396 | }
397 |
398 | #gameover-overlay {
399 | position: absolute;
400 | width: 100%;
401 | height: 100%;
402 | background-color: rgba(59, 60, 60, 0.9);
403 | }
404 | `,
405 | head = document.head || document.getElementsByTagName('head')[0],
406 | style = document.createElement('style');
407 |
408 | style.type = 'text/css';
409 | if (style.styleSheet){
410 | // This is required for IE8 and below.
411 | style.styleSheet.cssText = css;
412 | } else {
413 | style.appendChild(document.createTextNode(css));
414 | }
415 |
416 | head.appendChild(style);
417 | }
418 | }
419 |
420 | const ldOverlay = new TextOverlay();
421 |
422 | export default ldOverlay;
--------------------------------------------------------------------------------
/src/libs/ViewPort.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 BlueMagnificent
2 |
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 |
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 |
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 |
22 | export default class ViewPort {
23 | /**
24 | * Creates an instance of ViewPort.
25 | * @param {Object} scene
26 | * @param {Object} camera
27 | * @param {Object} renderer
28 | * @memberof ViewPort
29 | */
30 | constructor(scene, camera, renderer){
31 | this.scene = scene;
32 | this.camera = camera;
33 | this.renderer = renderer;
34 | }
35 |
36 | /**
37 | * Render a scene to the viewport based on the scene and camera
38 | *
39 | * @memberof ViewPort
40 | */
41 | renderToViewport(){
42 | this.renderer.render( this.scene, this.camera );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/threejs/stats.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){function h(a){c.appendChild(a.dom);return a}function k(a){for(var d=0;d