使用前端方式挑戰 Chrome 小恐龍遊戲高分
本站使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或重新修改使用,但需要註明來源。 ofollow,noindex">署名 4.0 國際 (CC BY 4.0)
本文作者: 蘇洋
建立時間: 2018年09月13日 統計字數: 4298字 閱讀時間: 9分鐘閱讀 本文連結: soulteary.com/2018/09/13/…
使用前端方式挑戰 Chrome 小恐龍遊戲高分
今天看論壇發現有人發帖說 Chrome週年慶祝
在“小恐龍”遊戲中埋入了新的選單,可以觸碰的 蛋糕 以及觸碰之後獲得的 生日帽 。
看到現在“小恐龍”這個彩蛋的改進,往事歷歷在目。但是很快,帖子中有人晒高分引起了我的注意:這個遊戲雖說簡單,但是在分數達到一定程度後,加速度會讓玩家 很難 繼續遊戲。
記得很早之前在機場玩過這個遊戲,記憶中獲取 三千以上的分數 還是挺困難的,更別提 八千分 ,所以我這裡推測這個玩家應該是有一些“特別的技巧”。
在遊戲中取得令人歎為觀止的高分,一般來說無非三種手段:
- 練習:勤學苦練,熟能生巧,加上極致的耐心。
- 工具:使用一些輔助設施來模擬人的操作。
- 外掛:針對難度或者得分倍數進行改造或者直接對結果進行修改、甚至破壞遊戲規則。
第一種方式我們暫且略過,後面如果實在閒,再進行嘗試,我們直接開始後面兩種方案的嘗試。
編寫輔助工具

