java - 如何实现 Unity 风格的 GetComponentJavaFX 中的 () 函数?
问题描述
我正在尝试制作具有实体组件系统风格的游戏。实体类有一个不同组件的列表,它们都扩展了 Component 类。如何创建一个函数来返回指定类的组件?(变换、物理等)。来自 Unity 的示例:Transform tf = player.GetComponent();
我在实体类中有这个功能:
@SuppressWarnings("unchecked")
public <T> T GetComponent(Class<T> T)
{
for (Component component : components)
{
if (component.getClass() == T)
{
System.out.println("Returned a component.");
return (T)component;
}
}
return null;
}
在 PhysicsComponent 中,我试图获得对 TransformComponent 的引用,如下所示:
public PhysicsComponent(Entity player)
{
this.tf = new TransformComponent(0, 0, 0, 0);
this.tf = player.GetComponent(tf.getClass());
}
getComponent 函数总是返回 null 因为我必须将组件作为参数传递给播放器构造函数以显示我希望播放器拥有的组件类,所以我不能在任何组件构造函数中引用播放器,因为我需要在播放器之前制作虚拟组件。
我怎样才能像 Unity 一样使用简单的 GetComponent(); 功能?
解决方案
有很多方法可以或多或少地完成您正在寻找的事情......我不熟悉“实体组件系统”或 Unity,但我构建了一个可能适合您需求的示例。
它以 Component 类型开始,我为此创建了一个空接口,但您可以将其设为抽象类或任何适合您需要的类型:
public interface Component {
}
我添加的下一个类是ComponentFactory
. 一个 ComponentFactory 创建一个固定类型的组件对象,给定一些参数。
public interface ComponentFactory<IN, T extends Component> {
Class<T> getComponentClass();
T createComponent(IN input);
}
下一个类是Lazy
,它只是添加了对 Lazy 的支持,但只对任何东西进行一次初始化。我稍后会使用它。
public static class Lazy<T> {
private volatile T value;
private final Supplier<? extends T> supplier;
public Lazy(Supplier<? extends T> supplier) {
this.supplier = supplier;
}
public T getValue() {
if (this.value == null) {
synchronized (this) {
if (this.value == null) {
this.value = this.supplier.get();
}
}
}
return this.value;
}
}
下一节课是Entity
。Entity 是您似乎已经拥有的类之一,但您遇到了困难,因为 Entity 需要将其组件传递给构造函数,但组件还需要在构造函数中传递的 Entity。实体现在不会接收在其构造函数中传递的组件,而是它可能在以后用于构造实际组件的工厂。
public static class Entity {
private final Map<Class<? extends Component>, Lazy<Component>> components;
public Entity(List<ComponentFactory<? super Entity, ?>> componentFactories) {
// do all of the basic construction
final Map<Class<? extends Component>, Lazy<Component>> components = new HashMap<>();
for (ComponentFactory<? super Entity, ?> factory : componentFactories) {
components.put(factory.getComponentClass(), new Lazy<>(() -> factory.createComponent(this)));
}
this.components = Collections.unmodifiableMap(components);
}
public <T extends Component> T getComponent(Class<T> componentClass) {
final Lazy<Component> lazy = this.components.get(componentClass);
final T component;
if (lazy != null) {
component = componentClass.cast(lazy.getValue());
} else {
component = null;
}
return component;
}
}
例子
作为一个例子,我创建了两个类“TransformComponent”,它接受一个实体和“PhysicsComponent”,它接受一个实体并使用该实体接收给定实体的TransformComponent。
public static class PhysicsComponent implements Component {
public static final ComponentFactory<Entity, PhysicsComponent> FACTORY = new ComponentFactory<>() {
@Override
public Class<PhysicsComponent> getComponentClass() {
return PhysicsComponent.class;
}
@Override
public PhysicsComponent createComponent(Entity input) {
return new PhysicsComponent(input);
}
};
private final TransformComponent tf;
public PhysicsComponent(Entity player) {
this.tf = player.getComponent(TransformComponent.class);
}
}
public static class TransformComponent implements Component {
public static final ComponentFactory<Entity, TransformComponent> FACTORY = new ComponentFactory<>() {
@Override
public Class<TransformComponent> getComponentClass() {
return TransformComponent.class;
}
@Override
public TransformComponent createComponent(Entity input) {
return new TransformComponent(input);
}
};
public TransformComponent(Entity player) {
}
}
请注意,两个 Component-Implementation 都有自己的工厂的公共静态最终变量。
最后,我们可以创建我们的玩家实体:
public static void example() {
final Entity player = new Entity(List.of(TransformComponent.FACTORY, PhysicsComponent.FACTORY));
final PhysicsComponent physicsComponent = player.getComponent(PhysicsComponent.class);
}
推荐阅读
- node.js - 如何在 NodeJS 中创建多个数据库 sequelize 会话
- python - 如何仿射变换一百张图像OpenCV Python
- python - 如何解决 LSTM 问题中的损失:nan & accuracy: 0.0000e+00?张量流 2.x
- php - Vscode 上的断点没有被流明框架击中
- google-apps-script - 修改代码 - 将 onEdit 转换为自定义菜单以运行 - Google Apps 脚本/Google 表格
- android - 当小部件提供者意图过滤器只有更新操作时,为什么会收到其他意图操作(Android)
- unity3d - 在 Unity 的背景层上运行大规模克隆的最佳方法是什么?
- android - 具有固定高度视图和其他填充空间的 Android 约束布局链
- android - React Native - Appium Studio 在导航到新屏幕时在 Android 上的视图层次结构中显示以前的屏幕组件
- java - Jasper Chart Customizer 根据类别值显示垂直线