network-wired网络基础

All Out 是以多人为先,但 CSL 的设计使你可以几乎像写单人游戏那样编写玩法。

关键思想是:

circle-info

所有 gameplay 状态会由服务器自动同步到客户端。你不需要编写 RPC 或“网络生成”对象。

权限(谁决定什么?)

作为一种经验法则:

  • 服务器:决定 gameplay 状态(伤害、奖励、生成、胜负、基于查询的碰撞等)

  • 客户端:渲染并播放外观效果(UI、粒子、屏幕震动、音效)

实际上,你的大部分代码会在服务器和客户端都运行——你只需守护 哪些工作 在何处运行。

本地与服务器检查

有两个你会不断使用的检查:

  • is_local_or_server():用于 gameplay UI 和输入处理(在服务器 + 本地客户端上运行)

  • is_local():用于纯粹的外观效果(仅在本地客户端上运行)

示例:

Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        // 用于 gameplay UI 和输入(在服务器 + 本地客户端上运行)
        if is_local_or_server() {
            // draw_ability_button(this, Shoot_Ability, 0);
            // 处理影响游戏状态的输入
            // 移动由系统自动处理
        }

        // 用于纯粹的外观效果(仅在本地客户端上运行)
        if is_local() {
            // UI.text(..., "Waiting for host to start the game...");
            // 粒子效果、装饰性 UI 等。
        }
    }
}
circle-exclamation

客户端特有状态

有时你需要 本地 不应影响游戏玩法且无需复制的状态:

  • UI 打开/关闭 切换

  • 相机震动计时器

  • 库存 UI 中的“最后悬停物品”

将这些作为字段保存,但只在 is_local() 检查 后读/写它们。

多人游戏安全规则

  • 避免将玩家状态放在全局变量中。 如果每个玩家需要自己的值,就把它存储在 Player.

  • 小心“单例”。 如果你确实需要一个全局管理器,确保它不会意外地存储每个玩家的数据。

  • 更倾向于确定性的服务器状态。 客户端应该对服务器的状态做出反应,而不是自行构造状态。

调试网络问题

  • 添加 log_info(...) 在服务器路径上(不仅是本地)记录,这样你可以看到权威性的决策。

  • 如果某些东西“在本地可行”但对其他玩家无效,通常是:

    • is_local() 守护的代码 本应由服务器负责,或

    • 被多个玩家覆盖的全局变量。

相关文档

最后更新于