Stage ja Actorite süsteem

Stage

Scene2D on mängu UI, mis luuakse kas SpriteBatchi ja/või Stage ja Actor-ite süsteemiga. Ühele Screen-ile võib panna mitu Stage-i. Hallates Screen-e abstraktse Game-klassi kaudu, seatakse vaid 1 Screen ja selle Stage/Stage-id korraga aktiivseks. See võimaldab Sreen-i ja ta Stage-ide haldust teha Screen-i klassis. Kui Game klassi asemel tegeleb Screen-ide vahetusega ApplicationListener või ApplicationAdapter, tuleb Screen-ide ja Stage-ide haldus teha ka nende klasside sees ning ka ise Screen-ide aktiviseerumise ja inaktiveeruse loogikat ise läbi viia.

Screen-i kasutamine ilma Stage-ita:

  • Peab ise haldama sprite-ide joonistamist, asukohta ja kustutamist.

  • Animatsioonide tegemiseks tuleb kasutada Animation-klassi.

  • Kasutaja sisendi jaoks tuleb laiendada InputProcessor-it ja ka ise sisendi halduse loogika paika panna.

Stage-i kasutamise eelised:

  • Sprite-id saab asendada Actor-itega.

  • Actor-ite positsiooni määravad vanemad WidgetGroup-is, sest WidgetGroup implementeerib Layout liidest.

  • Animatsioone saab teha Actions-klassi abil.

  • Stage-ile saab kergelt lisada InputProcessor-i (Gdx.input.setInputProcessor(stage)), ja Actor-itele lisada Listener-e, määramaks, kas sisendit haldab vanem või lapse Actor kuna Actor-itel on hierarhiline süsteem.

Actorile InputListener andmine:

actor.setBounds(0, 0, texture.getWidth(), texture.getHeight());

actor.addListener(new InputListener() {
    public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
        System.out.println("down");
        return true;
    }

    public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
        System.out.println("up");
    }
});

Tüüpilisel mängul on mängimise-ekraanil 3 kihti:

  1. Taust – Staatiline või dünaamiline taust, mis pole interaktiivne.

  2. Mänguobjektid – Tegelased, objektid ja klikitavad elemendid.

  3. HUD – Ekraani servadel asuv statistika (näiteks mängija punktid) ja nupud (näiteks pausinupp).

Sellise kihilise struktuuri loomiseks kasutatakse üldiselt kahte moodust:

  1. Kasutades ühte Stage-i ja jaotades Actor-id kolme Group-i, kus Stage renderdab neid vastavalt z-indeksi järjekorras.

  2. Tehes kolm eraldi Stage-i (backgroundStage, gameStage, hudStage) ning joonistades neid eraldi (backgroundStage.draw()).

Stage-i asemel saab samu tulemusi kasutades SpriteBatch-i, BitmapFont-i ja InputProcessor-i. Samuti võib AI olla eraldi Stage-ist. Kui aga kasutada mõlemat samal Screen-il korraga ehk Stage-i koos Actor-itega kui ka SpriteBatch-iga, mis ei asu Stage-i peal, peab arvestama, et Stage-il ja Camera'l on erinev Viewport.

Camera ja Stage'i Viewport

// Camera viewport:

private Viewport viewport;
private Camera camera;

public void create() {
    camera = new PerspectiveCamera();
    viewport = new FitViewport(800, 480, camera);
}

// Stage viewport:

private Stage stage;

public void create() {
    stage = new Stage(new StretchViewport(width, height));
}

Mitme erisuuruse ViewPort-i puhul on ka Camera 'l ja Stage-il erinev strateegia:

// Camera viewport:
viewport1.apply();
viewport1.draw
viewport2.apply();
viewport2.draw()()

// Stage viewport
stage1.getViewport().apply();
stage1.draw();
stage2.getViewport().apply();
stage2.draw();

Kasutades aga Camera't ja Stage-i koos:

