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 przez comparator i wywołuje processEntity() dla każdej jednostki za każdym razem, gdy EntitySystem 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łaj forceSort() 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ć w processEntity(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();
    }

}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow