• 奇奇怪怪的知识之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(){};
    

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

    脚本原地址

  • 相关阅读:
    各种素材类精品网站
    Java如何设置代理ip
    Spring事务的实现方式和原理以及隔离级别?
    Spring 是什么?
    线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?
    为什么用线程池?解释下线程池参数
    并发三大特性
    ThreadLocal的原理和使用场景。
    谈谈对线程安全的理解
    sleep,wait,join,yield
  • 原文地址:https://www.cnblogs.com/Lm-Ui-Gne/p/13730410.html
Copyright © 2020-2023  润新知