君子性非異也,擅假於物也。
網上有個老外曾經編寫過一個根據判斷X軸方向小恐龍和前面物品距離進行自動跳躍的程式,在稍加改造後,將下面的程式碼貼到控制檯中,即可完成小恐龍自動奔跑的神操作。
這裡添加了程式碼避免小恐龍跳過蛋糕、避而不吃,以及調整了對障礙物需要跳躍的高度判斷,防止小恐龍看到低飛的鳥兒迎面而上,當然,還有能夠在程式碼執行後,自動開始遊戲。
function TrexRunnerBot() { const makeKeyArgs = (keyCode) => { const preventDefault = () => void 0; return {keyCode, preventDefault}; }; const upKeyArgs = makeKeyArgs(38); const downKeyArgs = makeKeyArgs(40); const startArgs = makeKeyArgs(32); if (!Runner().playing) { Runner().onKeyDown(startArgs); setTimeout(() => { Runner().onKeyUp(startArgs); }, 500); } function conquerTheGame() { if (!Runner || !Runner().horizon.obstacles[0]) return; const obstacle = Runner().horizon.obstacles[0]; if (obstacle.typeConfig && obstacle.typeConfig.type === 'SNACK') return; if (needsToTackle(obstacle) && closeEnoughToTackle(obstacle)) tackle(obstacle); } function needsToTackle(obstacle) { return obstacle.yPos !== 50; } function closeEnoughToTackle(obstacle) { return obstacle.xPos <= Runner().currentSpeed * 18; } function tackle(obstacle) { if (isDuckable(obstacle)) { duck(); } else { jumpOver(obstacle); } } function isDuckable(obstacle) { return obstacle.yPos === 50; } function duck() { Runner().onKeyDown(downKeyArgs); setTimeout(() => { Runner().onKeyUp(downKeyArgs); }, 500); } function jumpOver(obstacle) { if (isNextObstacleCloseTo(obstacle)) jumpFast(); else Runner().onKeyDown(upKeyArgs); } function isNextObstacleCloseTo(currentObstacle) { const nextObstacle = Runner().horizon.obstacles[1]; return nextObstacle && nextObstacle.xPos - currentObstacle.xPos <= Runner().currentSpeed * 42; } function jumpFast() { Runner().onKeyDown(upKeyArgs); Runner().onKeyUp(upKeyArgs); } return {conquerTheGame: conquerTheGame}; } let bot = TrexRunnerBot(); let botInterval = setInterval(bot.conquerTheGame, 2); 複製程式碼
當然,為了你能夠在移動端的複製便捷,我這裡提供了壓縮版的程式碼。
function TrexRunnerBot(){function f(){Runner().onKeyDown(d);setTimeout(function(){Runner().onKeyUp(d)},500)}var b=function(a){return{keyCode:a,preventDefault:function(){}}},c=b(38),d=b(40),e=b(32);Runner().playing||(Runner().onKeyDown(e),setTimeout(function(){Runner().onKeyUp(e)},500));return{conquerTheGame:function(){if(Runner&&Runner().horizon.obstacles[0]){var a=Runner().horizon.obstacles[0];if((!a.typeConfig||"SNACK"!==a.typeConfig.type)&&50!==a.yPos&&a.xPos<=18*Runner().currentSpeed)if(50=== a.yPos)f();else{var b=Runner().horizon.obstacles[1];if(b&&b.xPos-a.xPos<=42*Runner().currentSpeed)Runner().onKeyDown(c),Runner().onKeyUp(c);else Runner().onKeyDown(c)}}}}}var bot=TrexRunnerBot(),botInterval=setInterval(bot.conquerTheGame,2); 複製程式碼
如果你想在桌面端瀏覽器遊玩小恐龍遊戲,除了斷網的操作外,還可以直接訪問 chrome://dino/
這個地址。
如果你想在手機上體驗小恐龍自動奔跑,請參考下面的操作:
javascript:
你的小恐龍就自個去浪了,不過這裡你獲取分數的速度依然和正常遊玩的玩家是一樣的,小恐龍走一步記一分。
那麼,接下來我們換個套路。
改寫計分邏輯
與其說改寫,不如說“劫持”。ES5 有一個很古老的 API, Object.defineProperty()
,藉助這個 API ,我們能夠輕易的修改現有物件上的屬性,配合重新定義物件具體內容的 getter
、 setter
描述符,可以做到對於屬性的劫持操作,是不是很眼熟?沒錯,這個方案也是老生常談的 MVVM 框架的雙向資料繫結的實現方案之一。
let hackScore = 0; Object.defineProperty(Runner.instance_, 'distanceRan', { get: () => hackScore, set: (value) => hackScore = value + Math.floor(Math.random() * 1000), configurable: true, enumerable: true, }); 複製程式碼
同樣提供了壓縮版本。
var hackScore=0;Object.defineProperty(Runner.instance_,"distanceRan",{get:function(){return hackScore},set:function(a){return hackScore=a+Math.floor(1E3*Math.random())},configurable:!0,enumerable:!0}); 複製程式碼
將上面程式碼執行之後,再次執行程式,你會發現你獲取分數的速度提升了一千倍。
如果你將第一個方案和這個方案的程式碼結合,會獲得一個能夠自動奔跑獲得高分的“智慧小恐龍”。
不過因為我們的“外掛”是基於計時器進行距離計算並模擬使用者操作的,當你獲得很高很高的分數之後,障礙物推進速度過快,一旦你進行視窗的來回切換,遊戲進行暫停和遊玩的狀態切換,很大概率上“外掛”操作會延時,導致 GAME OVER
。
如何能避免這個事情呢,我們來講講第三個套路。
破壞規則大法
如果說第一個方案起碼還有付出時間成本,模擬玩家操作一步一步按部就班的獲取分數;第二個方案偷天換日,一步當一千步使;那麼接下來的方案就顯得十分無恥了。
Runner.instance_.gameOver=function(){}; 複製程式碼
下面程式碼在執行之後,會清空遊戲的中斷邏輯,配合第二個方案的快速獲得分數的程式碼,你可以得到一隻擁有穿越障礙物能力的小恐龍:勇往無前,永不停歇,分數不停的增長,直到報錯。