Files
esengine/docs/use-cases.md
2025-06-10 13:12:14 +08:00

17 KiB
Raw Permalink Blame History

ECS框架使用场景示例

本文档展示ECS框架在不同类型游戏中的具体应用案例。

目录

  1. 小型休闲游戏
  2. 中型动作游戏
  3. 大型策略游戏
  4. MMO游戏

小型休闲游戏

场景:简单的飞机大战游戏

import { 
    Scene, 
    EntityManager, 
    Entity, 
    Component, 
    EntitySystem,
    Matcher 
} from '@esengine/ecs-framework';

// 组件定义
class PositionComponent extends Component {
    constructor(public x: number = 0, public y: number = 0) {
        super();
    }
}

class VelocityComponent extends Component {
    constructor(public x: number = 0, public y: number = 0) {
        super();
    }
}

class PlayerComponent extends Component {}
class EnemyComponent extends Component {}
class BulletComponent extends Component {}

// 游戏管理器
class PlaneWarGame {
    private scene: Scene;
    private entityManager: EntityManager;
    
    constructor() {
        this.scene = new Scene();
        this.entityManager = new EntityManager();
        this.setupGame();
    }
    
    private setupGame(): void {
        // 创建玩家
        const player = this.entityManager.createEntity("Player");
        player.addComponent(new PositionComponent(400, 500));
        player.addComponent(new VelocityComponent(0, 0));
        player.addComponent(new PlayerComponent());
        player.tag = 1; // 玩家标签
        
        // 创建敌人
        this.spawnEnemies(5);
        
        // 添加系统
        this.scene.addEntityProcessor(new MovementSystem());
        this.scene.addEntityProcessor(new CollisionSystem());
        this.scene.addEntityProcessor(new CleanupSystem());
    }
    
    private spawnEnemies(count: number): void {
        const enemies = this.scene.createEntities(count, "Enemy");
        enemies.forEach((enemy, index) => {
            enemy.addComponent(new PositionComponent(
                Math.random() * 800,
                -50
            ));
            enemy.addComponent(new VelocityComponent(0, 100));
            enemy.addComponent(new EnemyComponent());
            enemy.tag = 2; // 敌人标签
        });
    }
    
    public update(): void {
        this.scene.update();
    }
}

// 移动系统
class MovementSystem extends EntitySystem {
    constructor() {
        super(Matcher.empty().all(PositionComponent, VelocityComponent));
    }
    
    protected process(entities: Entity[]): void {
        const movingEntities = this.scene.querySystem.queryAll(
            PositionComponent, 
            VelocityComponent
        );
        
        movingEntities.entities.forEach(entity => {
            const pos = entity.getComponent(PositionComponent);
            const vel = entity.getComponent(VelocityComponent);
            
            pos.x += vel.x * Time.deltaTime;
            pos.y += vel.y * Time.deltaTime;
        });
    }
}

## 中型动作游戏

### 场景:2D平台跳跃游戏

```typescript
// 更复杂的组件
class HealthComponent extends Component {
    constructor(
        public maxHealth: number = 100,
        public currentHealth: number = 100
    ) {
        super();
    }
}

class AnimationComponent extends Component {
    constructor(
        public currentAnimation: string = "idle",
        public frameIndex: number = 0,
        public frameTime: number = 0
    ) {
        super();
    }
}

class PhysicsComponent extends Component {
    constructor(
        public mass: number = 1,
        public friction: number = 0.8,
        public isGrounded: boolean = false
    ) {
        super();
    }
}

// 平台游戏管理器
class PlatformGame {
    private scene: Scene;
    private entityManager: EntityManager;
    
    constructor() {
        this.scene = new Scene();
        this.entityManager = new EntityManager();
        this.setupGame();
    }
    
    private setupGame(): void {
        // 创建玩家
        this.createPlayer();
        
        // 创建敌人
        this.createEnemies(10);
        
        // 创建平台
        this.createPlatforms();
        
        // 添加系统(按更新顺序)
        this.scene.addEntityProcessor(new InputSystem()).updateOrder = 10;
        this.scene.addEntityProcessor(new PhysicsSystem()).updateOrder = 20;
        this.scene.addEntityProcessor(new AnimationSystem()).updateOrder = 30;
        this.scene.addEntityProcessor(new CombatSystem()).updateOrder = 40;
        this.scene.addEntityProcessor(new RenderSystem()).updateOrder = 50;
    }
    
    private createPlayer(): void {
        const player = this.entityManager.createEntity("Player");
        player.addComponent(new PositionComponent(100, 300));
        player.addComponent(new VelocityComponent(0, 0));
        player.addComponent(new HealthComponent(100));
        player.addComponent(new AnimationComponent("idle"));
        player.addComponent(new PhysicsComponent(1, 0.8));
        player.tag = 1;
    }
    
    private createEnemies(count: number): void {
        const enemies = this.scene.createEntities(count, "Enemy");
        enemies.forEach((enemy, index) => {
            enemy.addComponent(new PositionComponent(
                200 + index * 100,
                300
            ));
            enemy.addComponent(new VelocityComponent(0, 0));
            enemy.addComponent(new HealthComponent(50));
            enemy.addComponent(new AnimationComponent("patrol"));
            enemy.addComponent(new PhysicsComponent(0.8, 0.9));
            enemy.tag = 2;
        });
    }
    
    private createPlatforms(): void {
        const platforms = this.scene.createEntities(5, "Platform");
        platforms.forEach((platform, index) => {
            platform.addComponent(new PositionComponent(
                index * 200,
                400 + Math.random() * 100
            ));
            platform.tag = 3; // 平台标签
        });
    }
}

## 大型策略游戏

### 场景:即时战略游戏

```typescript
// 策略游戏组件
class UnitComponent extends Component {
    constructor(
        public unitType: string,
        public playerId: number,
        public level: number = 1
    ) {
        super();
    }
}

class AIComponent extends Component {
    constructor(
        public state: string = "idle",
        public target: Entity | null = null,
        public lastDecisionTime: number = 0
    ) {
        super();
    }
}

class ResourceComponent extends Component {
    constructor(
        public gold: number = 0,
        public wood: number = 0,
        public food: number = 0
    ) {
        super();
    }
}

// 策略游戏管理器
class StrategyGame {
    private scene: Scene;
    private entityManager: EntityManager;
    private players: Map<number, Entity> = new Map();
    
    constructor() {
        this.scene = new Scene();
        this.entityManager = new EntityManager();
        this.setupGame();
    }
    
    private setupGame(): void {
        // 创建玩家
        this.createPlayers(4);
        
        // 为每个玩家创建初始单位
        this.players.forEach((player, playerId) => {
            this.createInitialUnits(playerId, 10);
        });
        
        // 添加系统
        this.scene.addEntityProcessor(new AISystem()).updateOrder = 10;
        this.scene.addEntityProcessor(new CombatSystem()).updateOrder = 20;
        this.scene.addEntityProcessor(new ResourceSystem()).updateOrder = 30;
        this.scene.addEntityProcessor(new UnitManagementSystem()).updateOrder = 40;
    }
    
    private createPlayers(count: number): void {
        for (let i = 0; i < count; i++) {
            const player = this.entityManager.createEntity(`Player_${i}`);
            player.addComponent(new ResourceComponent(1000, 500, 100));
            player.tag = 10 + i; // 玩家标签从10开始
            this.players.set(i, player);
        }
    }
    
    private createInitialUnits(playerId: number, count: number): void {
        const units = this.scene.createEntities(count, `Unit_${playerId}`);
        
        units.forEach((unit, index) => {
            unit.addComponent(new PositionComponent(
                playerId * 200 + Math.random() * 100,
                playerId * 200 + Math.random() * 100
            ));
            unit.addComponent(new UnitComponent("warrior", playerId));
            unit.addComponent(new HealthComponent(100));
            unit.addComponent(new AIComponent());
            unit.tag = 20 + playerId; // 单位标签
        });
    }
    
