> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-bian-ji-qi/shi-yong-dai-ma-kuo-zhan/script-component.md).

# 使用脚本组件

使用 Script 组件为代码赋予功能，而无需深入整个项目结构。

借助新的 Script Component，可以创建在实体内部执行自定义代码的实体。

Script Component 允许执行实体的自定义行为，而无需直接操作 `index.ts` 以及可能的其他文件。

## 设置 Script Component

1. 通过点击 `+` 按钮并选择它，将 Script Component 添加到实体。通过点击 **+ Add New Script Module** 并选择一个名称，或者使用文件路径（浏览或拖放现有文件）创建一个新 Script。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-79378b201ff5d7fd7334d821c9c2ab0224da46b8%2Fnew-script-component.png?alt=media\&token=a70edded-3a9e-442e-90ce-271a4554b704)

2. 点击组件中的 CODE 按钮以打开默认代码编辑器。让我们检查一下它的结构。有关如何选择和管理默认编辑器的更多详情，请前往 [与代码结合](/creator/content-creator-zh/chang-jing-bian-ji-qi/shi-yong-dai-ma-kuo-zhan/overview.md).

## 了解 Script 结构

当 Script 首次打开时，它包含以下代码：

```ts
import { engine, Entity } from '@dcl/sdk/ecs'
import {} from '@dcl/sdk/math'

export class BuildingScript {
  /**
   * 属性
   * 定义你希望在各个方法之间复用的类字段。
   * 示例用法：this.myVariable
   */
   // private myVariable: boolean = true

  /**
   * 构造函数 / 输入
   * 这里声明的参数会显示在 Creator Hub 中的 Script Component UI 里。
   * 支持的类型：Entity、String、Number、Boolean、ActionCallback 和 Slider
   * 适用于使用滑块编辑的数字，例如 public speed: Slider<0, 10, 0.5> = 1
   *
   * 注意：编辑此文件后，点击 Script Component UI 中的刷新图标
   * 以查看更新后的输入项。
   *
   * 构造函数中的 `src` 和 `entity` 字段是内部引用所必需的。
   */
  constructor(
    public src: string,     // 请勿删除
    public entity: Entity,   // 请勿删除
    // 在下面添加你的自定义输入项
  ) {}

  /**
   * start()
   * 在脚本初始化时调用一次。
   */
  start() {
    // 脚本初始化
    console.log("BuildingScript initialized for entity:", this.entity);
  }

  /**
   * update(dt)
   * 每帧调用一次。
   * @param dt -（可选）距离上一帧的时间差（秒）
   */
  update(dt: number) {
    // 每帧调用
  }
}
```

这个类由三个主要部分组成：

* 该 **constructor**,
* 、 **start()** 方法
* 、 **update()** 方法。

## 构造函数

构造函数包含你希望在 Creator Hub 中从场景里动态公开和修改的参数。

```ts
export class BuildingScript {
  constructor(
    public src: string,
    public entity: Entity,
    public numericVariable: number, 
  ) {}
...
}
```

一旦文件保存， **Refresh** 按钮就会更新所有已完成的更改。

<img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-0e88676864e337ab55bf98ae8bd23e2775ec0c60%2Fscript-refresh-button.png?alt=media" alt="刷新按钮" width="360">

刷新后，Script Component 现在会显示 `numericVariable` ，这是在代码中添加的。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-8729a660cd9b4cd056ff33ad0a28fefe1b7814b1%2Fparameter-script-component.png?alt=media\&token=5dfa1800-9999-4809-ac67-53bc9a7c8671)

## 参数

如果不同实体在 Script 组件中使用同一个文件，它们仍然拥有独立的参数：如果场景中有两栋建筑， `building1` 和 `building2`，它们都带有指向 `BuildingScript.ts` 文件的 Script Component，那么每栋建筑都有自己独立的 `numericVariable` 参数，可以分别修改。

{% hint style="warning" %}
**重要说明**：不要修改/删除 `public src: string` 和 `public entity: Entity`。你可以在这些字段后面继续添加新的输入项。
{% endhint %}

