libgdx
Ashley Entity System
Szukaj…
Uwagi
Ashley Entity System to biblioteka Entity System zarządzana przez organizację LibGDX, która doskonale nadaje się do tworzenia gier. Zależy to od klas narzędzi LibGDX, ale można go używać z innymi strukturami gier Java nieopartymi na LibGDX.
Systemy jednostek zapewniają inny sposób zarządzania danymi i funkcjami w odniesieniu do dużych zestawów obiektów bez konieczności wzbogacania klas obiektów o dziedziczenie.
Wykorzystanie Ashleya może być pomocne dla osób poszukujących podejścia do modelowania obiektów, takiego jak Unity, ale z zakresem frameworka zamiast silnika gry.
Tworzenie komponentu
Komponenty to po prostu instancje, które implementują klasę komponentów 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;
}
Mapy komponentów zapewniają szybki sposób na dostęp do komponentów jednostek. Dwa typowe sposoby zarządzania mapami komponentów to albo utrzymywanie statycznej instancji w klasie komponentu, albo posiadanie klasy / wyliczenia, które zawiera wszystkie elementy mapujące dla wszystkich komponentów.
Nie ma potrzeby deklarowania mapowania dla typu komponentu więcej niż jeden raz w aplikacji.
Tworzenie systemu encji
Systemy jednostek to sposób wykonywania operacji na zbiorach jednostek. Komponenty zwykle nie powinny mieć logiki związanej z nimi, która dotyczy świadomości danych lub stanu innych instancji komponentów, ponieważ taka jest praca systemu encji. System encji nie może być zarejestrowany w więcej niż jednym silniku na raz.
Systemy jednostek nie powinny wykonywać więcej niż jednego rodzaju funkcji. MovementSystem powinien obsługiwać tylko pozycjonowanie i tym podobne, podczas gdy coś takiego jak RenderSystem powinno obsługiwać rysowanie bytów.
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
...
}
}
Czasami pomocne jest rozszerzenie EntitySystems o dodatkowe funkcje, takie jak w EntityListeners, dzięki czemu możesz śledzić tylko typy jednostek, na których chcesz operować, zamiast iterować wszystkie jednostki w silniku w każdym cyklu. EntityListeners są uruchamiane za każdym razem, gdy jednostka jest dodawana do tego samego silnika, w którym zarejestrowany jest system.
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
...
}
}
}
Śledzenie podzbioru jednostek, które system przetwarza przez cały czas, może być również optymalne, ponieważ można usunąć konkretną jednostkę z przetwarzania tego systemu bez konieczności usuwania powiązanego komponentu lub usuwania ich z silnika jako całości, jeśli jest to pożądane.
Tworzenie systemu sortowanej jednostki
Prosty
EntitySystem
który przetwarza każdą jednostkę z danej rodziny w kolejności określonej przezcomparator
i wywołujeprocessEntity()
dla każdej jednostki za każdym razem, gdyEntitySystem
jest aktualizowany. To naprawdę tylko wygoda, ponieważ systemy renderujące mają tendencję do iteracji po liście jednostek w posortowany sposób. Dodanie jednostek spowoduje, że lista jednostek zostanie zastosowana. WywołajforceSort()
jeśli zmieniłeś kryteria sortowania. Aby uzyskać więcej informacji, zobacz SortedIteratingSystem
W poniższym przykładzie kodu najlepsze wykorzystanie do renderowania twoich duszków w posortowanej kolejności według 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);
}
}
}
Tworzenie systemu iteracji interwałowej
Prosty system
EntitySystem
który przetwarza rodzinę bytów nie raz na ramkę, ale po danym interwale. Logikę przetwarzania encji należy umieścić wprocessEntity(Entity)
. Aby uzyskać więcej informacji, zobacz IntervalIteratingSystem
W poniższym przykładzie kodu najlepszym do tego celu jest krok w świecie fizyki.
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();
}
}