Files
esengine/docs/getting-started.md

508 lines
14 KiB
Markdown
Raw Normal View History

# 快速入门
本指南将帮助您快速上手 ECS Framework这是一个专业级的实体组件系统框架采用现代化架构设计专为高性能游戏开发打造。
2025-06-10 13:22:28 +08:00
## 安装
2025-06-08 21:50:50 +08:00
```bash
npm install @esengine/ecs-framework
```
2025-06-12 09:42:35 +08:00
## 更新机制说明
ECS框架需要在游戏引擎的更新循环中调用并传入deltaTime
```typescript
// 统一的更新方式让外部引擎传入deltaTime
Core.update(deltaTime);
```
2025-06-12 09:47:25 +08:00
**不同平台的集成方式:**
2025-06-12 09:42:35 +08:00
- **Laya引擎**:使用 `Laya.timer.delta / 1000`
- **Cocos Creator**:使用组件的 `update(deltaTime)` 参数
- **原生浏览器**自己计算deltaTime
- **Node.js服务器**自己计算deltaTime
**优势:**
- 与引擎时间系统完全同步
- 支持引擎的时间缩放和暂停功能
- 更精确的时间控制
- 统一的API简化集成
2025-06-10 13:22:28 +08:00
## 平台集成
2025-06-10 13:22:28 +08:00
### Laya引擎
2025-06-10 13:22:28 +08:00
```typescript
import { Scene as LayaScene } from "laya/display/Scene";
import { Core, Scene as ECSScene, EntityManager, EntitySystem } from '@esengine/ecs-framework';
2025-06-10 13:22:28 +08:00
class LayaECSGame extends LayaScene {
private ecsScene: ECSScene;
private entityManager: EntityManager;
constructor() {
super();
// 初始化ECS框架
Core.create(true);
this.ecsScene = new ECSScene();
this.ecsScene.name = "LayaGameScene";
Core.scene = this.ecsScene;
this.entityManager = new EntityManager();
this.setupSystems();
}
onAwake(): void {
super.onAwake();
// 使用Laya的帧循环更新ECS
Laya.timer.frameLoop(1, this, this.updateECS);
}
onDestroy(): void {
Laya.timer.clear(this, this.updateECS);
super.onDestroy();
}
private updateECS(): void {
2025-06-12 09:42:35 +08:00
// 使用Laya的deltaTime更新ECS
const deltaTime = Laya.timer.delta / 1000; // 转换为秒
Core.update(deltaTime);
2025-06-10 13:22:28 +08:00
}
private setupSystems(): void {
this.ecsScene.addEntityProcessor(new LayaRenderSystem(this));
this.ecsScene.addEntityProcessor(new MovementSystem());
}
}
2025-06-08 21:50:50 +08:00
2025-06-10 13:22:28 +08:00
// Laya渲染系统
class LayaRenderSystem extends EntitySystem {
private layaScene: LayaScene;
constructor(layaScene: LayaScene) {
super(Matcher.empty().all(PositionComponent, SpriteComponent));
this.layaScene = layaScene;
}
protected process(entities: Entity[]): void {
entities.forEach(entity => {
const pos = entity.getComponent(PositionComponent);
const sprite = entity.getComponent(SpriteComponent);
if (pos && sprite && sprite.layaSprite) {
sprite.layaSprite.x = pos.x;
sprite.layaSprite.y = pos.y;
}
});
}
}
2025-06-10 13:12:14 +08:00
2025-06-10 13:22:28 +08:00
// 使用方法
Laya.Scene.open("GameScene.scene", false, null, null, LayaECSGame);
```
2025-06-10 13:22:28 +08:00
### Cocos Creator
```typescript
2025-06-10 13:22:28 +08:00
import { Component as CocosComponent, _decorator } from 'cc';
import { Core, Scene as ECSScene, EntityManager, EntitySystem } from '@esengine/ecs-framework';
const { ccclass, property } = _decorator;
@ccclass('ECSGameManager')
export class ECSGameManager extends CocosComponent {
private ecsScene: ECSScene;
private entityManager: EntityManager;
start() {
// 初始化ECS框架
Core.create(true);
this.ecsScene = new ECSScene();
this.ecsScene.name = "CocosGameScene";
Core.scene = this.ecsScene;
this.entityManager = new EntityManager();
this.setupSystems();
}
update(deltaTime: number) {
2025-06-12 09:42:35 +08:00
// 使用Cocos Creator的deltaTime更新ECS
Core.update(deltaTime);
2025-06-10 13:22:28 +08:00
}
onDestroy() {
if (this.ecsScene) {
this.ecsScene.onDestroy();
}
}
private setupSystems(): void {
this.ecsScene.addEntityProcessor(new CocosRenderSystem(this.node));
this.ecsScene.addEntityProcessor(new MovementSystem());
}
public getEntityManager(): EntityManager {
return this.entityManager;
}
}
// Cocos渲染系统
class CocosRenderSystem extends EntitySystem {
private rootNode: Node;
constructor(rootNode: Node) {
super(Matcher.empty().all(PositionComponent, SpriteComponent));
this.rootNode = rootNode;
}
protected process(entities: Entity[]): void {
entities.forEach(entity => {
const pos = entity.getComponent(PositionComponent);
const sprite = entity.getComponent(SpriteComponent);
if (pos && sprite && sprite.cocosNode) {
sprite.cocosNode.setPosition(pos.x, pos.y);
}
});
}
}
// 将ECSGameManager脚本挂载到场景根节点
```
2025-06-10 13:22:28 +08:00
### Node.js后端
```typescript
2025-06-10 13:22:28 +08:00
import { Core, Scene, EntityManager, EntitySystem, Time } from '@esengine/ecs-framework';
class ServerGameManager {
private scene: Scene;
private entityManager: EntityManager;
2025-06-10 13:22:28 +08:00
private isRunning: boolean = false;
private tickRate: number = 60; // 60 TPS
private lastUpdate: number = Date.now();
constructor() {
2025-06-10 13:22:28 +08:00
Core.create(true);
this.scene = new Scene();
2025-06-10 13:22:28 +08:00
this.scene.name = "ServerScene";
Core.scene = this.scene;
2025-06-08 21:50:50 +08:00
2025-06-10 13:12:14 +08:00
this.entityManager = new EntityManager();
2025-06-10 13:22:28 +08:00
this.setupSystems();
}
public start(): void {
this.isRunning = true;
console.log(`游戏服务器启动TPS: ${this.tickRate}`);
this.gameLoop();
}
public stop(): void {
this.isRunning = false;
2025-06-08 21:50:50 +08:00
}
2025-06-10 13:22:28 +08:00
private gameLoop(): void {
if (!this.isRunning) return;
const now = Date.now();
const deltaTime = (now - this.lastUpdate) / 1000;
this.lastUpdate = now;
2025-06-12 09:42:35 +08:00
// 使用计算出的deltaTime更新ECS
Core.update(deltaTime);
2025-06-10 13:22:28 +08:00
const frameTime = 1000 / this.tickRate;
const processingTime = Date.now() - now;
const delay = Math.max(0, frameTime - processingTime);
setTimeout(() => this.gameLoop(), delay);
}
2025-06-10 13:22:28 +08:00
private setupSystems(): void {
this.scene.addEntityProcessor(new ServerMovementSystem());
this.scene.addEntityProcessor(new NetworkSyncSystem());
this.scene.addEntityProcessor(new AISystem());
}
2025-06-10 13:22:28 +08:00
public handlePlayerInput(playerId: string, input: any): void {
const playerEntity = this.findPlayerEntity(playerId);
if (playerEntity) {
const inputComp = playerEntity.getComponent(InputComponent);
if (inputComp) {
inputComp.updateInput(input);
}
}
}
public getWorldState(): any {
const entities = this.entityManager
.query()
.withAll(PositionComponent, NetworkComponent)
.execute();
return entities.map(entity => ({
id: entity.id,
position: entity.getComponent(PositionComponent),
}));
}
private findPlayerEntity(playerId: string): Entity | null {
const players = this.entityManager
.query()
.withAll(PlayerComponent)
.execute();
return players.find(player =>
player.getComponent(PlayerComponent).playerId === playerId
) || null;
}
}
2025-06-10 13:22:28 +08:00
// 启动服务器
const server = new ServerGameManager();
server.start();
```
2025-06-10 13:22:28 +08:00
### 原生浏览器
```typescript
2025-06-10 13:22:28 +08:00
import { Core, Scene, EntityManager, EntitySystem } from '@esengine/ecs-framework';
2025-06-10 13:22:28 +08:00
class BrowserGame {
private scene: Scene;
private entityManager: EntityManager;
constructor() {
Core.create(true);
this.scene = new Scene();
this.scene.name = "BrowserScene";
Core.scene = this.scene;
this.entityManager = new EntityManager();
this.setupSystems();
}
public start(): void {
this.createEntities();
this.gameLoop();
}
private gameLoop(): void {
2025-06-12 09:42:35 +08:00
let lastTime = 0;
const update = (currentTime: number) => {
// 计算deltaTime并更新ECS原生浏览器环境
const deltaTime = lastTime > 0 ? (currentTime - lastTime) / 1000 : 0.016;
lastTime = currentTime;
Core.update(deltaTime);
2025-06-10 13:22:28 +08:00
requestAnimationFrame(update);
};
2025-06-12 09:42:35 +08:00
requestAnimationFrame(update);
2025-06-10 13:22:28 +08:00
}
2025-06-10 13:22:28 +08:00
private setupSystems(): void {
this.scene.addEntityProcessor(new MovementSystem());
this.scene.addEntityProcessor(new RenderSystem());
}
2025-06-10 13:22:28 +08:00
private createEntities(): void {
const player = this.entityManager.createEntity("Player");
player.addComponent(new PositionComponent(400, 300));
player.addComponent(new VelocityComponent(0, 0));
}
}
2025-06-10 13:22:28 +08:00
const game = new BrowserGame();
game.start();
```
2025-06-10 13:22:28 +08:00
## 基础组件定义
```typescript
2025-06-10 13:22:28 +08:00
import { Component } from '@esengine/ecs-framework';
2025-06-08 21:50:50 +08:00
// 位置组件
class PositionComponent extends Component {
public x: number = 0;
public y: number = 0;
constructor(x: number = 0, y: number = 0) {
super();
this.x = x;
this.y = y;
}
2025-06-08 21:50:50 +08:00
public reset() {
this.x = 0;
this.y = 0;
}
}
// 速度组件
class VelocityComponent extends Component {
public x: number = 0;
public y: number = 0;
constructor(x: number = 0, y: number = 0) {
super();
this.x = x;
this.y = y;
}
2025-06-08 21:50:50 +08:00
public reset() {
this.x = 0;
this.y = 0;
}
}
// 生命值组件
class HealthComponent extends Component {
public maxHealth: number = 100;
public currentHealth: number = 100;
constructor(maxHealth: number = 100) {
super();
this.maxHealth = maxHealth;
this.currentHealth = maxHealth;
}
2025-06-08 21:50:50 +08:00
public reset() {
this.maxHealth = 100;
this.currentHealth = 100;
}
public takeDamage(damage: number): void {
this.currentHealth = Math.max(0, this.currentHealth - damage);
}
public heal(amount: number): void {
this.currentHealth = Math.min(this.maxHealth, this.currentHealth + amount);
}
public isDead(): boolean {
return this.currentHealth <= 0;
}
}
```
2025-06-10 13:22:28 +08:00
## 基础系统创建
```typescript
2025-06-10 13:22:28 +08:00
import { EntitySystem, Entity, Matcher, Time } from '@esengine/ecs-framework';
2025-06-08 21:50:50 +08:00
class MovementSystem extends EntitySystem {
2025-06-10 13:12:14 +08:00
constructor() {
super(Matcher.empty().all(PositionComponent, VelocityComponent));
}
2025-06-08 21:50:50 +08:00
protected process(entities: Entity[]): void {
2025-06-10 13:12:14 +08:00
const movingEntities = this.scene.querySystem.queryAll(PositionComponent, VelocityComponent);
2025-06-10 13:12:14 +08:00
movingEntities.entities.forEach(entity => {
const position = entity.getComponent(PositionComponent);
const velocity = entity.getComponent(VelocityComponent);
if (position && velocity) {
2025-06-10 13:22:28 +08:00
position.x += velocity.x * Time.deltaTime;
position.y += velocity.y * Time.deltaTime;
}
});
}
2025-06-08 21:50:50 +08:00
}
class HealthSystem extends EntitySystem {
2025-06-10 13:12:14 +08:00
constructor() {
super(Matcher.empty().all(HealthComponent));
}
2025-06-08 21:50:50 +08:00
protected process(entities: Entity[]): void {
2025-06-10 13:12:14 +08:00
const healthEntities = this.scene.querySystem.queryAll(HealthComponent);
2025-06-10 13:12:14 +08:00
healthEntities.entities.forEach(entity => {
const health = entity.getComponent(HealthComponent);
if (health && health.currentHealth <= 0) {
entity.destroy();
}
});
}
}
```
2025-06-10 13:22:28 +08:00
## 实体管理
2025-06-10 13:22:28 +08:00
```typescript
// 创建实体
const player = entityManager.createEntity("Player");
player.addComponent(new PositionComponent(100, 100));
player.addComponent(new VelocityComponent(5, 0));
player.addComponent(new HealthComponent(100));
// 批量创建实体
const enemies = scene.createEntities(50, "Enemy");
enemies.forEach(enemy => {
enemy.addComponent(new PositionComponent(Math.random() * 800, Math.random() * 600));
enemy.addComponent(new HealthComponent(50));
});
// 查询实体
const movingEntities = entityManager
.query()
.withAll(PositionComponent, VelocityComponent)
.execute();
const healthEntities = entityManager.getEntitiesWithComponent(HealthComponent);
const enemiesByTag = entityManager.getEntitiesByTag(2);
```
## 事件系统
2025-06-12 09:42:35 +08:00
推荐使用Scene的事件系统或EntityManager的事件系统
```typescript
2025-06-12 09:42:35 +08:00
// 使用EntityManager的事件系统推荐
const eventBus = entityManager.eventBus;
// 监听ECS事件
eventBus.onEntityCreated((data) => {
console.log(`实体创建: ${data.entityName}`);
});
2025-06-08 21:50:50 +08:00
2025-06-12 09:42:35 +08:00
eventBus.onComponentAdded((data) => {
console.log(`组件添加: ${data.componentType}`);
});
2025-06-08 21:50:50 +08:00
// 发射自定义事件
2025-06-12 09:42:35 +08:00
eventBus.emit('player:died', { player: entity, score: 1000 });
2025-06-08 21:50:50 +08:00
2025-06-12 09:42:35 +08:00
// 使用装饰器自动注册事件监听器
import { EventHandler } from '@esengine/ecs-framework';
class GameSystem {
@EventHandler('player:died')
onPlayerDied(data: { player: Entity; score: number }) {
console.log(`玩家死亡,得分: ${data.score}`);
}
}
2025-06-08 21:50:50 +08:00
```
2025-06-10 13:22:28 +08:00
## 性能监控
```typescript
2025-06-10 13:22:28 +08:00
// 获取场景统计
2025-06-10 13:12:14 +08:00
const sceneStats = scene.getStats();
2025-06-10 13:22:28 +08:00
console.log('实体数量:', sceneStats.entityCount);
console.log('系统数量:', sceneStats.processorCount);
2025-06-10 13:12:14 +08:00
2025-06-10 13:22:28 +08:00
// 获取查询统计
2025-06-10 13:12:14 +08:00
const queryStats = scene.querySystem.getStats();
console.log('查询统计:', queryStats);
```
## 下一步
- [EntityManager 使用指南](entity-manager-example.md) - 详细了解实体管理器的高级功能
- [性能优化指南](performance-optimization.md) - 深入了解三大性能优化系统
- [核心概念](core-concepts.md) - 深入了解 ECS 架构和设计原理
2025-06-10 13:22:28 +08:00
- [查询系统使用指南](query-system-usage.md) - 学习高性能查询系统的详细用法