> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/docs-zh/lai-zi-qi-ta-gong-ju/unity.md).

# Unity

***

如果你来自 Unity，你会对……感到很熟悉 **实体 + 组件**，一个 **层级**，一个 **检查器**，以及可重用的 **预制体**。最大的思维转变是 All Out 游戏是 **以多人为先**：正常游戏逻辑运行在预测客户端和权威服务器上，而引擎会为你同步受支持的状态。

## 简而言之：与 Unity 的不同之处

* **多人模式是默认的**：通常你 **不会** 编写 RPC、SyncVars 或 Netcode 生成逻辑。
* **编写一条游戏逻辑路径**：不要用……来保护正常游戏逻辑 `Game.is_server()` ，否则你会禁用预测。
* **有意地处理玩家 UI**:
  * 从该玩家的 `ao_late_update` 内部 `is_local_or_server()`.
  * 使用 `is_local()` 中，仅用于玩家特定的视觉覆盖。
* **避免全局单例状态**：多个玩家连接到同一个会话。优先将状态存储在玩家或世界组件上。
* **All Out 的游戏玩法是 2D**：位置和缩放使用 `v2`，而旋转是一个以度为单位的角度。
* **以移动端为先**：除非你的游戏明确面向 PC，否则避免只依赖键盘的假设。

## 概念映射（Unity → All Out）

| Unity                  | All Out                                                       |
| ---------------------- | ------------------------------------------------------------- |
| 场景                     | 场景（世界）                                                        |
| 游戏对象                   | 实体                                                            |
| 变换                     | 2D 实体变换（位置/旋转/缩放）                                             |
| 组件 / MonoBehaviour     | 组件（继承自 `组件`)                                                  |
| 预制体                    | 预制体资源（在编辑器中创建）                                                |
| 层级窗口                   | [层级](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/hierarchy.md)  |
| 检查器窗口                  | [检查器](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/inspector.md) |
| `Instantiate(prefab)`  | `Scene.instantiate(prefab_asset)`                             |
| `Start()` / `Update()` | `ao_start` / `ao_update(dt)` 生命周期                             |

## 项目布局：“脚本”和“资源”所在的位置

* **脚本**：你的游戏代码位于 `.csl` 文件中。新项目会以一个 `main.csl` ，它导入引擎并定义生命周期入口点。参见 [CSL 入门](/all-out-docs/docs-zh/jiao-ben-bian-xie/syntax.md).
* **资源**：游戏资源位于你的项目的 `/res` 目录下，并通过路径引用 **不带** 该 `/res` 前缀（例如： `"ui/button.png"`）。参见 [资源与资源](/all-out-docs/docs-zh/he-xin-yin-qing-gai-nian/assets-and-resources.md).

### 导入（重要区别）

在 Unity 中，每个 C# 脚本都会被编译，并且可以使用自己的 `using` 指令。在 All Out 中，请集中管理导入：

* 导入 `"core:ao"` 包裹在 `main.csl`
* 如果你添加一个文件夹（例如 `ui/`），导入该文件夹 **一次** 包裹在 `main.csl`
* 避免在其他文件中添加导入

示例：

```go
// main.csl
import "core:ao"
import "ui" // 可选：将 /scripts/ui 下的所有文件纳入作用域
```

## 生命周期：MonoBehaviour → CSL

在 Unity 中，你通常会将一个 `MonoBehaviour` 绑定到 GameObject，并实现：

* `Start()` / `Awake()`
* `Update()` / `LateUpdate()`
* `OnDestroy()`

在 CSL 中，你通常会使用：

* 全局过程位于 `main.csl` （用于游戏级设置）
* 组件上的生命周期方法

示例组件：

```go
// orbiter.csl
Orbiter :: class : Component {
    center: v2;
    radius: float;
    speed: float;
    angle: float;

    ao_start :: method() {
        center = entity.local_position;
        radius = 2.0;
        speed = 1.0;
        angle = 0.0;
    }

    ao_update :: method(dt: float) {
        angle += speed * dt;
        offset := v2{cos(angle) * radius, sin(angle) * radius};
        entity.set_local_position(center + offset);
    }
}
```

