今天早上刷微博的时候看到 @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){}
去掉就行了。
这一关是做者的谢幕,至此所有通关。