构造函数参数允许的类型有：

* `Entity`
* `字符串`
* `数值`
* `布尔值`
* `ActionCallback`
* `Slider<Min, Max, Step>`

### 带滑块的数字参数

将数字参数写成 `Slider<Min, Max, Step>` 即可使用滑块而不是普通数字框进行编辑。Creator Hub 会同时显示滑块和数字框。

```ts
constructor(
  public src: string,
  public entity: Entity,
  // 一个从 0 到 10、以 0.5 步长移动的滑块
  public speed: Slider<0, 10, 0.5> = 1,
) {}
```

* `Step` 是可选的，默认值为 `1`.
* 允许负数边界，例如 `Slider<-90, 90>`.
* 在运行时，该值是一个普通的 `数值`，因此 `this.speed` 的行为与其他数字参数相同。

{% hint style="info" %}
**📔 注意**： `public` 和 `private` 构造函数参数都会公开到 Creator Hub。 `private` 关键字只会限制在 `BuildingScript` 类内部的访问。更多详情请参阅 TypeScript 官方文档中的\
[参数属性](https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties).
{% endhint %}

### 在 Script 中访问参数

要从代码中访问参数的值，请使用表示法 `this.definedParameter`。例如， `this.numericVariable` 或 `this.entity`.

默认 Script 模板在 start() 方法中包含这一行：

`console.log("BuildingScript initialized for entity:", this.entity);`.

将其改成这样，以记录你在构造函数中定义的值：

`console.log("BuildingScript initialized with numericVariable:`, `this.numericVariable);`

请注意，当你在 Creator Hub UI 中更改参数值时，也应当能看到这里记录的值随之更新。

### 默认参数

构造函数默认包含一个 `src` 以及一个 `实体` 参数，这些对于脚本中的代码非常有用：

* `this.entity` 始终指向持有 `Script` 组件的实体，可用它来访问该实体的信息或向其添加组件。
* `this.src` 是脚本存储的路径。这在创建供他人使用的 Smart Item 时尤其有用。即使 Smart Item 的路径发生变化或被重命名，也可以使用这个字段来构造与其一起打包的文件路径。

```ts
export class BuildingScript {
  constructor(
    public src: string,
    public entity: Entity,
  ) {}

  start() {
    Material.setPbrMaterial(this.entity, {
      texture: Material.Texture.Common({
        src: this.src + '/images/myImage.png',
      })
    });
  }
}
```

上面的脚本会获取拥有该脚本的实体并为其应用纹理。它从一个 `.png` 文件中获取纹理，该文件打包在 Smart Item 文件夹内，位于名为 `/images`的子文件夹中。通过使用 `this.src`，我们可以确保文件路径始终已知，无论该 Smart Item 被导入到场景中的 `/assets/custom/itemName` 或 `/assets/asset-packs/itemName`

### 参数上的工具提示

为你的输入参数添加工具提示，这样用户就知道这些字段是用来做什么的，或者接受哪些值。用户会在 Script Component UI 中每个字段旁边看到一个工具提示图标，将鼠标悬停在图标上时可以阅读自定义文本。

要为构造函数添加工具提示，请在构造函数前添加一个注释块，并为每个工具提示写一行 `@param` ，后接字段名称和描述。

```ts
  /**
   * @param startDate - 事件的开始日期，格式为 YYYY-MM-DD
   * @param yOffset - 要在地面上方显示该物品多少米
   */
  constructor(
    public src: string,
    public entity: Entity,
    public startDate?: string,
    public yOffset: number = 0.5,
  ) {
  }
```

你可能需要点击 Script component UI 上的刷新图标才能看到工具提示的更改。

<img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-0e88676864e337ab55bf98ae8bd23e2775ec0c60%2Fscript-refresh-button.png?alt=media" alt="刷新按钮" width="360">

## start() & update() 方法

