LIBGDX Cambiando de pantalla
UNIDADE 2: Cambiando de pantalla
Cambiando de pantalla
Tal como comentamos anteriormente neste punto a forma de proceder para cambiar de pantalla é chamando ó método setScreen da clase Game.
Nota: Lembrar que no exemplo que estamos a seguir, mandamos o obxecto que deriva da clase Game como parámetro na chamada ó método setScreen, para que a outra pantalla poda ter referencia ó mesmo e poida volver a chamar ó método setScreen.
No noso exemplo....
Imos cambiar a pantalla inicial para que en vez de ir ó xogo directamente pase pola pantalla principal.
Preparación:
- Subide o seguinte gráfico ó cartafol GRAFICOS dentro do cartafol assets no proxecto Android.
- Agora imos modificar a clase PantallaPresentacion para crear unha cámara e visualizar o gráfico anterior.
Código da clase PantallaPresentacion
Obxectivo: visualizar a pantalla de presentación.
1 public class PantallaPresentacion implements Screen, InputProcessor{
2 private MeuXogoGame meuxogogame;
3
4 private OrthographicCamera camara2d;
5 private SpriteBatch spritebatch;
6 private static Texture fondo;
7
8 public PantallaPresentacion(MeuXogoGame meuxogogame){
9 this.meuxogogame=meuxogogame;
10
11 camara2d = new OrthographicCamera();
12 spritebatch = new SpriteBatch();
13 fondo = new Texture(Gdx.files.internal("GRAFICOS/LIBGDX_itin1_pantallapresentacion.png"));
14
15 }
16
17 @Override
18 public void render(float delta) {
19 // TODO Auto-generated method stub
20
21 spritebatch.begin();
22
23 spritebatch.draw(fondo,0,0,Mundo.TAMANO_MUNDO_ANCHO,Mundo.TAMANO_MUNDO_ALTO);
24
25 spritebatch.end();
26
27
28 }
29
30 @Override
31 public void resize(int width, int height) {
32 // TODO Auto-generated method stub
33
34 camara2d.setToOrtho(false, Mundo.TAMANO_MUNDO_ANCHO, Mundo.TAMANO_MUNDO_ALTO);
35 camara2d.update();
36
37 spritebatch.setProjectionMatrix(camara2d.combined);
38 spritebatch.disableBlending();
39
40 }
41
42 @Override
43 public void show() {
44 // TODO Auto-generated method stub
45 Gdx.input.setInputProcessor(this);
46
47 }
48
49 @Override
50 public void hide() {
51 // TODO Auto-generated method stub
52 // Neste caso non fai falta poñelo xa que imos ser nos o que chamemos a dispose cando cambiemos de pantalla.
53 //dispose();
54
55 }
56
57 @Override
58 public void pause() {
59 // TODO Auto-generated method stub
60 Gdx.input.setInputProcessor(null);
61
62 }
63
64 @Override
65 public void resume() {
66 // TODO Auto-generated method stub
67 Gdx.input.setInputProcessor(this);
68
69 }
70
71 @Override
72 public void dispose() {
73 // TODO Auto-generated method stub
74 Gdx.input.setInputProcessor(null);
75
76 spritebatch.dispose();
77 fondo.dispose();
78
79 }
80
81 @Override
82 public boolean keyDown(int keycode) {
83 // TODO Auto-generated method stub
84 return false;
85 }
86
87 @Override
88 public boolean keyUp(int keycode) {
89 // TODO Auto-generated method stub
90 return false;
91 }
92
93 @Override
94 public boolean keyTyped(char character) {
95 // TODO Auto-generated method stub
96 return false;
97 }
98
99 @Override
100 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
101 // TODO Auto-generated method stub
102 return false;
103 }
104
105 @Override
106 public boolean touchUp(int screenX, int screenY, int pointer, int button) {
107 // TODO Auto-generated method stub
108 return false;
109 }
110
111 @Override
112 public boolean touchDragged(int screenX, int screenY, int pointer) {
113 // TODO Auto-generated method stub
114 return false;
115 }
116
117 @Override
118 public boolean mouseMoved(int screenX, int screenY) {
119 // TODO Auto-generated method stub
120 return false;
121 }
122
123 @Override
124 public boolean scrolled(int amount) {
125 // TODO Auto-generated method stub
126 return false;
127 }
128
129
130 }
- Liña 38:
Atención:: Na liña 38 temos a seguinte instrución:
1 spritebatch.disableBlending();
O que fai dita liña é deshabilitar o uso de transparencias. Isto o facemos nesta pantalla xa que o fondo da mesma ocupa todo e non imos engadir novos gráficos que teñan transparencias.
No resto de pantallas (como a de Marcadores) imos escribir texto que vai ter transperencias polo que dita orde non se debe poñer ou se a poñemos (por ter un fondo por exemplo) deberemos chamar a orde contraria (spritebatch.enableBlending()) antes de debuxar o gráfico con transparencias.
Modificamos agora a clase principal MeuXogoGame para que chame á nova pantalla...
Código da clase MeuXogoGame
Obxectivo: chama á pantalla principal.
1 public class MeuXogoGame extends Game {
2
3
4 @Override
5 public void create() {
6 // TODO Auto-generated method stub
7
8 AssetsXogo.cargarTexturas();
9 setScreen(new PantallaPresentacion(this));
10 }
11
12 @Override
13 public void dispose(){
14 super.dispose();
15
16 AssetsXogo.liberarTexturas();
17 }
18 }
Agora temos que comprobar se pulsamos cada unha das opcións (botóns) e obrar en consecuencia. Debemos crear un rectángulo por cada unha das opcións (xa visto na sección das colisións) e comprobar se o dedo toca cada unha delas.
TAREFA 2.10 A FACER: Esta parte está asociada á realización dunha tarefa.
Facendo pause
En case todos os xogos podemos facer un pause do xogo para seguir posteriormente así como a opción de saír.
No caso do pause temos dúas opcións:
- Quedarnos na mesma pantalla e no caso de que o xogo pase ó estado de pause debuxar un gráfico no centro da pantalla que indique que está en pause.
Para esta opción só teríamos que non chamar ó método controladorXogo.update(delta) dentro do método render da clase PantallaXogo. Desta forma ningún personaxe se moverá. Teríamos que cambiar a variable booleana pause a true e facela static e public para que dende a clase RendererXogo poidamos verificar o seu valor e no caso de que valga true poñer o gráfico de pause no centro da pantalla. Teríamos que controlar o método touchdown para que no caso de estar en pause e tocar a pantalla volver a poñer o valor a false.
- Cambiar de pantalla e que ó premer volvamos ó xogo no punto onde o deixamos.
Para esta segunda opción imos modificar a clase PantallaPause para cargar o seguinte gráfico:
Levade este gráfico ó cartafol assets/GRAFICOS da versión Android e dádelle de nome LIBGDX_itin1_pantallapause.jpg.
Modificade o código da clase PantallaPause para que cargue o gráfico anterior.
Lembrar incluír a interface InputProcessor como xa vimos anteriormente.
Tamén deberedes liberar os recursos cando pase polo método hide (chamar ó método dispose nese intre e liberade a textura e o spritebach).
Preparando a clase PantallaXogo e RendererXogo:
Modificamos agora o código da RendererXogo para que visualice dúas iconas na parte inferior esquerda.
Aquí temos os gráficos a engadir no cartafol assets/GRAFICOS/CONTROIS da versión Android:
Como sempre os cargarmos na clase AssetsXogo cos nome indicados entre parénteses.
Despois modificamos a clase RendererXogo para que debuxe os novos controis. Como imos ter que indicar onde debuxalos podemos definir a súa posición e tamaño na clase Controis.
Código da clase Controis
Obxectivo: definir posición e tamaño das iconas pausa e saír.
1 public class Controis {
2
3 public final static Rectangle FONDO_NEGRO = new Rectangle(0, 0,
4 Mundo.TAMANO_MUNDO_ANCHO, 12);
5 public final static Rectangle CONTROL = new Rectangle(10, 40, 50, 70);
6 public final static int POSVIDAS = 60;
7
8 public final static Rectangle CONTROL_PAUSE = new Rectangle(30,0,10,10);
9 public final static Rectangle CONTROL_SAIR = new Rectangle(45,0,10,10);
10
11
12 }
Código da clase RendererXogo
Obxectivo: visualiza as iconas pausa e saír.
1 private void debuxarControis(){
2
3 // Fondo negro
4 spritebatch.draw(AssetsXogo.texturePuntoNegro, Controis.FONDO_NEGRO.x,Controis.FONDO_NEGRO.y,Controis.FONDO_NEGRO.width,Controis.FONDO_NEGRO.height);
5
6 spritebatch.draw(AssetsXogo.control, Controis.CONTROL.x,Controis.CONTROL.y,
7 Controis.CONTROL.width,Controis.CONTROL.height);
8
9 spritebatch.draw(AssetsXogo.texturePausa, Controis.CONTROL_PAUSE.x,Controis.CONTROL_PAUSE.y,Controis.CONTROL_PAUSE.width,Controis.CONTROL_PAUSE.height);
10 spritebatch.draw(AssetsXogo.textureSair, Controis.CONTROL_SAIR.x,Controis.CONTROL_SAIR.y,Controis.CONTROL_SAIR.width,Controis.CONTROL_SAIR.height);
11 }
Agora controlamos se prememos a opción de pausa e saír.
Código da clase PantallaXogo
Obxectivo: xestionamos a opción de premer pausa e saír.
1 @Override
2 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
3
4 // if (Gdx.app.getType()!=ApplicationType.Android) return false;
5
6 // TODO Auto-generated method stub
7 Vector3 vecTemporal = new Vector3(screenX,screenY,0);
8 rendererXogo.getCamara2d().unproject(vecTemporal);
9
10 Rectangle recTemporal = new Rectangle();
11
12 ...........................
13 // Falta o código feito na tarefa 2.8.B no que se controla cando prememos no control do alien
14
15
16 recTemporal.set(Controis.CONTROL_PAUSE.x,Controis.CONTROL_PAUSE.y,Controis.CONTROL_PAUSE.width,Controis.CONTROL_PAUSE.height);
17 if (Intersector.overlaps(dedo, recTemporal)){
18 pause = true;
19 }
20
21 recTemporal.set(Controis.CONTROL_SAIR.x,Controis.CONTROL_SAIR.y,Controis.CONTROL_SAIR.width,Controis.CONTROL_SAIR.height);
22 if (Intersector.overlaps(dedo, recTemporal)){
23 dispose();
24 meuXogoGame.setScreen(new PantallaPresentacion(meuXogoGame));
25 }
26
27
28
29 return false;
30 }
Como podemos comprobar a opción de saír non ten complicación, xa a temos vista na tarefa 2.10.
A chamada ó método dispose non se atopa no método hide xa que cando vaiamos á pantalla de pausa non queremos 'borrar' nada do xogo. Queremos ir con todo o estado do xogo e recuperalo ó volver.
Como facemos isto ? Como sempre temos varias opcións...Algunha delas:
- Poderíamos gardar o estado do xogo a disco e recuperalo ó volver. Esta opción non é aconsellable nunha pantalla de pausa e si no caso de querer gardar a partida para continuar outro día (neste xogo non ten moito sentido).
- Mandar como parámetro ó constructor da clase PantallaPause o obxecto da clase PantallaXogo desta forma:
Código da clase PantallaPause
Obxectivo: modifcamos o constructor para obter unha referencia á PantallaXogo.
1 public class PantallaPause implements Screen, InputProcessor{
2 ..............
3 private PantallaXogo pantallaXogo;
4
5 public PantallaPause(MeuXogoGame meuXogoGame, PantallaXogo pantallaXogo){
6
7 this.meuxogogame=meuxogogame;
8 this.pantallaXogo = pantallaXogo;
9
10 camara2d = new OrthographicCamera();
11 spritebatch = new SpriteBatch();
12 fondo = new Texture(Gdx.files.internal("GRAFICOS/LIBGDX_itin1_pantallapause.png"));
13
14 }
15 ..............
16 }
Agora no método render da clase PantallaXogo controlamos cando estamos en pause para mandar o control á PantallaPause:
Código da clase PantallaXogo
Obxectivo: controlamos se estamos en pause para ir á PantallaPause.
1 @Override
2 public void render(float delta) {
3 // TODO Auto-generated method stub
4
5 rendererXogo.render(delta);
6 controladorXogo.update(delta);
7
8 if (pause){
9 meuXogoGame.setScreen(new PantallaPause(meuXogoGame, this));
10 return;
11 }
12 }
Nota importante: Debemos facer return despois de chamar a setScreen, xa que a pesar que o control pasa a nova pantalla, se sigue executando o código do método render ata finalizar. Se temos código a continuación podemos ter un erro de execución.
Fixarse como no método setScreen enviamos non só a referencia a clase MeuXogoGame (para poder facer o setScreen) se non tamén unha referencia á propia clase PantallaXogo.
Agora só temos que controlar se se preme na pantalla PantallaPause volver ó control á PantallaXogo, pero usando a referencia pasada.
Código da clase PantallaPause
Obxectivo: devolvemos o control á PantallaXogo se prememos na pantalla.
1 @Override
2 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
3 // TODO Auto-generated method stub
4 meuxogogame.setScreen(pantallaXogo);
5 return false;
6 }
Se executades o código podedes comprobar que xa accedemos á pantalla de pausa cando prememos sobre o control, pero ó intentar continuar o xogo volve á pantalla de pausa. Isto é debido a que a variable pause segue valendo true cando regresamos e polo tanto volve a facer o setScreen da pantalla de pause.
Imos modificar isto para que o xogo cando entre en estado de pause (ó premer o botón de pause ou cando minimizamos (en desktop) ou cambiamos de aplicación (en móbil) ) poñamos a variable a true e cando volvamos (maximicemos ou volvamos nun móbil) cambie a false.
Código da clase PantallaXogo
Obxectivo: modificar a propiedade pause.
1 ................
2
3 @Override
4 public void pause() {
5 // TODO Auto-generated method stub
6 Gdx.input.setInputProcessor(null);
7 if (!finXogo) {
8 pause = true;
9 }
10
11 }
12
13 @Override
14 public void resume() {
15 // TODO Auto-generated method stub
16 Gdx.input.setInputProcessor(this);
17 pause=false;
18
19 }
20 @Override
21 public void show() {
22 // TODO Auto-generated method stub
23 Gdx.input.setInputProcessor(this);
24 pause=false;
25 }
26
27 ................
Nota: Fixarse como cando facemos a pausa do xogo minimizando a aplicación na versión desktop, pasamos polo evento pause, pero cando restauramos, non pasamos polo evento resume xa que cambiamos de pantalla (estamos na pantalla de pausa). Cando dende a pantalla de pausa chamamos ó método setScreen volvemos a pasar polo evento show.
Saíndo do xogo
Ó premer a icona de saír debemos ir á pantalla de presentación. Tamén imos engadir outra condición e é que se utilizamos máis de 15 vidas o xogo acaba.
Lembrar que temos que liberar os recursos.
Código da clase PantallaXogo
Obxectivo: Xestionar o fin do xogo.
1 @Override
2 public void render(float delta) {
3 // TODO Auto-generated method stub
4
5 rendererXogo.render(delta);
6 controladorXogo.update(delta);
7
8 if (meuMundo.getAlien().getNumVidas().size>=15)
9 finXogo=true;
10
11
12 if (pause){
13 Audio.stopMusica();
14 meuXogoGame.setScreen(new PantallaPause(meuXogoGame, this));
15 return;
16 }
17 if (finXogo){
18 meuXogoGame.setScreen(new PantallaMarcadores(meuXogoGame));
19 // Facemos o return xa que continua a execución ata que remate o render.
20 return;
21 }
22
23 }
24
25 @Override
26 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
27
28 vecTemporal.set(screenX,screenY,0);
29 rendererXogo.getCamara2d().unproject(vecTemporal);
30
31 dedo.set(vecTemporal.x,vecTemporal.y,2);
32 ..................
33
34 recTemporal.set(Controis.CONTROL_SAIR.x,Controis.CONTROL_SAIR.y,Controis.CONTROL_SAIR.width,Controis.CONTROL_SAIR.height);
35 if (Intersector.overlaps(dedo, recTemporal)){
36 sair=true;
37 meuXogoGame.setScreen(new PantallaPresentacion(meuXogoGame));
38 }
39
40
41
42 return false;
43 }
44 @Override
45 public void hide() {
46 // TODO Auto-generated method stub
47 if ((finXogo) || (sair)) dispose();
48
49 }
-- Ángel D. Fernández González -- (2015).