For the complete documentation index, see llms.txt. This page is also available as Markdown.

Unity

如果你用 Unity 制作过游戏,要开始使用 All Out,你需要了解一些关键差异!


如果你来自 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

组件(继承自 组件)

预制体

预制体资源(在编辑器中创建)

层级窗口

层级

检查器窗口

检查器

Instantiate(prefab)

Scene.instantiate(prefab_asset)

Start() / Update()

ao_start / ao_update(dt) 生命周期

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

  • 脚本:你的游戏代码位于 .csl 文件中。新项目会以一个 main.csl ,它导入引擎并定义生命周期入口点。参见 CSL 入门.

  • 资源:游戏资源位于你的项目的 /res 目录下,并通过路径引用 不带/res 前缀(例如: "ui/button.png")。参见 资源与资源.

导入(重要区别)

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

  • 导入 "core:ao" 包裹在 main.csl

  • 如果你添加一个文件夹(例如 ui/),导入该文件夹 一次 包裹在 main.csl

  • 避免在其他文件中添加导入

示例:

生命周期:MonoBehaviour → CSL

在 Unity 中,你通常会将一个 MonoBehaviour 绑定到 GameObject,并实现:

  • Start() / Awake()

  • Update() / LateUpdate()

  • OnDestroy()

在 CSL 中,你通常会使用:

  • 全局过程位于 main.csl (用于游戏级设置)

  • 组件上的生命周期方法

示例组件:

全局生命周期过程会在每个参与的场景模拟中运行;它们并不只在服务器上执行。后加入的客户端可能会收到一个其 start 生命周期已经运行过的组件,因此必要时请在 ao_on_state_sync 中根据同步状态重建表现层。参见 游戏/帧生命周期.

预制体:Unity 预制体 → All Out 预制体

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

  • 创建:参见 预制体

  • 运行时生成:

关联实例会保留根属性,但实例内部对组件字段的更改并不是独立的覆盖。参见 预制体.

“序列化字段”(在检查器中公开的变量)

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

然后将你的组件添加到 检查器 中的一个实体上,并按实体调整数值。

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

Unity 模式:

  • new GameObject() / Instantiate()

  • FindObjectOfType<T>(), GetComponentsInChildren<T>()

All Out 模式:

碰撞与触发器

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

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

参见 导航网格与碰撞.

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

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

  • 游戏输入/UI:从玩家身上绘制它,位于 ao_late_update 内部 is_local_or_server().

  • 玩家特定的视觉覆盖:使用 is_local().

参见 网络基础.

从 Unity 到 All Out 的常见坑点

  • 单例管理器:优先使用按玩家或按实体的状态,而不是全局 GameManager 风格的单例。

  • 导入习惯:从……导入引擎和文件夹 main.csl (不要把导入分散到很多文件中)。

  • 服务器守卫:不要把正常游戏逻辑包在 Game.is_server().

  • 3D 变换:决定设计如何映射到 2D 场景中,并使用渲染器层来控制绘制顺序。

  • 假设是单人游戏:始终思考“如果有 10 个玩家连接会怎样?”

  • 硬编码的桌面端输入:除非有意如此,否则避免要求键盘/鼠标。

下一步去哪里

最后更新于