| Index: chrome/renderer/resources/offline.js
|
| diff --git a/chrome/renderer/resources/offline.js b/chrome/renderer/resources/offline.js
|
| index e16dfa632e82fe28d2379e39d672617803cbb623..21bd28663501b1067115f1787391b51a846e9529 100644
|
| --- a/chrome/renderer/resources/offline.js
|
| +++ b/chrome/renderer/resources/offline.js
|
| @@ -47,7 +47,8 @@ function Runner(outerContainerId, opt_config) {
|
| this.activated = false;
|
| this.crashed = false;
|
| this.paused = false;
|
| -
|
| + this.inverted = false;
|
| + this.invertTimer = 0;
|
| this.resizeTimerId_ = null;
|
|
|
| this.playCount = 0;
|
| @@ -111,6 +112,8 @@ Runner.config = {
|
| GAP_COEFFICIENT: 0.6,
|
| GRAVITY: 0.6,
|
| INITIAL_JUMP_VELOCITY: 12,
|
| + INVERT_FADE_DURATION: 12000,
|
| + INVERT_DISTANCE: 700,
|
| MAX_CLOUDS: 6,
|
| MAX_OBSTACLE_LENGTH: 3,
|
| MAX_OBSTACLE_DUPLICATION: 2,
|
| @@ -142,6 +145,7 @@ Runner.classes = {
|
| CONTAINER: 'runner-container',
|
| CRASHED: 'crashed',
|
| ICON: 'icon-offline',
|
| + INVERTED: 'inverted',
|
| SNACKBAR: 'snackbar',
|
| SNACKBAR_SHOW: 'snackbar-show',
|
| TOUCH_CONTROLLER: 'controller'
|
| @@ -158,20 +162,24 @@ Runner.spriteDefinition = {
|
| CACTUS_SMALL: {x: 228, y: 2},
|
| CLOUD: {x: 86, y: 2},
|
| HORIZON: {x: 2, y: 54},
|
| + MOON: {x: 484, y: 2},
|
| PTERODACTYL: {x: 134, y: 2},
|
| RESTART: {x: 2, y: 2},
|
| - TEXT_SPRITE: {x: 484, y: 2},
|
| - TREX: {x: 677, y: 2}
|
| + TEXT_SPRITE: {x: 655, y: 2},
|
| + TREX: {x: 848, y: 2},
|
| + STAR: {x: 645, y: 2}
|
| },
|
| HDPI: {
|
| - CACTUS_LARGE: {x: 652,y: 2},
|
| - CACTUS_SMALL: {x: 446,y: 2},
|
| - CLOUD: {x: 166,y: 2},
|
| - HORIZON: {x: 2,y: 104},
|
| - PTERODACTYL: {x: 260,y: 2},
|
| - RESTART: {x: 2,y: 2},
|
| - TEXT_SPRITE: {x: 954,y: 2},
|
| - TREX: {x: 1338,y: 2}
|
| + CACTUS_LARGE: {x: 652, y: 2},
|
| + CACTUS_SMALL: {x: 446, y: 2},
|
| + CLOUD: {x: 166, y: 2},
|
| + HORIZON: {x: 2, y: 104},
|
| + MOON: {x: 954, y: 2},
|
| + PTERODACTYL: {x: 260, y: 2},
|
| + RESTART: {x: 2, y: 2},
|
| + TEXT_SPRITE: {x: 1294, y: 2},
|
| + TREX: {x: 1678, y: 2},
|
| + STAR: {x: 1276, y: 2}
|
| }
|
| };
|
|
|
| @@ -525,7 +533,8 @@ Runner.prototype = {
|
| this.horizon.update(0, this.currentSpeed, hasObstacles);
|
| } else {
|
| deltaTime = !this.started ? 0 : deltaTime;
|
| - this.horizon.update(deltaTime, this.currentSpeed, hasObstacles);
|
| + this.horizon.update(deltaTime, this.currentSpeed, hasObstacles,
|
| + this.inverted);
|
| }
|
|
|
| // Check for collisions.
|
| @@ -542,12 +551,34 @@ Runner.prototype = {
|
| this.gameOver();
|
| }
|
|
|
| - var playAcheivementSound = this.distanceMeter.update(deltaTime,
|
| + var playAchievementSound = this.distanceMeter.update(deltaTime,
|
| Math.ceil(this.distanceRan));
|
|
|
| - if (playAcheivementSound) {
|
| + if (playAchievementSound) {
|
| this.playSound(this.soundFx.SCORE);
|
| }
|
| +
|
| + // Night mode.
|
| + if (this.invertTimer > this.config.INVERT_FADE_DURATION) {
|
| + this.invertTimer = 0;
|
| + this.invertTrigger = false;
|
| + this.invert();
|
| + } else if (this.invertTimer) {
|
| + this.invertTimer += deltaTime;
|
| + } else {
|
| + var actualDistance =
|
| + this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan));
|
| +
|
| + if (actualDistance > 0) {
|
| + this.invertTrigger = !(actualDistance %
|
| + this.config.INVERT_DISTANCE);
|
| +
|
| + if (this.invertTrigger && this.invertTimer === 0) {
|
| + this.invertTimer += deltaTime;
|
| + this.invert();
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| if (!this.crashed) {
|
| @@ -774,7 +805,6 @@ Runner.prototype = {
|
| this.crashed = false;
|
| this.distanceRan = 0;
|
| this.setSpeed(this.config.SPEED);
|
| -
|
| this.time = getTimeStamp();
|
| this.containerEl.classList.remove(Runner.classes.CRASHED);
|
| this.clearCanvas();
|
| @@ -782,7 +812,7 @@ Runner.prototype = {
|
| this.horizon.reset();
|
| this.tRex.reset();
|
| this.playSound(this.soundFx.BUTTON_PRESS);
|
| -
|
| + this.invert(true);
|
| this.update();
|
| }
|
| },
|
| @@ -791,7 +821,8 @@ Runner.prototype = {
|
| * Pause the game if the tab is not in focus.
|
| */
|
| onVisibilityChange: function(e) {
|
| - if (document.hidden || document.webkitHidden || e.type == 'blur') {
|
| + if (document.hidden || document.webkitHidden || e.type == 'blur' ||
|
| + document.visibilityState != 'visible') {
|
| this.stop();
|
| } else if (!this.crashed) {
|
| this.tRex.reset();
|
| @@ -810,6 +841,21 @@ Runner.prototype = {
|
| sourceNode.connect(this.audioContext.destination);
|
| sourceNode.start(0);
|
| }
|
| + },
|
| +
|
| + /**
|
| + * Inverts the current page / canvas colors.
|
| + * @param {boolean} Whether to reset colors.
|
| + */
|
| + invert: function(reset) {
|
| + if (reset) {
|
| + document.body.classList.toggle(Runner.classes.INVERTED, false);
|
| + this.invertTimer = 0;
|
| + this.inverted = false;
|
| + } else {
|
| + this.inverted = document.body.classList.toggle(Runner.classes.INVERTED,
|
| + this.invertTrigger);
|
| + }
|
| }
|
| };
|
|
|
| @@ -1173,9 +1219,10 @@ function CollisionBox(x, y, w, h) {
|
| * @param {Object} dimensions
|
| * @param {number} gapCoefficient Mutipler in determining the gap.
|
| * @param {number} speed
|
| + * @param {number} opt_xOffset
|
| */
|
| function Obstacle(canvasCtx, type, spriteImgPos, dimensions,
|
| - gapCoefficient, speed) {
|
| + gapCoefficient, speed, opt_xOffset) {
|
|
|
| this.canvasCtx = canvasCtx;
|
| this.spritePos = spriteImgPos;
|
| @@ -1184,7 +1231,7 @@ function Obstacle(canvasCtx, type, spriteImgPos, dimensions,
|
| this.size = getRandomNum(1, Obstacle.MAX_OBSTACLE_LENGTH);
|
| this.dimensions = dimensions;
|
| this.remove = false;
|
| - this.xPos = 0;
|
| + this.xPos = dimensions.WIDTH + (opt_xOffset || 0);
|
| this.yPos = 0;
|
| this.width = 0;
|
| this.collisionBoxes = [];
|
| @@ -1225,7 +1272,6 @@ Obstacle.prototype = {
|
| }
|
|
|
| this.width = this.typeConfig.width * this.size;
|
| - this.xPos = this.dimensions.WIDTH - this.width;
|
|
|
| // Check if obstacle can be positioned at various heights.
|
| if (Array.isArray(this.typeConfig.yPos)) {
|
| @@ -1806,6 +1852,7 @@ function DistanceMeter(canvas, spritePos, canvasWidth) {
|
| this.defaultString = '';
|
| this.flashTimer = 0;
|
| this.flashIterations = 0;
|
| + this.invertTrigger = false;
|
|
|
| this.config = DistanceMeter.config;
|
| this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS;
|
| @@ -1949,7 +1996,6 @@ DistanceMeter.prototype = {
|
|
|
| if (!this.acheivement) {
|
| distance = this.getActualDistance(distance);
|
| -
|
| // Score has gone beyond the initial digit count.
|
| if (distance > this.maxScore && this.maxScoreUnits ==
|
| this.config.MAX_DISTANCE_UNITS) {
|
| @@ -2002,7 +2048,6 @@ DistanceMeter.prototype = {
|
| }
|
|
|
| this.drawHighScore();
|
| -
|
| return playSound;
|
| },
|
|
|
| @@ -2140,6 +2185,162 @@ Cloud.prototype = {
|
| //******************************************************************************
|
|
|
| /**
|
| + * Nightmode shows a moon and stars on the horizon.
|
| + */
|
| +function NightMode(canvas, spritePos, containerWidth) {
|
| + this.spritePos = spritePos;
|
| + this.canvas = canvas;
|
| + this.canvasCtx = canvas.getContext('2d');
|
| + this.xPos = containerWidth - 50;
|
| + this.yPos = 30;
|
| + this.currentPhase = 0;
|
| + this.opacity = 0;
|
| + this.containerWidth = containerWidth;
|
| + this.stars = [];
|
| + this.drawStars = false;
|
| + this.placeStars();
|
| +};
|
| +
|
| +/**
|
| + * @enum {number}
|
| + */
|
| +NightMode.config = {
|
| + FADE_SPEED: 0.035,
|
| + HEIGHT: 40,
|
| + MOON_SPEED: 0.25,
|
| + NUM_STARS: 2,
|
| + STAR_SIZE: 9,
|
| + STAR_SPEED: 0.3,
|
| + STAR_MAX_Y: 70,
|
| + WIDTH: 20
|
| +};
|
| +
|
| +NightMode.phases = [140, 120, 100, 60, 40, 20, 0];
|
| +
|
| +NightMode.prototype = {
|
| + /**
|
| + * Update moving moon, changing phases.
|
| + * @param {boolean} activated Whether night mode is activated.
|
| + * @param {number} delta
|
| + */
|
| + update: function(activated, delta) {
|
| + // Moon phase.
|
| + if (activated && this.opacity == 0) {
|
| + this.currentPhase++;
|
| +
|
| + if (this.currentPhase >= NightMode.phases.length) {
|
| + this.currentPhase = 0;
|
| + }
|
| + }
|
| +
|
| + // Fade in / out.
|
| + if (activated && (this.opacity < 1 || this.opacity == 0)) {
|
| + this.opacity += NightMode.config.FADE_SPEED;
|
| + } else if (this.opacity > 0) {
|
| + this.opacity -= NightMode.config.FADE_SPEED;
|
| + }
|
| +
|
| + // Set moon positioning.
|
| + if (this.opacity > 0) {
|
| + this.xPos = this.updateXPos(this.xPos, NightMode.config.MOON_SPEED);
|
| +
|
| + // Update stars.
|
| + if (this.drawStars) {
|
| + for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
|
| + this.stars[i].x = this.updateXPos(this.stars[i].x,
|
| + NightMode.config.STAR_SPEED);
|
| + }
|
| + }
|
| + this.draw();
|
| + } else {
|
| + this.opacity = 0;
|
| + this.placeStars();
|
| + }
|
| + this.drawStars = true;
|
| + },
|
| +
|
| + updateXPos: function(currentPos, speed) {
|
| + if (currentPos < -NightMode.config.WIDTH) {
|
| + currentPos = this.containerWidth;
|
| + } else {
|
| + currentPos -= speed;
|
| + }
|
| + return currentPos;
|
| + },
|
| +
|
| + draw: function() {
|
| + var moonSourceWidth = this.currentPhase == 3 ? NightMode.config.WIDTH * 2 :
|
| + NightMode.config.WIDTH;
|
| + var moonSourceHeight = NightMode.config.HEIGHT;
|
| + var moonSourceX = this.spritePos.x + NightMode.phases[this.currentPhase];
|
| + var moonOutputWidth = moonSourceWidth;
|
| + var starSize = NightMode.config.STAR_SIZE;
|
| + var starSourceX = Runner.spriteDefinition.LDPI.STAR.x;
|
| +
|
| + if (IS_HIDPI) {
|
| + moonSourceWidth *= 2;
|
| + moonSourceHeight *= 2;
|
| + moonSourceX = this.spritePos.x +
|
| + (NightMode.phases[this.currentPhase] * 2);
|
| + starSize *= 2;
|
| + starSourceX = Runner.spriteDefinition.HDPI.STAR.x;
|
| + }
|
| +
|
| + this.canvasCtx.save();
|
| + this.canvasCtx.globalAlpha = this.opacity;
|
| +
|
| + // Stars.
|
| + if (this.drawStars) {
|
| + for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
|
| + this.canvasCtx.drawImage(Runner.imageSprite,
|
| + starSourceX, this.stars[i].sourceY, starSize, starSize,
|
| + Math.round(this.stars[i].x), this.stars[i].y,
|
| + NightMode.config.STAR_SIZE, NightMode.config.STAR_SIZE);
|
| + }
|
| + }
|
| +
|
| + // Moon.
|
| + this.canvasCtx.drawImage(Runner.imageSprite, moonSourceX,
|
| + this.spritePos.y, moonSourceWidth, moonSourceHeight,
|
| + Math.round(this.xPos), this.yPos,
|
| + moonOutputWidth, NightMode.config.HEIGHT);
|
| +
|
| + this.canvasCtx.globalAlpha = 1;
|
| + this.canvasCtx.restore();
|
| + },
|
| +
|
| + // Do star placement.
|
| + placeStars: function() {
|
| + var segmentSize = Math.round(this.containerWidth /
|
| + NightMode.config.NUM_STARS);
|
| +
|
| + for (var i = 0; i < NightMode.config.NUM_STARS; i++) {
|
| + this.stars[i] = {};
|
| + this.stars[i].x = getRandomNum(segmentSize * i, segmentSize * (i + 1));
|
| + this.stars[i].y = getRandomNum(0, NightMode.config.STAR_MAX_Y);
|
| +
|
| + if (IS_HIDPI) {
|
| + this.stars[i].sourceY = Runner.spriteDefinition.HDPI.STAR.y +
|
| + NightMode.config.STAR_SIZE * 2 * i;
|
| + } else {
|
| + this.stars[i].sourceY = Runner.spriteDefinition.LDPI.STAR.y +
|
| + NightMode.config.STAR_SIZE * i;
|
| + }
|
| + }
|
| + },
|
| +
|
| + reset: function() {
|
| + this.currentPhase = 0;
|
| + this.opacity = 0;
|
| + this.update(false);
|
| + }
|
| +
|
| +};
|
| +
|
| +
|
| +//******************************************************************************
|
| +
|
| +/**
|
| * Horizon Line.
|
| * Consists of two connecting lines. Randomly assigns a flat / bumpy horizon.
|
| * @param {HTMLCanvasElement} canvas
|
| @@ -2287,6 +2488,7 @@ function Horizon(canvas, spritePos, dimensions, gapCoefficient) {
|
| this.horizonOffsets = [0, 0];
|
| this.cloudFrequency = this.config.CLOUD_FREQUENCY;
|
| this.spritePos = spritePos;
|
| + this.nightMode = null;
|
|
|
| // Cloud
|
| this.clouds = [];
|
| @@ -2294,7 +2496,6 @@ function Horizon(canvas, spritePos, dimensions, gapCoefficient) {
|
|
|
| // Horizon
|
| this.horizonLine = null;
|
| -
|
| this.init();
|
| };
|
|
|
| @@ -2319,6 +2520,8 @@ Horizon.prototype = {
|
| init: function() {
|
| this.addCloud();
|
| this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON);
|
| + this.nightMode = new NightMode(this.canvas, this.spritePos.MOON,
|
| + this.dimensions.WIDTH);
|
| },
|
|
|
| /**
|
| @@ -2327,10 +2530,12 @@ Horizon.prototype = {
|
| * @param {boolean} updateObstacles Used as an override to prevent
|
| * the obstacles from being updated / added. This happens in the
|
| * ease in section.
|
| + * @param {boolean} showNightMode Night mode activated.
|
| */
|
| - update: function(deltaTime, currentSpeed, updateObstacles) {
|
| + update: function(deltaTime, currentSpeed, updateObstacles, showNightMode) {
|
| this.runningTime += deltaTime;
|
| this.horizonLine.update(deltaTime, currentSpeed);
|
| + this.nightMode.update(showNightMode);
|
| this.updateClouds(deltaTime, currentSpeed);
|
|
|
| if (updateObstacles) {
|
| @@ -2365,6 +2570,8 @@ Horizon.prototype = {
|
| this.clouds = this.clouds.filter(function(obj) {
|
| return !obj.remove;
|
| });
|
| + } else {
|
| + this.addCloud();
|
| }
|
| },
|
|
|
| @@ -2404,6 +2611,10 @@ Horizon.prototype = {
|
| }
|
| },
|
|
|
| + removeFirstObstacle: function() {
|
| + this.obstacles.shift();
|
| + },
|
| +
|
| /**
|
| * Add a new obstacle.
|
| * @param {number} currentSpeed
|
| @@ -2422,7 +2633,7 @@ Horizon.prototype = {
|
|
|
| this.obstacles.push(new Obstacle(this.canvasCtx, obstacleType,
|
| obstacleSpritePos, this.dimensions,
|
| - this.gapCoefficient, currentSpeed));
|
| + this.gapCoefficient, currentSpeed, obstacleType.width));
|
|
|
| this.obstacleHistory.unshift(obstacleType.type);
|
|
|
| @@ -2454,6 +2665,7 @@ Horizon.prototype = {
|
| reset: function() {
|
| this.obstacles = [];
|
| this.horizonLine.reset();
|
| + this.nightMode.reset();
|
| },
|
|
|
| /**
|
|
|