    // 批量单位操作
    public createArmy(playerId: number, unitType: string, count: number): Entity[] {
        const units = this.scene.createEntities(count, `${unitType}_${playerId}`);
        
        // 批量配置组件
        units.forEach(unit => {
            unit.addComponent(new UnitComponent(unitType, playerId));
            unit.addComponent(new HealthComponent(100));
            unit.addComponent(new PositionComponent(
                Math.random() * 1000,
                Math.random() * 1000
            ));
            unit.tag = 20 + playerId;
        });
        
        return units;
    }
    
    // 查询玩家的所有单位
    public getPlayerUnits(playerId: number): Entity[] {
        return this.entityManager
            .query()
            .withAll(UnitComponent)
            .withTag(20 + playerId)
            .execute();
    }
    
    // 查询特定类型的单位
    public getUnitsByType(unitType: string): Entity[] {
        return this.entityManager
            .query()
            .withAll(UnitComponent)
            .where(entity => {
                const unit = entity.getComponent(UnitComponent);
                return unit && unit.unitType === unitType;
            })
            .execute();
    }
}

// AI系统
class AISystem extends EntitySystem {
    constructor() {
        super(Matcher.empty().all(AIComponent, UnitComponent));
    }
    
    protected process(entities: Entity[]): void {
        const aiUnits = this.entityManager
            .query()
            .withAll(AIComponent, UnitComponent)
            .execute();
        
        aiUnits.forEach(unit => {
            this.processAI(unit);
        });
    }
    
    private processAI(unit: Entity): void {
        const ai = unit.getComponent(AIComponent);
        const unitComp = unit.getComponent(UnitComponent);
        
        if (!ai || !unitComp) return;
        
        // 简单AI逻辑
        switch (ai.state) {
            case "idle":
                this.findTarget(unit);
                break;
            case "attack":
                this.attackTarget(unit);
                break;
            case "move":
                this.moveToTarget(unit);
                break;
        }
    }
    
    private findTarget(unit: Entity): void {
        const unitComp = unit.getComponent(UnitComponent);
        if (!unitComp) return;
        
        // 查找敌方单位
        const enemies = this.entityManager
            .query()
            .withAll(UnitComponent)
            .where(entity => {
                const enemyUnit = entity.getComponent(UnitComponent);
                return enemyUnit && enemyUnit.playerId !== unitComp.playerId;
            })
            .execute();
        
        if (enemies.length > 0) {
            const ai = unit.getComponent(AIComponent);
            if (ai) {
                ai.target = enemies[0];
                ai.state = "attack";
            }
        }
    }
    
    private attackTarget(unit: Entity): void {
        // 攻击逻辑
    }
    
    private moveToTarget(unit: Entity): void {
        // 移动逻辑
    }
}

## MMO游戏

### 场景:大型多人在线游戏

