libgdx
Ashley Entity System
Zoeken…
Opmerkingen
Ashley Entity System is een Entity System-bibliotheek die wordt beheerd door de LibGDX-organisatie en is zeer geschikt voor game-ontwikkeling. Het hangt af van LibGDX-nutsklassen, maar kan met wat werk worden gebruikt met andere Java-spelframeworks die niet op LibGDX zijn gebaseerd.
Entiteitssystemen bieden een andere manier om gegevens en functionaliteit voor grote sets objecten te beheren zonder de objectklassen rijk te maken aan overerving.
Het gebruik van Ashley kan een nuttige benadering zijn voor diegenen die op zoek zijn naar een objectmodelleringsbenadering zoals Unity biedt, maar met de scope van een framework in plaats van een game-engine.
Een component maken
Componenten zijn eenvoudigweg instanties die de Ashley-componentklasse implementeren.
import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
public class Position implements Component {
public static final ComponentMapper<Position> Map =
ComponentMapper.getFor(Position.class);
public float x = 0f,
y = 0f;
}
Componentenkaarten bieden een snelle manier om componenten op entiteiten te benaderen. Twee veel voorkomende manieren om uw componentmappen te beheren is om een statische instantie binnen de klasse van uw component te houden of om een klasse / opsomming te hebben die alle mappers voor al uw componenten bevat.
Het is niet nodig om een mapper voor een componenttype meer dan één keer aan te geven in uw toepassing.
Een entiteitssysteem maken
Entiteitssystemen zijn hoe u functionele bewerkingen uitvoert op sets van entiteiten. Aan componenten zou doorgaans geen logica moeten worden gekoppeld die bewustzijn van gegevens of de status van andere componentinstanties inhoudt, aangezien dat de taak van een entiteitssysteem is. Een entiteitssysteem kan niet bij meer dan één motor tegelijk worden geregistreerd.
Entiteitssystemen mogen niet meer dan één type functie uitvoeren. Een MovementSystem moet alleen positionering en dergelijke verwerken, terwijl zoiets als een RenderSystem de tekening van entiteiten moet verwerken.
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.ashley.core.Family;
public class MovementSystem extends EntitySystem {
//the type of components necessary for entities to have to be operated on
private static final Family FAMILY = Family.all(Position.class).get();
public MovementSystem () {
super();
}
/**
* The update method called every tick.
* @param deltaTime The time passed since last frame in seconds.
*/
public void update (float deltaTime) {
for (Entity e : this.getEngine().getEntitiesFor(FAMILY)) {
Position pos = Position.Map.get(e);
// do entity movement logic on component
...
}
}
Soms is het handig om uw EntitySystems uit te breiden met extra functionaliteit zoals die in EntityListeners, zodat u alleen de soorten entiteiten bijhoudt waarop u wilt werken, in plaats van elke cyclus over alle entiteiten in de motor te itereren. EntityListeners worden geactiveerd wanneer een entiteit wordt toegevoegd aan dezelfde engine waarop het systeem is geregistreerd.
import com.badlogic.ashley.core.EntityListener;
import com.badlogic.gdx.utils.Array;
public class MovementSystem extends EntitySystem implements EntityListener {
Array<Entity> moveables = new Array<>();
...
@Override
public void entityAdded(Entity entity) {
if (FAMILY.matches(entity)) {
moveables.add(entity);
}
}
@Override
public void entityRemoved(Entity entity) {
if (FAMILY.matches(entity)) {
moveables.removeValue(entity, true);
}
}
public void update (float deltaTime) {
for (Entity e : this.moveables) {
Position pos = Position.Map.get(e);
// do entity movement logic on component
...
}
}
}
Het bijhouden van een subset van entiteiten die het systeem te allen tijde verwerkt, kan ook optimaal zijn, omdat u een bepaalde entiteit uit de verwerking van dat systeem kunt verwijderen zonder de bijbehorende component te verwijderen of desgewenst uit de motor als geheel te verwijderen.
Een gesorteerd entiteitssysteem creëren
Een eenvoudig
EntitySystem
dat elke entiteit van een bepaalde familie in de door eencomparator
opgegeven volgorde verwerkt enprocessEntity()
voor elke entiteitEntitySystem
telkens wanneer hetEntitySystem
wordt bijgewerkt. Dit is eigenlijk slechts een gemaksklasse omdat rendering-systemen de neiging hebben om een lijst van entiteiten op een gesorteerde manier te doorlopen. Als u entiteiten toevoegt, wordt de entiteitenlijst opnieuw gebruikt. RoepforceSort()
als u uw sorteercriteria hebt gewijzigd. Zie SortedIteratingSystem voor meer informatie
In het onderstaande codevoorbeeld is het beste gebruik hiervoor het renderen van uw sprites in een gesorteerde volgorde door zindex.
public class SpriteComponent implements Component {
public TextureRegion region;
public int z = 0;
}
public class Mapper {
public static ComponentMapper<SpriteComponent> sprite = ComponentMapper.getFor(SpriteComponent.class);
}
public class RenderingSystem extends SortedIteratingSystem {
public RenderingSystem () {
super(Familly.all(SpriteComponent.class).get(), new ZComparator())
}
public void processEntity(Entity entity, float deltaTime) {
if(checkZIndexHasChangeValue()) {
forceSort();
}
}
private static class ZComparator implements Comparator<Entity> {
@Override
public int compare(Entity entityA, Entity entityB) {
return (int)Math.signum(Mapper.sprite.get(entityA).z - Mapper.sprite.get(entityB).z);
}
}
}
Creëren van een interval herhalend systeem
Een eenvoudig
EntitySystem
dat een familie van entiteiten niet één keer per frame, maar na een bepaald interval verwerkt. Entiteitsverwerkingslogica moet inprocessEntity(Entity)
worden geplaatst. Zie IntervalIteratingSystem voor meer informatie
In de onderstaande code voorbeeld, de beste gebruik hiervoor is de fysica wereld stap.
public class Constants {
public final static float TIME_STEP = 1 / 60.0f; // 60 fps
public final static int VELOCITY_ITERATIONS = 6;
public final static int POSITION_ITERATIONS = 2;
}
public class PhysicsSystem extends IntervalIteratingSystem {
public PhysicsSystem () {
super(Family.all(PhysicsComponent.class), Constants.TIME_STEP);
}
@Override
protected void processEntity(Entity entity) {
// process the physics component here with an interval of 60fps
}
@Override
protected void updateInterval() {
WorldManager.world.step(Constants.TIME_STEP, Constants.VELOCITY_ITERATIONS, Constants.POSITION_ITERATIONS);
super.updateInterval();
}
}