该 **start()** 方法包含的代码只会在实体创建时执行一次（在这种情况下，就是场景首次加载时）。

预览场景并检查日志（**提示**：你可以使用 `` ` `` 快捷键）：它会显示新消息，其中包含 `numericVariable` 参数，将图像文件设为材质上的纹理。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-a8d756ab46337ed47bf6d1d7ae97641abd4cee64%2Fscript-log-message.png?alt=media\&token=4ee0e8a6-7807-44b3-8e86-099e34b39ea7)

该 **update()** 另一方面，方法会在游戏的每一帧执行其代码（就像 Systems 一样）。例如，检查 `PlayerEntity` 的值，以在脚本中触发行为。

以下代码会在游戏的每一帧打印日志，当 `PlayerEntity` 高于先前定义的 `numericVariable`时，该值由创建者通过 Script Component UI 动态提供。

```ts
update(dt: number) {
    if (Transform.get(engine.PlayerEntity).position.y > this.numericVariable ) {
      console.log("The player's height is over ", this.numericVariable);
    }}
```

<img src="https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-07e4722b53743d2bac04744175a46fc25488cc36%2Fupdate-script-logs.png?alt=media" alt="Update Method" data-size="line">

第一条日志属于 start() 方法，表示我们设置了 numericVariable。第二条日志属于 update() 方法，当玩家高于该值时触发。

## 将动作公开到 Creator Hub

可以在 Script Component 脚本中定义一个 `Action` ，并使其可在 Creator Hub 的 UI 中访问。这使得可以触发这个 `Action` 与另一个实体一起使用。

```ts
  /**
   * 将此动作公开以便触发
   * @action
   */
  exposedAction(creatorHubParameter: number) {
    console.log("Triggered from another entity using parameter: ", this.creatorHubParameter);
  }
```

`creatorHubParameter` 将被公开为一个 `Action` 参数，以便赋予其自定义值。刷新 Script Component 后，这个新动作会作为 Actions 下拉菜单中的一个选项出现。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-d7b71673260d80622c4b5635526aa3444d84ccff%2Fscript-component-action.png?alt=media\&token=0bedbaf4-0eac-4548-a2fa-400b2d2de668)

添加 Action 后，Creator Hub 中的任何实体都可以通过 `触发器`

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-33aa38670114e43b0bb1beb493e2233642530167%2Fscript-component-action-trigger.png?alt=media\&token=acb49d50-040f-4215-81fd-f251f604fee6)

{% hint style="info" %}
**📔 注意**：你可以在 Script 中按需添加任意多个 Actions。它们都可以独立地从 `Action` 下拉菜单中访问。
{% endhint %}

## 从外部调用 Script 方法

要从另一个 Script 或从 `src/index.ts`调用 Script 方法，应遵循以下步骤：

1. 创建一个 `public` 方法写在 Script 类内部。
2. 运行 `npm run build` ，从场景根目录执行。
3. 在你想使用该 public 方法的文件中，添加 `import { callScriptMethod } from '~sdk/script-utils'`.
4. 调用 `callScriptMethod` 并传入所需参数（在本例中， `someParamter`).

下面是一个带有 `public` 方法公开

```ts
export class BuildingScript {
  constructor(
    public src: string,
    public entity: Entity,
    ...,
  ) {}

  public publicMethod(boolParameter: boolean, someNumberParameter: number) {
    if (boolParameter) {
      console.log("Public method called with parameter true!: ", someNumberParameter);
    } else {
      console.log("Public method called with parameter: false!", someNumberParameter);
    }
  }
...
}
```

要从 `src/index.ts`调用它，请使用：

```ts
import { callScriptMethod } from '~sdk/script-utils'


