奇奇怪怪的知识之Chrome小恐龙

日常摸鱼,无聊中打开了小恐龙。虽然手速跟的上,奈何实在是晃眼的不行。
身为程序猿,肯定是要学会偷懒的,搞个脚本吧。
程序猿的脚本那能叫脚本么,学术交流嘛。
先上小恐龙地址:
chrome://dino/

君子性非异也,擅假于物也。

找到了一个脚本,大概原理就是通过判断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);

你的小恐龙就自个去浪了,不过这里你获取分数的速度依然和正常游玩的玩家是一样的,小恐龙走一步记一分。

那么,接下来我们换个套路。

改写计分逻辑
与其说改写,不如说“劫持”。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,
});

将上面代码执行之后,再次运行程序,你会发现你获取分数的速度提升了一千倍。

如果你将第一个方案和这个方案的代码结合,会获得一个能够自动奔跑获得高分的“智能小恐龙”。

不过因为我们的“外挂”是基于计时器进行距离计算并模拟用户操作的,当你获得很高很高的分数之后,
障碍物推进速度过快,一旦你进行窗口的来回切换,游戏进行暂停和游玩的状态切换,
很大概率上“外挂”操作会延时,导致 GAME OVER。

如何能避免这个事情呢,我们来讲讲第三个套路。

破坏规则大法
如果说第一个方案起码还有付出时间成本,模拟玩家操作一步一步按部就班的获取分数;
第二个方案偷天换日,一步当一千步使;那么接下来的方案就显得十分无耻了。

Runner.instance_.gameOver=function(){};

下面代码在执行之后,会清空游戏的中断逻辑,配合第二个方案的快速获得分数的代码,
你可以得到一只拥有穿越障碍物能力的小恐龙:勇往无前,永不停歇,分数不停的增长,直到报错。

脚本原地址

原文地址:https://www.cnblogs.com/Lm-Ui-Gne/p/13730410.html