libgdx
Ashley Entity System
Suche…
Bemerkungen
Ashley Entity System ist eine Entity System-Bibliothek, die unter der LibGDX-Organisation verwaltet wird und sich für die Entwicklung von Spielen eignet. Dies hängt von den LibGDX-Dienstprogrammklassen ab, kann jedoch mit einigen anderen Java-Game-Frameworks verwendet werden, die nicht auf LibGDX basieren.
Entitätssysteme bieten eine andere Möglichkeit zum Verwalten von Daten und Funktionen für große Objektgruppen, ohne dass die Objektklassen mit Vererbung reich gemacht werden müssen.
Die Verwendung von Ashley kann für diejenigen hilfreich sein, die nach einem Objektmodellierungsansatz suchen, der von Unity bereitgestellt wird, jedoch mit dem Rahmen eines Frameworks anstelle einer Spiel-Engine.
Eine Komponente erstellen
Komponenten sind einfach Instanzen, die die Ashley-Komponentenklasse implementieren.
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;
}
Komponentenkarten bieten eine schnelle Möglichkeit, auf Komponenten in Entitäten zuzugreifen. Es gibt zwei gängige Methoden zum Verwalten Ihrer Komponentenzuordnungen, indem Sie entweder eine statische Instanz in der Klasse Ihrer Komponente behalten oder über eine Klasse / ein Enum verfügen, die alle Mapper für alle Komponenten enthält.
Es ist nicht erforderlich, einen Mapper für einen Komponententyp mehr als einmal in Ihrer Anwendung zu deklarieren.
Erstellen eines Entitätssystems
Entitätssysteme führen Sie aus, um funktionale Operationen für Entitätsgruppen durchzuführen. Komponenten sollte normalerweise keine Logik zugeordnet sein, die die Kenntnis der Daten oder des Zustands anderer Komponenteninstanzen erfordert, da dies die Aufgabe eines Entitätssystems ist. Ein Entitätssystem kann nicht für mehr als eine Engine gleichzeitig registriert werden.
Entitätssysteme sollten nicht mehr als eine Art von Funktion ausführen. Ein MovementSystem sollte nur die Positionierung und dergleichen behandeln, während ein RenderSystem etwa das Zeichnen von Entitäten übernehmen sollte.
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
...
}
}
In manchen Fällen ist es hilfreich, EntitySystems um zusätzliche Funktionen wie die in EntityListener vorhandenen zu erweitern, sodass Sie nur die Entitätstypen nachverfolgen können, mit denen Sie arbeiten möchten, anstatt alle Entitäten in der Engine in jedem Zyklus zu durchlaufen. EntityListener werden immer dann ausgelöst, wenn eine Entität derselben Engine hinzugefügt wird, bei der das System registriert ist.
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
...
}
}
}
Das Verfolgen einer Untergruppe von Entitäten, die das System zu jeder Zeit verarbeitet, kann auch optimal sein, da Sie eine bestimmte Entität aus der Verarbeitung dieses Systems entfernen können, ohne die zugehörige Komponente entfernen zu müssen oder sie ganz aus der Engine insgesamt zu entfernen.
Sortiertes Entitätssystem erstellen
Eine einfache
EntitySystem
, das jede Einheit aus einer Familie in der Größenordnung von einem bestimmten verarbeitetcomparator
und ruftprocessEntity()
für jede Einheit die jedes MalEntitySystem
aktualisiert wird. Dies ist wirklich nur eine Convenience-Klasse, da Rendering-Systeme dazu neigen, eine Liste von Entitäten in einer sortierten Weise zu durchlaufen. Durch das Hinzufügen von Entitäten wird die Entitätsliste neu sortiert. Rufen SieforceSort()
wenn Sie Ihre Sortierkriterien geändert haben. Weitere Informationen finden Sie unter SortedIteratingSystem
In dem folgenden Codebeispiel wird die Wiedergabe Ihrer Sprites in einer sortierten Reihenfolge nach zindex am besten verwendet.
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);
}
}
}
Erstellen eines Intervalliterationssystems
Ein einfaches
EntitySystem
, das eineEntitySystem
nicht pro Frame, sondern nach einem bestimmten Intervall verarbeitet. Die Entity-Verarbeitungslogik sollte inprocessEntity(Entity)
. Weitere Informationen finden Sie unter IntervalIteratingSystem
Im folgenden Codebeispiel ist die beste Verwendung für das der Physik Welt Schritt.
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();
}
}