Add ComponentMapper for faster retrieval of entity components

This commit is contained in:
Matt Low 2020-01-25 15:17:50 +04:00
parent d97c956607
commit f44f34b3de
8 changed files with 99 additions and 24 deletions

View File

@ -37,10 +37,10 @@ public class GameScreen extends Screen {
engine.registerComponentClass(AccelerationComponent.class); engine.registerComponentClass(AccelerationComponent.class);
engine.registerComponentClass(ModelComponent.class); engine.registerComponentClass(ModelComponent.class);
engine.registerSystem(new PlayerInputSystem()); engine.registerSystem(new PlayerInputSystem(engine));
engine.registerSystem(new MovementSystem()); engine.registerSystem(new MovementSystem(engine));
engine.registerSystem(new ScreenWrapSystem()); engine.registerSystem(new ScreenWrapSystem(engine));
engine.registerSystem(new ModelRenderSystem(graphics)); engine.registerSystem(new ModelRenderSystem(engine, graphics));
engine.ready(); engine.ready();

View File

@ -5,15 +5,20 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Polygon; import com.badlogic.gdx.math.Polygon;
import com.me.asteroids.Graphics; import com.me.asteroids.Graphics;
import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.ModelComponent;
import com.me.common.ecs.ComponentMapper;
import com.me.common.ecs.Engine;
import com.me.common.ecs.Entity; import com.me.common.ecs.Entity;
import com.me.common.ecs.EntitySystem; import com.me.common.ecs.EntitySystem;
public class ModelRenderSystem extends EntitySystem { public class ModelRenderSystem extends EntitySystem {
private ComponentMapper<ModelComponent> modelMapper;
private ShapeRenderer renderer; private ShapeRenderer renderer;
public ModelRenderSystem(Graphics graphics) { public ModelRenderSystem(Engine engine, Graphics graphics) {
super(ModelComponent.class); super(engine, ModelComponent.class);
this.modelMapper = engine.getComponentMapper(ModelComponent.class);
this.renderer = graphics.getShapeRenderer(); this.renderer = graphics.getShapeRenderer();
} }
@ -25,7 +30,7 @@ public class ModelRenderSystem extends EntitySystem {
@Override @Override
public void processEntity(Entity entity, float dt) { public void processEntity(Entity entity, float dt) {
ModelComponent modelComponent = entity.getComponent(ModelComponent.class); ModelComponent modelComponent = modelMapper.get(entity);
Polygon model = modelComponent.model; Polygon model = modelComponent.model;
renderer.polygon(model.getTransformedVertices()); renderer.polygon(model.getTransformedVertices());

View File

@ -6,6 +6,8 @@ import com.me.asteroids.components.AccelerationComponent;
import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.ModelComponent;
import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.PositionComponent;
import com.me.asteroids.components.VelocityComponent; import com.me.asteroids.components.VelocityComponent;
import com.me.common.ecs.ComponentMapper;
import com.me.common.ecs.Engine;
import com.me.common.ecs.Entity; import com.me.common.ecs.Entity;
import com.me.common.ecs.EntitySystem; import com.me.common.ecs.EntitySystem;
@ -13,20 +15,30 @@ public class MovementSystem extends EntitySystem {
private Vector2 tmp = new Vector2(); private Vector2 tmp = new Vector2();
public MovementSystem() { private ComponentMapper<PositionComponent> positionMapper;
super(PositionComponent.class, VelocityComponent.class); private ComponentMapper<VelocityComponent> velocityMapper;
private ComponentMapper<AccelerationComponent> accelMapper;
private ComponentMapper<ModelComponent> modelMapper;
public MovementSystem(Engine engine) {
super(engine, PositionComponent.class, VelocityComponent.class);
positionMapper = engine.getComponentMapper(PositionComponent.class);
velocityMapper = engine.getComponentMapper(VelocityComponent.class);
accelMapper = engine.getComponentMapper(AccelerationComponent.class);
modelMapper = engine.getComponentMapper(ModelComponent.class);
} }
@Override @Override
public void processEntity(Entity entity, float dt) { public void processEntity(Entity entity, float dt) {
PositionComponent positionComponent = entity.getComponent(PositionComponent.class); PositionComponent positionComponent = positionMapper.get(entity);
VelocityComponent velocityComponent = entity.getComponent(VelocityComponent.class); VelocityComponent velocityComponent = velocityMapper.get(entity);
Vector2 velocity = velocityComponent.velocity; Vector2 velocity = velocityComponent.velocity;
float maxVelocity = velocityComponent.maxVelocity; float maxVelocity = velocityComponent.maxVelocity;
Vector2 position = positionComponent.position; Vector2 position = positionComponent.position;
AccelerationComponent accelComponent = entity.getComponent(AccelerationComponent.class); AccelerationComponent accelComponent = accelMapper.get(entity);
if (accelComponent != null && !accelComponent.acceleration.isZero()) { if (accelComponent != null && !accelComponent.acceleration.isZero()) {
velocity.add(tmp.set(accelComponent.acceleration).scl(dt)); velocity.add(tmp.set(accelComponent.acceleration).scl(dt));
} }
@ -36,7 +48,7 @@ public class MovementSystem extends EntitySystem {
position.add(tmp.set(velocity).scl(dt)); position.add(tmp.set(velocity).scl(dt));
} }
ModelComponent modelComponent = entity.getComponent(ModelComponent.class); ModelComponent modelComponent = modelMapper.get(entity);
if (modelComponent != null) { if (modelComponent != null) {
Polygon model = modelComponent.model; Polygon model = modelComponent.model;
model.setPosition(position.x, position.y); model.setPosition(position.x, position.y);

View File

@ -8,6 +8,8 @@ import com.me.asteroids.components.AccelerationComponent;
import com.me.asteroids.components.PlayerComponent; import com.me.asteroids.components.PlayerComponent;
import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.PositionComponent;
import com.me.asteroids.components.VelocityComponent; import com.me.asteroids.components.VelocityComponent;
import com.me.common.ecs.ComponentMapper;
import com.me.common.ecs.Engine;
import com.me.common.ecs.Entity; import com.me.common.ecs.Entity;
import com.me.common.ecs.EntitySystem; import com.me.common.ecs.EntitySystem;
@ -15,20 +17,28 @@ public class PlayerInputSystem extends EntitySystem {
public Vector2 tmp = new Vector2(0, 1); public Vector2 tmp = new Vector2(0, 1);
public PlayerInputSystem() { private ComponentMapper<PositionComponent> positionMapper;
private ComponentMapper<VelocityComponent> velocityMapper;
private ComponentMapper<AccelerationComponent> accelMapper;
public PlayerInputSystem(Engine engine) {
super( super(
engine,
PositionComponent.class, PositionComponent.class,
VelocityComponent.class, VelocityComponent.class,
AccelerationComponent.class, AccelerationComponent.class,
PlayerComponent.class PlayerComponent.class
); );
positionMapper = engine.getComponentMapper(PositionComponent.class);
velocityMapper = engine.getComponentMapper(VelocityComponent.class);
accelMapper = engine.getComponentMapper(AccelerationComponent.class);
} }
@Override @Override
public void processEntity(Entity entity, float dt) { public void processEntity(Entity entity, float dt) {
PositionComponent positionComponent = entity.getComponent(PositionComponent.class); PositionComponent positionComponent = positionMapper.get(entity);
VelocityComponent velocityComponent = entity.getComponent(VelocityComponent.class); VelocityComponent velocityComponent = velocityMapper.get(entity);
AccelerationComponent accelComponent = entity.getComponent(AccelerationComponent.class); AccelerationComponent accelComponent = accelMapper.get(entity);
if (Gdx.input.isKeyPressed(Input.Keys.D)) { if (Gdx.input.isKeyPressed(Input.Keys.D)) {
positionComponent.rotation = Utils.rotate(positionComponent.rotation, -300 * dt); positionComponent.rotation = Utils.rotate(positionComponent.rotation, -300 * dt);

View File

@ -5,19 +5,26 @@ import com.badlogic.gdx.math.Vector2;
import com.me.asteroids.Constants; import com.me.asteroids.Constants;
import com.me.asteroids.components.ModelComponent; import com.me.asteroids.components.ModelComponent;
import com.me.asteroids.components.PositionComponent; import com.me.asteroids.components.PositionComponent;
import com.me.common.ecs.ComponentMapper;
import com.me.common.ecs.Engine;
import com.me.common.ecs.Entity; import com.me.common.ecs.Entity;
import com.me.common.ecs.EntitySystem; import com.me.common.ecs.EntitySystem;
public class ScreenWrapSystem extends EntitySystem { public class ScreenWrapSystem extends EntitySystem {
public ScreenWrapSystem() { private ComponentMapper<PositionComponent> positionMapper;
super(PositionComponent.class, ModelComponent.class); private ComponentMapper<ModelComponent> modelMapper;
public ScreenWrapSystem(Engine engine) {
super(engine, PositionComponent.class, ModelComponent.class);
positionMapper = engine.getComponentMapper(PositionComponent.class);
modelMapper = engine.getComponentMapper(ModelComponent.class);
} }
@Override @Override
public void processEntity(Entity entity, float dt) { public void processEntity(Entity entity, float dt) {
PositionComponent positionComponent = entity.getComponent(PositionComponent.class); PositionComponent positionComponent = positionMapper.get(entity);
ModelComponent modelComponent = entity.getComponent(ModelComponent.class); ModelComponent modelComponent = modelMapper.get(entity);
Vector2 position = positionComponent.position; Vector2 position = positionComponent.position;
Rectangle aabb = modelComponent.aabb; Rectangle aabb = modelComponent.aabb;

View File

@ -0,0 +1,19 @@
package com.me.common.ecs;
public class ComponentMapper<T extends Component> {
private Engine engine;
private ComponentType type;
private Class<T> typeClass;
public ComponentMapper(Engine engine, Class<T> typeClass) {
this.engine = engine;
this.type = ComponentType.getComponentType(typeClass);
this.typeClass = typeClass;
}
public T get(Entity entity) {
return typeClass.cast(engine.getEntityComponent(entity, type));
}
}

View File

@ -4,6 +4,9 @@ import com.badlogic.gdx.utils.Array;
import com.me.common.ecs.event.Event; import com.me.common.ecs.event.Event;
import com.me.common.ecs.event.Listener; import com.me.common.ecs.event.Listener;
import java.util.HashMap;
import java.util.Map;
public class Engine { public class Engine {
private Array<Entity> entities; private Array<Entity> entities;
@ -16,6 +19,8 @@ public class Engine {
private ListenerRegistry listenerRegistry; private ListenerRegistry listenerRegistry;
private Map<Class<? extends Component>, ComponentMapper> componentMappers;
public Engine() { public Engine() {
this.entities = new Array<>(); this.entities = new Array<>();
this.toActivate = new Array<>(); this.toActivate = new Array<>();
@ -24,6 +29,7 @@ public class Engine {
this.systems = new Array<>(); this.systems = new Array<>();
this.listenerRegistry = new ListenerRegistry(); this.listenerRegistry = new ListenerRegistry();
this.componentMappers = new HashMap<>();
} }
public void registerComponentClass(Class<? extends Component> clazz) { public void registerComponentClass(Class<? extends Component> clazz) {
@ -154,4 +160,18 @@ public class Engine {
return clazz.cast(components[type.getId()].get(entity.getId())); return clazz.cast(components[type.getId()].get(entity.getId()));
} }
protected Component getEntityComponent(Entity entity, ComponentType type) {
return components[type.getId()].get(entity.getId());
}
@SuppressWarnings("unchecked")
public <T extends Component> ComponentMapper<T> getComponentMapper(Class<T> typeClass) {
ComponentMapper<T> mapper = componentMappers.get(typeClass);
if (mapper == null) {
mapper = new ComponentMapper<>(this, typeClass);
componentMappers.put(typeClass, mapper);
}
return mapper;
}
} }

View File

@ -6,11 +6,13 @@ public abstract class EntitySystem {
private long typeBits; private long typeBits;
protected Engine engine;
protected Array<Entity> entities; protected Array<Entity> entities;
public EntitySystem(Class<? extends Component>... components) { public EntitySystem(Engine engine, Class<? extends Component>... components) {
typeBits = ComponentType.getMaskBits(components); this.engine = engine;
entities = new Array<>(); this.typeBits = ComponentType.getMaskBits(components);
this.entities = new Array<>(true, 16, Entity.class);
} }
public void preProcessing() {} public void preProcessing() {}