Loading...
Loading...
Compare original and translation side by side
// Good: Composable systems - each can be enabled/disabled independently
function applyVelocity(world: World) {}
function applyGravity(world: World) {}
function applyFriction(world: World) {}
function syncToDOM(world: World) {}
// Bad: Monolithic system - can't disable gravity without disabling everything
function updatePhysicsAndRender(world: World) {
// velocity, gravity, friction, DOM sync all in one function
}// 推荐:可组合System - 每个System可独立启用/禁用
function applyVelocity(world: World) {}
function applyGravity(world: World) {}
function applyFriction(world: World) {}
function syncToDOM(world: World) {}
// 不推荐:单体System - 无法在不关闭所有功能的情况下禁用重力
function updatePhysicsAndRender(world: World) {
// 速度、重力、摩擦力、DOM同步全部在一个函数中
}src/
├── core/ # Pure TypeScript, no view imports
│ ├── traits/
│ ├── systems/
│ ├── actions/
│ └── world.ts
└── features/ # View layer, organized by domainsrc/
├── core/ # 纯TypeScript代码,无视图导入
│ ├── traits/
│ ├── systems/
│ ├── actions/
│ └── world.ts
└── features/ # 视图层,按领域组织| Type | Syntax | Use when | Examples |
|---|---|---|---|
| SoA (Schema) | | Simple primitive data | |
| AoS (Callback) | | Complex objects/instances | |
| Tag | | No data, just a flag | |
| 类型 | 语法 | 适用场景 | 示例 |
|---|---|---|---|
| SoA(Schema) | | 简单原始数据 | |
| AoS(回调) | | 复杂对象/实例 | |
| 标签 | | 无数据,仅作为标记 | |
| Type | Pattern | Examples |
|---|---|---|
| Tags | Start with | |
| Relations | Prepositional | |
| Trait | Noun | |
| 类型 | 命名模式 | 示例 |
|---|---|---|
| 标签 | 以 | |
| Relation | 介词形式 | |
| Trait | 名词形式 | |
import { relation } from 'koota'
const ChildOf = relation({ autoDestroy: 'orphan' }) // Hierarchy
const Contains = relation({ store: { amount: 0 } }) // With data
const Targeting = relation({ exclusive: true }) // One target only
// Build graph
const parent = world.spawn()
const child = world.spawn(ChildOf(parent))
// Query children of parent
const children = world.query(ChildOf(parent))
// Query all entities with any ChildOf relation
const allChildren = world.query(ChildOf('*'))
// Get targets from entity
const items = entity.targetsFor(Contains) // Entity[]
const target = entity.targetFor(Targeting) // Entity | undefinedimport { relation } from 'koota'
const ChildOf = relation({ autoDestroy: 'orphan' }) // 层级结构
const Contains = relation({ store: { amount: 0 } }) // 携带数据
const Targeting = relation({ exclusive: true }) // 仅允许一个目标
// 构建图
const parent = world.spawn()
const child = world.spawn(ChildOf(parent))
// 查询parent的子实体
const children = world.query(ChildOf(parent))
// 查询所有带有ChildOf关联的实体
const allChildren = world.query(ChildOf('*'))
// 从实体获取目标
const items = entity.targetsFor(Contains) // Entity[]
const target = entity.targetFor(Targeting) // Entity | undefinedimport { trait, createWorld } from 'koota'
// 1. Define traits
const Position = trait({ x: 0, y: 0 })
const Velocity = trait({ x: 0, y: 0 })
const IsPlayer = trait()
// 2. Create world and spawn entities
const world = createWorld()
const player = world.spawn(Position({ x: 100, y: 50 }), Velocity, IsPlayer)
// 3. Query and update
world.query(Position, Velocity).updateEach(([pos, vel]) => {
pos.x += vel.x
pos.y += vel.y
})import { trait, createWorld } from 'koota'
// 1. 定义Trait
const Position = trait({ x: 0, y: 0 })
const Velocity = trait({ x: 0, y: 0 })
const IsPlayer = trait()
// 2. 创建World并生成实体
const world = createWorld()
const player = world.spawn(Position({ x: 100, y: 50 }), Velocity, IsPlayer)
// 3. 查询并更新
world.query(Position, Velocity).updateEach(([pos, vel]) => {
pos.x += vel.x
pos.y += vel.y
})// Spawn
const entity = world.spawn(Position, Velocity)
// Read/write traits
entity.get(Position) // Read trait data
entity.set(Position, { x: 10 }) // Write (triggers change events)
entity.add(IsPlayer) // Add trait
entity.remove(Velocity) // Remove trait
entity.has(Position) // Check if has trait
// Destroy
entity.destroy()entity.id() // Just the entity ID (reused after destroy)
entity // Full packed number (unique forever)TraitRecordentity.get()type PositionRecord = TraitRecord<typeof Position>// 生成实体
const entity = world.spawn(Position, Velocity)
// 读写Trait
entity.get(Position) // 读取Trait数据
entity.set(Position, { x: 10 }) // 写入(触发变更事件)
entity.add(IsPlayer) // 添加Trait
entity.remove(Velocity) // 移除Trait
entity.has(Position) // 检查是否拥有Trait
// 销毁实体
entity.destroy()entity.id() // 仅返回实体ID(销毁后可复用)
entity // 完整的打包数字(永久唯一)TraitRecordentity.get()type PositionRecord = TraitRecord<typeof Position>// Query and update
world.query(Position, Velocity).updateEach(([pos, vel]) => {
pos.x += vel.x
pos.y += vel.y
})
// Read-only iteration (no write-back)
const data: Array<{ x: number; y: number }> = []
world.query(Position, Velocity).readEach(([pos, vel]) => {
data.push({ x: pos.x, y: pos.y })
})
// Get first match
const player = world.queryFirst(IsPlayer, Position)
// Filter with modifiers
world.query(Position, Not(Velocity)) // Has Position but not Velocity
world.query(Or(IsPlayer, IsEnemy)) // Has either traitupdateEachreadEachNot()world.query(IsPlayer, Position, Velocity).updateEach(([pos, vel]) => {
// Array has 2 elements - IsPlayer (tag) excluded
})// 查询并更新
world.query(Position, Velocity).updateEach(([pos, vel]) => {
pos.x += vel.x
pos.y += vel.y
})
// 只读迭代(无写回操作)
const data: Array<{ x: number; y: number }> = []
world.query(Position, Velocity).readEach(([pos, vel]) => {
data.push({ x: pos.x, y: pos.y })
})
// 获取第一个匹配项
const player = world.queryFirst(IsPlayer, Position)
// 使用修饰符过滤
world.query(Position, Not(Velocity)) // 拥有Position但无Velocity
world.query(Or(IsPlayer, IsEnemy)) // 拥有任意一个TraitupdateEachreadEachNot()world.query(IsPlayer, Position, Velocity).updateEach(([pos, vel]) => {
// 数组包含2个元素 - IsPlayer(标签)被排除
})WorldEntity'koota''koota/react'entity.set()world.set()useTraitentity.changed(Trait)WorldEntity'koota''koota/react'entity.set()world.set()useTraitentity.changed(Trait)