全局生命周期过程会在每个参与的场景模拟中运行；它们并不只在服务器上执行。后加入的客户端可能会收到一个其 start 生命周期已经运行过的组件，因此必要时请在 `ao_on_state_sync` 中根据同步状态重建表现层。参见 [游戏/帧生命周期](/all-out-docs/docs-zh/jiao-ben-bian-xie/game-frame-lifecycle.md).

## 预制体：Unity 预制体 → All Out 预制体

All Out 预制体在编辑器中创建，可重复使用或在运行时生成。

* **创建**：参见 [预制体](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/prefabs.md)
* **运行时生成**:

```go
spawn_enemy :: proc() {
    prefab := get_asset(Prefab_Asset, "Enemies/BasicEnemy.prefab");
    e := Scene.instantiate(prefab, {10, 5});
}
```

{% hint style="info" %}
关联实例会保留根属性，但实例内部对组件字段的更改并不是独立的覆盖。参见 [预制体](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/prefabs.md).
{% endhint %}

## “序列化字段”（在检查器中公开的变量）

Unity 使用 `[SerializeField]` 和 public 字段来在检查器中暴露值。在 CSL 中，使用 `@ao_serialize` 来向编辑器暴露字段。

```go
Damage_On_Touch :: class : Component {
    damage: int = 10 @ao_serialize;
}
```

然后将你的组件添加到 [检查器](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/inspector.md) 中的一个实体上，并按实体调整数值。

## 生成与查询：Instantiate/Find → 场景 API

Unity 模式：

* `new GameObject()` / `Instantiate()`
* `FindObjectOfType<T>()`, `GetComponentsInChildren<T>()`

All Out 模式：

```go
// 创建和销毁实体
e := Scene.create_entity();
e.set_local_position({0, 0});
e.destroy();

// 遍历实体（仅在你真正需要“全部内容”时）
for e2: entity_iterator() {
}

// 遍历某一特定类型的组件
for player: component_iterator(Player) {
}
```

## 碰撞与触发器

一个启用的碰撞体，带有 `is_trigger` 设置后可调用 `on_trigger_start`, `on_trigger_stay`，以及 `on_trigger_end`。每个回调都会接收触发器碰撞体和另一个碰撞体。一个 `移动代理` 并非必需。

CSL 并未提供一个通用的实体接触回调，等同于 `OnCollisionEnter`。请使用触发器来处理进入/退出行为。对于广域感知，请查询附近的组件：

```go
nearby: [..]Pickup;
Scene.get_all_components_in_range(entity.local_position, 2.0, ref nearby);

for p: nearby {
    // 检查距离 / 应用效果 / 等等
}
```

参见 [导航网格与碰撞](/all-out-docs/docs-zh/he-xin-yin-qing-gai-nian/navmesh-and-collision.md).

## 多人游戏思维：输入、UI 以及“代码运行在哪里”

在 Unity 中，你常常可以假设“我的客户端拥有我的角色”。在 All Out 中，请只为共享的预测路径编写一次游戏逻辑：

* **游戏输入/UI**：从玩家身上绘制它，位于 `ao_late_update` 内部 `is_local_or_server()`.
* **玩家特定的视觉覆盖**：使用 `is_local()`.

参见 [网络基础](/all-out-docs/docs-zh/jiao-ben-bian-xie/networking-fundamentals.md).

## 从 Unity 到 All Out 的常见坑点

* **单例管理器**：优先使用按玩家或按实体的状态，而不是全局 `GameManager` 风格的单例。
* **导入习惯**：从……导入引擎和文件夹 `main.csl` （不要把导入分散到很多文件中）。
* **服务器守卫**：不要把正常游戏逻辑包在 `Game.is_server()`.
* **3D 变换**：决定设计如何映射到 2D 场景中，并使用渲染器层来控制绘制顺序。
* **假设是单人游戏**：始终思考“如果有 10 个玩家连接会怎样？”
* **硬编码的桌面端输入**：除非有意如此，否则避免要求键盘/鼠标。

## 下一步去哪里

* [CSL 入门](/all-out-docs/docs-zh/jiao-ben-bian-xie/syntax.md)
* [层级](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/hierarchy.md)
* [检查器](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/inspector.md)
* [预制体](/all-out-docs/docs-zh/shi-yong-bian-ji-qi/prefabs.md)
