| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 (function() { | 4 (function() { |
| 5 'use strict'; | 5 'use strict'; |
| 6 /** | 6 /** |
| 7 * T-Rex runner. | 7 * T-Rex runner. |
| 8 * @param {string} outerContainerId Outer containing element id. | 8 * @param {string} outerContainerId Outer containing element id. |
| 9 * @param {object} opt_config | 9 * @param {object} opt_config |
| 10 * @constructor | 10 * @constructor |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 | 80 |
| 81 /** @const */ | 81 /** @const */ |
| 82 var IS_HIDPI = window.devicePixelRatio > 1; | 82 var IS_HIDPI = window.devicePixelRatio > 1; |
| 83 | 83 |
| 84 /** @const */ | 84 /** @const */ |
| 85 var IS_MOBILE = window.navigator.userAgent.indexOf('Mobi') > -1; | 85 var IS_MOBILE = window.navigator.userAgent.indexOf('Mobi') > -1; |
| 86 | 86 |
| 87 /** @const */ | 87 /** @const */ |
| 88 var IS_TOUCH_ENABLED = 'ontouchstart' in window; | 88 var IS_TOUCH_ENABLED = 'ontouchstart' in window; |
| 89 | 89 |
| 90 /** @const */ |
| 91 var IS_IOS = window.navigator.userAgent.indexOf('CriOS') > -1; |
| 90 | 92 |
| 91 /** | 93 /** |
| 92 * Default game configuration. | 94 * Default game configuration. |
| 93 * @enum {number} | 95 * @enum {number} |
| 94 */ | 96 */ |
| 95 Runner.config = { | 97 Runner.config = { |
| 96 ACCELERATION: 0.001, | 98 ACCELERATION: 0.001, |
| 97 BG_CLOUD_SPEED: 0.2, | 99 BG_CLOUD_SPEED: 0.2, |
| 98 BOTTOM_PAD: 10, | 100 BOTTOM_PAD: 10, |
| 99 CLEAR_TIME: 3000, | 101 CLEAR_TIME: 3000, |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 var imgSource = imageSources[i]; | 246 var imgSource = imageSources[i]; |
| 245 this.images[imgSource.name] = document.getElementById(imgSource.id); | 247 this.images[imgSource.name] = document.getElementById(imgSource.id); |
| 246 } | 248 } |
| 247 this.init(); | 249 this.init(); |
| 248 }, | 250 }, |
| 249 | 251 |
| 250 /** | 252 /** |
| 251 * Load and decode base 64 encoded sounds. | 253 * Load and decode base 64 encoded sounds. |
| 252 */ | 254 */ |
| 253 loadSounds: function() { | 255 loadSounds: function() { |
| 254 this.audioContext = new AudioContext(); | 256 if (!IS_IOS) { |
| 255 var resourceTemplate = | 257 this.audioContext = new AudioContext(); |
| 256 document.getElementById(this.config.RESOURCE_TEMPLATE_ID).content; | 258 var resourceTemplate = |
| 259 document.getElementById(this.config.RESOURCE_TEMPLATE_ID).content; |
| 257 | 260 |
| 258 for (var sound in Runner.sounds) { | 261 for (var sound in Runner.sounds) { |
| 259 var soundSrc = resourceTemplate.getElementById(Runner.sounds[sound]).src; | 262 var soundSrc = |
| 260 soundSrc = soundSrc.substr(soundSrc.indexOf(',') + 1); | 263 resourceTemplate.getElementById(Runner.sounds[sound]).src; |
| 261 var buffer = decodeBase64ToArrayBuffer(soundSrc); | 264 soundSrc = soundSrc.substr(soundSrc.indexOf(',') + 1); |
| 265 var buffer = decodeBase64ToArrayBuffer(soundSrc); |
| 262 | 266 |
| 263 // Async, so no guarantee of order in array. | 267 // Async, so no guarantee of order in array. |
| 264 this.audioContext.decodeAudioData(buffer, function(index, audioData) { | 268 this.audioContext.decodeAudioData(buffer, function(index, audioData) { |
| 265 this.soundFx[index] = audioData; | 269 this.soundFx[index] = audioData; |
| 266 }.bind(this, sound)); | 270 }.bind(this, sound)); |
| 271 } |
| 267 } | 272 } |
| 268 }, | 273 }, |
| 269 | 274 |
| 270 /** | 275 /** |
| 271 * Sets the game speed. Adjust the speed accordingly if on a smaller screen. | 276 * Sets the game speed. Adjust the speed accordingly if on a smaller screen. |
| 272 * @param {number} opt_speed | 277 * @param {number} opt_speed |
| 273 */ | 278 */ |
| 274 setSpeed: function(opt_speed) { | 279 setSpeed: function(opt_speed) { |
| 275 var speed = opt_speed || this.currentSpeed; | 280 var speed = opt_speed || this.currentSpeed; |
| 276 | 281 |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 this.canvasCtx.clearRect(0, 0, this.dimensions.WIDTH, | 455 this.canvasCtx.clearRect(0, 0, this.dimensions.WIDTH, |
| 451 this.dimensions.HEIGHT); | 456 this.dimensions.HEIGHT); |
| 452 }, | 457 }, |
| 453 | 458 |
| 454 /** | 459 /** |
| 455 * Update the game frame. | 460 * Update the game frame. |
| 456 */ | 461 */ |
| 457 update: function() { | 462 update: function() { |
| 458 this.drawPending = false; | 463 this.drawPending = false; |
| 459 | 464 |
| 460 var now = performance.now(); | 465 var now = getTimeStamp(); |
| 461 var deltaTime = now - (this.time || now); | 466 var deltaTime = now - (this.time || now); |
| 462 this.time = now; | 467 this.time = now; |
| 463 | 468 |
| 464 if (this.activated) { | 469 if (this.activated) { |
| 465 this.clearCanvas(); | 470 this.clearCanvas(); |
| 466 | 471 |
| 467 if (this.tRex.jumping) { | 472 if (this.tRex.jumping) { |
| 468 this.tRex.updateJump(deltaTime, this.config); | 473 this.tRex.updateJump(deltaTime, this.config); |
| 469 } | 474 } |
| 470 | 475 |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 var isjumpKey = Runner.keycodes.JUMP[keyCode] || | 621 var isjumpKey = Runner.keycodes.JUMP[keyCode] || |
| 617 e.type == Runner.events.TOUCHEND || | 622 e.type == Runner.events.TOUCHEND || |
| 618 e.type == Runner.events.MOUSEDOWN; | 623 e.type == Runner.events.MOUSEDOWN; |
| 619 | 624 |
| 620 if (this.isRunning() && isjumpKey) { | 625 if (this.isRunning() && isjumpKey) { |
| 621 this.tRex.endJump(); | 626 this.tRex.endJump(); |
| 622 } else if (Runner.keycodes.DUCK[keyCode]) { | 627 } else if (Runner.keycodes.DUCK[keyCode]) { |
| 623 this.tRex.speedDrop = false; | 628 this.tRex.speedDrop = false; |
| 624 } else if (this.crashed) { | 629 } else if (this.crashed) { |
| 625 // Check that enough time has elapsed before allowing jump key to restart. | 630 // Check that enough time has elapsed before allowing jump key to restart. |
| 626 var deltaTime = performance.now() - this.time; | 631 var deltaTime = getTimeStamp() - this.time; |
| 627 | 632 |
| 628 if (Runner.keycodes.RESTART[keyCode] || | 633 if (Runner.keycodes.RESTART[keyCode] || |
| 629 (e.type == Runner.events.MOUSEUP && e.target == this.canvas) || | 634 (e.type == Runner.events.MOUSEUP && e.target == this.canvas) || |
| 630 (deltaTime >= this.config.GAMEOVER_CLEAR_TIME && | 635 (deltaTime >= this.config.GAMEOVER_CLEAR_TIME && |
| 631 Runner.keycodes.JUMP[keyCode])) { | 636 Runner.keycodes.JUMP[keyCode])) { |
| 632 this.restart(); | 637 this.restart(); |
| 633 } | 638 } |
| 634 } else if (this.paused && isjumpKey) { | 639 } else if (this.paused && isjumpKey) { |
| 635 this.play(); | 640 this.play(); |
| 636 } | 641 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 this.gameOverPanel.draw(); | 681 this.gameOverPanel.draw(); |
| 677 } | 682 } |
| 678 | 683 |
| 679 // Update the high score. | 684 // Update the high score. |
| 680 if (this.distanceRan > this.highestScore) { | 685 if (this.distanceRan > this.highestScore) { |
| 681 this.highestScore = Math.ceil(this.distanceRan); | 686 this.highestScore = Math.ceil(this.distanceRan); |
| 682 this.distanceMeter.setHighScore(this.highestScore); | 687 this.distanceMeter.setHighScore(this.highestScore); |
| 683 } | 688 } |
| 684 | 689 |
| 685 // Reset the time clock. | 690 // Reset the time clock. |
| 686 this.time = performance.now(); | 691 this.time = getTimeStamp(); |
| 687 }, | 692 }, |
| 688 | 693 |
| 689 stop: function() { | 694 stop: function() { |
| 690 this.activated = false; | 695 this.activated = false; |
| 691 this.paused = true; | 696 this.paused = true; |
| 692 cancelAnimationFrame(this.raqId); | 697 cancelAnimationFrame(this.raqId); |
| 693 this.raqId = 0; | 698 this.raqId = 0; |
| 694 }, | 699 }, |
| 695 | 700 |
| 696 play: function() { | 701 play: function() { |
| 697 if (!this.crashed) { | 702 if (!this.crashed) { |
| 698 this.activated = true; | 703 this.activated = true; |
| 699 this.paused = false; | 704 this.paused = false; |
| 700 this.tRex.update(0, Trex.status.RUNNING); | 705 this.tRex.update(0, Trex.status.RUNNING); |
| 701 this.time = performance.now(); | 706 this.time = getTimeStamp(); |
| 702 this.update(); | 707 this.update(); |
| 703 } | 708 } |
| 704 }, | 709 }, |
| 705 | 710 |
| 706 restart: function() { | 711 restart: function() { |
| 707 if (!this.raqId) { | 712 if (!this.raqId) { |
| 708 this.playCount++; | 713 this.playCount++; |
| 709 this.runningTime = 0; | 714 this.runningTime = 0; |
| 710 this.activated = true; | 715 this.activated = true; |
| 711 this.crashed = false; | 716 this.crashed = false; |
| 712 this.distanceRan = 0; | 717 this.distanceRan = 0; |
| 713 this.setSpeed(this.config.SPEED); | 718 this.setSpeed(this.config.SPEED); |
| 714 | 719 |
| 715 this.time = performance.now(); | 720 this.time = getTimeStamp(); |
| 716 this.containerEl.classList.remove(Runner.classes.CRASHED); | 721 this.containerEl.classList.remove(Runner.classes.CRASHED); |
| 717 this.clearCanvas(); | 722 this.clearCanvas(); |
| 718 this.distanceMeter.reset(this.highestScore); | 723 this.distanceMeter.reset(this.highestScore); |
| 719 this.horizon.reset(); | 724 this.horizon.reset(); |
| 720 this.tRex.reset(); | 725 this.tRex.reset(); |
| 721 this.playSound(this.soundFx.BUTTON_PRESS); | 726 this.playSound(this.soundFx.BUTTON_PRESS); |
| 722 | 727 |
| 723 this.update(); | 728 this.update(); |
| 724 } | 729 } |
| 725 }, | 730 }, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 801 function getRandomNum(min, max) { | 806 function getRandomNum(min, max) { |
| 802 return Math.floor(Math.random() * (max - min + 1)) + min; | 807 return Math.floor(Math.random() * (max - min + 1)) + min; |
| 803 } | 808 } |
| 804 | 809 |
| 805 | 810 |
| 806 /** | 811 /** |
| 807 * Vibrate on mobile devices. | 812 * Vibrate on mobile devices. |
| 808 * @param {number} duration Duration of the vibration in milliseconds. | 813 * @param {number} duration Duration of the vibration in milliseconds. |
| 809 */ | 814 */ |
| 810 function vibrate(duration) { | 815 function vibrate(duration) { |
| 811 if (IS_MOBILE) { | 816 if (IS_MOBILE && window.navigator.vibrate) { |
| 812 window.navigator['vibrate'](duration); | 817 window.navigator.vibrate(duration); |
| 813 } | 818 } |
| 814 } | 819 } |
| 815 | 820 |
| 816 | 821 |
| 817 /** | 822 /** |
| 818 * Create canvas element. | 823 * Create canvas element. |
| 819 * @param {HTMLElement} container Element to append canvas to. | 824 * @param {HTMLElement} container Element to append canvas to. |
| 820 * @param {number} width | 825 * @param {number} width |
| 821 * @param {number} height | 826 * @param {number} height |
| 822 * @param {string} opt_classname | 827 * @param {string} opt_classname |
| (...skipping 21 matching lines...) Expand all Loading... |
| 844 var arrayBuffer = new ArrayBuffer(len); | 849 var arrayBuffer = new ArrayBuffer(len); |
| 845 var bytes = new Uint8Array(arrayBuffer); | 850 var bytes = new Uint8Array(arrayBuffer); |
| 846 | 851 |
| 847 for (var i = 0; i < len; i++) { | 852 for (var i = 0; i < len; i++) { |
| 848 bytes[i] = str.charCodeAt(i); | 853 bytes[i] = str.charCodeAt(i); |
| 849 } | 854 } |
| 850 return bytes.buffer; | 855 return bytes.buffer; |
| 851 } | 856 } |
| 852 | 857 |
| 853 | 858 |
| 859 /** |
| 860 * Return the current timestamp. |
| 861 * @return {number} |
| 862 */ |
| 863 function getTimeStamp() { |
| 864 return IS_IOS ? new Date().getTime() : performance.now(); |
| 865 } |
| 866 |
| 867 |
| 854 //****************************************************************************** | 868 //****************************************************************************** |
| 855 | 869 |
| 856 | 870 |
| 857 /** | 871 /** |
| 858 * Game over panel. | 872 * Game over panel. |
| 859 * @param {!HTMLCanvasElement} canvas | 873 * @param {!HTMLCanvasElement} canvas |
| 860 * @param {!HTMLImage} textSprite | 874 * @param {!HTMLImage} textSprite |
| 861 * @param {!HTMLImage} restartImg | 875 * @param {!HTMLImage} restartImg |
| 862 * @param {!Object} dimensions Canvas dimensions. | 876 * @param {!Object} dimensions Canvas dimensions. |
| 863 * @constructor | 877 * @constructor |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1417 this.timer += deltaTime; | 1431 this.timer += deltaTime; |
| 1418 | 1432 |
| 1419 // Update the status. | 1433 // Update the status. |
| 1420 if (opt_status) { | 1434 if (opt_status) { |
| 1421 this.status = opt_status; | 1435 this.status = opt_status; |
| 1422 this.currentFrame = 0; | 1436 this.currentFrame = 0; |
| 1423 this.msPerFrame = Trex.animFrames[opt_status].msPerFrame; | 1437 this.msPerFrame = Trex.animFrames[opt_status].msPerFrame; |
| 1424 this.currentAnimFrames = Trex.animFrames[opt_status].frames; | 1438 this.currentAnimFrames = Trex.animFrames[opt_status].frames; |
| 1425 | 1439 |
| 1426 if (opt_status == Trex.status.WAITING) { | 1440 if (opt_status == Trex.status.WAITING) { |
| 1427 this.animStartTime = performance.now(); | 1441 this.animStartTime = getTimeStamp(); |
| 1428 this.setBlinkDelay(); | 1442 this.setBlinkDelay(); |
| 1429 } | 1443 } |
| 1430 } | 1444 } |
| 1431 | 1445 |
| 1432 // Game intro animation, T-rex moves in from the left. | 1446 // Game intro animation, T-rex moves in from the left. |
| 1433 if (this.playingIntro && this.xPos < this.config.START_X_POS) { | 1447 if (this.playingIntro && this.xPos < this.config.START_X_POS) { |
| 1434 this.xPos += Math.round((this.config.START_X_POS / | 1448 this.xPos += Math.round((this.config.START_X_POS / |
| 1435 this.config.INTRO_DURATION) * deltaTime); | 1449 this.config.INTRO_DURATION) * deltaTime); |
| 1436 } | 1450 } |
| 1437 | 1451 |
| 1438 if (this.status == Trex.status.WAITING) { | 1452 if (this.status == Trex.status.WAITING) { |
| 1439 this.blink(performance.now()); | 1453 this.blink(getTimeStamp()); |
| 1440 } else { | 1454 } else { |
| 1441 this.draw(this.currentAnimFrames[this.currentFrame], 0); | 1455 this.draw(this.currentAnimFrames[this.currentFrame], 0); |
| 1442 } | 1456 } |
| 1443 | 1457 |
| 1444 // Update the frame position. | 1458 // Update the frame position. |
| 1445 if (this.timer >= this.msPerFrame) { | 1459 if (this.timer >= this.msPerFrame) { |
| 1446 this.currentFrame = this.currentFrame == | 1460 this.currentFrame = this.currentFrame == |
| 1447 this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1; | 1461 this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1; |
| 1448 this.timer = 0; | 1462 this.timer = 0; |
| 1449 } | 1463 } |
| (...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2229 | 2243 |
| 2230 /** | 2244 /** |
| 2231 * Add a new cloud to the horizon. | 2245 * Add a new cloud to the horizon. |
| 2232 */ | 2246 */ |
| 2233 addCloud: function() { | 2247 addCloud: function() { |
| 2234 this.clouds.push(new Cloud(this.canvas, this.cloudImg, | 2248 this.clouds.push(new Cloud(this.canvas, this.cloudImg, |
| 2235 this.dimensions.WIDTH)); | 2249 this.dimensions.WIDTH)); |
| 2236 } | 2250 } |
| 2237 }; | 2251 }; |
| 2238 })(); | 2252 })(); |
| OLD | NEW |