Chromium Code Reviews| 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 |
| 26 this.dimensions = Runner.defaultDimensions; | 26 this.dimensions = Runner.defaultDimensions; |
|
mmenke
2017/07/05 18:51:29
I guess these are now logical dimensions, as oppos
edwardjung
2017/07/06 19:33:20
Done.
| |
| 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 |
| 36 this.highestScore = 0; | 36 this.highestScore = 0; |
| (...skipping 52 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 TOP_MARGIN: 35, | |
| 129 TOP_POSITION_WEIGHT: 10 | |
|
mmenke
2017/07/05 18:51:29
Should document these, and name them so it's clear
edwardjung
2017/07/06 19:33:19
Done.
| |
| 125 }; | 130 }; |
| 126 | 131 |
| 127 | 132 |
| 128 /** | 133 /** |
| 129 * Default dimensions. | 134 * Default dimensions. |
| 130 * @enum {string} | 135 * @enum {string} |
| 131 */ | 136 */ |
| 132 Runner.defaultDimensions = { | 137 Runner.defaultDimensions = { |
| 133 WIDTH: DEFAULT_WIDTH, | 138 WIDTH: DEFAULT_WIDTH, |
| 134 HEIGHT: 150 | 139 HEIGHT: 150 |
| 135 }; | 140 }; |
| 136 | 141 |
| 137 | 142 |
| 138 /** | 143 /** |
| 139 * CSS class names. | 144 * CSS class names. |
| 140 * @enum {string} | 145 * @enum {string} |
| 141 */ | 146 */ |
| 142 Runner.classes = { | 147 Runner.classes = { |
| 148 ARCADE_MODE: 'arcade-mode', | |
| 143 CANVAS: 'runner-canvas', | 149 CANVAS: 'runner-canvas', |
| 144 CONTAINER: 'runner-container', | 150 CONTAINER: 'runner-container', |
| 145 CRASHED: 'crashed', | 151 CRASHED: 'crashed', |
| 146 ICON: 'icon-offline', | 152 ICON: 'icon-offline', |
| 147 INVERTED: 'inverted', | 153 INVERTED: 'inverted', |
| 148 SNACKBAR: 'snackbar', | 154 SNACKBAR: 'snackbar', |
| 149 SNACKBAR_SHOW: 'snackbar-show', | 155 SNACKBAR_SHOW: 'snackbar-show', |
| 150 TOUCH_CONTROLLER: 'controller' | 156 TOUCH_CONTROLLER: 'controller' |
| 151 }; | 157 }; |
| 152 | 158 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 MOUSEUP: 'mouseup', | 224 MOUSEUP: 'mouseup', |
| 219 RESIZE: 'resize', | 225 RESIZE: 'resize', |
| 220 TOUCHEND: 'touchend', | 226 TOUCHEND: 'touchend', |
| 221 TOUCHSTART: 'touchstart', | 227 TOUCHSTART: 'touchstart', |
| 222 VISIBILITY: 'visibilitychange', | 228 VISIBILITY: 'visibilitychange', |
| 223 BLUR: 'blur', | 229 BLUR: 'blur', |
| 224 FOCUS: 'focus', | 230 FOCUS: 'focus', |
| 225 LOAD: 'load' | 231 LOAD: 'load' |
| 226 }; | 232 }; |
| 227 | 233 |
| 228 | |
| 229 Runner.prototype = { | 234 Runner.prototype = { |
| 230 /** | 235 /** |
| 231 * Whether the easter egg has been disabled. CrOS enterprise enrolled devices. | 236 * Whether the easter egg has been disabled. CrOS enterprise enrolled devices. |
| 232 * @return {boolean} | 237 * @return {boolean} |
| 233 */ | 238 */ |
| 234 isDisabled: function() { | 239 isDisabled: function() { |
| 235 return loadTimeData && loadTimeData.valueExists('disabledEasterEgg'); | 240 return loadTimeData && loadTimeData.valueExists('disabledEasterEgg'); |
| 236 }, | 241 }, |
| 237 | 242 |
| 238 /** | 243 /** |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 */ | 416 */ |
| 412 adjustDimensions: function() { | 417 adjustDimensions: function() { |
| 413 clearInterval(this.resizeTimerId_); | 418 clearInterval(this.resizeTimerId_); |
| 414 this.resizeTimerId_ = null; | 419 this.resizeTimerId_ = null; |
| 415 | 420 |
| 416 var boxStyles = window.getComputedStyle(this.outerContainerEl); | 421 var boxStyles = window.getComputedStyle(this.outerContainerEl); |
| 417 var padding = Number(boxStyles.paddingLeft.substr(0, | 422 var padding = Number(boxStyles.paddingLeft.substr(0, |
| 418 boxStyles.paddingLeft.length - 2)); | 423 boxStyles.paddingLeft.length - 2)); |
| 419 | 424 |
| 420 this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - padding * 2; | 425 this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - padding * 2; |
| 426 if (this.isArcadeMode()) { | |
| 427 this.dimensions.WIDTH = Math.min(DEFAULT_WIDTH, this.dimensions.WIDTH); | |
| 428 if (this.activated) { | |
| 429 this.setContainerScale(); | |
| 430 } | |
| 431 } | |
| 421 | 432 |
| 422 // Redraw the elements back onto the canvas. | 433 // Redraw the elements back onto the canvas. |
| 423 if (this.canvas) { | 434 if (this.canvas) { |
| 424 this.canvas.width = this.dimensions.WIDTH; | 435 this.canvas.width = this.dimensions.WIDTH; |
| 425 this.canvas.height = this.dimensions.HEIGHT; | 436 this.canvas.height = this.dimensions.HEIGHT; |
| 426 | 437 |
| 427 Runner.updateCanvasScaling(this.canvas); | 438 Runner.updateCanvasScaling(this.canvas); |
| 428 | 439 |
| 429 this.distanceMeter.calcXPos(this.dimensions.WIDTH); | 440 this.distanceMeter.calcXPos(this.dimensions.WIDTH); |
| 430 this.clearCanvas(); | 441 this.clearCanvas(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 } else if (this.crashed) { | 490 } else if (this.crashed) { |
| 480 this.restart(); | 491 this.restart(); |
| 481 } | 492 } |
| 482 }, | 493 }, |
| 483 | 494 |
| 484 | 495 |
| 485 /** | 496 /** |
| 486 * Update the game status to started. | 497 * Update the game status to started. |
| 487 */ | 498 */ |
| 488 startGame: function() { | 499 startGame: function() { |
| 500 this.setArcadeMode(); | |
| 489 this.runningTime = 0; | 501 this.runningTime = 0; |
| 490 this.playingIntro = false; | 502 this.playingIntro = false; |
| 491 this.tRex.playingIntro = false; | 503 this.tRex.playingIntro = false; |
| 492 this.containerEl.style.webkitAnimation = ''; | 504 this.containerEl.style.webkitAnimation = ''; |
| 493 this.playCount++; | 505 this.playCount++; |
| 494 | 506 |
| 495 // Handle tabbing off the page. Pause the current game. | 507 // Handle tabbing off the page. Pause the current game. |
| 496 document.addEventListener(Runner.events.VISIBILITY, | 508 document.addEventListener(Runner.events.VISIBILITY, |
| 497 this.onVisibilityChange.bind(this)); | 509 this.onVisibilityChange.bind(this)); |
| 498 | 510 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 819 this.distanceMeter.reset(this.highestScore); | 831 this.distanceMeter.reset(this.highestScore); |
| 820 this.horizon.reset(); | 832 this.horizon.reset(); |
| 821 this.tRex.reset(); | 833 this.tRex.reset(); |
| 822 this.playSound(this.soundFx.BUTTON_PRESS); | 834 this.playSound(this.soundFx.BUTTON_PRESS); |
| 823 this.invert(true); | 835 this.invert(true); |
| 824 this.update(); | 836 this.update(); |
| 825 } | 837 } |
| 826 }, | 838 }, |
| 827 | 839 |
| 828 /** | 840 /** |
| 841 * Whether the game should go into arcade mode. | |
| 842 * @return {boolean} | |
| 843 */ | |
| 844 isArcadeMode: function() { | |
| 845 return document.title == ARCADE_MODE_URL; | |
| 846 }, | |
| 847 | |
| 848 /** | |
| 849 * Hides offline messaging for a fullscreen game only experience. | |
| 850 */ | |
| 851 setArcadeMode: function() { | |
| 852 if (this.isArcadeMode()) { | |
|
mmenke
2017/07/05 18:51:29
I'd suggest moving this to the callsite, to make i
edwardjung
2017/07/06 19:33:20
Done.
| |
| 853 document.body.classList.add(Runner.classes.ARCADE_MODE); | |
| 854 this.setContainerScale(); | |
| 855 } | |
| 856 }, | |
| 857 | |
| 858 /** | |
| 859 * Sets the scaling for arcade mode. | |
| 860 */ | |
| 861 setContainerScale: function() { | |
|
mmenke
2017/07/05 18:51:29
setContainerScaleForArcadeMode?
edwardjung
2017/07/06 19:33:19
Changed to: setArcadeModeContainerScale
| |
| 862 var windowHeight = window.innerHeight; | |
| 863 var scaleHeight = windowHeight / this.dimensions.HEIGHT; | |
| 864 var scaleWidth = window.innerWidth / this.dimensions.WIDTH; | |
| 865 var scale = Math.max(1, Math.min(scaleHeight, scaleWidth)); | |
|
mmenke
2017/07/05 18:51:29
So does this mean you can see farther if you make
edwardjung
2017/07/06 19:33:19
No, this just scales up the game container in the
| |
| 866 var position = Math.max(-Runner.config.TOP_MARGIN, (windowHeight - | |
| 867 (this.dimensions.HEIGHT * scale)) / Runner.config.TOP_POSITION_WEIGHT); | |
|
mmenke
2017/07/05 18:51:29
So I guess this is figuring out how much extra hei
edwardjung
2017/07/06 19:33:20
Did you mean"
Math.max(-Runner.config.TOP_MARGI
mmenke
2017/07/07 16:28:10
No, I did not - dividing by percents generally mea
edwardjung
2017/07/10 15:17:11
Aaah, got it. Switched to to 0.1.
| |
| 868 this.containerEl.style.transform = 'scale(' + scale + ') translateY(' + | |
| 869 position + 'px)'; | |
| 870 }, | |
| 871 | |
| 872 /** | |
| 829 * Pause the game if the tab is not in focus. | 873 * Pause the game if the tab is not in focus. |
| 830 */ | 874 */ |
| 831 onVisibilityChange: function(e) { | 875 onVisibilityChange: function(e) { |
| 832 if (document.hidden || document.webkitHidden || e.type == 'blur' || | 876 if (document.hidden || document.webkitHidden || e.type == 'blur' || |
| 833 document.visibilityState != 'visible') { | 877 document.visibilityState != 'visible') { |
| 834 this.stop(); | 878 this.stop(); |
| 835 } else if (!this.crashed) { | 879 } else if (!this.crashed) { |
| 836 this.tRex.reset(); | 880 this.tRex.reset(); |
| 837 this.play(); | 881 this.play(); |
| 838 } | 882 } |
| (...skipping 1850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2689 | 2733 |
| 2690 /** | 2734 /** |
| 2691 * Add a new cloud to the horizon. | 2735 * Add a new cloud to the horizon. |
| 2692 */ | 2736 */ |
| 2693 addCloud: function() { | 2737 addCloud: function() { |
| 2694 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, | 2738 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, |
| 2695 this.dimensions.WIDTH)); | 2739 this.dimensions.WIDTH)); |
| 2696 } | 2740 } |
| 2697 }; | 2741 }; |
| 2698 })(); | 2742 })(); |
| OLD | NEW |