访问节点和组件
在神岛引擎的组件系统中,了解如何正确访问节点和组件是开发的基础。本文将详细介绍相关操作方法。
访问节点
1. 创建节点
typescript
// 创建节点时绑定实体
const playerNode = new EntityNode(world.querySelector("#实体名称"));
2. 查找已有节点
typescript
import { find } from "@dao3fun/component";
// 通过实体查找对应的节点
const entity = world.querySelector("#NPC");
new EntityNode(entity);
const node = find(entity);
if (node) {
console.log("找到节点!节点uuid:", node.uuid);
} else {
console.log("未找到节点!");
}
3. 在组件中访问当前节点
typescript
@apclass("PlayerComponent")
export class PlayerComponent extends Component<GameEntity> {
start() {
// 通过 this.node 访问当前组件所属的节点
console.log("当前节点:", this.node);
// 访问节点上的实体
console.log("节点实体:", this.node.entity);
}
}
访问组件
1. 添加组件
typescript
@apclass("MovementComponent")
export class MovementComponent extends Component<GameEntity> {
speed = 5;
start() {
console.log("移动组件已添加!speed值:", this.speed);
}
}
// 方式1:通过组件类添加
const node = new EntityNode(null);
node.addComponent(MovementComponent);
// 方式2:通过组件名称添加
node.addComponent("MovementComponent");
// 方式3:添加组件时传入配置
node.addComponent(MovementComponent, {
speed: 10,
});
2. 获取组件
typescript
@apclass("PlayerController")
export class PlayerController extends Component<GameEntity> {
start() {
// 方式1:通过组件类获取
const movement = this.node.getComponent(MovementComponent);
// 方式2:通过组件名称获取
const movement2 = this.node.getComponent("MovementComponent");
if (movement) {
movement.speed = 15;
}
}
}
3. 获取多个组件
typescript
@apclass("GameManager")
export class GameManager extends Component<GameEntity> {
start() {
// 获取节点上的所有组件
const allComponents = Array.from(this.node.components.values());
console.log("所有组件:", allComponents);
// 获取特定类型的所有组件
const movements = this.node.getComponents(MovementComponent);
console.log("所有移动组件:", movements);
}
}
4. 移除组件
typescript
@apclass("ComponentManager")
export class ComponentManager extends Component<GameEntity> {
start() {
// 方式1:通过组件类移除
this.node.removeComponent(MovementComponent);
// 方式2:通过组件名称移除
this.node.removeComponent("MovementComponent");
}
}
实战示例
角色控制系统
typescript
@apclass("MovementComponent")
export class MovementComponent extends Component<GameEntity> {
speed = 5;
move(direction: GameVector3) {
this.node.entity.position = this.node.entity.position.add(
direction.multiply(this.speed)
);
}
}
@apclass("PlayerController")
export class PlayerController extends Component<GameEntity> {
private movement: MovementComponent | null = null;
start() {
// 获取移动组件
this.movement = this.node.getComponent(MovementComponent);
// 如果没有移动组件,自动添加一个
if (!this.movement) {
this.movement = this.node.addComponent(MovementComponent);
}
// 监听按键事件
world.onPress(({ button }) => {
if (!this.movement) return;
switch (button) {
case "ArrowRight":
this.movement.move(new GameVector3(1, 0, 0));
break;
case "ArrowLeft":
this.movement.move(new GameVector3(-1, 0, 0));
break;
}
});
}
}
注意事项
组件获取检查
- 总是检查 getComponent 的返回值是否为 null
- 考虑组件可能不存在的情况
组件依赖管理
- 在 start 中获取所需的组件引用
- 必要时自动添加依赖的组件
性能优化
- 缓存经常使用的组件引用
- 避免在 update 中重复获取组件
常见问题
Q: 为什么获取不到我添加的组件?
A: 检查以下几点:
- 组件类是否使用了 @apclass 装饰器
- 组件名称是否正确
- 组件是否已经被成功添加到节点上
Q: 如何在组件间共享数据?
A: 可以通过以下方式:
- 通过节点获取其他组件直接访问
- 使用事件系统进行通信
- 使用全局状态管理
Q: 组件的获取时机应该是什么时候?
A: 建议在 start 生命周期中获取所需的组件引用,这时所有组件都已完成加载。