```typescript
// MMO特有组件
class NetworkComponent extends Component {
    constructor(
        public playerId: string,
        public isLocal: boolean = false,
        public lastSyncTime: number = 0
    ) {
        super();
    }
}

class InventoryComponent extends Component {
    public items: Map<string, number> = new Map();
    
    addItem(itemId: string, count: number): void {
        const current = this.items.get(itemId) || 0;
        this.items.set(itemId, current + count);
    }
}

class GuildComponent extends Component {
    constructor(
        public guildId: string,
        public rank: string = "member"
    ) {
        super();
    }
}

// MMO游戏管理器
class MMOGame {
    private scene: Scene;
    private entityManager: EntityManager;
    private localPlayerId: string;
    
    constructor(localPlayerId: string) {
        this.scene = new Scene();
        this.entityManager = new EntityManager();
        this.localPlayerId = localPlayerId;
        this.setupGame();
    }
    
    private setupGame(): void {
        // 添加MMO特有系统
        this.scene.addEntityProcessor(new NetworkSyncSystem()).updateOrder = 5;
        this.scene.addEntityProcessor(new PlayerSystem()).updateOrder = 10;
        this.scene.addEntityProcessor(new NPCSystem()).updateOrder = 15;
        this.scene.addEntityProcessor(new GuildSystem()).updateOrder = 20;
        this.scene.addEntityProcessor(new InventorySystem()).updateOrder = 25;
    }
    
    // 创建玩家角色
    public createPlayer(playerId: string, isLocal: boolean = false): Entity {
        const player = this.entityManager.createEntity(`Player_${playerId}`);
        player.addComponent(new PositionComponent(0, 0));
        player.addComponent(new HealthComponent(1000));
        player.addComponent(new NetworkComponent(playerId, isLocal));
        player.addComponent(new InventoryComponent());
        player.tag = isLocal ? 1 : 2; // 本地玩家标签1远程玩家标签2
        
        return player;
    }
    
    // 批量创建NPC
    public createNPCs(count: number): Entity[] {
        const npcs = this.scene.createEntities(count, "NPC");
        
        npcs.forEach((npc, index) => {
            npc.addComponent(new PositionComponent(
                Math.random() * 2000,
                Math.random() * 2000
            ));
            npc.addComponent(new HealthComponent(500));
            npc.addComponent(new AIComponent("patrol"));
            npc.tag = 3; // NPC标签
        });
        
        return npcs;
    }
    
    // 查询附近的玩家
    public getNearbyPlayers(centerX: number, centerY: number, radius: number): Entity[] {
        return this.entityManager
            .query()
            .withAll(PositionComponent, NetworkComponent)
            .where(entity => {
                const pos = entity.getComponent(PositionComponent);
                if (!pos) return false;
                
                const distance = Math.sqrt(
                    Math.pow(pos.x - centerX, 2) + 
                    Math.pow(pos.y - centerY, 2)
                );
                return distance <= radius;
            })
            .execute();
    }
    
    // 查询公会成员
    public getGuildMembers(guildId: string): Entity[] {
        return this.entityManager
            .query()
            .withAll(GuildComponent, NetworkComponent)
            .where(entity => {
                const guild = entity.getComponent(GuildComponent);
                return guild && guild.guildId === guildId;
            })
            .execute();
    }
    
    // 获取在线玩家统计
    public getOnlinePlayerStats(): any {
        const allPlayers = this.entityManager.getEntitiesWithComponent(NetworkComponent);
        const localPlayers = this.entityManager.getEntitiesByTag(1);
        const remotePlayers = this.entityManager.getEntitiesByTag(2);
        
        return {
            total: allPlayers.length,
            local: localPlayers.length,
            remote: remotePlayers.length
        };
    }
}

// 网络同步系统
class NetworkSyncSystem extends EntitySystem {
    constructor() {
        super(Matcher.empty().all(NetworkComponent));
    }
    
    protected process(entities: Entity[]): void {
        const networkEntities = this.entityManager.getEntitiesWithComponent(NetworkComponent);
        
        networkEntities.forEach(entity => {
            const network = entity.getComponent(NetworkComponent);
            if (!network || network.isLocal) return;
            
            // 同步远程实体数据
            this.syncRemoteEntity(entity);
        });
    }
    
    private syncRemoteEntity(entity: Entity): void {
        // 网络同步逻辑
        const network = entity.getComponent(NetworkComponent);
        if (!network) return;
        
        const currentTime = Date.now();
        if (currentTime - network.lastSyncTime > 100) { // 100ms同步一次
            // 发送同步数据
            network.lastSyncTime = currentTime;
        }
    }
}

## 性能优化建议

### 小型游戏(< 1000实体
- 使用简单的查询方法
- 不需要复杂的优化
- 重点关注代码可读性

### 中型游戏1000-10000实体
- 使用标签查询优化性能
- 实现基础的对象池
- 缓存频繁查询的结果

### 大型游戏10000-100000实体
- 使用时间分片处理大量实体
- 实现空间分区优化邻近查询
- 使用批量操作减少单次调用开销

### MMO游戏100000+实体)
- 实现分区管理,只处理相关区域的实体
- 使用异步处理避免阻塞主线程
- 实现智能缓存和预加载机制

## 总结

ECS框架的灵活性使其能够适应各种规模的游戏开发需求

1. **小型游戏**:简单直接,快速开发
2. **中型游戏**:平衡性能和复杂度
3. **大型游戏**:充分利用优化特性
4. **MMO游戏**:处理海量实体和复杂交互

选择合适的架构模式和优化策略可以让ECS框架在不同场景下都发挥最佳性能。