What frontend technologies power Athena Crisis?
This post might have stale content, as HEAD is 11 commits ahead.
详细解释这个游戏使用到的前端技术架构,他是如何使用前端技术栈实现这样的回合制策略游戏,详细解释
现在我有足够的信息来创建一个详细的技术架构解析。让我生成完整的文档:
##Athena Crisis 前端技术架构详细解析
基于对源代码的深入探索,我将为您详细解释这个回合制策略游戏如何使用前端技术栈实现的。
##📐 整体架构设计
###核心特点:单体仓库(Monorepo) + 分层模块化
项目采用 pnpm workspace 管理的 Monorepo 结构,将关键逻辑分成独立的包(以希腊神命名),每个包专注于特定领域:
athena-crisis/
├── athena/ # 地图状态和算法 (Client/Server)
├── apollo/ # 游戏状态和命令系统 (Client/Server)
├── hera/ # 渲染引擎和游戏界面 (Client)
├── dionysus/ # AI 系统 (Client/Server)
├── ui/ # 设计系统和UI组件 (Client)
├── art/ # 资源管理 (Client/Build)
├── hermes/ # 战役数据结构 (Client/Server)
└── i18n/ # 国际化 (Client/Build)
##🏗️ 核心模块架构详解
###1. ATHENA 包 - 地图和数据结构层
职责:维护游戏世界的完整状态,包含所有算法计算
// 关键数据结构
class MapData {
// 地图的完整状态
readonly size: { width: number; height: number };
readonly config: MapConfig;
readonly tiles: TileMap;
readonly buildings: ImmutableMap<Vector, Building>;
readonly units: ImmutableMap<Vector, Unit>;
readonly players: Teams;
readonly decorators: DecoratorMap;
readonly fog: boolean;
readonly vision: VisionT;
}
核心特性:
- 不可变数据结构 (
@nkzw/immutable-map):所有游戏对象都是不可变的,便于撤销/重做和重放 - Vector 坐标系:网格化的坐标表示
- 视野系统(Vision):处理战争迷雾和玩家可见性
- 性能算法:
fastpriorityqueue- 路径寻找算法优化skmeans- 聚类算法用于地图生成
// 关键算法示例
getMovementPath(from: Vector, to: Vector): Vector[] // A* 寻路
calculateDamage(attacker: Unit, defender: Unit): number
getRescuableVectors(from: Vector): Set<Vector>
###2. APOLLO 包 - 游戏命令和状态机
职责:处理所有游戏动作、验证和状态转换
// 行动类型定义
type Action =
| MoveAction
| AttackUnitAction
| AttackBuildingAction
| CaptureAction
| CreateUnitAction
| CreateBuildingAction
| EndTurnAction
| HealAction
// ... 等20多种
// 执行游戏动作
function execute(
map: MapData,
vision: VisionT,
action: Action,
mutateAction?: MutateActionResponseFn,
): [ActionResponse, MapData] | null
关键设计模式:
-
Command Pattern(命令模式)
- 每个玩家操作都是一个
Action对象 - 通过
execute()函数转换为ActionResponse - 可以编码/解码用于网络传输
- 每个玩家操作都是一个
-
Immutable State Pattern(不可变状态模式)
type GameState = ReadonlyArray<[ActionResponse, MapData]>; // 每次动作都产生一个新的 (动作, 地图状态) 元组 -
Action Encoding(动作编码)
- 自动生成的编码/解码器(
codegen包) - 通过编码减小网络传输大小
- 支持游戏回放
- 自动生成的编码/解码器(
###3. HERA 包 - 渲染引擎和游戏逻辑层
职责:游戏的视觉呈现和交互管理(最复杂的包)
####3.1 渲染系统
采用 混合渲染方案:
// Canvas 2D 用于瓦片地图渲染(性能优先)
const Tiles = ({ map, tileSize, vision }) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
useLayoutEffect(() => {
const canvas = canvasRef.current!;
const context = canvas.getContext('2d')!;
// 预渲染所有地形瓦片到 Canvas
map.forEachTile((vector, tile, layer, modifier) => {
renderTile(context, tileset, map, vision, frame, vector, ...);
});
}, [map, vision]);
};
// React/Framer Motion 用于精灵和动画
const Unit = ({ position, unit, animation }) => (
<motion.div
initial={initialPosition}
animate={targetPosition}
transition={{ duration: animationDuration }}
>
<img src={unitSprite} />
</motion.div>
);
性能优化:
- Canvas 预渲染:地形、建筑、装饰物一次性渲染到 Canvas
- 虚拟化:只渲染视口内的精灵
- Memoization:缓存帧计算结果
- RequestAnimationFrame:帧同步渲染
####3.2 GameMap 组件 - 核心状态管理
这是整个游戏逻辑的中枢,采用 Class Component 架构(性能和稳定性):
class GameMap extends Component<Props, State> {
// 核心状态
state: State = {
map: MapData;
animations: Animations; // 当前运行的所有动画
selectedUnit: Unit | null;
selectedPosition: Vector | null;
behavior: MapBehavior | null; // 当前行为模式
vision: VisionT;
radius: RadiusInfo | null; // 选中单位的可移动范围
// ... 40+ 个状态字段
};
// 输入处理
private _navigate = (direction: NavigationDirection) => {
// 网格导航逻辑
};
private _select = (vector: Vector) => {
// 选择单位/建筑
};
private _action = (action: Action) => {
// 执行游戏动作 -> 发送到 Worker -> 处理响应
};
// 异步动作队列(保证顺序执行)
private _actionQueue: Promise<void> | null = null;
}
核心特性:
-
Behavior Pattern(行为模式)
interface MapBehavior { type: string; select?: (vector: Vector, state: State, actions: Actions) => StateLike | null; enter?: (vector: Vector, state: State, actions: Actions) => StateLike | null; activate?: (state: State, actions: Actions) => StateLike | null; deactivate?: (actions: Actions) => StateLike | null; } // 子类:BaseB行为、MenuBehavior、MoveBehavior、AttackBehavior 等 -
动画队列系统
// 所有动画使用 ImmutableMap 管理 animations: ImmutableMap<AnimationKey, Animation> // 动画完成后自动移除 // 支持并发播放多个动画
####3.3 动画系统
采用 Framer Motion 和 自定义计时器:
// 动画类型(20+ 种)
type Animation =
| MoveAnimation
| AttackAnimation
| ExplosionAnimation
| HealAnimation
| SpawnAnimation
| DamageAnimation
| UpgradeAnimation
// ...
// 动画配置(可调整速度)
type AnimationConfig = {
AnimationDuration: number; // 单位移动时间
ExplosionStep: number;
BaseEffectDuration: number;
};
// 动画渲染
<MapAnimations
animations={state.animations}
animationConfig={state.animationConfig}
position={position}
onAnimationComplete={handleAnimationComplete}
/>
###4. 输入处理系统
// 统一的输入抽象层
import Input from '@deities/ui/controls/Input.tsx';
Input.register('navigate', handleNavigate);
Input.register('accept', handleAccept);
Input.register('cancel', handleCancel);
// 支持多种输入:
// - 键盘
// - 鼠标/触摸(指针事件)
// - 游戏手柄(gamepad)
// - 移动设备长按
###5. 网络和 Worker 系统
采用 Web Worker 处理昂贵的游戏逻辑计算:
// hera/workers/gameAction.tsx - Worker 线程
self.onmessage = async (event: MessageEvent<ClientGameActionRequest>) => {
const [plainMap, encodedEffects, action, mutateAction] = event.data;
const map = MapData.fromObject(plainMap);
// 在 Worker 中执行 Apollo 的 execute() 函数
const [actionResponse, initialActiveMap, gameState] =
await executeGameAction(map, vision, effects, action);
// 发送结果回主线程
event.ports[0].postMessage([
encodeActionResponse(actionResponse),
initialActiveMap.toJSON(),
encodeGameState(gameState),
]);
};
优势:
- 不阻塞 UI 线程的复杂计算
- AI 决策在 Worker 中进行
- 路径寻找、伤害计算等卸载到后台
###6. UI 设计系统
采用 @emotion/css 实现样式:
// 像素艺术风格的设计系统
const pixelatedStyle = css`
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
`;
// CSS 变量管理
const cssVar = (name: string) => `--${name}`;
applyVar('scale', 2); // 全局缩放
// 响应式布局
getInlineUIState(map, tileSize, scale) {
return window.innerWidth > scale * (map.size.width + 2) * tileSize;
}
##🔄 游戏流程和状态转换
###一个完整的游戏回合流程
1. 用户输入 (keyboard/mouse/gamepad)
↓
2. Input 事件处理 -> 转换为 Action
↓
3. GameMap._action()
├─ 验证动作的合法性 (execute in apollo)
├─ 发送到 Worker 处理
├─ 编码结果以减小大小
└─ 网络发送 (如果是多人)
↓
4. onAction() 回调获得 GameActionResponse
├─ actionResponse (动作结果)
├─ initialActiveMap (变化前的地图)
└─ gameState (完整的游戏状态)
↓
5. processActionResponse() 处理响应
├─ 应用动画效果
├─ 播放音效
├─ 更新 UI
└─ 生成下一个 Animation
↓
6. MapAnimations 播放所有动画
├─ Move 动画
├─ Attack 动画
├─ Damage 数字飘动
└─ 特效 (爆炸、治疗等)
↓
7. 动画完成 -> 状态更新
↓
8. Behavior 模式转换
└─ 返回到选择单位状态
##🚀 性能优化策略
###1. 数据结构优化
// 使用 ImmutableMap 而非普通对象
// 优势:
// - O(1) 克隆操作(结构共享)
// - 自动追踪变化
// - 支持时间旅行调试
const units = ImmutableMap<Vector, Unit>()
.set(vec(1, 1), unit1)
.set(vec(2, 2), unit2);
// 克隆整个 Map 的成本 = O(1),不是 O(n)
const newUnits = units.set(vec(3, 3), unit3);
###2. 渲染优化
// Canvas 预渲染地形
// 只使用 React 管理动动画的精灵层
// 使用 memo 避免不必要的重渲染
export default memo(function Unit({ unit, position }) {
// ...
});
// 虚拟化长列表
<ListVirtualizer>
{units.map(unit => <UnitCard />)}
</ListVirtualizer>
###3. 计算优化
// 缓存帧计算
const frameCache = new Map<AttackSprite, CSSProperties[]>();
const getFrames = (sprite: AttackSprite) => {
const cached = frameCache.get(sprite);
if (cached) return cached;
const frames = generateFrames(sprite);
frameCache.set(sprite, frames);
return frames;
};
// 使用 fastpriorityqueue 优化 A* 寻路
import FastPriorityQueue from 'fastpriorityqueue';
// 时间预算:控制每帧最多做多少计算
// 防止卡顿
###4. 内存优化
// 对大地图使用编码存储
function encodeGameState(gameState: GameState): EncodedGameState {
return gameState.map(([actionResponse, map]) => [
encodeActionResponse(actionResponse), // 压缩
map.toJSON(),
]);
}
// 支持游戏回放而无需存储完整状态快照
##🎮 AI 系统实现
采用 分层 AI 架构:
// dionysus/BaseAI.tsx
abstract class BaseAI {
protected gameState: GameState = [];
protected execute(map: MapData, action: Action): MapData | null {
const response = execute(map, this.getVision(map), action);
if (response) {
this.appendActionResponse(response[0], map, response[1]);
return this.gameState.at(-1)?.[1] || null;
}
return null;
}
// 子类覆盖此方法实现特定 AI 策略
abstract getTurn(map: MapData): Action | null;
}
// dionysus/DionysusAlpha.tsx - 实现具体 AI 策略
class DionysusAlpha extends BaseAI {
getTurn(map: MapData): Action | null {
// 评估所有可能的动作
// 返回最优的动作
return this.findBestAction(map);
}
}
##📦 技术栈总结
| 层级 | 技术 | 用途 |
|---|---|---|
| UI 框架 | React 19 + TypeScript | 组件化 UI |
| 样式 | @emotion/css | CSS-in-JS |
| 动画 | Framer Motion 12 | 平滑动画 |
| 路由 | React Router 7 | 页面导航 |
| 音效 | Howler.js | 音频处理 |
| 构建 | Vite 7 | 快速构建 |
| 编译 | SWC | 超快速编译 |
| 代码生成 | fbtee | i18n 和编码生成 |
| 数据结构 | ImmutableMap | 不可变状态 |
| 算法 | fastpriorityqueue | A* 寻路 |
| 工作线程 | Web Worker | 后台计算 |
##🔑 关键设计模式总结
- Command Pattern - 游戏动作作为可序列化的命令
- State Pattern - 每个玩家回合的不同行为模式
- Observer Pattern - 事件驱动的输入系统
- Strategy Pattern - 可插拔的 AI 策略
- Factory Pattern - 动画和行为的创建
- Immutable State - 所有游戏状态都是不可变的
- Worker Thread - 后台线程处理复杂计算
##🎯 为什么这样设计
- 可维护性:模块化设计,每个包责任单一
- 可重用性:Apollo 和 Athena 既可用于 Client 也可用于 Server
- 性能:Canvas 渲染 + Worker 计算 + 不可变数据结构
- 测试性:每个包都有单独的测试,支持快照测试
- 可扩展性:易于添加新的 AI 策略、行为、动画
- 回放支持:所有游戏动作可以编码/解码,支持完整的游戏回放
这个架构是一个生产级别的游戏引擎架构,既考虑了性能,也考虑了可维护性和扩展性。
END OF POST