奇奇怪怪的知识之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(){};
下面代码在执行之后,会清空游戏的中断逻辑,配合第二个方案的快速获得分数的代码,
你可以得到一只拥有穿越障碍物能力的小恐龙:勇往无前,永不停歇,分数不停的增长,直到报错。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通