星空晶体 发表于 2025-3-15 16:12:41

[原创]SAPI 基础教程 —— 总目录 & 第一期 初识事件


前言

第一期 第二期 第三期

1.20.30 及之后,失去了物品方块事件。而在 1.21.20 及之后,需要假日创造者的组件等随假日创造者离去。对基岩版附加包算是一个不小的打击。这时候,Script API 成为了许多人的选择。
ScriptAPI 通过使用 JavaScript 语言 编写自定义事件、自定义组件、菜单/表单等,在游戏里实现丰富的功能,以弥补被删除的功能 或实现更多丰富的功能。
JavaScript 是什么?
JavaScript 是一种编程语言,用于前端,但很多时候也可以用于许多平台的脚本开发,Script API 就是在Minecraft 基岩版中附加包使用 JavaScript ,来达到丰富的效果。
学习 JavaScript:本教程需要 JavaScript 基础,有条件可以学习 TypeScript,因为官方文档中代码实例是用 TypeScript 语言的。关于 JavaScript 教程、TypeScript 教程以及两者关系,请详见:
JavaScript:https://www.runoob.com/js/js-tutorial.html
TypeScript & 两者区别:https://www.runoob.com/typescript/ts-tutorial.html
在这篇教程中,无法完全展现Script API全部甚至一Server 库的全部,只会将 Server库重要部分,因此需要多次查阅官方附加包文档。
官方Script API文档:https://learn.microsoft.com/zh-cn/minecraft/creator/scriptapi/?view=minecraft-bedrock-stable
正式查看提醒
本教程要对附加包开发有基本认识,如果没有,可以查看这篇教程:面向附加包开发新人的一些建议
下面教程中,将把 Script API 简称为 SAPI。
本教程需要大家建议,欢迎在本主题下方提建议!
创建文件

打开你的附加包项目,在行为包 manifest.json 清单文件中,在 modules 字段下写入:
{
            "type": "script",
            "language": "javascript",
            "uuid": "",
            "entry": "scripts/xxx.js",//自行选择xxx部分
            "version": [
                0,
                0,
                1
            ]
      }
这段代码中的 “entry” 是 SAPI 的主 JavaScript 文件路径。“language” 是编写 SAPI 的语言,当然这里只能目前写上 JavaScript。
接着在 modules 字段下写入 dependencies 数组:
"dependencies": [
      {
            "module_name": "@minecraft/server",
            "version": "1.17.0"
      }
]
此字段用于引入 server 库,server 库包含了大量修改 Minecraft 原版的类型。“version” 字段表示 server 库的版本,建议使用高版本,可以在 https://www.npmjs.com/package/@minecraft/server 查看最新版本。
注:若库使用版本号末尾带 -beta 或 -alpha 的 SAPI 项目,请在导入游戏测试时,在创建存档时打上“测试版 API”实验性。
完整清单是这样的:
{
    "format_version": 2,
    "header": {
      "name": "名称",
      "description": "介绍",
      "uuid": "",
      "version": [
            0,
            0,
            1
      ],
      "min_engine_version": [
            1,
            21,
            0
      ]
    },
    "modules": [
      {
            "type": "script",
            "language": "javascript",
            "uuid": "",
            "entry": "scripts/xxx.js",//自行选择xxx部分
            "version": [
                0,
                0,
                1
            ]
      }
    ],
    "dependencies": [
      {
            "module_name": "@minecraft/server",
            "version": "1.17.0"
      }
    ]
}
现在一切准备好,在项目行为包中创建scripts 文件夹,并在其中创建清单所写的 JavaScript 文件名。进入文件,写入以下内容:
import { world, system } from "@minecraft/server"
括号中的 world、system 是库的类型,当然也可以写成:
import * from "@minecraft/server"
这段代码导入库的所有类,如果要选择需要的库,在括号里写上库名。
提示:为了分类导入所库,可以在库名后写入“as xxx”,使用时只需要用所名。在后者导入方式加入 as,可以在使用时库前有个后缀。
注意:开头不必引入所有库,可以等到需要时在导入。
before 类事件

brfore 类事件是实际事件立即发生的事,可以取消和修改将发生的事件。
注意:在事件发生之前,有任何修改游戏状态的 API 都会无法运行。
此处描述不准确,代改动
下面是 before 类事件可用的属性:
以下描述可能与实际有误差
名称作用effectAdd为实体添加效果事件
entityRemove删除实体*时事件
explosion爆炸时事件
itemUse成功使用物品时事件
itemUseOn对某方块使用物品时事件
playerBreakBlock玩家打破方块时事件
playerGameModeChange玩家模式改变时事件
playerInteractWithBlock玩家与方块交互时事件