public void create() {
   Viewport viewport = new FitViewport(worldWidth, worldHeight);
   SpriteBatch spriteBatch = new SpriteBatch();
   Stage stage = new Stage(new FitViewport(worldWidth, worldHeight));
   stage.getViewport().getCamera().position.setZero(); // (valikuline) kaamera keskele panek
}

public void render() {
    viewport.apply();
    spriteBatch.setProjectionMatrix(viewport.getCamera().combined);
    spriteBatch.begin();
    // spriteBatch.draw() sisendparameetritega
    spriteBatch.end();
    stage.getViewport().apply();
    stage.draw();
}

Actor

Kõik Stage-i elemendid on tavaliselt esindatud Actor-itena. Stage joonistab, uuendab ja eemaldab enda peal olevad Actor-id automaatselt. Kui Actor ei panda Stage-i peale, peab Actor-it ise haldama.

Actorite omadused:

  1. Positsioon – vasaku alumise nurga kaugus oma vanemast, kui Actor kuulub Group-i. Ka animatsiooni saab selle omadusi järgi lisada (asukoha muutusele lisaks anda aja-parameeter), kasutades Action-it.

  2. Suurus – ristkülikukujuline kuju.

  3. Vanem – kui Actor kuulub Group-i, siis kes on tema vanem.

  4. Skaleerimisvõime – suuruse muutmise võime, millele saab ka aja-parameetri kaasa anda Action-it kasutades.

  5. Pööramisvõime – millele saab ka aja-parameetri kaasa anda, et sujuvust muuta, Action-it kasutades.

  6. Z-indeks – kas Actor asub teiste peal või all.

  7. Värv – värvus ja läbipaistvus, millele saab ka aja-parameetri kaasa anda Action-it kasutades.

Actor-itel on olemas erinevad Listener-id, kuid keerukamate Event-ide jaoks on vaja Actor-eid laiendada või Listener-e kohandada. Actor-i alamtüübil Widget-il on juba sisseehitatud kasutaja sisendi haldamine ning lisaks kasutab Widget Layout liidest. WidgetGroup koosneb mitmest Widget-ist ehk peale Actor-i on WidgetGroup ka Group-i alamtüüp.

Actorite hierarhia:

Actor
│
├── Layout Widgetid: määravad widgetite paigutuse Stage'il.
│   ├── WidgetGroup: kui Widgetil on lapsed
│   │   ├── ScrollPane: keritavus
│   │   ├── SplitPane
│   │   ├── Tree
│   │   ├── HorizontalGroup
│   │   ├── VerticalGroup
│   │   └── Stack: Actorid pannakse üksteise peale
│   ├── Table: Saab vanemaks panna terve Stagei (setFillParent(true))
│   ├── Container:
│   └── Window: UI-aknad
│       └── Dialog
│
├── Widgetid: kasutaja sisendi jaoks
│   ├── Label
│   ├── Button
│   │   ├── TextButton
│   │   ├── ImageButton
│   │   └── CheckBox
│   ├── ProgressBar
│   │   ├── Slider
│   │   └── ProgressBar
│   ├── List
│   ├── SelectBox: Rippmenüü
│   ├── TextField
│   ├── TextArea: Mitmerealine tekstiväli
│   └── Touchpad
│
├── Image  (`TextureRegioniga` või `Drawable`)
└── CustomActor

Widget-it ja WidgetGroup-i saab luua ka Stage-ita, rakendades mõlemale pack meetodit ning kasutades SpriteBatch-i Widget-i joonistamiseks.

Label ja Table ilma Stage'ita

private SpriteBatch batch;
private Label label;
private Skin skin;
private Table table;

public void create() {
    batch = new SpriteBatch();
    skin = new Skin(Gdx.files.internal("uiskin.json"));
    label = new Label("Hello!", skin);
    label.pack();
    label.setPosition(100, 100);
    table = new Table();
    table.add(label);
    table.pack();
}

public void render() {
    batch.begin();
    label.draw(batch, 1);
    batch.end();
}

Lingid: