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 asendadaActor
-itega.Actor
-ite positsiooni määravad vanemadWidgetGroup
-is, sestWidgetGroup
implementeeribLayout
liidest.Animatsioone saab teha
Actions
-klassi abil.Stage
-ile saab kergelt lisadaInputProcessor
-i (Gdx.input.setInputProcessor(stage)
), jaActor
-itele lisadaListener
-e, määramaks, kas sisendit haldab vanem või lapseActor
kunaActor
-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:
Taust – Staatiline või dünaamiline taust, mis pole interaktiivne.
Mänguobjektid – Tegelased, objektid ja klikitavad elemendid.
HUD
– Ekraani servadel asuv statistika (näiteks mängija punktid) ja nupud (näiteks pausinupp).
Sellise kihilise struktuuri loomiseks kasutatakse üldiselt kahte moodust:
Kasutades ühte
Stage
-i ja jaotadesActor
-id kolmeGroup
-i, kusStage
renderdab neid vastavalt z-indeksi järjekorras.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:¶
Positsioon – vasaku alumise nurga kaugus oma vanemast, kui
Actor
kuulubGroup
-i. Ka animatsiooni saab selle omadusi järgi lisada (asukoha muutusele lisaks anda aja-parameeter), kasutadesAction
-it.Suurus – ristkülikukujuline kuju.
Vanem – kui
Actor
kuulubGroup
-i, siis kes on tema vanem.Skaleerimisvõime – suuruse muutmise võime, millele saab ka aja-parameetri kaasa anda
Action
-it kasutades.Pööramisvõime – millele saab ka aja-parameetri kaasa anda, et sujuvust muuta,
Action
-it kasutades.Z-indeks – kas
Actor
asub teiste peal või all.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();
}
Näide meie mängust "Stage" ja "Actor" kasutamise kohta.¶
Kogu kood on leitav siin -> näidismäng.
Siin kasutatakse "Stage" mängu põhimenüü kuvamiseks. Selleks kasutatakse "Table" (et hõlpsasti määrata vajalik kohanduv paigutus), tabelisse lisatakse teised Actor'id – nupud, ja seejärel lisatakse Table Stage'i.
Samuti uuendatakse meetodis "resize" Stage'i viewport vastavalt akna suurusele. Ja ei tohi renderdamisel unustada kasutada meetodit stage.draw().
public class TitleScreen extends ScreenAdapter {
private final Stage stage;
public TitleScreen(Game game) {
stage = new Stage();
// NB! important line - will make the stage listen for user input
// For example when this is not set no hover or click events will be triggered
Gdx.input.setInputProcessor(stage);
// menu buttons
var startButton = getButton(20, "Start", () -> {
// send a message to the server that the player wants to join the game
ServerConnection.getInstance().getClient().sendTCP(new GameJoinMessage());
game.setScreen(new GameScreen(game));
});
var exitButton = getButton(20, "Exit", () -> Gdx.app.exit());
// positioning the buttons. you can think of the following as a table (or flexbox) in HTML
var table = new Table();
table.setFillParent(true);
table.add(startButton).padBottom(20);
table.row();
table.add(exitButton);
stage.addActor(table);
}
/**
* Renders the TitleScreen, clearing it and drawing the buttons.
*
* @param delta time since last frame.
*/
@Override
public void render(float delta) {
super.render(delta);
// clear the screen
Gdx.gl.glClearColor(192 / 255f, 192 / 255f, 192 / 255f, 1); // to get that win 95 look
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// draw the buttons
stage.act(delta);
stage.draw();
}
@Override
public void resize(int width, int height) {
super.resize(width, height);
stage.getViewport().update(width, height, true);
}
}
Kogu kood on leitav siin -> näidismäng
Veel üks kasutusnäide – seekord HUD-i kuvamiseks.
/**
* Info overlay that contains information about: player names, lives, game status, game time.
*
* @param spriteBatch used for rendering all visual elements. Using the same spritebatch as the Arena (players,
* bullets etc.) helps with scaling and resizing
*/
public Hud(SpriteBatch spriteBatch) {
localPLayerId = ServerConnection.getInstance().getClient().getID();
// The viewport with current hardcoded width and height works decently with most screen/window sizes
// There's no need for additional font re-scaling when adjusting the window size
Viewport viewport = new FitViewport(640, 480, new OrthographicCamera());
// Create a stage to render the HUD content
stage = new Stage(viewport, spriteBatch);
// Create a table to display fields such as lives count
Table table = createHudTable();
table.setDebug(false); // true - outline all table cells, labels with a red line (makes table non-transparent)
stage.addActor(table);
}
/**
* Table manages where different fields such as player names and lives are displayed on the screen
*/
private Table createHudTable() {
// For simple tables, using an empty placeholder label is usually the easiest solution to adjust alignment
Label emptyLabel = createLabel("", Color.WHITE, LABEL_SIZE);
Table table = new Table();
table.setFillParent(true); // Fill whole screen
table.top(); // Align the table's content to the top
table.padTop(TABLE_PADDING_TOP);
// First row: player names and time
table.add(localPlayerNameLabel);
table.add(timeLabel);
table.add(remotePlayerNameLabel);
table.row().expandX(); // make the row fill the entire width of the screen
// Second row: player lives
table.add(localPlayerLivesLabel);
table.add(emptyLabel); // empty label as a placeholder for alignment
table.add(remotePlayerLivesLabel);
table.row().expandX();
// Third row: game status message
table.add(gameStatusLabel)
.colspan(3) // Make the label span across all 3 table columns
.padTop(GAME_STATUS_LABEL_PADDING_TOP)
.align(Align.center); // Center-align the label within the table cell
table.row();
return table;
}
Table kasutamine Stage'is on väga mugav, kuna see võimaldab hõlpsasti ja visuaalselt meeldivalt paigutada teisi elemente (Label, Button). Table'isse saab lisada väliseid ja sisemisi ääremarginaale, laiendada ridu horisontaalselt, paigutada elemente keskele, vasakule või paremale jne.