> 编程
从 2.49 版本起,除了 LeekScript,你还可以用 JavaScript、TypeScript 或 Python 来编写韭葱的 AI。AI 运行在一个安全且确定性的环境中,可以使用游戏完整的战斗 API,并且能和用其他任何语言编写的 AI 对战。
刚入门?跟着 JavaScript / TypeScript 教程一步步学习,写出你的第一个 AI。
AI 使用哪种语言,由其文件的扩展名决定:
| 语言 | 扩展名 | |---------|-----------| | LeekScript | (无) | | JavaScript | .js 或 .mjs | | TypeScript | .ts 或 .mts | | Python | .py |
语言可以在创建文件时选择(编辑器中的“新建 AI”按钮),也可以在注册时设为第一个 AI 的默认语言。重命名文件时改动扩展名,就会改变它的语言。
每个回合,引擎都会执行你的 AI。有两种写法:
简单 AI:直接编写代码,每回合都会重新执行一遍(在全新的作用域中运行,不保留任何状态):
有状态的 AI:定义一个 turn() 函数。文件主体只会求值一次(在这里声明你的类和需要跨回合保留的变量),之后每回合都会重新调用 turn():
在 TypeScript 或 JavaScript 中,如果文件里含有 import 或 export,它就变成了一个模块:这时按常规方式声明的 turn() 函数只在模块内部可见,引擎找不到它。这种情况下要用 export function turn() 来声明:
游戏 API 以面向对象的形式提供。没有全局变量 me:你的实体要通过 Fight.me 获取。
和 LeekScript 不同,这里既没有全局函数,也没有“扁平”的常量(getNearestEnemy()、WEAPON_PISTOL……):整个 API 都通过下面这些对象来访问。
API 返回的实体都带有具体类型:enemy instanceof Leek、enemy instanceof Bulb……
| 类 | 主要成员 | |--------|--------------------| | Entity | life、maxLife、tp、mp、strength、agility、wisdom、resistance、science、magic、level、name、cell、weapon、weapons、chips、effects、states、summons、alive、dead、isAlly()、isEnemy()、distance(cible) | | Me | Entity 的全部成员,外加各种动作:moveToward(cible)、moveAwayFrom(cible)、useWeapon(cible)、useChip(puce, cible)、setWeapon(arme)、say(message)、summon(puce, case, ia)、canUseWeapon(cible)、weaponCell(cible)、chipCells(puce, cible)、weaponTargets(case)…… | | Cell | x、y、empty、obstacle、entity、distance(cible)、pathLength(cible)、lineOfSight(cible)、path(cible) | | Weapon / Chip | cost、minRange、maxRange、area、launchType、maxUses、needsLos、features(Chip 另有 cooldown 和 currentCooldown) | | Effect | type、value、caster、turns、critical、item、target | | Feature | type、minValue、maxValue、turns、targets |
除了这些类,还有四个单例:
| 单例 | 作用 | 主要成员 | |-----------|------|--------------------| | Fight | 战斗 | me、turn、getNearestEnemy()、getFarthestEnemy()、getEnemies()、getAliveEnemies()、getAllies()、getAlliedTurret()…… | | Field | 地图 | cellFromXY(x, y)、getObstacles()、distance(a, b)、pathLength(a, b)、lineOfSight(a, b)、path(a, b) | | Registers | 跨战斗的持久存储 | get(clé)、set(clé, valeur)、delete(clé)、all() | | Debug | 在地图上做可视化标记 | mark(cases, couleur)、markText(cases, texte)、show(case)、clearMarks()、pause() |
常量都归在各自所属的类下,分为两种形式:
Weapon.pistol、Chip.bandage、me.weapon === Weapon.pistol。Effect.DAMAGE、State.UNHEALABLE、Entity.Stat.STRENGTH、Entity.Type.LEEK、Cell.Type.EMPTY、Item.Area.CIRCLE_1、Item.LaunchType.LINE、Fight.Type.SOLO、Fight.Context.GARDEN、Field.NEXUS……编辑器的自动补全(Weapon.、Effect.、Entity.Stat.……)会列出所有可用的成员。
把你的 AI 拆分成 ES 模块(import / export):
只能访问你自己的文件:无法访问磁盘、网络和系统。
在 .ts 文件中,编辑器会实时检查你的类型:整个战斗 API 都有类型定义(类、方法、常量),并带有完整的自动补全。到了战斗时,TypeScript 会由官方编译器 tsc 转译成 JavaScript,再交给同一个引擎执行。类型错误会让 AI 变得无效,就像 LeekScript 中的编译错误一样。
Math.random() 用战斗的随机种子初始化,时钟(Date.now()、performance.now())是冻结的,这样战斗就能原样重放。console.log() 的输出会重定向到战斗日志,就像 LeekScript 中的 debug():它的输出会显示在战报里。Impossible de charger les données du jeu.
Vérifiez votre connexion et réessayez.