libgdx
Ashley Entity System
Ricerca…
Osservazioni
Ashley Entity System è una libreria di sistemi Entity gestita dall'organizzazione LibGDX, adatta per lo sviluppo di giochi. Dipende dalle classi di utilità LibGDX, ma può essere utilizzato con altri framework di giochi Java non basati su LibGDX con un po 'di lavoro.
I sistemi Entity forniscono un modo diverso di gestire dati e funzionalità verso insiemi di oggetti di grandi dimensioni senza dover rendere le classi oggetto ricche di ereditarietà.
Utilizzare Ashley potrebbe essere un approccio utile per chi cerca un approccio di modellazione di oggetti come fornisce Unity, ma con l'ambito di un framework al posto del motore di gioco.
Creazione di un componente
I componenti sono semplicemente istanze che implementano la classe del componente Ashley.
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;
}
Le mappe dei componenti forniscono un modo rapido per accedere ai componenti sulle entità. Due modi comuni per gestire le mappe dei componenti consiste nel mantenere un'istanza statica all'interno della classe del componente o in una classe / enum che contiene tutti i programmi di definizione per tutti i componenti.
Non è necessario dichiarare un mapper per un tipo di componente più di una volta nell'applicazione.
Creazione di un sistema di entità
I sistemi di entità sono il modo in cui si eseguono operazioni funzionali su gruppi di entità. I componenti in genere non dovrebbero avere una logica associata a essi che implichi la consapevolezza dei dati o dello stato di altre istanze del componente, poiché questo è il lavoro di un sistema di entità. Un sistema di entità non può essere registrato su più di un motore alla volta.
I sistemi di entità non devono eseguire più di un tipo di funzione. Un MovementSystem dovrebbe gestire solo il posizionamento e simili, mentre qualcosa come un RenderSystem dovrebbe gestire il disegno di entità.
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
...
}
}
A volte è utile estendere il tuo EntitySystems con funzionalità aggiuntive come quelle che si trovano in EntityListeners in modo da tenere traccia solo dei tipi di entità su cui desideri operare, invece di iterare su tutte le entità nel motore ogni ciclo. EntityListeners vengono attivati ogni volta che un'entità viene aggiunta allo stesso motore su cui è registrato il sistema.
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
...
}
}
}
Anche tenere traccia di un sottoinsieme di entità che il sistema elabora in ogni momento può essere ottimale, in quanto è possibile rimuovere una particolare entità dall'elaborazione di quel sistema senza dover rimuovere il componente di associazione o rimuoverle dal motore nel suo insieme se lo si desidera.
Creazione di un sistema di entità ordinate
Un
EntitySystem
semplice che elabora ciascuna entità di una determinata famiglia nell'ordine specificato da uncomparator
e chiamaprocessEntity()
per ogni entità ogni volta cheEntitySystem
viene aggiornato. Questa è davvero solo una classe di convenienza in quanto i sistemi di rendering tendono a scorrere su un elenco di entità in modo ordinato. L'aggiunta di entità farà ricorrere alla lista delle entità. ChiamaforceSort()
se hai modificato i criteri di ordinamento. Per maggiori informazioni, vedere SortedIteratingSystem
Nell'esempio di codice seguente, il miglior utilizzo per questo il rendering dei tuoi sprite in un ordine ordinato da 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);
}
}
}
Creazione di un sistema di iterazione a intervalli
Un semplice
EntitySystem
che elabora una famiglia di entità non una sola volta per fotogramma, ma dopo un dato intervallo. La logica di elaborazione delle entità deve essere inserita inprocessEntity(Entity)
. Per maggiori informazioni, vedere IntervalIteratingSystem
Nell'esempio di codice seguente, il miglior utilizzo per questo è il passo del mondo fisico.
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();
}
}