| 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 |
| 11 * @export | 11 * @export |
| 12 */ | 12 */ |
| 13 function Runner(outerContainerId, opt_config) { | 13 function Runner(outerContainerId, opt_config) { |
| 14 // Singleton | 14 // Singleton |
| 15 if (Runner.instance_) { | 15 if (Runner.instance_) { |
| 16 return Runner.instance_; | 16 return Runner.instance_; |
| 17 } | 17 } |
| 18 Runner.instance_ = this; | 18 Runner.instance_ = this; |
| 19 | 19 |
| 20 this.outerContainerEl = document.querySelector(outerContainerId); | 20 this.outerContainerEl = document.querySelector(outerContainerId); |
| 21 this.containerEl = null; | 21 this.containerEl = null; |
| 22 this.snackbarEl = null; | 22 this.snackbarEl = null; |
| 23 | 23 |
| 24 this.config = opt_config || Runner.config; | 24 this.config = opt_config || Runner.config; |
| 25 | 25 // Logical dimensions of the container. |
| 26 this.dimensions = Runner.defaultDimensions; | 26 this.dimensions = Runner.defaultDimensions; |
| 27 | 27 |
| 28 this.canvas = null; | 28 this.canvas = null; |
| 29 this.canvasCtx = null; | 29 this.canvasCtx = null; |
| 30 | 30 |
| 31 this.tRex = null; | 31 this.tRex = null; |
| 32 | 32 |
| 33 this.distanceMeter = null; | 33 this.distanceMeter = null; |
| 34 this.distanceRan = 0; | 34 this.distanceRan = 0; |
| 35 | 35 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 | 89 |
| 90 /** @const */ | 90 /** @const */ |
| 91 var IS_IOS = /iPad|iPhone|iPod/.test(window.navigator.platform); | 91 var IS_IOS = /iPad|iPhone|iPod/.test(window.navigator.platform); |
| 92 | 92 |
| 93 /** @const */ | 93 /** @const */ |
| 94 var IS_MOBILE = /Android/.test(window.navigator.userAgent) || IS_IOS; | 94 var IS_MOBILE = /Android/.test(window.navigator.userAgent) || IS_IOS; |
| 95 | 95 |
| 96 /** @const */ | 96 /** @const */ |
| 97 var IS_TOUCH_ENABLED = 'ontouchstart' in window; | 97 var IS_TOUCH_ENABLED = 'ontouchstart' in window; |
| 98 | 98 |
| 99 /** @const */ |
| 100 var ARCADE_MODE_URL = 'chrome://dino/'; |
| 101 |
| 99 /** | 102 /** |
| 100 * Default game configuration. | 103 * Default game configuration. |
| 101 * @enum {number} | 104 * @enum {number} |
| 102 */ | 105 */ |
| 103 Runner.config = { | 106 Runner.config = { |
| 104 ACCELERATION: 0.001, | 107 ACCELERATION: 0.001, |
| 105 BG_CLOUD_SPEED: 0.2, | 108 BG_CLOUD_SPEED: 0.2, |
| 106 BOTTOM_PAD: 10, | 109 BOTTOM_PAD: 10, |
| 107 CLEAR_TIME: 3000, | 110 CLEAR_TIME: 3000, |
| 108 CLOUD_FREQUENCY: 0.5, | 111 CLOUD_FREQUENCY: 0.5, |
| 109 GAMEOVER_CLEAR_TIME: 750, | 112 GAMEOVER_CLEAR_TIME: 750, |
| 110 GAP_COEFFICIENT: 0.6, | 113 GAP_COEFFICIENT: 0.6, |
| 111 GRAVITY: 0.6, | 114 GRAVITY: 0.6, |
| 112 INITIAL_JUMP_VELOCITY: 12, | 115 INITIAL_JUMP_VELOCITY: 12, |
| 113 INVERT_FADE_DURATION: 12000, | 116 INVERT_FADE_DURATION: 12000, |
| 114 INVERT_DISTANCE: 700, | 117 INVERT_DISTANCE: 700, |
| 115 MAX_BLINK_COUNT: 3, | 118 MAX_BLINK_COUNT: 3, |
| 116 MAX_CLOUDS: 6, | 119 MAX_CLOUDS: 6, |
| 117 MAX_OBSTACLE_LENGTH: 3, | 120 MAX_OBSTACLE_LENGTH: 3, |
| 118 MAX_OBSTACLE_DUPLICATION: 2, | 121 MAX_OBSTACLE_DUPLICATION: 2, |
| 119 MAX_SPEED: 13, | 122 MAX_SPEED: 13, |
| 120 MIN_JUMP_HEIGHT: 35, | 123 MIN_JUMP_HEIGHT: 35, |
| 121 MOBILE_SPEED_COEFFICIENT: 1.2, | 124 MOBILE_SPEED_COEFFICIENT: 1.2, |
| 122 RESOURCE_TEMPLATE_ID: 'audio-resources', | 125 RESOURCE_TEMPLATE_ID: 'audio-resources', |
| 123 SPEED: 6, | 126 SPEED: 6, |
| 124 SPEED_DROP_COEFFICIENT: 3 | 127 SPEED_DROP_COEFFICIENT: 3, |
| 128 ARCADE_MODE_TOP_POSITION_PERCENT: 0.1 |
| 125 }; | 129 }; |
| 126 | 130 |
| 127 | 131 |
| 128 /** | 132 /** |
| 129 * Default dimensions. | 133 * Default dimensions. |
| 130 * @enum {string} | 134 * @enum {string} |
| 131 */ | 135 */ |
| 132 Runner.defaultDimensions = { | 136 Runner.defaultDimensions = { |
| 133 WIDTH: DEFAULT_WIDTH, | 137 WIDTH: DEFAULT_WIDTH, |
| 134 HEIGHT: 150 | 138 HEIGHT: 150 |
| 135 }; | 139 }; |
| 136 | 140 |
| 137 | 141 |
| 138 /** | 142 /** |
| 139 * CSS class names. | 143 * CSS class names. |
| 140 * @enum {string} | 144 * @enum {string} |
| 141 */ | 145 */ |
| 142 Runner.classes = { | 146 Runner.classes = { |
| 147 ARCADE_MODE: 'arcade-mode', |
| 143 CANVAS: 'runner-canvas', | 148 CANVAS: 'runner-canvas', |
| 144 CONTAINER: 'runner-container', | 149 CONTAINER: 'runner-container', |
| 145 CRASHED: 'crashed', | 150 CRASHED: 'crashed', |
| 146 ICON: 'icon-offline', | 151 ICON: 'icon-offline', |
| 147 INVERTED: 'inverted', | 152 INVERTED: 'inverted', |
| 148 SNACKBAR: 'snackbar', | 153 SNACKBAR: 'snackbar', |
| 149 SNACKBAR_SHOW: 'snackbar-show', | 154 SNACKBAR_SHOW: 'snackbar-show', |
| 150 TOUCH_CONTROLLER: 'controller' | 155 TOUCH_CONTROLLER: 'controller' |
| 151 }; | 156 }; |
| 152 | 157 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 MOUSEUP: 'mouseup', | 223 MOUSEUP: 'mouseup', |
| 219 RESIZE: 'resize', | 224 RESIZE: 'resize', |
| 220 TOUCHEND: 'touchend', | 225 TOUCHEND: 'touchend', |
| 221 TOUCHSTART: 'touchstart', | 226 TOUCHSTART: 'touchstart', |
| 222 VISIBILITY: 'visibilitychange', | 227 VISIBILITY: 'visibilitychange', |
| 223 BLUR: 'blur', | 228 BLUR: 'blur', |
| 224 FOCUS: 'focus', | 229 FOCUS: 'focus', |
| 225 LOAD: 'load' | 230 LOAD: 'load' |
| 226 }; | 231 }; |
| 227 | 232 |
| 228 | |
| 229 Runner.prototype = { | 233 Runner.prototype = { |
| 230 /** | 234 /** |
| 231 * Whether the easter egg has been disabled. CrOS enterprise enrolled devices. | 235 * Whether the easter egg has been disabled. CrOS enterprise enrolled devices. |
| 232 * @return {boolean} | 236 * @return {boolean} |
| 233 */ | 237 */ |
| 234 isDisabled: function() { | 238 isDisabled: function() { |
| 235 return loadTimeData && loadTimeData.valueExists('disabledEasterEgg'); | 239 return loadTimeData && loadTimeData.valueExists('disabledEasterEgg'); |
| 236 }, | 240 }, |
| 237 | 241 |
| 238 /** | 242 /** |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 */ | 415 */ |
| 412 adjustDimensions: function() { | 416 adjustDimensions: function() { |
| 413 clearInterval(this.resizeTimerId_); | 417 clearInterval(this.resizeTimerId_); |
| 414 this.resizeTimerId_ = null; | 418 this.resizeTimerId_ = null; |
| 415 | 419 |
| 416 var boxStyles = window.getComputedStyle(this.outerContainerEl); | 420 var boxStyles = window.getComputedStyle(this.outerContainerEl); |
| 417 var padding = Number(boxStyles.paddingLeft.substr(0, | 421 var padding = Number(boxStyles.paddingLeft.substr(0, |
| 418 boxStyles.paddingLeft.length - 2)); | 422 boxStyles.paddingLeft.length - 2)); |
| 419 | 423 |
| 420 this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - padding * 2; | 424 this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - padding * 2; |
| 425 if (this.isArcadeMode()) { |
| 426 this.dimensions.WIDTH = Math.min(DEFAULT_WIDTH, this.dimensions.WIDTH); |
| 427 if (this.activated) { |
| 428 this.setArcadeModeContainerScale(); |
| 429 } |
| 430 } |
| 421 | 431 |
| 422 // Redraw the elements back onto the canvas. | 432 // Redraw the elements back onto the canvas. |
| 423 if (this.canvas) { | 433 if (this.canvas) { |
| 424 this.canvas.width = this.dimensions.WIDTH; | 434 this.canvas.width = this.dimensions.WIDTH; |
| 425 this.canvas.height = this.dimensions.HEIGHT; | 435 this.canvas.height = this.dimensions.HEIGHT; |
| 426 | 436 |
| 427 Runner.updateCanvasScaling(this.canvas); | 437 Runner.updateCanvasScaling(this.canvas); |
| 428 | 438 |
| 429 this.distanceMeter.calcXPos(this.dimensions.WIDTH); | 439 this.distanceMeter.calcXPos(this.dimensions.WIDTH); |
| 430 this.clearCanvas(); | 440 this.clearCanvas(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 } else if (this.crashed) { | 489 } else if (this.crashed) { |
| 480 this.restart(); | 490 this.restart(); |
| 481 } | 491 } |
| 482 }, | 492 }, |
| 483 | 493 |
| 484 | 494 |
| 485 /** | 495 /** |
| 486 * Update the game status to started. | 496 * Update the game status to started. |
| 487 */ | 497 */ |
| 488 startGame: function() { | 498 startGame: function() { |
| 499 if (this.isArcadeMode()) { |
| 500 this.setArcadeMode(); |
| 501 } |
| 489 this.runningTime = 0; | 502 this.runningTime = 0; |
| 490 this.playingIntro = false; | 503 this.playingIntro = false; |
| 491 this.tRex.playingIntro = false; | 504 this.tRex.playingIntro = false; |
| 492 this.containerEl.style.webkitAnimation = ''; | 505 this.containerEl.style.webkitAnimation = ''; |
| 493 this.playCount++; | 506 this.playCount++; |
| 494 | 507 |
| 495 // Handle tabbing off the page. Pause the current game. | 508 // Handle tabbing off the page. Pause the current game. |
| 496 document.addEventListener(Runner.events.VISIBILITY, | 509 document.addEventListener(Runner.events.VISIBILITY, |
| 497 this.onVisibilityChange.bind(this)); | 510 this.onVisibilityChange.bind(this)); |
| 498 | 511 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 this.distanceMeter.reset(this.highestScore); | 832 this.distanceMeter.reset(this.highestScore); |
| 820 this.horizon.reset(); | 833 this.horizon.reset(); |
| 821 this.tRex.reset(); | 834 this.tRex.reset(); |
| 822 this.playSound(this.soundFx.BUTTON_PRESS); | 835 this.playSound(this.soundFx.BUTTON_PRESS); |
| 823 this.invert(true); | 836 this.invert(true); |
| 824 this.update(); | 837 this.update(); |
| 825 } | 838 } |
| 826 }, | 839 }, |
| 827 | 840 |
| 828 /** | 841 /** |
| 842 * Whether the game should go into arcade mode. |
| 843 * @return {boolean} |
| 844 */ |
| 845 isArcadeMode: function() { |
| 846 return document.title == ARCADE_MODE_URL; |
| 847 }, |
| 848 |
| 849 /** |
| 850 * Hides offline messaging for a fullscreen game only experience. |
| 851 */ |
| 852 setArcadeMode: function() { |
| 853 document.body.classList.add(Runner.classes.ARCADE_MODE); |
| 854 this.setArcadeModeContainerScale(); |
| 855 }, |
| 856 |
| 857 /** |
| 858 * Sets the scaling for arcade mode. |
| 859 */ |
| 860 setArcadeModeContainerScale: function() { |
| 861 var windowHeight = window.innerHeight; |
| 862 var scaleHeight = windowHeight / this.dimensions.HEIGHT; |
| 863 var scaleWidth = window.innerWidth / this.dimensions.WIDTH; |
| 864 var scale = Math.max(1, Math.min(scaleHeight, scaleWidth)); |
| 865 var scaledCanvasHeight = this.dimensions.HEIGHT * scale; |
| 866 // Positions the game container at 10% of the available vertical window |
| 867 // height minus the game container height. |
| 868 var translateY = Math.max(0, (windowHeight - scaledCanvasHeight) * |
| 869 Runner.config.ARCADE_MODE_TOP_POSITION_PERCENT); |
| 870 this.containerEl.style.transform = 'scale(' + scale + ') translateY(' + |
| 871 translateY + 'px)'; |
| 872 }, |
| 873 |
| 874 /** |
| 829 * Pause the game if the tab is not in focus. | 875 * Pause the game if the tab is not in focus. |
| 830 */ | 876 */ |
| 831 onVisibilityChange: function(e) { | 877 onVisibilityChange: function(e) { |
| 832 if (document.hidden || document.webkitHidden || e.type == 'blur' || | 878 if (document.hidden || document.webkitHidden || e.type == 'blur' || |
| 833 document.visibilityState != 'visible') { | 879 document.visibilityState != 'visible') { |
| 834 this.stop(); | 880 this.stop(); |
| 835 } else if (!this.crashed) { | 881 } else if (!this.crashed) { |
| 836 this.tRex.reset(); | 882 this.tRex.reset(); |
| 837 this.play(); | 883 this.play(); |
| 838 } | 884 } |
| (...skipping 1850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2689 | 2735 |
| 2690 /** | 2736 /** |
| 2691 * Add a new cloud to the horizon. | 2737 * Add a new cloud to the horizon. |
| 2692 */ | 2738 */ |
| 2693 addCloud: function() { | 2739 addCloud: function() { |
| 2694 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, | 2740 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, |
| 2695 this.dimensions.WIDTH)); | 2741 this.dimensions.WIDTH)); |
| 2696 } | 2742 } |
| 2697 }; | 2743 }; |
| 2698 })(); | 2744 })(); |
| OLD | NEW |