前言最近我逛各位大佬的博客时，看到了将chrome的离线游戏嵌入博客，就觉得比较有意思，想抄过来，发现原博客的实现方法和源代码实在粗糙，于是我在github上找到了源码，将其进一步更方便嵌入博客，现在讲讲步骤。试玩正文仅需一个JS文件即可runner.js代码如下!function (A, i) { "object" == typeof exports && "object" == typeof module ? module.exports = i() : "function" == typeof define && define.amd ? define([], i) : "object" == typeof exports ? exports.initRunner = i() : A.initRunner = i() }(this, function () { return function (A) { function i(s) { if (t[s]) return t[s].exports; var e = t[s] = {exports: {}, id: s, loaded: !1}; return A[s].call(e.exports, e, e.exports, i), e.loaded = !0, e.exports } var t = {}; return i.m = A, i.c = t, i.p = "", i(0) }([function (A, i, t) { document.body.insertAdjacentHTML("beforeend", t(3)), t(5); const s = t(6); A.exports = function (A, i) { var t = "string" == typeof A ? document.querySelector(A) : A; return t.classList.add("interstitial-wrapper"), new s(t, i) } }, function (A, i, t) { i = A.exports = t(2)(), i.push([A.id, ".interstitial-wrapper{box-sizing:border-box;margin:0 auto;max-width:600px}.runner-container{width:44px}.runner-canvas,.runner-container{height:150px;max-width:600px;overflow:hidden}.runner-canvas{opacity:1;position:relative;z-index:2}.inverted{transition:-webkit-filter 1.5s cubic-bezier(.65,.05,.36,1),background-color 1.5s cubic-bezier(.65,.05,.36,1);will-change:-webkit-filter,background-color;-webkit-filter:invert(100%);background-color:#000}.controller{background:hsla(0,0%,97%,.1);height:100vh;left:0;position:absolute;top:0;width:100vw;z-index:1}#offline-resources{display:none}", ""]) }, function (A, i) { A.exports = function () { var A = []; return A.toString = function () { for (var A = [], i = 0; i < this.length; i++) { var t = this[i]; t[2] ? A.push("@media " + t[2] + "{" + t[1] + "}") : A.push(t[1]) } return A.join("") }, A.i = function (i, t) { "string" == typeof i && (i = null, i, ""); for (var s = {}, e = 0; e < this.length; e++) { var n = this[e][0]; "number" == typeof n && (s[n] = !0) } for (e = 0; e < i.length; e++) { var o = i[e]; "number" == typeof o[0] && s[o[0]] || (t && !o[2] ? o[2] = t : t && (o[2] = "(" + o[2] + ") and (" + t + ")"), A.push(o)) } }, A } }, function (A, i) { A.exports = ' '; }, function (A, i, t) { function s(A, i) { for (var t = 0; t < A.length; t++) { var s = A[t], e = I[s.id]; if (e) { e.refs++; for (var n = 0; n < e.parts.length; n++) e.parts[n](s.parts[n]); for (; n < s.parts.length; n++) e.parts.push(r(s.parts[n], i)) } else { for (var o = [], n = 0; n < s.parts.length; n++) o.push(r(s.parts[n], i)); I[s.id] = {id: s.id, refs: 1, parts: o} } } } function e(A) { for (var i = [], t = {}, s = 0; s < A.length; s++) { var e = A[s], n = e[0], o = e[1], h = e[2], a = e[3], r = {css: o, media: h, sourceMap: a}; t[n] ? t[n].parts.push(r) : i.push(t[n] = {id: n, parts: [r]}) } return i } function n(A, i) { var t = l(), s = m[m.length - 1]; if ("top" === A.insertAt) s ? s.nextSibling ? t.insertBefore(i, s.nextSibling) : t.appendChild(i) : t.insertBefore(i, t.firstChild), m.push(i); else { if ("bottom" !== A.insertAt) throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'."); t.appendChild(i) } } function o(A) { A.parentNode.removeChild(A); var i = m.indexOf(A); i >= 0 && m.splice(i, 1) } function h(A) { var i = document.createElement("style"); return i.type = "text/css", n(A, i), i } function a(A) { var i = document.createElement("link"); return i.rel = "stylesheet", n(A, i), i } function r(A, i) { var t, s, e; if (i.singleton) { var n = p++; t = C || (C = h(i)), s = c.bind(null, t, n, !1), e = c.bind(null, t, n, !0) } else A.sourceMap && "function" == typeof URL && "function" == typeof URL.createObjectURL && "function" == typeof URL.revokeObjectURL && "function" == typeof Blob && "function" == typeof btoa ? (t = a(i), s = d.bind(null, t), e = function () { o(t), t.href && URL.revokeObjectURL(t.href) }) : (t = h(i), s = g.bind(null, t), e = function () { o(t) }); return s(A), function (i) { if (i) { if (i.css === A.css && i.media === A.media && i.sourceMap === A.sourceMap) return; s(A = i) } else e() } } function c(A, i, t, s) { var e = t ? "" : s.css; if (A.styleSheet) A.styleSheet.cssText = f(i, e); else { var n = document.createTextNode(e), o = A.childNodes; o[i] && A.removeChild(o[i]), o.length ? A.insertBefore(n, o[i]) : A.appendChild(n) } } function g(A, i) { var t = i.css, s = i.media; if (s && A.setAttribute("media", s), A.styleSheet) A.styleSheet.cssText = t; else { for (; A.firstChild;) A.removeChild(A.firstChild); A.appendChild(document.createTextNode(t)) } } function d(A, i) { var t = i.css, s = i.sourceMap; s && (t += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(s)))) + " */"); var e = new Blob([t], {type: "text/css"}), n = A.href; A.href = URL.createObjectURL(e), n && URL.revokeObjectURL(n) } var I = {}, E = function (A) { var i; return function () { return "undefined" == typeof i && (i = A.apply(this, arguments)), i } }, u = E(function () { return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()) }), l = E(function () { return document.head || document.getElementsByTagName("head")[0] }), C = null, p = 0, m = []; A.exports = function (A, i) { i = i || {}, "undefined" == typeof i.singleton && (i.singleton = u()), "undefined" == typeof i.insertAt && (i.insertAt = "bottom"); var t = e(A); return s(t, i), function (A) { for (var n = [], o = 0; o < t.length; o++) { var h = t[o], a = I[h.id]; a.refs--, n.push(a) } if (A) { var r = e(A); s(r, i) } for (var o = 0; o < n.length; o++) { var a = n[o]; if (0 === a.refs) { for (var c = 0; c < a.parts.length; c++) a.parts[c](); delete I[a.id] } } } }; var f = function () { var A = []; return function (i, t) { return A[i] = t, A.filter(Boolean).join("\n") } }() }, function (A, i, t) { var s = t(1); "string" == typeof s && (s = A.id, s, ""); t(4)(s, {}); s.locals && (A.exports = s.locals) }, function (A, i) { function t(A, i) { this.outerContainerEl = "string" == typeof A ? document.querySelector(A) : A, this.containerEl = null, this.config = i || t.config, this.dimensions = t.defaultDimensions, this.canvas = null, this.canvasCtx = null, this.tRex = null, this.distanceMeter = null, this.distanceRan = 0, this.highestScore = 0, this.time = 0, this.runningTime = 0, this.msPerFrame = 1e3 / V, this.currentSpeed = this.config.SPEED, this.obstacles = [], this.started = !1, this.activated = !1, this.crashed = !1, this.paused = !1, this.inverted = !1, this.invertTimer = 0, this.resizeTimerId_ = null, this.playCount = 0, this.audioBuffer = null, this.soundFx = {}, this.audioContext = null, this.images = {}, this.imagesLoaded = 0, this.loadImages() } function s(A, i) { return Math.floor(Math.random() * (i - A + 1)) + A } function e(A) { D && window.navigator.vibrate && window.navigator.vibrate(A) } function n(A, i, s, e) { var n = document.createElement("canvas"); return n.className = e ? t.classes.CANVAS + " " + e : t.classes.CANVAS, n.width = i, n.height = s, A.appendChild(n), n } function o(A) { for (var i = A.length / 4 * 3, t = atob(A), s = new ArrayBuffer(i), e = new Uint8Array(s), n = 0; i > n; n++) e[n] = t.charCodeAt(n); return e.buffer } function h() { return T ? (new Date).getTime() : performance.now() } function a(A, i, t, s) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.canvasDimensions = s, this.textImgPos = i, this.restartImgPos = t, this.draw() } function r(A, i, s) { var e = (t.defaultDimensions.WIDTH + A.xPos, new I(i.xPos + 1, i.yPos + 1, i.config.WIDTH - 2, i.config.HEIGHT - 2)), n = new I(A.xPos + 1, A.yPos + 1, A.typeConfig.width * A.size - 2, A.typeConfig.height - 2); if (s && g(s, e, n), d(e, n)) for (var o = A.collisionBoxes, h = i.ducking ? u.collisionBoxes.DUCKING : u.collisionBoxes.RUNNING, a = 0; a < h.length; a++) for (var r = 0; r < o.length; r++) { var E = c(h[a], e), l = c(o[r], n), C = d(E, l); if (s && g(s, E, l), C) return [E, l] } return !1 } function c(A, i) { return new I(A.x + i.x, A.y + i.y, A.width, A.height) } function g(A, i, t) { A.save(), A.strokeStyle = "#f00", A.strokeRect(i.x, i.y, i.width, i.height), A.strokeStyle = "#0f0", A.strokeRect(t.x, t.y, t.width, t.height), A.restore() } function d(A, i) { var t = !1, s = (A.x, A.y, i.x); i.y; return A.x < s + i.width && A.x + A.width > s && A.y < i.y + i.height && A.height + A.y > i.y && (t = !0), t } function I(A, i, t, s) { this.x = A, this.y = i, this.width = t, this.height = s } function E(A, i, t, e, n, o, h) { this.canvasCtx = A, this.spritePos = t, this.typeConfig = i, this.gapCoefficient = n, this.size = s(1, E.MAX_OBSTACLE_LENGTH), this.dimensions = e, this.remove = !1, this.xPos = e.WIDTH + (h || 0), this.yPos = 0, this.width = 0, this.collisionBoxes = [], this.gap = 0, this.speedOffset = 0, this.currentFrame = 0, this.timer = 0, this.init(o) } function u(A, i) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.spritePos = i, this.xPos = 0, this.yPos = 0, this.groundYPos = 0, this.currentFrame = 0, this.currentAnimFrames = [], this.blinkDelay = 0, this.animStartTime = 0, this.timer = 0, this.msPerFrame = 1e3 / V, this.config = u.config, this.status = u.status.WAITING, this.jumping = !1, this.ducking = !1, this.jumpVelocity = 0, this.reachedMinHeight = !1, this.speedDrop = !1, this.jumpCount = 0, this.jumpspotX = 0, this.init() } function l(A, i, s) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.image = t.imageSprite, this.spritePos = i, this.x = 0, this.y = 5, this.currentDistance = 0, this.maxScore = 0, this.highScore = 0, this.container = null, this.digits = [], this.acheivement = !1, this.defaultString = "", this.flashTimer = 0, this.flashIterations = 0, this.invertTrigger = !1, this.config = l.config, this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS, this.init(s) } function C(A, i, t) { this.canvas = A, this.canvasCtx = this.canvas.getContext("2d"), this.spritePos = i, this.containerWidth = t, this.xPos = t, this.yPos = 0, this.remove = !1, this.cloudGap = s(C.config.MIN_CLOUD_GAP, C.config.MAX_CLOUD_GAP), this.init() } function p(A, i, t) { this.spritePos = i, this.canvas = A, this.canvasCtx = A.getContext("2d"), this.xPos = t - 50, this.yPos = 30, this.currentPhase = 0, this.opacity = 0, this.containerWidth = t, this.stars = [], this.drawStars = !1, this.placeStars() } function m(A, i) { this.spritePos = i, this.canvas = A, this.canvasCtx = A.getContext("2d"), this.sourceDimensions = {}, this.dimensions = m.dimensions, this.sourceXPos = [this.spritePos.x, this.spritePos.x + this.dimensions.WIDTH], this.xPos = [], this.yPos = 0, this.bumpThreshold = .5, this.setSourceDimensions(), this.draw() } function f(A, i, t, s) { this.canvas = A, this.canvasCtx = this.canvas.getContext("2d"), this.config = f.config, this.dimensions = t, this.gapCoefficient = s, this.obstacles = [], this.obstacleHistory = [], this.horizonOffsets = [0, 0], this.cloudFrequency = this.config.CLOUD_FREQUENCY, this.spritePos = i, this.nightMode = null, this.clouds = [], this.cloudSpeed = this.config.BG_CLOUD_SPEED, this.horizonLine = null, this.init() } A.exports = t; var S = 600, V = 60, Q = window.devicePixelRatio > 1, T = window.navigator.userAgent.indexOf("CriOS") > -1 || "UIWebViewForStaticFileContent" == window.navigator.userAgent, D = window.navigator.userAgent.indexOf("Mobi") > -1 || T; "ontouchstart" in window; t.config = { ACCELERATION: .001, BG_CLOUD_SPEED: .2, BOTTOM_PAD: 10, CLEAR_TIME: 3e3, CLOUD_FREQUENCY: .5, GAMEOVER_CLEAR_TIME: 750, GAP_COEFFICIENT: .6, GRAVITY: .6, INITIAL_JUMP_VELOCITY: 12, INVERT_FADE_DURATION: 12e3, INVERT_DISTANCE: 700, MAX_CLOUDS: 6, MAX_OBSTACLE_LENGTH: 3, MAX_OBSTACLE_DUPLICATION: 2, MAX_SPEED: 13, MIN_JUMP_HEIGHT: 35, MOBILE_SPEED_COEFFICIENT: 1.2, RESOURCE_TEMPLATE_ID: "audio-resources", SPEED: 6, SPEED_DROP_COEFFICIENT: 3 }, t.defaultDimensions = {WIDTH: S, HEIGHT: 150}, t.classes = { CANVAS: "runner-canvas", CONTAINER: "runner-container", CRASHED: "crashed", ICON: "icon-offline", INVERTED: "inverted", SNACKBAR: "snackbar", SNACKBAR_SHOW: "snackbar-show", TOUCH_CONTROLLER: "controller" }, t.spriteDefinition = { LDPI: { CACTUS_LARGE: {x: 332, y: 2}, 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: 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}, 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} } }, t.sounds = { BUTTON_PRESS: "offline-sound-press", HIT: "offline-sound-hit", SCORE: "offline-sound-reached" }, t.keycodes = { JUMP: {38: 1, 32: 1}, DUCK: {40: 1}, RESTART: {13: 1} }, t.events = { ANIM_END: "webkitAnimationEnd", CLICK: "click", KEYDOWN: "keydown", KEYUP: "keyup", MOUSEDOWN: "mousedown", MOUSEUP: "mouseup", RESIZE: "resize", TOUCHEND: "touchend", TOUCHSTART: "touchstart", VISIBILITY: "visibilitychange", BLUR: "blur", FOCUS: "focus", LOAD: "load" }, t.prototype = { updateConfigSetting: function (A, i) { if (A in this.config && void 0 != i) switch (this.config[A] = i, A) { case"GRAVITY": case"MIN_JUMP_HEIGHT": case"SPEED_DROP_COEFFICIENT": this.tRex.config[A] = i; break; case"INITIAL_JUMP_VELOCITY": this.tRex.setJumpVelocity(i); break; case"SPEED": this.setSpeed(i) } }, loadImages: function () { Q ? (t.imageSprite = document.getElementById("offline-resources-2x"), this.spriteDef = t.spriteDefinition.HDPI) : (t.imageSprite = document.getElementById("offline-resources-1x"), this.spriteDef = t.spriteDefinition.LDPI), this.init() }, loadSounds: function () { if (!T && window.AudioContext) { this.audioContext = new AudioContext; var A = document.getElementById(this.config.RESOURCE_TEMPLATE_ID).content; for (var i in t.sounds) { var s = A.getElementById(t.sounds[i]).src; s = s.substr(s.indexOf(",") + 1); var e = o(s); this.audioContext.decodeAudioData(e, function (A, i) { this.soundFx[A] = i }.bind(this, i)) } } }, setSpeed: function (A) { var i = A || this.currentSpeed; if (this.dimensions.WIDTH < S) { var t = i * this.dimensions.WIDTH / S * this.config.MOBILE_SPEED_COEFFICIENT; this.currentSpeed = t > i ? i : t } else A && (this.currentSpeed = A) }, init: function () { this.adjustDimensions(), this.setSpeed(), this.containerEl = document.createElement("div"), this.containerEl.className = t.classes.CONTAINER, this.canvas = n(this.containerEl, this.dimensions.WIDTH, this.dimensions.HEIGHT, t.classes.PLAYER), this.canvasCtx = this.canvas.getContext("2d"), this.canvasCtx.fillStyle = "#f7f7f7", this.canvasCtx.fill(), t.updateCanvasScaling(this.canvas), this.horizon = new f(this.canvas, this.spriteDef, this.dimensions, this.config.GAP_COEFFICIENT), this.distanceMeter = new l(this.canvas, this.spriteDef.TEXT_SPRITE, this.dimensions.WIDTH), this.tRex = new u(this.canvas, this.spriteDef.TREX), this.outerContainerEl.appendChild(this.containerEl), D && this.createTouchController(), this.startListening(), this.update(), window.addEventListener(t.events.RESIZE, this.debounceResize.bind(this)) }, createTouchController: function () { this.touchController = document.createElement("div"), this.touchController.className = t.classes.TOUCH_CONTROLLER }, debounceResize: function () { this.resizeTimerId_ || (this.resizeTimerId_ = setInterval(this.adjustDimensions.bind(this), 250)) }, adjustDimensions: function () { clearInterval(this.resizeTimerId_), this.resizeTimerId_ = null; var A = window.getComputedStyle(this.outerContainerEl), i = Number(A.paddingLeft.substr(0, A.paddingLeft.length - 2)); this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - 2 * i, this.canvas && (this.canvas.width = this.dimensions.WIDTH, this.canvas.height = this.dimensions.HEIGHT, t.updateCanvasScaling(this.canvas), this.distanceMeter.calcXPos(this.dimensions.WIDTH), this.clearCanvas(), this.horizon.update(0, 0, !0), this.tRex.update(0), this.activated || this.crashed || this.paused ? (this.containerEl.style.width = this.dimensions.WIDTH + "px", this.containerEl.style.height = this.dimensions.HEIGHT + "px", this.distanceMeter.update(0, Math.ceil(this.distanceRan)), this.stop()) : this.tRex.draw(0, 0), this.crashed && this.gameOverPanel && (this.gameOverPanel.updateDimensions(this.dimensions.WIDTH), this.gameOverPanel.draw())) }, playIntro: function () { if (this.started || this.crashed) this.crashed && this.restart(); else { this.playingIntro = !0, this.tRex.playingIntro = !0; var A = "@-webkit-keyframes intro { from { width:" + u.config.WIDTH + "px }to { width: " + this.dimensions.WIDTH + "px }}"; document.styleSheets[0].insertRule(A, 0), this.containerEl.addEventListener(t.events.ANIM_END, this.startGame.bind(this)), this.containerEl.style.webkitAnimation = "intro .4s ease-out 1 both", this.containerEl.style.width = this.dimensions.WIDTH + "px", this.touchController && this.outerContainerEl.appendChild(this.touchController), this.activated = !0, this.started = !0 } }, startGame: function () { this.runningTime = 0, this.playingIntro = !1, this.tRex.playingIntro = !1, this.containerEl.style.webkitAnimation = "", this.playCount++, document.addEventListener(t.events.VISIBILITY, this.onVisibilityChange.bind(this)), window.addEventListener(t.events.BLUR, this.onVisibilityChange.bind(this)), window.addEventListener(t.events.FOCUS, this.onVisibilityChange.bind(this)) }, clearCanvas: function () { this.canvasCtx.clearRect(0, 0, this.dimensions.WIDTH, this.dimensions.HEIGHT) }, update: function () { this.drawPending = !1; var A = h(), i = A - (this.time || A); if (this.time = A, this.activated) { this.clearCanvas(), this.tRex.jumping && this.tRex.updateJump(i), this.runningTime += i; var t = this.runningTime > this.config.CLEAR_TIME; 1 != this.tRex.jumpCount || this.playingIntro || this.playIntro(), this.playingIntro ? this.horizon.update(0, this.currentSpeed, t) : (i = this.started ? i : 0, this.horizon.update(i, this.currentSpeed, t, this.inverted)); var s = t && r(this.horizon.obstacles[0], this.tRex); s ? this.gameOver() : (this.distanceRan += this.currentSpeed * i / this.msPerFrame, this.currentSpeed < this.config.MAX_SPEED && (this.currentSpeed += this.config.ACCELERATION)); var e = this.distanceMeter.update(i, Math.ceil(this.distanceRan)); if (e && this.playSound(this.soundFx.SCORE), this.invertTimer > this.config.INVERT_FADE_DURATION) this.invertTimer = 0, this.invertTrigger = !1, this.invert(); else if (this.invertTimer) this.invertTimer += i; else { var n = this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan)); n > 0 && (this.invertTrigger = !(n % this.config.INVERT_DISTANCE), this.invertTrigger && 0 === this.invertTimer && (this.invertTimer += i, this.invert())) } } this.crashed || (this.tRex.update(i), this.raq()) }, handleEvent: function (A) { return function (i, t) { switch (i) { case t.KEYDOWN: case t.TOUCHSTART: case t.MOUSEDOWN: this.onKeyDown(A); break; case t.KEYUP: case t.TOUCHEND: case t.MOUSEUP: this.onKeyUp(A) } }.bind(this)(A.type, t.events) }, startListening: function () { document.addEventListener(t.events.KEYDOWN, this), document.addEventListener(t.events.KEYUP, this), D ? (this.touchController.addEventListener(t.events.TOUCHSTART, this), this.touchController.addEventListener(t.events.TOUCHEND, this), this.containerEl.addEventListener(t.events.TOUCHSTART, this)) : (document.addEventListener(t.events.MOUSEDOWN, this), document.addEventListener(t.events.MOUSEUP, this)) }, stopListening: function () { document.removeEventListener(t.events.KEYDOWN, this), document.removeEventListener(t.events.KEYUP, this), D ? (this.touchController.removeEventListener(t.events.TOUCHSTART, this), this.touchController.removeEventListener(t.events.TOUCHEND, this), this.containerEl.removeEventListener(t.events.TOUCHSTART, this)) : (document.removeEventListener(t.events.MOUSEDOWN, this), document.removeEventListener(t.events.MOUSEUP, this)) }, onKeyDown: function (A) { D && A.preventDefault(), this.crashed || !t.keycodes.JUMP[A.keyCode] && A.type != t.events.TOUCHSTART || (this.activated || (this.loadSounds(), this.activated = !0), this.tRex.jumping || this.tRex.ducking || (this.playSound(this.soundFx.BUTTON_PRESS), this.tRex.startJump(this.currentSpeed))), this.crashed && A.type == t.events.TOUCHSTART && A.currentTarget == this.containerEl && this.restart(), this.activated && !this.crashed && t.keycodes.DUCK[A.keyCode] && (A.preventDefault(), this.tRex.jumping ? this.tRex.setSpeedDrop() : this.tRex.jumping || this.tRex.ducking || this.tRex.setDuck(!0)) }, onKeyUp: function (A) { var i = String(A.keyCode), s = t.keycodes.JUMP[i] || A.type == t.events.TOUCHEND || A.type == t.events.MOUSEDOWN; if (this.isRunning() && s) this.tRex.endJump(); else if (t.keycodes.DUCK[i]) this.tRex.speedDrop = !1, this.tRex.setDuck(!1); else if (this.crashed) { var e = h() - this.time; (t.keycodes.RESTART[i] || this.isLeftClickOnCanvas(A) || e >= this.config.GAMEOVER_CLEAR_TIME && t.keycodes.JUMP[i]) && this.restart() } else this.paused && s && (this.tRex.reset(), this.play()) }, isLeftClickOnCanvas: function (A) { return null != A.button && A.button < 2 && A.type == t.events.MOUSEUP && A.target == this.canvas }, raq: function () { this.drawPending || (this.drawPending = !0, this.raqId = requestAnimationFrame(this.update.bind(this))) }, isRunning: function () { return !!this.raqId }, gameOver: function () { this.playSound(this.soundFx.HIT), e(200), this.stop(), this.crashed = !0, this.distanceMeter.acheivement = !1, this.tRex.update(100, u.status.CRASHED), this.gameOverPanel ? this.gameOverPanel.draw() : this.gameOverPanel = new a(this.canvas, this.spriteDef.TEXT_SPRITE, this.spriteDef.RESTART, this.dimensions), this.distanceRan > this.highestScore && (this.highestScore = Math.ceil(this.distanceRan), this.distanceMeter.setHighScore(this.highestScore)), this.time = h() }, stop: function () { this.activated = !1, this.paused = !0, cancelAnimationFrame(this.raqId), this.raqId = 0 }, play: function () { this.crashed || (this.activated = !0, this.paused = !1, this.tRex.update(0, u.status.RUNNING), this.time = h(), this.update()) }, restart: function () { this.raqId || (this.playCount++, this.runningTime = 0, this.activated = !0, this.crashed = !1, this.distanceRan = 0, this.setSpeed(this.config.SPEED), this.time = h(), this.containerEl.classList.remove(t.classes.CRASHED), this.clearCanvas(), this.distanceMeter.reset(this.highestScore), this.horizon.reset(), this.tRex.reset(), this.playSound(this.soundFx.BUTTON_PRESS), this.invert(!0), this.update()) }, onVisibilityChange: function (A) { document.hidden || document.webkitHidden || "blur" == A.type || "visible" != document.visibilityState ? this.stop() : this.crashed || (this.tRex.reset(), this.play()) }, playSound: function (A) { if (A) { var i = this.audioContext.createBufferSource(); i.buffer = A, i.connect(this.audioContext.destination), i.start(0) } }, invert: function (A) { A ? (document.body.classList.toggle(t.classes.INVERTED, !1), this.invertTimer = 0, this.inverted = !1) : this.inverted = document.body.classList.toggle(t.classes.INVERTED, this.invertTrigger) } }, t.updateCanvasScaling = function (A, i, t) { var s = A.getContext("2d"), e = Math.floor(window.devicePixelRatio) || 1, n = Math.floor(s.webkitBackingStorePixelRatio) || 1, o = e / n; if (e !== n) { var h = i || A.width, a = t || A.height; return A.width = h * o, A.height = a * o, A.style.width = h + "px", A.style.height = a + "px", s.scale(o, o), !0 } return 1 == e && (A.style.width = A.width + "px", A.style.height = A.height + "px"), !1 }, a.dimensions = { TEXT_X: 0, TEXT_Y: 13, TEXT_WIDTH: 191, TEXT_HEIGHT: 11, RESTART_WIDTH: 36, RESTART_HEIGHT: 32 }, a.prototype = { updateDimensions: function (A, i) { this.canvasDimensions.WIDTH = A, i && (this.canvasDimensions.HEIGHT = i) }, draw: function () { var A = a.dimensions, i = this.canvasDimensions.WIDTH / 2, s = A.TEXT_X, e = A.TEXT_Y, n = A.TEXT_WIDTH, o = A.TEXT_HEIGHT, h = Math.round(i - A.TEXT_WIDTH / 2), r = Math.round((this.canvasDimensions.HEIGHT - 25) / 3), c = A.TEXT_WIDTH, g = A.TEXT_HEIGHT, d = A.RESTART_WIDTH, I = A.RESTART_HEIGHT, E = i - A.RESTART_WIDTH / 2, u = this.canvasDimensions.HEIGHT / 2; Q && (e *= 2, s *= 2, n *= 2, o *= 2, d *= 2, I *= 2), s += this.textImgPos.x, e += this.textImgPos.y, this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, h, r, c, g), this.canvasCtx.drawImage(t.imageSprite, this.restartImgPos.x, this.restartImgPos.y, d, I, E, u, A.RESTART_WIDTH, A.RESTART_HEIGHT) } }, E.MAX_GAP_COEFFICIENT = 1.5, E.MAX_OBSTACLE_LENGTH = 3, E.prototype = { init: function (A) { if (this.cloneCollisionBoxes(), this.size > 1 && this.typeConfig.multipleSpeed > A && (this.size = 1), this.width = this.typeConfig.width * this.size, Array.isArray(this.typeConfig.yPos)) { var i = D ? this.typeConfig.yPosMobile : this.typeConfig.yPos; this.yPos = i[s(0, i.length - 1)] } else this.yPos = this.typeConfig.yPos; this.draw(), this.size > 1 && (this.collisionBoxes[1].width = this.width - this.collisionBoxes[0].width - this.collisionBoxes[2].width, this.collisionBoxes[2].x = this.width - this.collisionBoxes[2].width), this.typeConfig.speedOffset && (this.speedOffset = Math.random() > .5 ? this.typeConfig.speedOffset : -this.typeConfig.speedOffset), this.gap = this.getGap(this.gapCoefficient, A) }, draw: function () { var A = this.typeConfig.width, i = this.typeConfig.height; Q && (A = 2 * A, i = 2 * i); var s = A * this.size * (.5 * (this.size - 1)) + this.spritePos.x; this.currentFrame > 0 && (s += A * this.currentFrame), this.canvasCtx.drawImage(t.imageSprite, s, this.spritePos.y, A * this.size, i, this.xPos, this.yPos, this.typeConfig.width * this.size, this.typeConfig.height) }, update: function (A, i) { this.remove || (this.typeConfig.speedOffset && (i += this.speedOffset), this.xPos -= Math.floor(i * V / 1e3 * A), this.typeConfig.numFrames && (this.timer += A, this.timer >= this.typeConfig.frameRate && (this.currentFrame = this.currentFrame == this.typeConfig.numFrames - 1 ? 0 : this.currentFrame + 1, this.timer = 0)), this.draw(), this.isVisible() || (this.remove = !0)) }, getGap: function (A, i) { var t = Math.round(this.width * i + this.typeConfig.minGap * A), e = Math.round(t * E.MAX_GAP_COEFFICIENT); return s(t, e) }, isVisible: function () { return this.xPos + this.width > 0 }, cloneCollisionBoxes: function () { for (var A = this.typeConfig.collisionBoxes, i = A.length - 1; i >= 0; i--) this.collisionBoxes[i] = new I(A[i].x, A[i].y, A[i].width, A[i].height) } }, E.types = [{ type: "CACTUS_SMALL", width: 17, height: 35, yPos: 105, multipleSpeed: 4, minGap: 120, minSpeed: 0, collisionBoxes: [new I(0, 7, 5, 27), new I(4, 0, 6, 34), new I(10, 4, 7, 14)] }, { type: "CACTUS_LARGE", width: 25, height: 50, yPos: 90, multipleSpeed: 7, minGap: 120, minSpeed: 0, collisionBoxes: [new I(0, 12, 7, 38), new I(8, 0, 7, 49), new I(13, 10, 10, 38)] }, { type: "PTERODACTYL", width: 46, height: 40, yPos: [100, 75, 50], yPosMobile: [100, 50], multipleSpeed: 999, minSpeed: 8.5, minGap: 150, collisionBoxes: [new I(15, 15, 16, 5), new I(18, 21, 24, 6), new I(2, 14, 4, 3), new I(6, 10, 4, 7), new I(10, 8, 6, 9)], numFrames: 2, frameRate: 1e3 / 6, speedOffset: .8 }], u.config = { DROP_VELOCITY: -5, GRAVITY: .6, HEIGHT: 47, HEIGHT_DUCK: 25, INIITAL_JUMP_VELOCITY: -10, INTRO_DURATION: 1500, MAX_JUMP_HEIGHT: 30, MIN_JUMP_HEIGHT: 30, SPEED_DROP_COEFFICIENT: 3, SPRITE_WIDTH: 262, START_X_POS: 50, WIDTH: 44, WIDTH_DUCK: 59 }, u.collisionBoxes = { DUCKING: [new I(1, 18, 55, 25)], RUNNING: [new I(22, 0, 17, 16), new I(1, 18, 30, 9), new I(10, 35, 14, 8), new I(1, 24, 29, 5), new I(5, 30, 21, 4), new I(9, 34, 15, 4)] }, u.status = { CRASHED: "CRASHED", DUCKING: "DUCKING", JUMPING: "JUMPING", RUNNING: "RUNNING", WAITING: "WAITING" }, u.BLINK_TIMING = 7e3, u.animFrames = { WAITING: {frames: [44, 0], msPerFrame: 1e3 / 3}, RUNNING: {frames: [88, 132], msPerFrame: 1e3 / 12}, CRASHED: {frames: [220], msPerFrame: 1e3 / 60}, JUMPING: {frames: [0], msPerFrame: 1e3 / 60}, DUCKING: {frames: [262, 321], msPerFrame: 125} }, u.prototype = { init: function () { this.blinkDelay = this.setBlinkDelay(), this.groundYPos = t.defaultDimensions.HEIGHT - this.config.HEIGHT - t.config.BOTTOM_PAD, this.yPos = this.groundYPos, this.minJumpHeight = this.groundYPos - this.config.MIN_JUMP_HEIGHT, this.draw(0, 0), this.update(0, u.status.WAITING) }, setJumpVelocity: function (A) { this.config.INIITAL_JUMP_VELOCITY = -A, this.config.DROP_VELOCITY = -A / 2 }, update: function (A, i) { this.timer += A, i && (this.status = i, this.currentFrame = 0, this.msPerFrame = u.animFrames[i].msPerFrame, this.currentAnimFrames = u.animFrames[i].frames, i == u.status.WAITING && (this.animStartTime = h(), this.setBlinkDelay())), this.playingIntro && this.xPos < this.config.START_X_POS && (this.xPos += Math.round(this.config.START_X_POS / this.config.INTRO_DURATION * A)), this.status == u.status.WAITING ? this.blink(h()) : this.draw(this.currentAnimFrames[this.currentFrame], 0), this.timer >= this.msPerFrame && (this.currentFrame = this.currentFrame == this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1, this.timer = 0), this.speedDrop && this.yPos == this.groundYPos && (this.speedDrop = !1, this.setDuck(!0)) }, draw: function (A, i) { var s = A, e = i, n = this.ducking && this.status != u.status.CRASHED ? this.config.WIDTH_DUCK : this.config.WIDTH, o = this.config.HEIGHT; Q && (s *= 2, e *= 2, n *= 2, o *= 2), s += this.spritePos.x, e += this.spritePos.y, this.ducking && this.status != u.status.CRASHED ? this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, this.xPos, this.yPos, this.config.WIDTH_DUCK, this.config.HEIGHT) : (this.ducking && this.status == u.status.CRASHED && this.xPos++, this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, this.xPos, this.yPos, this.config.WIDTH, this.config.HEIGHT)) }, setBlinkDelay: function () { this.blinkDelay = Math.ceil(Math.random() * u.BLINK_TIMING) }, blink: function (A) { var i = A - this.animStartTime; i >= this.blinkDelay && (this.draw(this.currentAnimFrames[this.currentFrame], 0), 1 == this.currentFrame && (this.setBlinkDelay(), this.animStartTime = A)) }, startJump: function (A) { this.jumping || (this.update(0, u.status.JUMPING), this.jumpVelocity = this.config.INIITAL_JUMP_VELOCITY - A / 10, this.jumping = !0, this.reachedMinHeight = !1, this.speedDrop = !1) }, endJump: function () { this.reachedMinHeight && this.jumpVelocity < this.config.DROP_VELOCITY && (this.jumpVelocity = this.config.DROP_VELOCITY) }, updateJump: function (A, i) { var t = u.animFrames[this.status].msPerFrame, s = A / t; this.speedDrop ? this.yPos += Math.round(this.jumpVelocity * this.config.SPEED_DROP_COEFFICIENT * s) : this.yPos += Math.round(this.jumpVelocity * s), this.jumpVelocity += this.config.GRAVITY * s, (this.yPos < this.minJumpHeight || this.speedDrop) && (this.reachedMinHeight = !0), (this.yPos < this.config.MAX_JUMP_HEIGHT || this.speedDrop) && this.endJump(), this.yPos > this.groundYPos && (this.reset(), this.jumpCount++), this.update(A) }, setSpeedDrop: function () { this.speedDrop = !0, this.jumpVelocity = 1 }, setDuck: function (A) { A && this.status != u.status.DUCKING ? (this.update(0, u.status.DUCKING), this.ducking = !0) : this.status == u.status.DUCKING && (this.update(0, u.status.RUNNING), this.ducking = !1) }, reset: function () { this.yPos = this.groundYPos, this.jumpVelocity = 0, this.jumping = !1, this.ducking = !1, this.update(0, u.status.RUNNING), this.midair = !1, this.speedDrop = !1, this.jumpCount = 0 } }, l.dimensions = { WIDTH: 10, HEIGHT: 13, DEST_WIDTH: 11 }, l.yPos = [0, 13, 27, 40, 53, 67, 80, 93, 107, 120], l.config = { MAX_DISTANCE_UNITS: 5, ACHIEVEMENT_DISTANCE: 100, COEFFICIENT: .025, FLASH_DURATION: 250, FLASH_ITERATIONS: 3 }, l.prototype = { init: function (A) { var i = ""; this.calcXPos(A), this.maxScore = this.maxScoreUnits; for (var t = 0; t < this.maxScoreUnits; t++) this.draw(t, 0), this.defaultString += "0", i += "9"; this.maxScore = parseInt(i) }, calcXPos: function (A) { this.x = A - l.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1) }, draw: function (A, i, t) { var s = l.dimensions.WIDTH, e = l.dimensions.HEIGHT, n = l.dimensions.WIDTH * i, o = 0, h = A * l.dimensions.DEST_WIDTH, a = this.y, r = l.dimensions.WIDTH, c = l.dimensions.HEIGHT; if (Q && (s *= 2, e *= 2, n *= 2), n += this.spritePos.x, o += this.spritePos.y, this.canvasCtx.save(), t) { var g = this.x - 2 * this.maxScoreUnits * l.dimensions.WIDTH; this.canvasCtx.translate(g, this.y) } else this.canvasCtx.translate(this.x, this.y); this.canvasCtx.drawImage(this.image, n, o, s, e, h, a, r, c), this.canvasCtx.restore() }, getActualDistance: function (A) { return A ? Math.round(A * this.config.COEFFICIENT) : 0 }, update: function (A, i) { var t = !0, s = !1; if (this.acheivement) this.flashIterations <= this.config.FLASH_ITERATIONS ? (this.flashTimer += A, this.flashTimer < this.config.FLASH_DURATION ? t = !1 : this.flashTimer > 2 * this.config.FLASH_DURATION && (this.flashTimer = 0, this.flashIterations++)) : (this.acheivement = !1, this.flashIterations = 0, this.flashTimer = 0); else if (i = this.getActualDistance(i), i > this.maxScore && this.maxScoreUnits == this.config.MAX_DISTANCE_UNITS ? (this.maxScoreUnits++, this.maxScore = parseInt(this.maxScore + "9")) : this.distance = 0, i > 0) { i % this.config.ACHIEVEMENT_DISTANCE == 0 && (this.acheivement = !0, this.flashTimer = 0, s = !0); var e = (this.defaultString + i).substr(-this.maxScoreUnits); this.digits = e.split("") } else this.digits = this.defaultString.split(""); if (t) for (var n = this.digits.length - 1; n >= 0; n--) this.draw(n, parseInt(this.digits[n])); return this.drawHighScore(), s }, drawHighScore: function () { this.canvasCtx.save(), this.canvasCtx.globalAlpha = .8; for (var A = this.highScore.length - 1; A >= 0; A--) this.draw(A, parseInt(this.highScore[A], 10), !0); this.canvasCtx.restore() }, setHighScore: function (A) { A = this.getActualDistance(A); var i = (this.defaultString + A).substr(-this.maxScoreUnits); this.highScore = ["10", "11", ""].concat(i.split("")) }, reset: function () { this.update(0), this.acheivement = !1 } }, C.config = { HEIGHT: 14, MAX_CLOUD_GAP: 400, MAX_SKY_LEVEL: 30, MIN_CLOUD_GAP: 100, MIN_SKY_LEVEL: 71, WIDTH: 46 }, C.prototype = { init: function () { this.yPos = s(C.config.MAX_SKY_LEVEL, C.config.MIN_SKY_LEVEL), this.draw() }, draw: function () { this.canvasCtx.save(); var A = C.config.WIDTH, i = C.config.HEIGHT; Q && (A = 2 * A, i = 2 * i), this.canvasCtx.drawImage(t.imageSprite, this.spritePos.x, this.spritePos.y, A, i, this.xPos, this.yPos, C.config.WIDTH, C.config.HEIGHT), this.canvasCtx.restore() }, update: function (A) { this.remove || (this.xPos -= Math.ceil(A), this.draw(), this.isVisible() || (this.remove = !0)) }, isVisible: function () { return this.xPos + C.config.WIDTH > 0 } }, p.config = { FADE_SPEED: .035, HEIGHT: 40, MOON_SPEED: .25, NUM_STARS: 2, STAR_SIZE: 9, STAR_SPEED: .3, STAR_MAX_Y: 70, WIDTH: 20 }, p.phases = [140, 120, 100, 60, 40, 20, 0], p.prototype = { update: function (A, i) { if (A && 0 == this.opacity && (this.currentPhase++, this.currentPhase >= p.phases.length && (this.currentPhase = 0)), A && (this.opacity < 1 || 0 == this.opacity) ? this.opacity += p.config.FADE_SPEED : this.opacity > 0 && (this.opacity -= p.config.FADE_SPEED), this.opacity > 0) { if (this.xPos = this.updateXPos(this.xPos, p.config.MOON_SPEED), this.drawStars) for (var t = 0; t < p.config.NUM_STARS; t++) this.stars[t].x = this.updateXPos(this.stars[t].x, p.config.STAR_SPEED); this.draw() } else this.opacity = 0, this.placeStars(); this.drawStars = !0 }, updateXPos: function (A, i) { return A < -p.config.WIDTH ? A = this.containerWidth : A -= i, A }, draw: function () { var A = 3 == this.currentPhase ? 2 * p.config.WIDTH : p.config.WIDTH, i = p.config.HEIGHT, s = this.spritePos.x + p.phases[this.currentPhase], e = A, n = p.config.STAR_SIZE, o = t.spriteDefinition.LDPI.STAR.x; if (Q && (A *= 2, i *= 2, s = this.spritePos.x + 2 * p.phases[this.currentPhase], n *= 2, o = t.spriteDefinition.HDPI.STAR.x), this.canvasCtx.save(), this.canvasCtx.globalAlpha = this.opacity, this.drawStars) for (var h = 0; h < p.config.NUM_STARS; h++) this.canvasCtx.drawImage(t.imageSprite, o, this.stars[h].sourceY, n, n, Math.round(this.stars[h].x), this.stars[h].y, p.config.STAR_SIZE, p.config.STAR_SIZE); this.canvasCtx.drawImage(t.imageSprite, s, this.spritePos.y, A, i, Math.round(this.xPos), this.yPos, e, p.config.HEIGHT), this.canvasCtx.globalAlpha = 1, this.canvasCtx.restore() }, placeStars: function () { for (var A = Math.round(this.containerWidth / p.config.NUM_STARS), i = 0; i < p.config.NUM_STARS; i++) this.stars[i] = {}, this.stars[i].x = s(A * i, A * (i + 1)), this.stars[i].y = s(0, p.config.STAR_MAX_Y), Q ? this.stars[i].sourceY = t.spriteDefinition.HDPI.STAR.y + 2 * p.config.STAR_SIZE * i : this.stars[i].sourceY = t.spriteDefinition.LDPI.STAR.y + p.config.STAR_SIZE * i }, reset: function () { this.currentPhase = 0, this.opacity = 0, this.update(!1) } }, m.dimensions = {WIDTH: 600, HEIGHT: 12, YPOS: 127}, m.prototype = { setSourceDimensions: function () { for (var A in m.dimensions) Q ? "YPOS" != A && (this.sourceDimensions[A] = 2 * m.dimensions[A]) : this.sourceDimensions[A] = m.dimensions[A], this.dimensions[A] = m.dimensions[A]; this.xPos = [0, m.dimensions.WIDTH], this.yPos = m.dimensions.YPOS }, getRandomType: function () { return Math.random() > this.bumpThreshold ? this.dimensions.WIDTH : 0 }, draw: function () { this.canvasCtx.drawImage(t.imageSprite, this.sourceXPos[0], this.spritePos.y, this.sourceDimensions.WIDTH, this.sourceDimensions.HEIGHT, this.xPos[0], this.yPos, this.dimensions.WIDTH, this.dimensions.HEIGHT), this.canvasCtx.drawImage(t.imageSprite, this.sourceXPos[1], this.spritePos.y, this.sourceDimensions.WIDTH, this.sourceDimensions.HEIGHT, this.xPos[1], this.yPos, this.dimensions.WIDTH, this.dimensions.HEIGHT) }, updateXPos: function (A, i) { var t = A, s = 0 == A ? 1 : 0; this.xPos[t] -= i, this.xPos[s] = this.xPos[t] + this.dimensions.WIDTH, this.xPos[t] <= -this.dimensions.WIDTH && (this.xPos[t] += 2 * this.dimensions.WIDTH, this.xPos[s] = this.xPos[t] - this.dimensions.WIDTH, this.sourceXPos[t] = this.getRandomType() + this.spritePos.x) }, update: function (A, i) { var t = Math.floor(.06 * i * A); this.xPos[0] <= 0 ? this.updateXPos(0, t) : this.updateXPos(1, t), this.draw() }, reset: function () { this.xPos[0] = 0, this.xPos[1] = m.dimensions.WIDTH } }, f.config = { BG_CLOUD_SPEED: .2, BUMPY_THRESHOLD: .3, CLOUD_FREQUENCY: .5, HORIZON_HEIGHT: 16, MAX_CLOUDS: 6 }, f.prototype = { init: function () { this.addCloud(), this.horizonLine = new m(this.canvas, this.spritePos.HORIZON), this.nightMode = new p(this.canvas, this.spritePos.MOON, this.dimensions.WIDTH) }, update: function (A, i, t, s) { this.runningTime += A, this.horizonLine.update(A, i), this.nightMode.update(s), this.updateClouds(A, i), t && this.updateObstacles(A, i) }, updateClouds: function (A, i) { var t = this.cloudSpeed / 1e3 * A * i, s = this.clouds.length; if (s) { for (var e = s - 1; e >= 0; e--) this.clouds[e].update(t); var n = this.clouds[s - 1]; s < this.config.MAX_CLOUDS && this.dimensions.WIDTH - n.xPos > n.cloudGap && this.cloudFrequency > Math.random() && this.addCloud(), this.clouds = this.clouds.filter(function (A) { return !A.remove }) } else this.addCloud() }, updateObstacles: function (A, i) { for (var t = this.obstacles.slice(0), s = 0; s < this.obstacles.length; s++) { var e = this.obstacles[s]; e.update(A, i), e.remove && t.shift() } if (this.obstacles = t, this.obstacles.length > 0) { var n = this.obstacles[this.obstacles.length - 1]; n && !n.followingObstacleCreated && n.isVisible() && n.xPos + n.width + n.gap < this.dimensions.WIDTH && (this.addNewObstacle(i), n.followingObstacleCreated = !0) } else this.addNewObstacle(i) }, removeFirstObstacle: function () { this.obstacles.shift() }, addNewObstacle: function (A) { var i = s(0, E.types.length - 1), e = E.types[i]; if (this.duplicateObstacleCheck(e.type) || A < e.minSpeed) this.addNewObstacle(A); else { var n = this.spritePos[e.type]; this.obstacles.push(new E(this.canvasCtx, e, n, this.dimensions, this.gapCoefficient, A, e.width)), this.obstacleHistory.unshift(e.type), this.obstacleHistory.length > 1 && this.obstacleHistory.splice(t.config.MAX_OBSTACLE_DUPLICATION) } }, duplicateObstacleCheck: function (A) { for (var i = 0, s = 0; s < this.obstacleHistory.length; s++) i = this.obstacleHistory[s] == A ? i + 1 : 0; return i >= t.config.MAX_OBSTACLE_DUPLICATION }, reset: function () { this.obstacles = [], this.horizonLine.reset(), this.nightMode.reset() }, resize: function (A, i) { this.canvas.width = A, this.canvas.height = i }, addCloud: function () { this.clouds.push(new C(this.canvas, this.spritePos.CLOUD, this.dimensions.WIDTH)) } } }]) });一般网页使用方法很简单，如果在一般的网页中使用直接添加 其中runner.js可以为任意地址，你可以把runner放在本地，也可以把runner放在OSS（阿里云对象储存）等储存。Typecho博客我们还可以将这段代码嵌入到博客里去，当然因为在这里图个方便，我直接使用iframe方法来引入，比较方便，我在这贴下我的方法 很简单啊，就一句话就可以了，当然你也可以选择常规的方式去嵌入。我的方法是引入我OSS（阿里云对象储存）存放的html文件，所以要保证你的OSS（阿里云对象储存）和你的网站活的一样久。index.html的网页源码如下 Runner 你可以自己存放在本地服务器去引用，js同理注意在typecho中的markdown语法!!!你的代码!!!这样是嵌入代码，记得是英文感叹号。不要直接复制我的代码使用，因为设置了Referer白名单防止盗链，直接使用是无效的。本方法支持手机，电脑，等设备玩耍。本文转自：XSY的FUN天地