今天早上刷微博的時候看到 @fakefish 分享了一個遊戲微博,遊戲的名字叫作《Untrusted》,經過修改JS代碼來通關的遊戲,做者把遊戲代碼託管在了Github上,遊戲地址在 http://alexnisnevich.github.i... 。git
這關簡單,移動玩家對象@先拾取⌘後發現你能夠操做關卡代碼了,把生成#號柵欄的代碼刪除掉,而後移動到出口就行了。github
這關看着挺嚇人的,路都被#號給各類攔着了,可是其實讀一下代碼發現也就那麼回事。13行的new ROT.Map.DividedMaze(map.getWidth(), map.getHeight())
負責根據地圖大小生成迷宮,30行到33行在出口的四個方向生成了#號阻攔咱們。看着其實挺恐怖的,可是其實咱們只要開闢一個新思路不移動@對象到出口而是把出口移動到對象邊上就行了。算法
固然沒辦法移動現有的這個出口了,我就嘗試着再新建了一個出口在@的旁邊。map.placeObject(7,6,'exit');
,一次性成功!canvas
這一關#柵欄把@和出口給隔開來了,首先想到的是把生成#柵欄的代碼刪除掉。可是很不幸的是過關驗證函數validateLeve()
上清楚的寫着必定要有必定數量的柵欄才行。因此咱們轉變思路,用柵欄把@和出口都包括進去就行了。爲了方便我就直接生成在了邊緣了。segmentfault
for (y = 0; y <= map.getHeight(); y++) { map.placeObject(0, y, 'block'); map.placeObject(map.getWidth(), y, 'block'); } for (x = 0; x <= map.getWidth(); x++) { map.placeObject(x, 0, 'block'); map.placeObject(x, map.getHeight()-1, 'block'); }
這一關和上一關的感受是同樣的,應該能夠抄襲上一關的代碼。不過你仔細讀代碼的話會發現比上一關少了過關驗證函數。因此我這裏就取巧用了第二關的方法,用 map.placeObject(map.getWidth() - 5, map.getHeight() - 5, 'exit');
在@對象旁邊新建了一個出口。數組
初看血紅的圖像可能還以爲興奮,以爲直接移動過去就行了。不過仔細一看代碼你就會發現不是那麼回事。代碼隨機在地圖上生成了75個看不見的mine
對象,不能觸碰到它,不然就Game Over。dom
要越過無形的東西只要讓它現行知道它的方位避開它就行了,因此咱們能夠用map.setSquareColor(x, y, '#000')
給他們都附上一個顏色。ide
這一關就比較高級了,有一個攻擊者來守護出口,而且會跟隨你的步伐靠近你並殺掉你。個人第一想法比較簡單,就是創建一個橫向屏障讓其沒法靠近我,不過爲了能讓本身到達出口位置,我設置了一個空的出口。函數
for(var x = 0; x < map.getWidth()-3; x++) { map.placeObject(x, 11, 'block') }
這一關有一個電話符號,吃了它就能夠在移動過程當中執行回調函數。在過關路上有不一樣顏色的障礙物,若是@對象顏色和障礙物的顏色不同就不容許經過。結合以上兩個消息,獲得的解決辦法是經過一次障礙物前用電話回調函數進行一次「變裝」就行了,爲了方便我直接指定了在障礙物的前一個位置進行「換裝「。spa
if(player.atLocation(24, 12) || player.atLocation(33,12)) player.setColor('#f00'); if(player.atLocation(27,12) || player.atLocation(36,12)) player.setColor('#ff0'); if(player.atLocation(30,12)) player.setColor('#0f0');
到這裏就成功進入第二章了!這一關出現了一片一片的綠森林,不幸的是路被他們給擋住了。可供咱們修改的代碼也很是有限,僅僅只能修改101行的幾個字符。能夠看到functionList
是一個函數組成的數組,看代碼的意思應該是讓咱們給電話回調函數指定一個functionList
裏面設置好的函數。
理解一下後咱們就能想到利用電話回調函數執行從新生成森林的代碼generateForest
,這樣每次@對象旁邊的道路就會「開闢」出來。
哈哈這關作的很漂亮,乘船過河的說。這裏咱們發現能夠自定義對象,raft
對象的transport
參數提醒了咱們能夠經過設置這個參數讓@對象穿過本身。因此我另闢蹊徑,本身建立了一個能夠經過的通道。
map.defineObject('bridge', { 'type': 'dynamic', 'symbol': 'H', 'color': '#420', 'transport': true, 'behavior': function () {} }); for (var y = 5; y < 15; y++) { map.placeObject(1, y, 'bridge'); }
這一關有各類攻擊者擋住你的去路。由於能夠自定義各個攻擊者的行爲函數,因此我這裏的想法是讓攻擊者自動讓出一個通道出來。
map.defineObject('attackDrone', { 'type': 'dynamic', 'symbol': 'd', 'color': 'red', 'onCollision': function (player) { player.killedBy('an attack drone'); }, 'behavior': function (me) { if(me.getY() == 12) me.move('left') if(me.getY() == 11) me.move('down') } }); map.defineObject('reinforcementDrone', { 'type': 'dynamic', 'symbol': 'd', 'color': 'yellow', 'onCollision': function (player) { player.killedBy('a reinforcement drone'); }, 'behavior': function (me) { me.move('down'); } }); map.defineObject('defenseDrone', { 'type': 'dynamic', 'symbol': 'd', 'color': 'green', 'onCollision': function (player) { player.killedBy('a defense drone'); }, 'behavior': function (me) { if(me.getX() == map.getWidth() - 10) return false; if(me.getY() == 12) me.move('right') if(me.getY() == 11) me.move('down') } });
一樣是控制對象的運動行爲,須要良好的控制R機器人拿到K鑰匙並交給@後才能順利通關。這裏比較簡單,只要讓R在能右的時候往右走不能右走的時候往下走就行了,而後@在門口靜候機器人送鑰匙過來就好啦。
me.canMove('right')?me.move('right'):me.move('down')
哈哈,和上關以同樣,不太高級了一點增長了兩個阻礙物。解法是同樣的,看我的的控制狀況了,個人想法比較簡單,就是左邊的話是能下就下不能下就右,右邊就是能上就上,不能上就右。
if(me.getX() < map.getWidth() / 2 || me.getX() == map.getWidth() - 2) me.canMove('down') ? me.move('down') : me.move('right') else me.canMove('up') ? me.move('up') : me.move('right')
這一關在上一關的基礎上又更上一層樓,出了個迷宮。開始我絞盡腦汁想怎麼讓機器人自動出來的算法,不過想來我是實在沒有那個本事了。後來突發奇想,既然以前的關卡中有攻擊者對象根據@對象的操做作出反應,那麼我也能夠經過@對象來控制機器人咯?因此我比較簡單的設置了一個上下左右四個位置,只要@在這個位置上就作出對應的操做。不過做者的Github項目裏面收錄了各類機器人自動和人工控制的算法,比我這個好用多了,你們能夠去欣賞一下:官方第13關的解決辦法收錄。
這關本身的代碼太dirty了就不放上來了
這一關很簡單,就是用同顏色的鑰匙開同顏色的鎖,而後最終拿到A並過關的意思。能夠操做的地方很少,一看就是讓咱們設置當開綠鎖的時候咱們應該把哪把鑰匙獻上。要麼是redKey
要麼是blueKey
,greenKey
本身確定是不可能了。經過實驗你會發現答案是blueKey
。
具體的緣由應該是修改這個值以後若是你開綠鎖的時候有這個東西就會丟,若是沒有就直接溢出錯誤了,跳過了丟的動做。因此 @nightire 棋高一着的填寫了theAlgorithm
也是能夠的,這樣一把綠鑰匙都不用丟了。而紅鑰匙之因此不適合的緣由是由於整個運動過程當中會比藍鑰匙多扔一個藍鑰匙,而下面獲取Algorithm的過程當中須要一個藍鑰匙去解鎖藍鎖,而後就麼有而後了。
這一關我也想了好久,一樣是過河,可是比以前那關少了一條船,最重要的是能夠修改代碼的地方很少。我想了一下以爲既然在行爲中player被killed了那我就能夠再新建一個player了,而後我填寫了map.placePlayer(map.getWidth()-2,map.getHeight())
這個代碼後成功了,可是並非我想的同樣。實際上這裏是利用"產生異常會中斷函數執行"的特性來打斷死亡函數的執行。因此能夠在括號內一個未定義的函數來打斷,例如gogogo();
,我填寫的placePlayer()
在已經有一個player的狀況也會拋出異常因此也能夠過關。(原理這塊感謝 @DanoR 的補充)
這關是隨機新建了25個無形的牆壁(你還不能刪除這些牆壁,由於validateLeve()
函數有驗證),每一個牆壁有一個顏色若是@對象的顏色和牆壁顏色不一樣的話就會被撞,相同就會經過。
因爲做者很是好心的給出了一部分代碼讓咱們經過canvas
將無形的牆壁變的有形,大大的下降了問題的難度。因此咱們只要讓無形的顏色變成有形的顏色,在經過牆壁以前「換裝」成相應的顏色就行了。換裝一樣是用電話回調函數,不過由於不知道怎麼獲取最近的牆壁的顏色,我選擇的是在牆壁的顏色(總共3個)隨機,最多隻要點兩下就會粗來正確的顏色了。
function createLaser(centerX, centerY, angleInDegrees, length, color) { var angleInRadians = angleInDegrees * Math.PI / 180; var x1 = centerX - Math.cos(angleInRadians) * length / 2; var y1 = centerY + Math.sin(angleInRadians) * length / 2; var x2 = centerX + Math.cos(angleInRadians) * length / 2; var y2 = centerY - Math.sin(angleInRadians) * length / 2; // map.createLine() creates a line with an effect when // the player moves over it, but doesn't display it map.createLine([x1, y1], [x2, y2], function (player) { if (player.getColor() != color) { player.killedBy('a ' + color + ' laser'); } }); // using canvas to draw the line var ctx = map.getCanvasContext(); ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = 5; ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); } player.setPhoneCallback(function(){ var colors = ['red', 'yellow', 'teal']; colors.filter(function(color){ return player.getColor() != color; }); player.setColor(colors[parseInt(Math.random()*(colors.length-1))]); })
其它解:
getRandomInt()
複寫致使長條方塊生成位置固定的方法很是的贊。這關大概的意思是每一個紫色的出口都是傳送門,可是你不知道你是傳送到下一個傳送門仍是荊棘中。因此咱們的目標是讓傳送到傳送門的傳送門給咱們顯示出來,這裏我利用上一關剛學會的canvas
作標記操做。
if(t1.getType() == 'teleporter' && t2.getType() == 'teleporter') { var t1p = map.getCanvasCoords(t1); canvas.strokeStyle = 'green'; canvas.moveTo(t1p.x, t1p.y); canvas.lineTo(t1p.x+5,t1p.y+5); canvas.stroke(); }
這一關是讓咱們編寫一個jump()
回調函數讓@跳過"懸崖"抵達出口。不過咱們若是真的被jump
這個詞給迷惑住了的話可能真的會想一下子。我看了一下電話回調函數中執行jump()
函數的條件是當@對象下面不是空,那就是當即能夠執行了(初始狀態下面是#號不是空)。因此我直接在懸崖上架了一座橋讓@「跳」過去。
這一關由於做者的更新,增長了一個頁面中只能有520個#號存在致使了以前建立#的辦法失效了。不過不能新建#號咱還不能建自定義的符號麼,恩哼,一樣是橋,#號是橋,■就不是橋了麼。
function jump() { map.defineObject('bridge', { 'type': 'item', 'symbol': '■', 'color': 'yellow' }); for(x = Math.floor(w/2)-5; x<Math.floor(w/2)+5; x++) { map.placeObject(x, Math.floor(h/2), 'bridge'); } }
不過樓下 @vISvLee 君根據17關「蟲洞理論「經過自定義兩個時空隧道鏈接亮點看起來也很是的炫酷,你們不妨試一試。總之來講你們就是不要被jump
這個詞給侷限住了。
這關沒怎麼理解真諦,大概的意思是讓紅色和綠色的@碰到一塊吧,反正我隨便左右上下左右上下的按了一通就過去了。不過有大牛看出了來龍去脈,我摘抄一下:
19 巨坑爹的一關 我竟然認真的讀了該主頁 而且認爲一個玩TCS 的副教授人搞人機交互 以及 UI 毫無不妥。畢竟高德納不也寫了LATEX嘛。。 而後看到它把Lorem 放上去還以爲頗有藝術性。。 而後以爲這哥們的姓頗有特點 竟然叫Eval 天生搞計算機的命啊。。。 而後我就去搜了一下 沒找到 paper 才意識到被蒙了。 。。。。。。 忒缺德了。 欺負老實人啊。。。。
總之。。 這是個抓蟲子 遊戲 網頁本質上是一個 遞歸組合 也就是 盒子裏面套盒子 按上會走到 外面的盒子 按下 會進入裏面的盒子 按左右會 走到 並列的盒子 操縱綠色符號追擊紅色符號 策略就是 首先走到根盒子 而後看紅色在哪一個盒子 就進入哪一個盒子 儘量地 在它外面的盒子 而後 慢慢接近它 很容易就抓到了。。
這一關是天降毒雨,咱們必須頂着毒雨和上面的BOSS做鬥爭,消滅全部的BOSS以後拿到A以後才能通關。這關我想了好久,而後在我翻API的時候忽然發現有map.overrideKey
這個函數,能夠複寫一個方向鍵的回調函數,解決了我想了半天沒辦法觸發的問題。而後咱們只要作向上發射的子彈去消滅BOSS就行了。這裏由於咱們要往右上下移動,因此我選擇複寫了左方向鍵。
map.defineObject('arrow', { 'type': 'dynamic', 'symbol': '↑', 'color': 'green', 'interval': 100, 'projectile': true, 'behavior': function (me) { me.move('up'); } }); function shoot() { for (x = 0; x < map.getWidth(); x++) { map.placeObject(x,12,'arrow'); } } map.overrideKey('left', shoot); }
這一關是耗費我最久的一關了,什麼阻礙都沒有,而後你也不能夠操做代碼,可是就是無法過關。看代碼的緣由應該是map.finalLevel
這個值變成True了表示最後一關,因此就沒辦法再下一關了。
最後搜索了一下發現原來Menu界面下能夠查看scripts文件夾,由於以前正好有看過遊戲的Github地址,因此知道這應該就是遊戲的源碼了,並且發現有幾個文件是呈黑色的,彷佛能夠修改的說。進Object.js
文件修改exit
對象的行爲判斷函數,把if(!map.finalLevel){}
去掉就行了。
這一關是做者的謝幕,至此所有通關。