codeCSL 入门

CSL 是 All Out 的自定义编程语言,旨在让编写多人游戏像创建单人游戏一样简单。

CSL 是 All Out 的自定义脚本语言。它是静态类型的,最像 Go/Odin——只是 游戏状态会自动从服务器同步到客户端.

circle-info

你不需要编写 RPC、SyncVars 或自定义复制。专注于游戏逻辑;平台会为你处理网络。

你的第一个脚本(main.csl)

当你创建新项目时,All Out 会生成一个 main.csl 在你的项目的 scripts/ 文件夹中。

import "core:ao"

// ============================================================================
// 全局生命周期
// ============================================================================

ao_before_scene_load :: proc() {
    // 注册物品定义、货币等。
    // 在场景创建之前运行。
}

ao_start :: proc() {
    // 场景开始时调用一次。
}

ao_update :: proc(dt: float) {
    // 每帧调用。
}

ao_late_update :: proc(dt: float) {
    // 在 ao_update 之后每帧调用。
}

// ============================================================================
// 玩家生命周期
// ============================================================================

Player :: class : Player_Base {
    ao_start :: method() {
    }

    ao_update :: method(dt: float) {
    }

    ao_late_update :: method(dt: float) {
    }

    ao_end :: method() {
    }
}

例如,在每个玩家加入时记录一条消息:

如果你想更深入了解这些函数何时运行,请参见 游戏/帧生命周期.

导入

你的 main.csl 应当导入 core:ao 以及你创建的任何文件夹(例如 ui/, abilities/等)。

circle-exclamation

声明(变量和常量)

声明会把一个名字绑定到一个值。

变量

或者 <type><expression> 都可以省略:

常量

常量使用 :: 并且必须是编译期常量:

这是无效的(因为 a 不是编译期常量):

类型

原始类型

  • 有符号整数: s8, s16, s32, s64

  • 无符号整数: u8, u16, u32, u64

  • 布尔值: b8, b16, b32, b64

  • 浮点数: f32, f64

  • 别名:

    • int == s64

    • uint == u64

    • bool == b8

    • float == f32

  • 向量: v2, v3, v4

  • string

  • typeid

  • 任意

向量类型

v2 具有 .x, .y; v3 还增加了 .z; v4 还增加了 .w ——全部都是 float 字段:

结构体和类

结构体是 值类型 (赋值时会复制)。类是 引用类型 (你用 new).

结构体(值类型)

类(引用类型)

继承

结构体/类可以继承自其他结构体/类:

过程和方法

过程(过程)

过程是普通值,可以像其他值一样被赋值/存储:

方法(方法)

使用 method() 在结构体/类内部。方法有一个隐式的 this 引用参数。

字段访问 vs 方法调用

使用 . 用于字段, -> 用于方法:

circle-info

任何过程都可以作为“方法”调用,只要它的第一个参数匹配接收者类型。这是 CSL 中常见的模式。

数组

CSL 有几种你会经常使用的“类数组”类型:

  • 固定数组: [4]int

  • 切片 / 管理数组: []T (通常用作数组的“只读视图”)

  • 动态数组: [..]T (可调整大小的列表)

  • 非托管数组: [^]T (用于内置 API 签名,例如 format_string, log_info等——将值作为 {a, b, c})

动态数组暴露 .data, .count.capacity,并使用方法调用语法进行操作:

有关完整指南(包括删除模式),请参见 数组和集合.

控制流

如果 / 否则

Switch

While / for / foreach

类型转换

使用 expr.(T) 进行类型转换:

按引用传递: ref (推荐)

当你需要修改参数时, 优先使用 ref 而不是原始指针。

回调:函数指针 + userdata(无闭包)

CSL 没有闭包。内联的 proc(...) { ... } 不能捕获周围变量。

要携带上下文,就把回调和一个 userdata: Object 字段配对使用:

类型信息(把类型作为值)

typeid 值可以传递给多态过程:

最佳实践(All Out 中的 CSL)

  • 避免全局游戏状态。 多个玩家连接时——将每个玩家的状态存储在 Player 上,而不是其他地方。

  • 分离视觉效果逻辑与游戏逻辑。 使用 is_local() 用于仅本地的 UI/粒子效果,且 is_local_or_server() 用于必须在服务器 + 本地客户端上运行的游戏输入。

  • 面向移动端的默认设置。 除非你的游戏明确以 PC 为重点,否则不要依赖键盘/鼠标输入。

  • 如果你对语法或 API 不确定,请查看 api_reference/ 文件夹,它会在你的项目中生成(其中包含最新的 core.csl 表面)。

最后更新于