export function main() {
    const buildingEntity = engine.getEntityOrNullByName("building")
    if (buildingEntity) {
        const scriptMethod = callScriptMethod(
            buildingEntity,
            "assets/scene/Scripts/BuildingScript.tsx",
            "publicMethod",
            false,
            3,
        )

        scriptMethod
    }
}
```

首先， `main` 函数会查找 `Entity` 拥有 Script 组件的实体。其次，如果 `Entity` 存在， `callScriptMethod` 则会使用以下参数调用：

1. `实体`: `Entity` 并且带有 `public` 方法。
2. `scriptPath`: `path` 其中 `Script` 类所在的位置。
3. `methodName`：要调用的 `public` 方法名称。
4. `...args`：方法的参数。本例中有两个。应按顺序依次添加。

第三，调用定义好的 `callScriptMethod`，在本例中， `scriptMethod`.

在给定参数值后，输出为：

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-32c18509225406a1f8162b0d9719fc1e38ed8da0%2Fscript-component-public-method.png?alt=media\&token=c0876cd3-198e-4530-8ca6-1edfcb3cca7c)

{% hint style="info" %}
**📔 注意**：你可以遵循相同的逻辑，从另一个脚本或文件中调用一个 `public` Script 方法。你可以用它来获取或更改 `public` Script 类中变量的值。
{% endhint %}

## 从脚本中触发其他实体的动作

可以在 Script 类构造函数中使用类型为 `ActionCallback` 的参数。这允许从脚本的方法中触发另一个 `Entity`的 `Action` 通过 Creator Hub UI 定义的动作。

在这个例子中， `anotherEntityAction` 被添加为一个 `public` 参数，将图像文件设为材质上的纹理。

```ts
export class BuildingScript {
  constructor(
    public src: string,
    public entity: Entity,
    public anotherEntityAction: ActionCallback,
    ...,
  ) {}
  ...
}
```

一个可选的 `Entity` 和 `Action` 现在可以在 Creator Hub UI 中刷新 Script Component 时使用。 `球体` 是场景中一个已经存在的实体，它有一个名为 `缩放`.

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-a264fa3fe8ceb754877b1022f0c653d3cb29ece6%2Fscript-component-action-callback.png?alt=media\&token=70b7820e-4093-4e84-92a1-9b25aedf1a02)

的动作。另一个实体的动作现在可以在 Script 类中访问。它可以以很多不同方式使用。下面的例子中，按下 E 将触发 `this.anotherEntityAction` ，通过定义一个 `pointerEventsSystem` 在 `起始` 方法。

```ts
  start() {
    pointerEventsSystem.onPointerDown(
      {
        entity: this.entity,
        opts: {
          button: InputAction.IA_PRIMARY,
          hoverText: "Press E to trigger an Action from another Entity.",
        },
      },
      () => {
        this.anotherEntityAction();
      }
    );
  }
```

### 可选动作回调

一个 `ActionCallback` 创作者未连接的参数是 `undefined`，其类型是 `ActionCallback | undefined`。调用前先检查，这样无论动作是否连接，脚本都能正常工作：

```ts
if (this.anotherEntityAction) {
  this.anotherEntityAction();
}
```

{% hint style="info" %}
**📔 注意**：结合公开和触发 `操作` 是一个非常强大的工具。你可以在一个实体上定义 Script Component，使用一个 `public` 方法公开一个动作，然后从另一个实体的 Script Component 中通过一个 `ActionCallback` 参数，将图像文件设为材质上的纹理。
{% endhint %}

## 另请参阅

* [智能项目 - 基础](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/smart-items.md)
* [智能物件 - 高级](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/smart-items-advanced.md)
* [状态和条件](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/states-and-conditions.md)
* [让任意项目变为智能项目](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/make-any-item-smart.md)
* [SDK 快速入门](/creator/content-creator-zh/chang-jing-sdk7/ru-men/sdk-101.md)：跟随这个迷你教程快速入门。
* [开发工作流](/creator/content-creator-zh/chang-jing-sdk7/ru-men/dev-workflow.md)：阅读此内容以全面了解场景创建流程。
* [示例](https://studios.decentraland.org/resources?sdk_version=SDK7)：直接深入查看可运行的示例场景。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-bian-ji-qi/shi-yong-dai-ma-kuo-zhan/script-component.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
