Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: chrome/renderer/resources/offline.js

Issue 1486653003: Offline easter egg bug fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merge Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/renderer/resources/neterror.css ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 29 matching lines...) Expand all
40 this.runningTime = 0; 40 this.runningTime = 0;
41 this.msPerFrame = 1000 / FPS; 41 this.msPerFrame = 1000 / FPS;
42 this.currentSpeed = this.config.SPEED; 42 this.currentSpeed = this.config.SPEED;
43 43
44 this.obstacles = []; 44 this.obstacles = [];
45 45
46 this.started = false; 46 this.started = false;
47 this.activated = false; 47 this.activated = false;
48 this.crashed = false; 48 this.crashed = false;
49 this.paused = false; 49 this.paused = false;
50 50 this.inverted = false;
51 this.invertTimer = 0;
51 this.resizeTimerId_ = null; 52 this.resizeTimerId_ = null;
52 53
53 this.playCount = 0; 54 this.playCount = 0;
54 55
55 // Sound FX. 56 // Sound FX.
56 this.audioBuffer = null; 57 this.audioBuffer = null;
57 this.soundFx = {}; 58 this.soundFx = {};
58 59
59 // Global web audio context for playing sounds. 60 // Global web audio context for playing sounds.
60 this.audioContext = null; 61 this.audioContext = null;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 Runner.config = { 105 Runner.config = {
105 ACCELERATION: 0.001, 106 ACCELERATION: 0.001,
106 BG_CLOUD_SPEED: 0.2, 107 BG_CLOUD_SPEED: 0.2,
107 BOTTOM_PAD: 10, 108 BOTTOM_PAD: 10,
108 CLEAR_TIME: 3000, 109 CLEAR_TIME: 3000,
109 CLOUD_FREQUENCY: 0.5, 110 CLOUD_FREQUENCY: 0.5,
110 GAMEOVER_CLEAR_TIME: 750, 111 GAMEOVER_CLEAR_TIME: 750,
111 GAP_COEFFICIENT: 0.6, 112 GAP_COEFFICIENT: 0.6,
112 GRAVITY: 0.6, 113 GRAVITY: 0.6,
113 INITIAL_JUMP_VELOCITY: 12, 114 INITIAL_JUMP_VELOCITY: 12,
115 INVERT_FADE_DURATION: 12000,
116 INVERT_DISTANCE: 700,
114 MAX_CLOUDS: 6, 117 MAX_CLOUDS: 6,
115 MAX_OBSTACLE_LENGTH: 3, 118 MAX_OBSTACLE_LENGTH: 3,
116 MAX_OBSTACLE_DUPLICATION: 2, 119 MAX_OBSTACLE_DUPLICATION: 2,
117 MAX_SPEED: 13, 120 MAX_SPEED: 13,
118 MIN_JUMP_HEIGHT: 35, 121 MIN_JUMP_HEIGHT: 35,
119 MOBILE_SPEED_COEFFICIENT: 1.2, 122 MOBILE_SPEED_COEFFICIENT: 1.2,
120 RESOURCE_TEMPLATE_ID: 'audio-resources', 123 RESOURCE_TEMPLATE_ID: 'audio-resources',
121 SPEED: 6, 124 SPEED: 6,
122 SPEED_DROP_COEFFICIENT: 3 125 SPEED_DROP_COEFFICIENT: 3
123 }; 126 };
(...skipping 11 matching lines...) Expand all
135 138
136 /** 139 /**
137 * CSS class names. 140 * CSS class names.
138 * @enum {string} 141 * @enum {string}
139 */ 142 */
140 Runner.classes = { 143 Runner.classes = {
141 CANVAS: 'runner-canvas', 144 CANVAS: 'runner-canvas',
142 CONTAINER: 'runner-container', 145 CONTAINER: 'runner-container',
143 CRASHED: 'crashed', 146 CRASHED: 'crashed',
144 ICON: 'icon-offline', 147 ICON: 'icon-offline',
148 INVERTED: 'inverted',
145 SNACKBAR: 'snackbar', 149 SNACKBAR: 'snackbar',
146 SNACKBAR_SHOW: 'snackbar-show', 150 SNACKBAR_SHOW: 'snackbar-show',
147 TOUCH_CONTROLLER: 'controller' 151 TOUCH_CONTROLLER: 'controller'
148 }; 152 };
149 153
150 154
151 /** 155 /**
152 * Sprite definition layout of the spritesheet. 156 * Sprite definition layout of the spritesheet.
153 * @enum {Object} 157 * @enum {Object}
154 */ 158 */
155 Runner.spriteDefinition = { 159 Runner.spriteDefinition = {
156 LDPI: { 160 LDPI: {
157 CACTUS_LARGE: {x: 332, y: 2}, 161 CACTUS_LARGE: {x: 332, y: 2},
158 CACTUS_SMALL: {x: 228, y: 2}, 162 CACTUS_SMALL: {x: 228, y: 2},
159 CLOUD: {x: 86, y: 2}, 163 CLOUD: {x: 86, y: 2},
160 HORIZON: {x: 2, y: 54}, 164 HORIZON: {x: 2, y: 54},
165 MOON: {x: 484, y: 2},
161 PTERODACTYL: {x: 134, y: 2}, 166 PTERODACTYL: {x: 134, y: 2},
162 RESTART: {x: 2, y: 2}, 167 RESTART: {x: 2, y: 2},
163 TEXT_SPRITE: {x: 484, y: 2}, 168 TEXT_SPRITE: {x: 655, y: 2},
164 TREX: {x: 677, y: 2} 169 TREX: {x: 848, y: 2},
170 STAR: {x: 645, y: 2}
165 }, 171 },
166 HDPI: { 172 HDPI: {
167 CACTUS_LARGE: {x: 652,y: 2}, 173 CACTUS_LARGE: {x: 652, y: 2},
168 CACTUS_SMALL: {x: 446,y: 2}, 174 CACTUS_SMALL: {x: 446, y: 2},
169 CLOUD: {x: 166,y: 2}, 175 CLOUD: {x: 166, y: 2},
170 HORIZON: {x: 2,y: 104}, 176 HORIZON: {x: 2, y: 104},
171 PTERODACTYL: {x: 260,y: 2}, 177 MOON: {x: 954, y: 2},
172 RESTART: {x: 2,y: 2}, 178 PTERODACTYL: {x: 260, y: 2},
173 TEXT_SPRITE: {x: 954,y: 2}, 179 RESTART: {x: 2, y: 2},
174 TREX: {x: 1338,y: 2} 180 TEXT_SPRITE: {x: 1294, y: 2},
181 TREX: {x: 1678, y: 2},
182 STAR: {x: 1276, y: 2}
175 } 183 }
176 }; 184 };
177 185
178 186
179 /** 187 /**
180 * Sound FX. Reference to the ID of the audio tag on interstitial page. 188 * Sound FX. Reference to the ID of the audio tag on interstitial page.
181 * @enum {string} 189 * @enum {string}
182 */ 190 */
183 Runner.sounds = { 191 Runner.sounds = {
184 BUTTON_PRESS: 'offline-sound-press', 192 BUTTON_PRESS: 'offline-sound-press',
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 // First jump triggers the intro. 526 // First jump triggers the intro.
519 if (this.tRex.jumpCount == 1 && !this.playingIntro) { 527 if (this.tRex.jumpCount == 1 && !this.playingIntro) {
520 this.playIntro(); 528 this.playIntro();
521 } 529 }
522 530
523 // The horizon doesn't move until the intro is over. 531 // The horizon doesn't move until the intro is over.
524 if (this.playingIntro) { 532 if (this.playingIntro) {
525 this.horizon.update(0, this.currentSpeed, hasObstacles); 533 this.horizon.update(0, this.currentSpeed, hasObstacles);
526 } else { 534 } else {
527 deltaTime = !this.started ? 0 : deltaTime; 535 deltaTime = !this.started ? 0 : deltaTime;
528 this.horizon.update(deltaTime, this.currentSpeed, hasObstacles); 536 this.horizon.update(deltaTime, this.currentSpeed, hasObstacles,
537 this.inverted);
529 } 538 }
530 539
531 // Check for collisions. 540 // Check for collisions.
532 var collision = hasObstacles && 541 var collision = hasObstacles &&
533 checkForCollision(this.horizon.obstacles[0], this.tRex); 542 checkForCollision(this.horizon.obstacles[0], this.tRex);
534 543
535 if (!collision) { 544 if (!collision) {
536 this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame; 545 this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame;
537 546
538 if (this.currentSpeed < this.config.MAX_SPEED) { 547 if (this.currentSpeed < this.config.MAX_SPEED) {
539 this.currentSpeed += this.config.ACCELERATION; 548 this.currentSpeed += this.config.ACCELERATION;
540 } 549 }
541 } else { 550 } else {
542 this.gameOver(); 551 this.gameOver();
543 } 552 }
544 553
545 var playAcheivementSound = this.distanceMeter.update(deltaTime, 554 var playAchievementSound = this.distanceMeter.update(deltaTime,
546 Math.ceil(this.distanceRan)); 555 Math.ceil(this.distanceRan));
547 556
548 if (playAcheivementSound) { 557 if (playAchievementSound) {
549 this.playSound(this.soundFx.SCORE); 558 this.playSound(this.soundFx.SCORE);
550 } 559 }
560
561 // Night mode.
562 if (this.invertTimer > this.config.INVERT_FADE_DURATION) {
563 this.invertTimer = 0;
564 this.invertTrigger = false;
565 this.invert();
566 } else if (this.invertTimer) {
567 this.invertTimer += deltaTime;
568 } else {
569 var actualDistance =
570 this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan));
571
572 if (actualDistance > 0) {
573 this.invertTrigger = !(actualDistance %
574 this.config.INVERT_DISTANCE);
575
576 if (this.invertTrigger && this.invertTimer === 0) {
577 this.invertTimer += deltaTime;
578 this.invert();
579 }
580 }
581 }
551 } 582 }
552 583
553 if (!this.crashed) { 584 if (!this.crashed) {
554 this.tRex.update(deltaTime); 585 this.tRex.update(deltaTime);
555 this.raq(); 586 this.raq();
556 } 587 }
557 }, 588 },
558 589
559 /** 590 /**
560 * Event handler. 591 * Event handler.
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 }, 798 },
768 799
769 restart: function() { 800 restart: function() {
770 if (!this.raqId) { 801 if (!this.raqId) {
771 this.playCount++; 802 this.playCount++;
772 this.runningTime = 0; 803 this.runningTime = 0;
773 this.activated = true; 804 this.activated = true;
774 this.crashed = false; 805 this.crashed = false;
775 this.distanceRan = 0; 806 this.distanceRan = 0;
776 this.setSpeed(this.config.SPEED); 807 this.setSpeed(this.config.SPEED);
777
778 this.time = getTimeStamp(); 808 this.time = getTimeStamp();
779 this.containerEl.classList.remove(Runner.classes.CRASHED); 809 this.containerEl.classList.remove(Runner.classes.CRASHED);
780 this.clearCanvas(); 810 this.clearCanvas();
781 this.distanceMeter.reset(this.highestScore); 811 this.distanceMeter.reset(this.highestScore);
782 this.horizon.reset(); 812 this.horizon.reset();
783 this.tRex.reset(); 813 this.tRex.reset();
784 this.playSound(this.soundFx.BUTTON_PRESS); 814 this.playSound(this.soundFx.BUTTON_PRESS);
785 815 this.invert(true);
786 this.update(); 816 this.update();
787 } 817 }
788 }, 818 },
789 819
790 /** 820 /**
791 * Pause the game if the tab is not in focus. 821 * Pause the game if the tab is not in focus.
792 */ 822 */
793 onVisibilityChange: function(e) { 823 onVisibilityChange: function(e) {
794 if (document.hidden || document.webkitHidden || e.type == 'blur') { 824 if (document.hidden || document.webkitHidden || e.type == 'blur' ||
825 document.visibilityState != 'visible') {
795 this.stop(); 826 this.stop();
796 } else if (!this.crashed) { 827 } else if (!this.crashed) {
797 this.tRex.reset(); 828 this.tRex.reset();
798 this.play(); 829 this.play();
799 } 830 }
800 }, 831 },
801 832
802 /** 833 /**
803 * Play a sound. 834 * Play a sound.
804 * @param {SoundBuffer} soundBuffer 835 * @param {SoundBuffer} soundBuffer
805 */ 836 */
806 playSound: function(soundBuffer) { 837 playSound: function(soundBuffer) {
807 if (soundBuffer) { 838 if (soundBuffer) {
808 var sourceNode = this.audioContext.createBufferSource(); 839 var sourceNode = this.audioContext.createBufferSource();
809 sourceNode.buffer = soundBuffer; 840 sourceNode.buffer = soundBuffer;
810 sourceNode.connect(this.audioContext.destination); 841 sourceNode.connect(this.audioContext.destination);
811 sourceNode.start(0); 842 sourceNode.start(0);
812 } 843 }
844 },
845
846 /**
847 * Inverts the current page / canvas colors.
848 * @param {boolean} Whether to reset colors.
849 */
850 invert: function(reset) {
851 if (reset) {
852 document.body.classList.toggle(Runner.classes.INVERTED, false);
853 this.invertTimer = 0;
854 this.inverted = false;
855 } else {
856 this.inverted = document.body.classList.toggle(Runner.classes.INVERTED,
857 this.invertTrigger);
858 }
813 } 859 }
814 }; 860 };
815 861
816 862
817 /** 863 /**
818 * Updates the canvas size taking into 864 * Updates the canvas size taking into
819 * account the backing store pixel ratio and 865 * account the backing store pixel ratio and
820 * the device pixel ratio. 866 * the device pixel ratio.
821 * 867 *
822 * See article by Paul Lewis: 868 * See article by Paul Lewis:
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
1166 //****************************************************************************** 1212 //******************************************************************************
1167 1213
1168 /** 1214 /**
1169 * Obstacle. 1215 * Obstacle.
1170 * @param {HTMLCanvasCtx} canvasCtx 1216 * @param {HTMLCanvasCtx} canvasCtx
1171 * @param {Obstacle.type} type 1217 * @param {Obstacle.type} type
1172 * @param {Object} spritePos Obstacle position in sprite. 1218 * @param {Object} spritePos Obstacle position in sprite.
1173 * @param {Object} dimensions 1219 * @param {Object} dimensions
1174 * @param {number} gapCoefficient Mutipler in determining the gap. 1220 * @param {number} gapCoefficient Mutipler in determining the gap.
1175 * @param {number} speed 1221 * @param {number} speed
1222 * @param {number} opt_xOffset
1176 */ 1223 */
1177 function Obstacle(canvasCtx, type, spriteImgPos, dimensions, 1224 function Obstacle(canvasCtx, type, spriteImgPos, dimensions,
1178 gapCoefficient, speed) { 1225 gapCoefficient, speed, opt_xOffset) {
1179 1226
1180 this.canvasCtx = canvasCtx; 1227 this.canvasCtx = canvasCtx;
1181 this.spritePos = spriteImgPos; 1228 this.spritePos = spriteImgPos;
1182 this.typeConfig = type; 1229 this.typeConfig = type;
1183 this.gapCoefficient = gapCoefficient; 1230 this.gapCoefficient = gapCoefficient;
1184 this.size = getRandomNum(1, Obstacle.MAX_OBSTACLE_LENGTH); 1231 this.size = getRandomNum(1, Obstacle.MAX_OBSTACLE_LENGTH);
1185 this.dimensions = dimensions; 1232 this.dimensions = dimensions;
1186 this.remove = false; 1233 this.remove = false;
1187 this.xPos = 0; 1234 this.xPos = dimensions.WIDTH + (opt_xOffset || 0);
1188 this.yPos = 0; 1235 this.yPos = 0;
1189 this.width = 0; 1236 this.width = 0;
1190 this.collisionBoxes = []; 1237 this.collisionBoxes = [];
1191 this.gap = 0; 1238 this.gap = 0;
1192 this.speedOffset = 0; 1239 this.speedOffset = 0;
1193 1240
1194 // For animated obstacles. 1241 // For animated obstacles.
1195 this.currentFrame = 0; 1242 this.currentFrame = 0;
1196 this.timer = 0; 1243 this.timer = 0;
1197 1244
(...skipping 20 matching lines...) Expand all
1218 */ 1265 */
1219 init: function(speed) { 1266 init: function(speed) {
1220 this.cloneCollisionBoxes(); 1267 this.cloneCollisionBoxes();
1221 1268
1222 // Only allow sizing if we're at the right speed. 1269 // Only allow sizing if we're at the right speed.
1223 if (this.size > 1 && this.typeConfig.multipleSpeed > speed) { 1270 if (this.size > 1 && this.typeConfig.multipleSpeed > speed) {
1224 this.size = 1; 1271 this.size = 1;
1225 } 1272 }
1226 1273
1227 this.width = this.typeConfig.width * this.size; 1274 this.width = this.typeConfig.width * this.size;
1228 this.xPos = this.dimensions.WIDTH - this.width;
1229 1275
1230 // Check if obstacle can be positioned at various heights. 1276 // Check if obstacle can be positioned at various heights.
1231 if (Array.isArray(this.typeConfig.yPos)) { 1277 if (Array.isArray(this.typeConfig.yPos)) {
1232 var yPosConfig = IS_MOBILE ? this.typeConfig.yPosMobile : 1278 var yPosConfig = IS_MOBILE ? this.typeConfig.yPosMobile :
1233 this.typeConfig.yPos; 1279 this.typeConfig.yPos;
1234 this.yPos = yPosConfig[getRandomNum(0, yPosConfig.length - 1)]; 1280 this.yPos = yPosConfig[getRandomNum(0, yPosConfig.length - 1)];
1235 } else { 1281 } else {
1236 this.yPos = this.typeConfig.yPos; 1282 this.yPos = this.typeConfig.yPos;
1237 } 1283 }
1238 1284
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
1799 this.currentDistance = 0; 1845 this.currentDistance = 0;
1800 this.maxScore = 0; 1846 this.maxScore = 0;
1801 this.highScore = 0; 1847 this.highScore = 0;
1802 this.container = null; 1848 this.container = null;
1803 1849
1804 this.digits = []; 1850 this.digits = [];
1805 this.acheivement = false; 1851 this.acheivement = false;
1806 this.defaultString = ''; 1852 this.defaultString = '';
1807 this.flashTimer = 0; 1853 this.flashTimer = 0;
1808 this.flashIterations = 0; 1854 this.flashIterations = 0;
1855 this.invertTrigger = false;
1809 1856
1810 this.config = DistanceMeter.config; 1857 this.config = DistanceMeter.config;
1811 this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; 1858 this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS;
1812 this.init(canvasWidth); 1859 this.init(canvasWidth);
1813 }; 1860 };
1814 1861
1815 1862
1816 /** 1863 /**
1817 * @enum {number} 1864 * @enum {number}
1818 */ 1865 */
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1942 * @param {number} distance 1989 * @param {number} distance
1943 * @param {number} deltaTime 1990 * @param {number} deltaTime
1944 * @return {boolean} Whether the acheivement sound fx should be played. 1991 * @return {boolean} Whether the acheivement sound fx should be played.
1945 */ 1992 */
1946 update: function(deltaTime, distance) { 1993 update: function(deltaTime, distance) {
1947 var paint = true; 1994 var paint = true;
1948 var playSound = false; 1995 var playSound = false;
1949 1996
1950 if (!this.acheivement) { 1997 if (!this.acheivement) {
1951 distance = this.getActualDistance(distance); 1998 distance = this.getActualDistance(distance);
1952
1953 // Score has gone beyond the initial digit count. 1999 // Score has gone beyond the initial digit count.
1954 if (distance > this.maxScore && this.maxScoreUnits == 2000 if (distance > this.maxScore && this.maxScoreUnits ==
1955 this.config.MAX_DISTANCE_UNITS) { 2001 this.config.MAX_DISTANCE_UNITS) {
1956 this.maxScoreUnits++; 2002 this.maxScoreUnits++;
1957 this.maxScore = parseInt(this.maxScore + '9'); 2003 this.maxScore = parseInt(this.maxScore + '9');
1958 } else { 2004 } else {
1959 this.distance = 0; 2005 this.distance = 0;
1960 } 2006 }
1961 2007
1962 if (distance > 0) { 2008 if (distance > 0) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1995 } 2041 }
1996 2042
1997 // Draw the digits if not flashing. 2043 // Draw the digits if not flashing.
1998 if (paint) { 2044 if (paint) {
1999 for (var i = this.digits.length - 1; i >= 0; i--) { 2045 for (var i = this.digits.length - 1; i >= 0; i--) {
2000 this.draw(i, parseInt(this.digits[i])); 2046 this.draw(i, parseInt(this.digits[i]));
2001 } 2047 }
2002 } 2048 }
2003 2049
2004 this.drawHighScore(); 2050 this.drawHighScore();
2005
2006 return playSound; 2051 return playSound;
2007 }, 2052 },
2008 2053
2009 /** 2054 /**
2010 * Draw the high score. 2055 * Draw the high score.
2011 */ 2056 */
2012 drawHighScore: function() { 2057 drawHighScore: function() {
2013 this.canvasCtx.save(); 2058 this.canvasCtx.save();
2014 this.canvasCtx.globalAlpha = .8; 2059 this.canvasCtx.globalAlpha = .8;
2015 for (var i = this.highScore.length - 1; i >= 0; i--) { 2060 for (var i = this.highScore.length - 1; i >= 0; i--) {
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
2133 */ 2178 */
2134 isVisible: function() { 2179 isVisible: function() {
2135 return this.xPos + Cloud.config.WIDTH > 0; 2180 return this.xPos + Cloud.config.WIDTH > 0;
2136 } 2181 }
2137 }; 2182 };
2138 2183
2139 2184
2140 //****************************************************************************** 2185 //******************************************************************************
2141 2186
2142 /** 2187 /**
2188 * Nightmode shows a moon and stars on the horizon.
2189 */
2190 function NightMode(canvas, spritePos, containerWidth) {
2191 this.spritePos = spritePos;
2192 this.canvas = canvas;
2193 this.canvasCtx = canvas.getContext('2d');
2194 this.xPos = containerWidth - 50;
2195 this.yPos = 30;
2196 this.currentPhase = 0;
2197 this.opacity = 0;
2198 this.containerWidth = containerWidth;
2199 this.stars = [];
2200 this.drawStars = false;
2201 this.placeStars();
2202 };
2203
2204 /**
2205 * @enum {number}
2206 */
2207 NightMode.config = {
2208 FADE_SPEED: 0.035,
2209 HEIGHT: 40,
2210 MOON_SPEED: 0.25,
2211 NUM_STARS: 2,
2212 STAR_SIZE: 9,
2213 STAR_SPEED: 0.3,
2214 STAR_MAX_Y: 70,
2215 WIDTH: 20
2216 };
2217
2218 NightMode.phases = [140, 120, 100, 60, 40, 20, 0];
2219
2220 NightMode.prototype = {
2221 /**
2222 * Update moving moon, changing phases.
2223 * @param {boolean} activated Whether night mode is activated.
2224 * @param {number} delta
2225 */
2226 update: function(activated, delta) {
2227 // Moon phase.
2228 if (activated && this.opacity == 0) {
2229 this.currentPhase++;
2230
2231 if (this.currentPhase >= NightMode.phases.length) {
2232 this.currentPhase = 0;
2233 }
2234 }
2235
2236 // Fade in / out.
2237 if (activated && (this.opacity < 1 || this.opacity == 0)) {
2238 this.opacity += NightMode.config.FADE_SPEED;
2239 } else if (this.opacity > 0) {
2240 this.opacity -= NightMode.config.FADE_SPEED;
2241 }
2242
2243 // Set moon positioning.
2244 if (this.opacity > 0) {
2245 this.xPos = this.updateXPos(this.xPos, NightMode.config.MOON_SPEED);
2246
2247 // Update stars.
2248 if (this.drawStars) {
2249 for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
2250 this.stars[i].x = this.updateXPos(this.stars[i].x,
2251 NightMode.config.STAR_SPEED);
2252 }
2253 }
2254 this.draw();
2255 } else {
2256 this.opacity = 0;
2257 this.placeStars();
2258 }
2259 this.drawStars = true;
2260 },
2261
2262 updateXPos: function(currentPos, speed) {
2263 if (currentPos < -NightMode.config.WIDTH) {
2264 currentPos = this.containerWidth;
2265 } else {
2266 currentPos -= speed;
2267 }
2268 return currentPos;
2269 },
2270
2271 draw: function() {
2272 var moonSourceWidth = this.currentPhase == 3 ? NightMode.config.WIDTH * 2 :
2273 NightMode.config.WIDTH;
2274 var moonSourceHeight = NightMode.config.HEIGHT;
2275 var moonSourceX = this.spritePos.x + NightMode.phases[this.currentPhase];
2276 var moonOutputWidth = moonSourceWidth;
2277 var starSize = NightMode.config.STAR_SIZE;
2278 var starSourceX = Runner.spriteDefinition.LDPI.STAR.x;
2279
2280 if (IS_HIDPI) {
2281 moonSourceWidth *= 2;
2282 moonSourceHeight *= 2;
2283 moonSourceX = this.spritePos.x +
2284 (NightMode.phases[this.currentPhase] * 2);
2285 starSize *= 2;
2286 starSourceX = Runner.spriteDefinition.HDPI.STAR.x;
2287 }
2288
2289 this.canvasCtx.save();
2290 this.canvasCtx.globalAlpha = this.opacity;
2291
2292 // Stars.
2293 if (this.drawStars) {
2294 for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
2295 this.canvasCtx.drawImage(Runner.imageSprite,
2296 starSourceX, this.stars[i].sourceY, starSize, starSize,
2297 Math.round(this.stars[i].x), this.stars[i].y,
2298 NightMode.config.STAR_SIZE, NightMode.config.STAR_SIZE);
2299 }
2300 }
2301
2302 // Moon.
2303 this.canvasCtx.drawImage(Runner.imageSprite, moonSourceX,
2304 this.spritePos.y, moonSourceWidth, moonSourceHeight,
2305 Math.round(this.xPos), this.yPos,
2306 moonOutputWidth, NightMode.config.HEIGHT);
2307
2308 this.canvasCtx.globalAlpha = 1;
2309 this.canvasCtx.restore();
2310 },
2311
2312 // Do star placement.
2313 placeStars: function() {
2314 var segmentSize = Math.round(this.containerWidth /
2315 NightMode.config.NUM_STARS);
2316
2317 for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
2318 this.stars[i] = {};
2319 this.stars[i].x = getRandomNum(segmentSize * i, segmentSize * (i + 1));
2320 this.stars[i].y = getRandomNum(0, NightMode.config.STAR_MAX_Y);
2321
2322 if (IS_HIDPI) {
2323 this.stars[i].sourceY = Runner.spriteDefinition.HDPI.STAR.y +
2324 NightMode.config.STAR_SIZE * 2 * i;
2325 } else {
2326 this.stars[i].sourceY = Runner.spriteDefinition.LDPI.STAR.y +
2327 NightMode.config.STAR_SIZE * i;
2328 }
2329 }
2330 },
2331
2332 reset: function() {
2333 this.currentPhase = 0;
2334 this.opacity = 0;
2335 this.update(false);
2336 }
2337
2338 };
2339
2340
2341 //******************************************************************************
2342
2343 /**
2143 * Horizon Line. 2344 * Horizon Line.
2144 * Consists of two connecting lines. Randomly assigns a flat / bumpy horizon. 2345 * Consists of two connecting lines. Randomly assigns a flat / bumpy horizon.
2145 * @param {HTMLCanvasElement} canvas 2346 * @param {HTMLCanvasElement} canvas
2146 * @param {Object} spritePos Horizon position in sprite. 2347 * @param {Object} spritePos Horizon position in sprite.
2147 * @constructor 2348 * @constructor
2148 */ 2349 */
2149 function HorizonLine(canvas, spritePos) { 2350 function HorizonLine(canvas, spritePos) {
2150 this.spritePos = spritePos; 2351 this.spritePos = spritePos;
2151 this.canvas = canvas; 2352 this.canvas = canvas;
2152 this.canvasCtx = canvas.getContext('2d'); 2353 this.canvasCtx = canvas.getContext('2d');
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2280 this.canvas = canvas; 2481 this.canvas = canvas;
2281 this.canvasCtx = this.canvas.getContext('2d'); 2482 this.canvasCtx = this.canvas.getContext('2d');
2282 this.config = Horizon.config; 2483 this.config = Horizon.config;
2283 this.dimensions = dimensions; 2484 this.dimensions = dimensions;
2284 this.gapCoefficient = gapCoefficient; 2485 this.gapCoefficient = gapCoefficient;
2285 this.obstacles = []; 2486 this.obstacles = [];
2286 this.obstacleHistory = []; 2487 this.obstacleHistory = [];
2287 this.horizonOffsets = [0, 0]; 2488 this.horizonOffsets = [0, 0];
2288 this.cloudFrequency = this.config.CLOUD_FREQUENCY; 2489 this.cloudFrequency = this.config.CLOUD_FREQUENCY;
2289 this.spritePos = spritePos; 2490 this.spritePos = spritePos;
2491 this.nightMode = null;
2290 2492
2291 // Cloud 2493 // Cloud
2292 this.clouds = []; 2494 this.clouds = [];
2293 this.cloudSpeed = this.config.BG_CLOUD_SPEED; 2495 this.cloudSpeed = this.config.BG_CLOUD_SPEED;
2294 2496
2295 // Horizon 2497 // Horizon
2296 this.horizonLine = null; 2498 this.horizonLine = null;
2297
2298 this.init(); 2499 this.init();
2299 }; 2500 };
2300 2501
2301 2502
2302 /** 2503 /**
2303 * Horizon config. 2504 * Horizon config.
2304 * @enum {number} 2505 * @enum {number}
2305 */ 2506 */
2306 Horizon.config = { 2507 Horizon.config = {
2307 BG_CLOUD_SPEED: 0.2, 2508 BG_CLOUD_SPEED: 0.2,
2308 BUMPY_THRESHOLD: .3, 2509 BUMPY_THRESHOLD: .3,
2309 CLOUD_FREQUENCY: .5, 2510 CLOUD_FREQUENCY: .5,
2310 HORIZON_HEIGHT: 16, 2511 HORIZON_HEIGHT: 16,
2311 MAX_CLOUDS: 6 2512 MAX_CLOUDS: 6
2312 }; 2513 };
2313 2514
2314 2515
2315 Horizon.prototype = { 2516 Horizon.prototype = {
2316 /** 2517 /**
2317 * Initialise the horizon. Just add the line and a cloud. No obstacles. 2518 * Initialise the horizon. Just add the line and a cloud. No obstacles.
2318 */ 2519 */
2319 init: function() { 2520 init: function() {
2320 this.addCloud(); 2521 this.addCloud();
2321 this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON); 2522 this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON);
2523 this.nightMode = new NightMode(this.canvas, this.spritePos.MOON,
2524 this.dimensions.WIDTH);
2322 }, 2525 },
2323 2526
2324 /** 2527 /**
2325 * @param {number} deltaTime 2528 * @param {number} deltaTime
2326 * @param {number} currentSpeed 2529 * @param {number} currentSpeed
2327 * @param {boolean} updateObstacles Used as an override to prevent 2530 * @param {boolean} updateObstacles Used as an override to prevent
2328 * the obstacles from being updated / added. This happens in the 2531 * the obstacles from being updated / added. This happens in the
2329 * ease in section. 2532 * ease in section.
2533 * @param {boolean} showNightMode Night mode activated.
2330 */ 2534 */
2331 update: function(deltaTime, currentSpeed, updateObstacles) { 2535 update: function(deltaTime, currentSpeed, updateObstacles, showNightMode) {
2332 this.runningTime += deltaTime; 2536 this.runningTime += deltaTime;
2333 this.horizonLine.update(deltaTime, currentSpeed); 2537 this.horizonLine.update(deltaTime, currentSpeed);
2538 this.nightMode.update(showNightMode);
2334 this.updateClouds(deltaTime, currentSpeed); 2539 this.updateClouds(deltaTime, currentSpeed);
2335 2540
2336 if (updateObstacles) { 2541 if (updateObstacles) {
2337 this.updateObstacles(deltaTime, currentSpeed); 2542 this.updateObstacles(deltaTime, currentSpeed);
2338 } 2543 }
2339 }, 2544 },
2340 2545
2341 /** 2546 /**
2342 * Update the cloud positions. 2547 * Update the cloud positions.
2343 * @param {number} deltaTime 2548 * @param {number} deltaTime
(...skipping 14 matching lines...) Expand all
2358 if (numClouds < this.config.MAX_CLOUDS && 2563 if (numClouds < this.config.MAX_CLOUDS &&
2359 (this.dimensions.WIDTH - lastCloud.xPos) > lastCloud.cloudGap && 2564 (this.dimensions.WIDTH - lastCloud.xPos) > lastCloud.cloudGap &&
2360 this.cloudFrequency > Math.random()) { 2565 this.cloudFrequency > Math.random()) {
2361 this.addCloud(); 2566 this.addCloud();
2362 } 2567 }
2363 2568
2364 // Remove expired clouds. 2569 // Remove expired clouds.
2365 this.clouds = this.clouds.filter(function(obj) { 2570 this.clouds = this.clouds.filter(function(obj) {
2366 return !obj.remove; 2571 return !obj.remove;
2367 }); 2572 });
2573 } else {
2574 this.addCloud();
2368 } 2575 }
2369 }, 2576 },
2370 2577
2371 /** 2578 /**
2372 * Update the obstacle positions. 2579 * Update the obstacle positions.
2373 * @param {number} deltaTime 2580 * @param {number} deltaTime
2374 * @param {number} currentSpeed 2581 * @param {number} currentSpeed
2375 */ 2582 */
2376 updateObstacles: function(deltaTime, currentSpeed) { 2583 updateObstacles: function(deltaTime, currentSpeed) {
2377 // Obstacles, move to Horizon layer. 2584 // Obstacles, move to Horizon layer.
(...skipping 19 matching lines...) Expand all
2397 this.dimensions.WIDTH) { 2604 this.dimensions.WIDTH) {
2398 this.addNewObstacle(currentSpeed); 2605 this.addNewObstacle(currentSpeed);
2399 lastObstacle.followingObstacleCreated = true; 2606 lastObstacle.followingObstacleCreated = true;
2400 } 2607 }
2401 } else { 2608 } else {
2402 // Create new obstacles. 2609 // Create new obstacles.
2403 this.addNewObstacle(currentSpeed); 2610 this.addNewObstacle(currentSpeed);
2404 } 2611 }
2405 }, 2612 },
2406 2613
2614 removeFirstObstacle: function() {
2615 this.obstacles.shift();
2616 },
2617
2407 /** 2618 /**
2408 * Add a new obstacle. 2619 * Add a new obstacle.
2409 * @param {number} currentSpeed 2620 * @param {number} currentSpeed
2410 */ 2621 */
2411 addNewObstacle: function(currentSpeed) { 2622 addNewObstacle: function(currentSpeed) {
2412 var obstacleTypeIndex = getRandomNum(0, Obstacle.types.length - 1); 2623 var obstacleTypeIndex = getRandomNum(0, Obstacle.types.length - 1);
2413 var obstacleType = Obstacle.types[obstacleTypeIndex]; 2624 var obstacleType = Obstacle.types[obstacleTypeIndex];
2414 2625
2415 // Check for multiples of the same type of obstacle. 2626 // Check for multiples of the same type of obstacle.
2416 // Also check obstacle is available at current speed. 2627 // Also check obstacle is available at current speed.
2417 if (this.duplicateObstacleCheck(obstacleType.type) || 2628 if (this.duplicateObstacleCheck(obstacleType.type) ||
2418 currentSpeed < obstacleType.minSpeed) { 2629 currentSpeed < obstacleType.minSpeed) {
2419 this.addNewObstacle(currentSpeed); 2630 this.addNewObstacle(currentSpeed);
2420 } else { 2631 } else {
2421 var obstacleSpritePos = this.spritePos[obstacleType.type]; 2632 var obstacleSpritePos = this.spritePos[obstacleType.type];
2422 2633
2423 this.obstacles.push(new Obstacle(this.canvasCtx, obstacleType, 2634 this.obstacles.push(new Obstacle(this.canvasCtx, obstacleType,
2424 obstacleSpritePos, this.dimensions, 2635 obstacleSpritePos, this.dimensions,
2425 this.gapCoefficient, currentSpeed)); 2636 this.gapCoefficient, currentSpeed, obstacleType.width));
2426 2637
2427 this.obstacleHistory.unshift(obstacleType.type); 2638 this.obstacleHistory.unshift(obstacleType.type);
2428 2639
2429 if (this.obstacleHistory.length > 1) { 2640 if (this.obstacleHistory.length > 1) {
2430 this.obstacleHistory.splice(Runner.config.MAX_OBSTACLE_DUPLICATION); 2641 this.obstacleHistory.splice(Runner.config.MAX_OBSTACLE_DUPLICATION);
2431 } 2642 }
2432 } 2643 }
2433 }, 2644 },
2434 2645
2435 /** 2646 /**
(...skipping 11 matching lines...) Expand all
2447 return duplicateCount >= Runner.config.MAX_OBSTACLE_DUPLICATION; 2658 return duplicateCount >= Runner.config.MAX_OBSTACLE_DUPLICATION;
2448 }, 2659 },
2449 2660
2450 /** 2661 /**
2451 * Reset the horizon layer. 2662 * Reset the horizon layer.
2452 * Remove existing obstacles and reposition the horizon line. 2663 * Remove existing obstacles and reposition the horizon line.
2453 */ 2664 */
2454 reset: function() { 2665 reset: function() {
2455 this.obstacles = []; 2666 this.obstacles = [];
2456 this.horizonLine.reset(); 2667 this.horizonLine.reset();
2668 this.nightMode.reset();
2457 }, 2669 },
2458 2670
2459 /** 2671 /**
2460 * Update the canvas width and scaling. 2672 * Update the canvas width and scaling.
2461 * @param {number} width Canvas width. 2673 * @param {number} width Canvas width.
2462 * @param {number} height Canvas height. 2674 * @param {number} height Canvas height.
2463 */ 2675 */
2464 resize: function(width, height) { 2676 resize: function(width, height) {
2465 this.canvas.width = width; 2677 this.canvas.width = width;
2466 this.canvas.height = height; 2678 this.canvas.height = height;
2467 }, 2679 },
2468 2680
2469 /** 2681 /**
2470 * Add a new cloud to the horizon. 2682 * Add a new cloud to the horizon.
2471 */ 2683 */
2472 addCloud: function() { 2684 addCloud: function() {
2473 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, 2685 this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD,
2474 this.dimensions.WIDTH)); 2686 this.dimensions.WIDTH));
2475 } 2687 }
2476 }; 2688 };
2477 })(); 2689 })();
OLDNEW
« no previous file with comments | « chrome/renderer/resources/neterror.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698