playerInteractWithEntity玩家与实体交互时事件
playerLeave玩家离开时事件
weatherChange天气变化时事件
*删除实体并非类似于kill指令一样清除实体,而是直接移除实体。
写法:
world.beforeEvents.xxx(上属性).subscribe((event) =>{})
event 是事件数据,也可以用其他名比如i。事件数据是事件发生时的内容,比如:
import {
    world,
    system
} from "@minecraft/server"
world.beforeEvents.playerBreakBlock.subscribe((event) => {
    const player = event.player
    system.run(() => {
      player.runCommand(`say @s 你打破了一方块!`)
    })
})
event.player 是打破方块的玩家,player 是 playerBreakBlock 事件数据的玩家。event.player赋予的变量类型就是 Player 类,在 Player 类中runCommand 方法是实体执行命令的方法。
效果如图:
https://i.ibb.co/tTckhz0Z/wb65u-gu1s2.gif
注:为什么要在 player.runCommand()外添加一个 system.run(() => {…})?
由于 beforeEvents 的问题,若直接写上会报错无法运行。因此要执行方法或一个函数需要在外加一个 system.run(() => {…}) 以执行。

那么可用的事件都有哪些可用数据事件呢?它们代表什么呢?可见下表:

事件名数据事件及其作用
effectAdd[布尔值]cancel:取消
[整数]duration:持续时间
[字符串]effectType:效果类型
entity:效果添加某实体上
entityRemoveremovedEntity
explosion[布尔值]cancel:取消爆炸事件
itemUse待补充
playerBreakBlock[布尔值]cancel:取消挖掘方块事件
itemStack:物品堆叠
player:此事件玩家
playerGameModeChange[布尔值]cancel:取消游戏模式
fromGameMode:当前游戏模式
player:改变游戏模式的玩家
toGameMode:改变游戏模式为目标

playerInteractWithBlockblock:玩家与之交互的方块
blockFace:与方块交互的方块面
[布尔值]cancel:取消交互事件
itemStack:物品堆叠
与之交互的玩家
playerInteractWithEntity[布尔值]cancel:取消此事件
itemStack:物品堆叠
player:交互玩家
target:目标实体
playerLeaveplayer 离开玩家
weatherChange[布尔值]cancel:取消此事件
[整数]duration: 天气持续时间[刻单位]
newWeather:要改变的新天气
previousWeather:先前的天气
下面是一个片段代码实例:
import { world, system } from "@minecraft/server"
import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui"

world.beforeEvents.itemUse.subscribe((event) => {
    const huchu = event.itemStack
    const player = event.source
    if (huchu.typeId == `minecraft:snowball`) system.run(() => Action(player))
})
这段代码中,event 作为事件数据,event.itemStack 是玩家的手中物品,而 event.source 是使用物品的玩家。
但为了检测玩家手中物品是什么,就需要判断:在上述表格里已说,变量 huchu 的内容 event.itemStack 其实就是一个 itemStack 类,可使用 itemStack 的属性、方法。在这里,为了确保玩家使用的物品(命名空间)是 minecraft:snowball,就需要使用 huchu.typeId 来确定手中物品。若是,就会执行下面 Action(player) 函数。

同样,也有一个 afterEvent,但它可在整个世界运作。
after 类事件

after 类事件与 before 类事件相似,有数据事件,其中部分事件与 before 类事件重合,但是 after 类没有取消,同时也是延迟运行。

下面是部分可用的 after 类事件与其事件数据:
由于事件过多,仅展示一小部分,且官方文档可能随时有变动,了解最新内容请以官方文档为主。

chatSend 聊天框输入事件message:输入内容
sender:输入玩家
entityHealthChanged 实体血量改变事件
entity:实体
newValue:原血量
oldValue:现血量
playerPlaceBlock 玩家放置方块事件block:放置的方块
dimension:维度
player:放置的玩家
playerSpawn 玩家生成player:生成的玩家

下面是事件 playerSpawn 的实例:
import * as mc from '@minecraft/server'
import {
    ActionFormData
} from '@minecraft/server-ui'

function yad(player) {
    console.log(typeof(player));
    const yad1 = new ActionFormData()
      .title(`死亡次数`)
      .body(`你已经死了${playerDienum}`)
      .button(`结束`)

      yad1.show(player)
      .then((yad2) => {
            if (yad2.selection == 0) {
                player.runCommand(`say @s ${playerDienum}`)
            }
      })
}

var playerDienum = 0

mc.world.afterEvents.playerSpawn.subscribe(event => {
    const player=event.player
    yad(player)
    playerDienum++
})
在这里,玩家的初始生成和死亡后重生都算生成,当玩家死后,事件就会执行,弹出次数弹窗与次数。
player 是 event.player,它是指此事件的玩家,每当死亡,玩家的次数就会增一。
这里就可以制作一个统计玩家死亡次数的插件。
结语
本帖我们知道了什么事 before after 类事件,初步学会部分 SAPI,当然,为了详细,我们还需要学会例如 Entity Player Block 等类。
请根据官方文档为最新参考源。
本教程由于部分原因拖延了几天发布,本教材也需要大家的建议与支持,下期再见!

页: [1]
查看完整版本: [原创]SAPI 基础教程 —— 总目录 & 第一期 初识事件