# 节点的创建与销毁

本文将介绍如何在神岛引擎中创建和销毁节点，以及相关的最佳实践。

## 创建节点

### 基础创建方法

```typescript
// 创建节点并绑定实体
const entity = world.querySelector("#实体名字");
const playerNode = new EntityNode(entity);
```

### 创建带组件的节点

```typescript
@apclass("PlayerComponent")
class PlayerComponent extends Component<GameEntity> {
  speed = 5;
}

// 方法1：先创建节点，再添加组件
const node = new EntityNode();
node.addComponent(PlayerComponent);

// 方法2：链式调用添加多个组件
const node2 = new EntityNode()
  .addComponent(PlayerComponent)
  .addComponent(HealthComponent)
  .addComponent(InputComponent);
```

### 创建预制体节点

```typescript
// 定义预制体配置
const playerPrefab = {
  components: [
    {
      type: "PlayerComponent",
      props: { speed: 10 },
    },
    {
      type: "HealthComponent",
      props: { maxHealth: 100 },
    },
  ],
};

// 从预制体创建节点
function createFromPrefab(prefab: any): EntityNode {
  const node = new EntityNode();

  prefab.components.forEach((comp) => {
    node.addComponent(comp.type, comp.props);
  });

  return node;
}

// 使用预制体创建节点
const playerNode = createFromPrefab(playerPrefab);
```

## 销毁节点

### 基础销毁方法

```typescript
@apclass("GameManager")
class GameManager extends Component<GameEntity> {
  private playerNode: EntityNode | null = null;

  start() {
    this.playerNode = new EntityNode();
  }

  destroyPlayer() {
    if (this.playerNode) {
      // 销毁节点
      this.playerNode.destroy();
      this.playerNode = null;
    }
  }
}
```

### 销毁生命周期

```typescript
@apclass("PlayerComponent")
class PlayerComponent extends Component<GameEntity> {
  start() {
    console.log("玩家组件启动");
  }

  onDestroy() {
    // 在组件被销毁前执行清理工作
    console.log("玩家组件即将销毁");
    this.cleanup();
  }

  private cleanup() {
    // 清理资源、取消事件监听等
  }
}
```

## 最佳实践

### 1. 节点池管理

```typescript
class NodePool {
  private static pools: Map<string, EntityNode[]> = new Map();

  static obtain(name: string): EntityNode {
    const pool = this.pools.get(name) || [];
    return pool.pop() || this.createNode(name);
  }

  static recycle(name: string, node: EntityNode) {
    if (!this.pools.has(name)) {
      this.pools.set(name, []);
    }
    this.pools.get(name)?.push(node);
  }

  private static createNode(name: string): EntityNode {
    // 根据名称创建对应类型的节点
    return new EntityNode();
  }
}

// 使用节点池
const bullet = NodePool.obtain("bullet");
// ... 使用节点 ...
NodePool.recycle("bullet", bullet);
```

### 2. 安全的销毁检查

```typescript
@apclass("SafeComponent")
class SafeComponent extends Component<GameEntity> {
  private timers: number[] = [];
  private eventHandlers: Function[] = [];

  start() {
    // 注册事件和定时器
    this.eventHandlers.push(
      world.onPress(() => {
        console.log("按键事件");
      })
    );

    this.timers.push(
      setInterval(() => {
        console.log("定时器执行");
      }, 1000)
    );
  }

  onDestroy() {
    // 清理所有事件监听
    this.eventHandlers.forEach((handler) => {
      handler.cancel();
    });

    // 清理所有定时器
    this.timers.forEach((timer) => {
      clearInterval(timer);
    });
  }
}
```

## 注意事项

1. **内存管理**

   - 及时销毁不需要的节点
   - 使用节点池管理频繁创建/销毁的对象
   - 销毁节点时清理所有资源和引用

2. **销毁顺序**

   - 节点销毁时会自动销毁其上的所有组件
   - 组件的 onDestroy 会在节点销毁时被调用
   - 确保在 onDestroy 中清理所有资源

3. **引用管理**
   - 销毁节点后将其引用设为 null
   - 检查节点是否已被销毁后再使用
   - 避免保留已销毁节点的引用

## 常见问题

### Q: 节点销毁后还能重新使用吗？

A: 不能。节点一旦销毁就无法恢复，需要创建新的节点。建议使用节点池进行管理。

### Q: 销毁节点时需要手动销毁组件吗？

A: 不需要。节点销毁时会自动销毁其上的所有组件。
