主题
WasiCore 框架概述
本文用于查阅框架分工。有地图编辑器或 Unity / Urho 经验的读者,可先读理解星火迁移已有知识;零基础用户可直接从快速开始做出第一个可玩目标。具体功能按需组合现成玩法系统和引擎能力,不要求整个项目只采用一种方式。
架构设计
WasiCore 采用分层架构设计,各层职责明确,通过接口进行通信。
系统架构图
┌─────────────────────────────────────────────────────────┐
│ 应用层 (Game Entry) │
├─────────────────────────────────────────────────────────┤
│ UI层 (GameUI) │
├─────────────────────────────────────────────────────────┤
│ 游戏逻辑层 (GameCore) │
├──────────────────────────┬──────────────────────────────┤
│ 数据层 (GameData) │ 场景图引擎封装 (GameGraph) │
├──────────────────────────┴──────────────────────────────┤
│ 引擎层 (Engine Interface / Urho3D) │
├─────────────────────────────────────────────────────────┤
│ 平台层 (Platform) │
└─────────────────────────────────────────────────────────┘> GameGraph 是连接 GameCore 游戏逻辑与底层 Urho3D 引擎的桥梁,提供节点、物理、资源、材质等能力。Unit、Actor、Scene 可以通过类型明确的入口访问底层节点与组件。表现节点、单位绑定节点和场景根有不同用途,unit.GetNode() 的双端语义也不同;实际写法与控制归属见 GameCore 与 GameGraph 桥接,能力清单见 GameGraph 总览。
网络架构
┌──────────────┐ ┌──────────────┐
│ 客户端 │◄────────►│ 服务器 │
│ (Client) │ │ (Server) │
├──────────────┤ ├──────────────┤
│ GameUI │ │ Game Logic │
│ Rendering │ │ Simulation │
│ Input │ │ Authority │
├──────────────┤ ├──────────────┤
│ Protocol │ │ Protocol │
│ Client │ │ Server │
└──────────────┘ └──────────────┘
▲ ▲
└──────── Network ─────────┘
(MessagePack)游戏体系选型指南
WasiCore 框架包含两套可独立或组合使用的体系。选择正确的体系是游戏架构决策的第一步。
> 如果用户只说“2D 游戏”或“3D 游戏”,不要直接按视觉维度选择路线。先读 游戏架构路线、SCE 场景空间模型与 Canvas/GameGraph 边界:区分 SCE Unit/技能系统、直接 GameGraph SceneGraph、Canvas/GameUI 绘制路线,再判断 SCE 场景使用 Surface2D 还是 Volumetric3D。
体系一:核心游戏逻辑体系(GameCore + GameData)
提供的能力:Entity/Unit/Ability/Buff/Item/Effect/Order/AI/Trigger/GameData/Player/DualEndEvent
设计目标:服务器权威、数据驱动、自动同步的单位制联机游戏。这条路线可以承载 3D 画面、2.5D 单层地表或真 3D 多层空间;空间语义由 GameDataScene.SpaceModel 决定,而不是由画面风格决定。
适合的游戏类型:
- MOBA / RTS / 塔防 — Unit + Ability + AI + Order
- RPG / ARPG — Unit + Ability + Buff + Item + Quest
- 回合制策略 — Entity + GameData + Trigger
- 需要联机对战、排行榜、云存档的任何游戏
核心优势:
- 服务端创建 Entity/Unit → 自动同步到所有客户端
- 内置技能/Buff/物品/冷却/属性系统,无需从零编写
- 触发器系统支持图形化编辑器(无需写代码即可编排逻辑)
- 双端事件 / TypedMessage / ProtoCustomMessage 三级通信机制
体系二:场景图引擎封装(GameGraph)
提供的能力:Node/SceneGraph/Component/Physics/Physics2D/Material/Resource/ScriptComponent
设计目标:通用的 3D/2D 场景图与物理引擎封装,底层对接 Urho3D。用户可以直接用 SceneGraph / Node 构造 3D 游戏或工具预览,而不经过 SCE Unit/技能系统;代价是不会自动获得 Unit、Ability、Buff、AI、目标过滤等高层玩法框架。
适合的游戏类型:
- 物理解谜 / 弹球 / 弹珠台 — Physics2D + ScriptComponent
- 平台跳跃 / 横版动作 — Physics2D + ScriptComponent
- 3D 场景展示 / 沙盒搭建 — Node + StaticMesh + Light + Material
- 赛车 / 自由物理模拟 — RigidBody + CollisionShape
> 关键边界:GameGraph 已双端化,但子系统运行端不同。 > > | 模块 | 客户端专属 | 双端可用 | > |------|:----------😐:--------😐 > | Graphics(Light, Zone, Skybox, Camera, StaticMesh, PrimitiveShape, Drawable) | 全部 | — | > | MaterialSystem(Material, MaterialPBR, MaterialFlatLambert 等) | 全部 | — | > | Physics2D(RigidBody2D, PhysicsWorld2D, 所有 Collision/Constraint 2D 组件) | — | 全部 | > | ResourceSystem | MeshBuilder | Mesh, Texture2D, Shader, Prefab | > | NodeSystem 核心 | — | Node, SceneGraph, 发布/复制模式 | > | Physics 3D | — | RigidBody, PhysicsWorld, CollisionShape | > | Scripts | — | ScriptComponent | > > 客户端本地创建的 GameGraph 仍只是本地表现层,不会自动获得联机同步、服务器权威逻辑或持久化。需要同步脚本创建的 GameGraph 场景时,应在服务端创建 replicated SceneGraph 并按玩家 Publish(player);多数完整联机游戏仍建议以核心体系为主体,再组合 GameGraph。
两套体系的组合方式
大多数成熟的游戏会同时使用两套体系,让它们各司其职:
服务端 客户端
┌────────────────────┐ ┌────────────────────────────────┐
│ GameCore 核心体系 │ ──同步──▶ │ GameCore 核心体系 │
│ • Unit 创建/销毁 │ │ • Unit 状态同步接收 │
│ • Ability 施放判定 │ │ • 事件驱动 Actor 表现 │
│ • 属性计算 │ │ │
│ • AI 决策 │ │ GameGraph 场景图/表现层 │
│ • 碰撞判定(2D/3D) │ │ • Light/Zone/Skybox 场景搭建 │
│ │ │ • Material 材质控制 │
│ GameGraph │ │ • Physics2D 本地表现/映射 │
│ • Node/SceneGraph │ │ • ScriptComponent 帧逻辑 │
│ • 2D/3D物理/发布图 │ │ • StaticMesh/PrimitiveShape │
└────────────────────┘ └────────────────────────────────┘典型组合模式:
| 模式 | 服务端用 | 客户端用 | 适合 |
|---|---|---|---|
| 纯核心体系 | Entity/Unit/Ability/Trigger | Actor 视觉表现 + UI | 传统 MOBA/RTS/RPG(通常是 Surface2D 单层地表,但画面仍可 3D 渲染) |
| 核心 + GameGraph 渲染增强 | 同上 | 核心体系 + Light/Zone/Skybox/Material 搭建 3D 场景 | 需要精细 3D 画面的联机游戏;不等于必须使用 Volumetric3D |
| 核心 + GameGraph 物理增强 | Unit/Ability 管理游戏逻辑;必要时服务端 Physics2D/3D 做权威模拟 | 接收 replicated Node,或用 Physics2D 做本地表现/预测 | 联机游戏中需要额外 2D/3D 物理对象或物理表现 |
| 服务端 GameGraph 发布图 | SceneGraph + 2D/3D Physics + Publish(player) | 接收 replicated SceneGraph / Node 事件 | 非 Unit 的服务端权威 2D/3D 物件、机关、调试对象 |
| 纯客户端 GameGraph | 不使用 | 全部用本地 GameGraph | 单机物理游戏/原型验证 |
桥接方式:
csharp
using GameGraph.NodeSystem;
// scene 是已经加载完成的 SCE 场景。
var graph = scene.GetSceneGraph();
#if CLIENT
// 在保留 Unit 玩法的同时,查询已有表现组件。
var model = unit.GetAnimatedModel();
var controller = unit.GetAnimationController();
#endif需要物理角色或自定义绑定节点时,先确定移动、同步与清理归属,再添加相应组件,详见桥接参考。
选型决策流程
你的游戏需要联机/对战/服务器逻辑吗?
├── 是 → 默认以核心体系(GameCore)承载游戏规则和持久化
│ ├── 游戏类型是单位制(有角色/技能/属性)?
│ │ ├── 是 → Unit + Ability + Buff(核心体系主力)
│ │ └── 否 → Entity + GameData + 自定义逻辑
│ └── 需要同步非 Unit 的 3D 场景物件吗?
│ ├── 是 → 服务端 GameGraph 发布图(高级路径)
│ └── 否 → 只在客户端组合 GameGraph 表现或 Actor 系统
└── 否(纯单机/原型)→ 可以纯用 GameGraph
└── 但未来要加联机?→ 建议一开始就引入核心体系🎯 核心概念
1. 游戏类自动注册 (IGameClass Auto-Registration)
WasiCore 框架提供了自动游戏类注册机制,简化了系统初始化过程。
🔧 IGameClass 接口
csharp
/// <summary>
/// Register game classes that are used in the game setups.
/// </summary>
public interface IGameClass
{
static abstract void OnRegisterGameClass();
}自动注册机制
实现方式:
- 代码生成器扫描:编译时自动扫描所有实现
IGameClass的类 - 自动生成注册代码:生成
AssemblySetup.g.cs文件 - 运行时自动调用:游戏启动时自动调用所有
OnRegisterGameClass()方法
使用示例:
csharp
// 定义游戏类
public class MyGameSystem : IGameClass
{
public static void OnRegisterGameClass()
{
// 系统初始化逻辑
Game.OnGameDataInitialization += OnGameDataInitialization;
Game.Logger.LogInformation("🎮 MyGameSystem initialized");
}
private static void OnGameDataInitialization()
{
// 游戏数据初始化
}
}生成的注册代码:
csharp
// 自动生成的 AssemblySetup.g.cs
public static class AssemblySetup
{
public static void Setup()
{
// 自动注册所有 IGameClass
GameCore.GameSystem.Game.OnRegisterGameClasses +=
GameCore.GameSystem.Game.RegisterGameClass<MyGameSystem>;
}
}主要优势
- 零配置:无需手动注册,编译时自动处理
- 类型安全:编译时检查,避免运行时错误
- 依赖管理:支持程序集间的依赖关系自动处理
- 统一初始化:所有系统在统一的生命周期中初始化
重要提示
- 无需手动调用:
OnRegisterGameClass()方法会被框架自动调用 - 静态方法:必须是静态方法,因为在类实例化之前调用
- 幂等性:确保多次调用的安全性(避免重复注册)
Game.GameModeLink不可用:OnRegisterGameClass()在GameModeLink赋值之前执行,此阶段不能用Game.GameModeLink判断游戏模式。游戏模式判断应放在OnGameDataInitialization或OnGameTriggerInitialization的 handler 中- 客户端 UI 时序:
OnGameUIInitialization早于OnGameTriggerInitialization。如需初始化 UI,必须在OnRegisterGameClass()阶段提前订阅 - 完整生命周期:完整启动顺序与阶段职责请见
guides/FrameworkLifecycle.md
2. 坐标系统 (Coordinate System)
WasiCore 框架采用特定的坐标系统约定,请务必区分2D场景和3D空间的不同约定。
重要区分:2D场景 vs 3D空间
2D场景坐标系统(UI、地图俯视图):
场景坐标系统(2D俯视视角):
(0,0) ←─────────────────────► X轴正方向(右方)
│
│
│
│
▼
Y轴正方向(下方)3D空间坐标系统(实际游戏世界):
3D空间坐标系统:
▲ Z轴正方向(上方,高度轴)
│
│
│
(0,0,0)├─────────────► Y轴正方向(前后,深度)
╱
╱
▼
X轴正方向(左右,水平)
XY平面 = 地面📐 关键约定说明
2D场景约定(用于UI、小地图等):
- 原点位置:场景
(0,0)点位于地图的左上方 - X轴正方向:指向右方
- Y轴正方向:指向下方
3D空间约定(用于游戏世界、物理、形状等):
- X轴正方向:水平方向(左右移动)
- Y轴正方向:水平方向(前后移动,深度)
- Z轴正方向:高度方向(上下移动,跳跃轴)
- XY平面:地面水平面
- Z轴:高度轴,Z=0为地面,Z>0为空中
坐标系手性说明
WasiCore使用左手坐标系(Left-handed coordinate system),与Unreal Engine保持一致:
左手定则验证:
👍 拇指 → X轴正方向(右)
👆 食指 → Y轴正方向(前)
🖕 中指 → Z轴正方向(上)默认镜头设置:
- Yaw: -90° (水平旋转)
- Pitch: -70° (俯视角)
- Roll: 0° (无倾斜)
- 默认视角:俯视角2.5D镜头
- 默认镜头下的原点位置:左上角
这种设计的优势:
- 兼容性:与Unreal Engine的坐标系完全一致
- 标准化:遵循主流3D引擎的左手坐标系约定
- 简化开发:减少从其他引擎迁移的坐标转换复杂度
与其他引擎的差异
| 引擎/系统 | 原点位置 | Y轴正方向 | 坐标系手性 | 备注 |
|---|---|---|---|---|
| WasiCore | 左上角 | 前方 | 左手坐标系 | 与UE一致,默认俯视角,默认镜头Yaw有-90°的旋转,因此默认镜头下,原点位置在左上角 |
| Unity | 中心或左下 | 上方 | 左手坐标系 | 3D世界坐标系 |
| Unreal Engine | 中心 | 前方 | 左手坐标系 | 与WasiCore一致 |
| DirectX | 左下 | 上方 | 左手坐标系 | 传统3D约定 |
| OpenGL | 左下 | 上方 | 右手坐标系 | 传统3D约定 |
| Web/UI | 左上 | 下方 | 2D坐标系 | 仅2D平面 |
实际应用场景
这种坐标系统约定会影响以下开发场景:
1. 2D场景使用(地图、UI):
csharp
// 地图左上角(2D场景)
var topLeft = new ScenePoint(0, 0, scene);
// 向右移动100单位(2D场景)
var moveRight = new ScenePoint(100, 0, scene);
// 向下移动100单位(2D场景)
var moveDown = new ScenePoint(0, 100, scene);2. 3D空间使用(游戏世界):
csharp
// 地面位置(3D空间)
var groundPosition = new ScenePoint(new Vector3(100, 200, 0), scene);
// 跳跃中的角色(3D空间)
var jumpingPlayer = new ScenePoint(new Vector3(100, 200, 50), scene);
// 飞行物体(3D空间)
var flyingObject = new ScenePoint(new Vector3(100, 200, 150), scene);3. 物理和移动(3D空间):
csharp
// 水平移动:X或Y增加
unit.MoveTo(new ScenePoint(new Vector3(newX, newY, currentZ), scene));
// 垂直移动(跳跃):Z增加
unit.MoveTo(new ScenePoint(new Vector3(currentX, currentY, newZ), scene));
// 重力下落:Z减少
velocity.Z -= gravity * deltaTime;开发建议
针对 AI 助手的关键提醒:
- 3D游戏开发:始终使用Z轴作为高度轴(跳跃、重力、飞行)
- 2D界面开发:使用传统的XY坐标系(Y向下)
- 物理系统:重力作用在Z轴负方向,跳跃在Z轴正方向
- 形状创建:Vector3(x, y, z)中,XY为地面位置,Z为高度
- 碰撞检测:地面接触检查Z坐标,水平距离检查XY坐标
2D方向常量(UI、地图):
csharp
public static class Direction2D
{
public static readonly Vector2 Up = new(0, -1); // Y减少(2D向上)
public static readonly Vector2 Down = new(0, 1); // Y增加(2D向下)
public static readonly Vector2 Left = new(-1, 0); // X减少
public static readonly Vector2 Right = new(1, 0); // X增加
}3D方向参考值(游戏世界):
| 方向 | Vector3 | 说明 |
|---|---|---|
| 前 | (0, 1, 0) | Y 正方向 |
| 后 | (0, -1, 0) | Y 负方向 |
| 左 | (-1, 0, 0) | X 负方向 |
| 右 | (1, 0, 0) | X 正方向 |
| 上 | (0, 0, 1) | Z 正方向(跳跃) |
| 下 | (0, 0, -1) | Z 负方向(重力) |
> 框架不提供 Direction3D 静态类,需要在项目中自行定义方向常量。详细信息请参考 坐标系统指南。
3. 实体系统 (Entity System)
实体系统是游戏对象的基础,专门处理游戏逻辑、状态管理和网络同步。
csharp
// 实体层次结构(游戏逻辑)
Entity
├── Unit // 单位(玩家、NPC)
├── Building // 建筑
├── Item // 物品
├── Effect // 逻辑效果
└── Projectile // 投射物关键特性:
- 组件化设计:实体通过组件组合功能
- 生命周期管理:自动处理创建、更新、销毁
- 网络同步:内置网络同步机制
- 服务端权威:所有实体必须在服务端创建
4. 表现系统 (Actor System)
表现系统专注于游戏世界的视觉表现,与实体系统形成明确的职责分离。
csharp
// 表现层次结构(视觉表现)
Actor
├── ActorModel // 模型表现
├── ActorParticle // 粒子表现
├── ActorSound // 声音表现
├── ActorText // 文本表现
├── ActorBeam // 光束表现
└── ActorSegmented // 分段表现关键特性:
- 轻量级创建:客户端可直接创建
- 视觉专注:专门处理模型、特效、声音
- 灵活生命周期:支持瞬态和持久化
- 附着系统:支持复杂的视觉层次结构
5. 架构分离原则
游戏对象架构 - 职责分离:
Entity 家族(游戏逻辑) Actor 家族(视觉表现)
┌─────────────────────┐ ┌─────────────────────┐
│ • 服务端权威 │ │ • 客户端创建 │
│ • 状态同步 │ │ • 视觉效果 │
│ • 游戏逻辑 │ │ • 轻量级 │
│ • 属性管理 │ │ • 瞬态/持久 │
└─────────────────────┘ └─────────────────────┘
│ │
└─────── 可以协作 ─────────────┘设计原则:
- Entity 负责 "逻辑的" - 状态、属性、行为、同步
- Actor 负责 "看到的" - 模型、特效、动画、声音
- 两者可以协作但职责明确分离
6. 技能系统 (Ability System)
技能系统提供了灵活的技能定义和执行框架。
核心组件:
- Ability:技能定义
- Effect:技能效果
- Modifier:属性修改器
- Cooldown:冷却管理
- Cost:消耗管理
执行流程:
- 检查施法条件(冷却、消耗、目标)
- 支付消耗
- 执行效果链
- 应用修改器
- 触发事件
7. UI系统 (UI System)
基于控件树的UI系统,支持数据绑定和事件路由。
控件层次:
UIRoot
├── Control
│ ├── Panel
│ ├── Button
│ ├── Label
│ └── ...
└── Layout
├── StackPanel
├── Grid
└── Canvas特性:
- 属性系统:丰富的控件属性
- 事件路由:冒泡和隧道事件
- 数据绑定:MVVM模式支持
- 布局系统:灵活的布局管理
UI模板数据结构 vs 运行时属性
⚠️ 重要区别:UI系统中的属性访问方式在模板定义和运行时控件中有所不同。
在UI模板 (GameData) 中:
csharp
// 布局属性位于 Layout 对象下
_ = new GameDataControlButton(Control.TestButton)
{
Layout = new() // 布局属性在 Layout 对象中
{
Width = 500,
Height = 90,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
Event = new() // 事件位于 Event 对象下
{
OnPointerClicked = (s, e) => { /* 处理点击 */ }
}
};在运行时控件类中:
csharp
// 属性直接作为控件的属性
var button = new Button
{
Width = 500, // 直接属性
Height = 90, // 直接属性
HorizontalAlignment = HorizontalAlignment.Center, // 直接属性
VerticalAlignment = VerticalAlignment.Center // 直接属性
};
// 事件直接订阅
button.OnPointerClicked += (s, e) => { /* 处理点击 */ }; // 直接事件关键差异总结:
- 模板定义:
Layout.Width、Event.OnPointerClicked - 运行时控件:
Width、OnPointerClicked(直接属性/事件)
这种设计允许模板系统更好地组织和管理复杂的UI数据结构,同时为运行时提供简洁直观的API。
8. 事件系统 (Event System)
基于发布-订阅模式的事件系统,支持同步和异步事件。
csharp
// 事件流程
EventSource → EventBus → EventHandler
↓ ↓ ↓
发布者 事件总线 订阅者事件类型:
- 游戏事件:游戏逻辑相关
- UI事件:用户交互
- 网络事件:网络状态变化
- 系统事件:系统级别事件
9. 数据系统 (Data System)
统一的游戏数据管理系统,支持热重载和版本控制。
数据类型:
- 静态数据:配置表、常量
- 动态数据:运行时数据
- 持久化数据:存档数据
WebAssembly 运行环境限制
WasiCore 编译为 WebAssembly 运行,有以下关键限制:
- 无线程池:
Task.Run()和TaskCreationOptions.RunContinuationsAsynchronously禁用,直接await异步方法;TaskCompletionSource使用默认构造函数 - 无 Task.Delay:使用
Game.Delay()替代 - 无 Console:使用
Game.Logger.LogInformation()参数化模板 - JSON 序列化不支持多维数组:需要网络传输(服务端/客户端通信)的数据不能使用
[,],改用一维数组
相关文档
- 坐标系统指南 — 详细坐标系说明
- 快速入门 — 第一个游戏
- 框架约束与排错入口 — 编译、初始化、异步与资源
- GameGraph 概览 — 场景图和物理
- API 参考 — 各系统 API 概览