https://manuais.iessanclemente.net/index.php?title=LIBGDX_As_interfaces_para_capturar_eventos&feed=atom&action=historyLIBGDX As interfaces para capturar eventos - Historial de revisiones2024-03-29T13:32:40ZHistorial de revisiones de esta página en el wikiMediaWiki 1.36.2https://manuais.iessanclemente.net/index.php?title=LIBGDX_As_interfaces_para_capturar_eventos&diff=52937&oldid=prevAngelfg en 17:27 2 feb 20152015-02-02T17:27:58Z<p></p>
<p><b>Página nueva</b></p><div><span style="font-size:150%;">UNIDADE 2: Interface de xestión de eventos</span><br />
<br/><br />
<br/><br />
<br />
===As interfaces===<br />
<br />
Información na wiki: https://github.com/libgdx/libgdx/wiki/Event-handling<br />
<br />
O motor libgdx ten dúas interfaces para xestionar todos os eventos:<br />
<br />
* InputProcessor: Xestiona os eventos de pulsación de teclas, pulsación sobre a pantalla (móbil), e arrastre do dedo pola pantalla (móbil)...<br />
* GestureListener: Xestiona outro tipo de eventos coma son os de dobre pulsación (evento tap), o clásico movemento con dous dedos para facer un zoom da pantalla (evento zoom)....Esta interface está explicada na [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Xestion_Eventos_GestureListener Unidade 3: Xestión de Eventos: GestureListener].<br />
<br />
<br />
Para engadir unha interface temos que utilizar a palabra implements na definición da clase igual que fixemos coa interface Screen. Ó facelo vos dará un erro sobre o nome da clase. Se situades o rato enriba do erro aparecerá unha opción de '''Add unimplimented methods''' que debemos escoller.<br />
<br />
'''Código da clase PantallaXogo'''<br/><br />
'''Obxectivo:''' engadir unha interface de xestión de eventos.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="1" ><br />
<br />
public class PantallaXogo implements Screen,InputProcessor {<br />
...............<br />
@Override<br />
public boolean keyDown(int keycode) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean keyUp(int keycode) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean keyTyped(char character) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean touchDown(int screenX, int screenY, int pointer, int button) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean touchUp(int screenX, int screenY, int pointer, int button) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean touchDragged(int screenX, int screenY, int pointer) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean mouseMoved(int screenX, int screenY) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
@Override<br />
public boolean scrolled(int amount) {<br />
// TODO Auto-generated method stub<br />
return false;<br />
}<br />
<br />
...............<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Os eventos que controlamos con esta interface son:<br />
<br />
*keyDown(): Tecla premida.<br />
*keyUp(): Tecla liberada.<br />
*keyTyped(): Tecla premida e xera un carácter unidade.<br />
*touchDown(): O dedo prema a pantalla (móbil) ou o botón do rato é premido.<br />
*touchUp(): O dedo deixa de premer a pantalla ou o botón do rato deixa de ser premido.<br />
*touchDragged(): Dedo ou rato é arrastrado pola pantalla. No caso do rato o botón debe estar presionado.<br />
*mouseMoved(): O rato se move pola pantalla e non se pulsa ningún botón.<br />
*scrolled(): Cando se preme a roda de scroll do rato.<br />
<br />
Como vemos todos os método devolven un boolean. Este é usado no caso de que teñamos diferentes interfaces de xestión de eventos no mesmo xogo e non queremos que o evento se traslade á seguinte interface (poñeríase return true). Normalmente o deixaremos por defecto.<br />
<br />
Unha vez temos a interface temos que ''informar'' á nosa clase que os eventos teñen que ir a dita interface.<br />
<br />
Isto o logramos chamando ó método [http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Input.html#setInputProcessor-com.badlogic.gdx.InputProcessor- Gdx.input.setInputProcessor(obxecto)] indicando como obxecto o obxecto da clase que ten implementada a interface. No noso caso this:<br />
*Gdx.input.setInputProcessor(this)<br />
<br />
Onde temos que poñer dita orde ?<br />
<br />
*O poñeremos nos métodos show e resume.<br />
<br />
Cando acabamos de xestionar os eventos chamaremos ó mesmo método pero enviando null como obxecto:<br />
*Gdx.input.setInputProcessor(null)<br />
<br />
Onde temos que poñer dita orde ?<br />
<br />
*O poñeremos nos métodos pause, hide e dispose (pode ser que non sexa necesario poñelo en hide se programamos que cando cambiemos de pantalla chamemos ó método dispose).<br />
<br />
<br />
'''Código da clase PantallaXogo'''<br/><br />
'''Obxectivo:''' Informar á clase onde se atopa a xestión de eventos.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="5,11,17,24,31" ><br />
......................<br />
@Override<br />
public void show() {<br />
// TODO Auto-generated method stub<br />
Gdx.input.setInputProcessor(this);<br />
}<br />
<br />
@Override<br />
public void hide() {<br />
// TODO Auto-generated method stub<br />
Gdx.input.setInputProcessor(null);<br />
}<br />
<br />
@Override<br />
public void pause() {<br />
// TODO Auto-generated method stub<br />
Gdx.input.setInputProcessor(null);<br />
<br />
}<br />
<br />
@Override<br />
public void resume() {<br />
// TODO Auto-generated method stub<br />
Gdx.input.setInputProcessor(this);<br />
<br />
}<br />
<br />
@Override<br />
public void dispose() {<br />
// TODO Auto-generated method stub<br />
Gdx.input.setInputProcessor(null);<br />
rendererxogo.dispose();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
<br />
Agora xa temos todo preparado para xestionar os eventos. Empecemos coa parte máis sinxela (a versión PC) e faremos que cando prememos as teclas do cursor movamos algo.<br />
<br />
Como estamos programando seguindo o [http://manuais.iessanclemente.net/index.php?title=LIBGDX_MVC MVC], teremos que informar á clase controladora que se pulsou unha tecla e actuar en consecuencia.<br />
<br />
Como o facemos ?<br />
<br />
Existen moitas alternativas. Eu vos vou expoñer a que aprendín.<br />
<br />
Definimos na clase ControladorXogo un tipo de datos [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Anexo_tipos_de_datos#Enum Enum] cos diferentes controis que podemos ter sobre o noso xogo. Neste caso teremos as catro teclas dos cursores:<br />
<br />
<syntaxhighlight lang="java" line enclose="div"><br />
public enum Keys {<br />
ESQUERDA,DEREITA,ARRIBA,ABAIXO<br />
}<br />
</syntaxhighlight><br />
<br />
Despois definimos un [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Anexo_tipos_de_datos#HashMap hashmap] e o inicializamos a false (lembrar importar a clase coa combinación de teclas Control+Shift+O).<br />
<br />
<syntaxhighlight lang="java" line enclose="div"><br />
HashMap<Keys, Boolean> keys = new HashMap<ControladorXogo.Keys, Boolean>();<br />
{<br />
keys.put(Keys.ESQUERDA, false);<br />
keys.put(Keys.DEREITA, false);<br />
keys.put(Keys.ARRIBA, false); <br />
keys.put(Keys.ABAIXO, false); <br />
};<br />
</syntaxhighlight><br />
<br />
E por último, para poder acceder a esta variable dende a clase PantallaXogo, faremos os método pulsarTecla e liberarTecla dentro desta clase ControladorXogo:<br />
<br />
<syntaxhighlight lang="java" line enclose="div"><br />
/**<br />
* Modifica o estado do mapa de teclas e pon a true <br />
* @param tecla: tecla pulsada<br />
*/<br />
public void pulsarTecla(Keys tecla){<br />
keys.put(tecla, true);<br />
}<br />
/**<br />
* Modifica o estado do mapa de teclas e pon a false<br />
* @param tecla: tecla liberada<br />
*/<br />
public void liberarTecla(Keys tecla){<br />
keys.put(tecla, false);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Agora só queda chamar a estes métodos dende a clase PantallaXogo...<br />
<br />
'''Código da clase PantallaXogo'''<br/><br />
'''Obxectivo:''' Informar á clase controladora da tecla pulsada (lembrar importar o paquete Input coa combinación de teclas Contro+Shift+O).<br />
<syntaxhighlight lang="java" line enclose="div"><br />
@Override<br />
public boolean keyDown(int keycode) {<br />
// TODO Auto-generated method stub<br />
// Liberamos as teclas para que se arrastramos o dedo a outro control sen soltar o anterior non xunte o efecto<br />
controladorXogo.liberarTecla(ControladorXogo.Keys.ABAIXO);<br />
controladorXogo.liberarTecla(ControladorXogo.Keys.ARRIBA);<br />
controladorXogo.liberarTecla(ControladorXogo.Keys.ESQUERDA);<br />
controladorXogo.liberarTecla(ControladorXogo.Keys.DEREITA);<br />
<br />
switch(keycode){<br />
case Input.Keys.UP:<br />
controladorXogo.pulsarTecla(ControladorXogo.Keys.ARRIBA);<br />
break;<br />
case Input.Keys.DOWN:<br />
controladorXogo.pulsarTecla(ControladorXogo.Keys.ABAIXO);<br />
break;<br />
case Input.Keys.LEFT:<br />
controladorXogo.pulsarTecla(ControladorXogo.Keys.ESQUERDA);<br />
break;<br />
case Input.Keys.RIGHT:<br />
controladorXogo.pulsarTecla(ControladorXogo.Keys.DEREITA);<br />
break;<br />
}<br />
<br />
<br />
return false;<br />
}<br />
</syntaxhighlight><br />
<br />
Como vedes non ten moita complicación. Simplemente comprobamos que tecla se preme e informamos á clase controladora.<br />
<br/><br />
-----<br />
'''TAREFA 2.7 A FACER:''' Esta parte está asociada á realización dunha tarefa. <br />
-----<br />
<br/><br />
<br />
'''Exercicio proposto''':<br />
Agora é necesario mover o alien. Isto o facemos na clase ControladorXogo modificando a súa velocidade en función da tecla pulsada. Vos atrevedes a facelo ?<br />
<br />
Pistas:<br />
* O alien ten unha mesma velocidade (non varía, non ten aceleración) pero pode moverse nos dous eixes (x/y). Teredes que crear na clase Alien os métodos necesarios para modificar dita velocidade en cada un dous eixes e obter dita velocidade.<br />
* O método update terá que ter en conta a velocidade nos dous eixes. Neste xogo non permitimos que se mova en diagonal xa que cando prememos unha tecla desactivamos as anteriores.<br />
* Lembrar que na clase ControladorXogo debemos modificar a velocidade cando se preme a tecla correspondente e para de moverse cando soltamos a tecla.<br />
* Lembrar chamar ó método update do alien dende a clase ControladorXogo.<br />
<br />
<br />
<br />
'''Posible solución:'''<br />
<br />
'''Código da clase Alien'''<br/><br />
'''Obxectivo:''' Definimos os métodos para xestionar a velocidade nos eixes x/y e modificamos o método update.<br />
<br />
<syntaxhighlight lang="java" line enclose="div"><br />
public class Alien extends Personaxe{<br />
<br />
private Vector2 velocidade;<br />
<br />
public Alien(Vector2 posicion, Vector2 tamano, float velocidade_max) {<br />
super(posicion, tamano, velocidade_max);<br />
<br />
velocidade = new Vector2(0,0);<br />
<br />
}<br />
<br />
public float getVelocidadeX(){<br />
return velocidade.x;<br />
}<br />
public float getVelocidadeY(){<br />
return velocidade.y;<br />
}<br />
<br />
public void setVelocidadeX(float x){<br />
velocidade.x = x;<br />
<br />
}<br />
public void setVelocidadeY(float y){<br />
velocidade.y = y;<br />
}<br />
<br />
@Override<br />
public void update(float delta) {<br />
// TODO Auto-generated method stub<br />
<br />
setPosicion(getPosicion().x+velocidade.x*delta, getPosicion().y+velocidade.y*delta);<br />
<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Como vemos usamos un Vector2 para gardar as dúas velocidades. Cando prememos unha tecla faremos que dita velocidade valga a velocidade máxima (a que lle mandamos no constructor cando instanciamos o obxecto alien)<br />
<br />
'''Código da clase ControladorXogo'''<br/><br />
'''Obxectivo:''' Modificamos a velocidade do alien en función da tecla pulsada.<br />
<br />
<syntaxhighlight lang="java" line enclose="div" highlight="12-16,32,34,37-53"><br />
public class ControladorXogo {<br />
<br />
private Mundo meuMundo;<br />
private Alien alien;<br />
....................<br />
public ControladorXogo(Mundo mundo) {<br />
this.meuMundo = mundo;<br />
alien = meuMundo.getAlien();<br />
}<br />
....................<br />
<br />
private void controlarAlien(float delta){<br />
<br />
// Actualiza Alien<br />
alien.update(delta);<br />
}<br />
<br />
/**<br />
* Vai chamar a todos os métodos para mover e controlar os personaxes Tamén<br />
* xestionará os eventos producidos polo usuario e que veñen dende a clase<br />
* PantallaXogo<br />
* <br />
* @param delta<br />
*/<br />
public void update(float delta) {<br />
<br />
controlarCoches(delta);<br />
controlarRochas(delta);<br />
controlarTroncos(delta);<br />
<br />
controlarNave(delta);<br />
controlarAlien(delta);<br />
<br />
procesarEntradas();<br />
<br />
}<br />
private void procesarEntradas(){<br />
<br />
if (keys.get(Keys.DEREITA))<br />
alien.setVelocidadeX(alien.velocidade_max);<br />
if (keys.get(Keys.ESQUERDA))<br />
alien.setVelocidadeX(-alien.velocidade_max);<br />
if (!(keys.get(Keys.ESQUERDA)) && (!(keys.get(Keys.DEREITA))))<br />
alien.setVelocidadeX(0);<br />
<br />
if (keys.get(Keys.ARRIBA))<br />
alien.setVelocidadeY(alien.velocidade_max);<br />
if (keys.get(Keys.ABAIXO))<br />
alien.setVelocidadeY(-alien.velocidade_max);<br />
if (!(keys.get(Keys.ARRIBA)) && (!(keys.get(Keys.ABAIXO))))<br />
alien.setVelocidadeY(0);<br />
<br />
}<br />
</syntaxhighlight> <br />
<br />
<u><b>Nota:</b></u> Modificar a orde de chamada do método debuxarAlien na clase RendererXogo para que sexa a última. Desta forma o alien vaise debuxar por enriba de todos os demais elementos.<br />
<br />
<br/><br />
<br/><br />
Agora imos facer unha pequena modificación no xogo para que a parte baixa da pantalla conte cunha banda negra onde van ir as vidas salvadas e o crono do xogo.<br />
<br />
Isto xa deberiades ser capaces de facelo. Só temos que debuxar a textura baseada no gráfico LIBGDX_puntonegro.jpg que temos feito da tarefa 2.3. Como imos ter que gardar o tamaño desta banda negra para poder debuxalo dende a clase RendererXogo e facer que o Alien non poida baixar dende a clase ControladorXogo, imos definir o tamaño nunha clase de nome Controis que a definiremos no paquete principal.<br />
<br />
'''Código da clase Controis'''<br/><br />
'''Obxectivo:''' Gardamos o tamaño dos controis utilizados no xogo. Neste caso o tamaño da banda negra inferior.<br />
<syntaxhighlight lang="java" line enclose="div"><br />
public class Controis {<br />
<br />
public final static Rectangle FONDO_NEGRO = new Rectangle(0,0,Mundo.TAMANO_MUNDO_ANCHO,12);<br />
}<br />
<br />
</syntaxhighlight> <br />
<br />
Agora debuxamos dito control na clase RendererXogo:<br />
<br />
'''Código da clase RendererXogo'''<br/><br />
'''Obxectivo:''' Debuxar a banda inferior negra.<br />
<syntaxhighlight lang="java" line enclose="div" highlight="2-8,25"><br />
..............<br />
private void debuxarControis(){<br />
<br />
// Fondo negro<br />
spritebatch.draw(AssetsXogo.texturePuntoNegro, Controis.FONDO_NEGRO.x,Controis.FONDO_NEGRO.y,Controis.FONDO_NEGRO.width,Controis.FONDO_NEGRO.height);<br />
<br />
}<br />
<br />
public void render(float delta) {<br />
Gdx.gl.glClearColor(0, 0, 0, 1);<br />
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);<br />
<br />
spritebatch.begin();<br />
<br />
debuxarFondo();<br />
<br />
debuxarNave();<br />
<br />
debuxarCoches();<br />
debuxarRochas();<br />
debuxarTroncos();<br />
<br />
debuxarAlien();<br />
<br />
debuxarControis();<br />
spritebatch.end();<br />
<br />
if (debugger) {<br />
debugger();<br />
}<br />
}<br />
</syntaxhighlight> <br />
<br />
<br />
<br/><br />
<br/><br />
'''Exercicio proposto''':<br />
Facer que o alien non saia da pantalla, é dicir, que se mova nos límites do noso mundo e que non poda ir máis abaixo da banda inferior negra.<br />
<br />
<br/><br />
'''Posible solución:'''<br/><br />
'''Código da clase ControladorXogo'''<br/><br />
'''Obxectivo:''' Facer que o Alien se mova dentro dos límites da pantalla.<br />
<br />
<syntaxhighlight lang="java" line enclose="div" highlight="7-26"><br />
....................<br />
private void controlarAlien(float delta){<br />
<br />
// Actualiza Alien<br />
alien.update(delta);<br />
<br />
// Impide que se mova fora dos límites da pantalla<br />
if (alien.getPosicion().x <=0){<br />
alien.setPosicion(0, alien.getPosicion().y);<br />
}<br />
else {<br />
if (alien.getPosicion().x >= Mundo.TAMANO_MUNDO_ANCHO-alien.getTamano().x){<br />
alien.setPosicion(Mundo.TAMANO_MUNDO_ANCHO-alien.getTamano().x, alien.getPosicion().y);<br />
}<br />
<br />
}<br />
<br />
if (alien.getPosicion().y <=Controis.FONDO_NEGRO.height){<br />
alien.setPosicion(alien.getPosicion().x,Controis.FONDO_NEGRO.height);<br />
}<br />
else {<br />
if (alien.getPosicion().y >= Mundo.TAMANO_MUNDO_ALTO-alien.getTamano().y){<br />
alien.setPosicion(alien.getPosicion().x, Mundo.TAMANO_MUNDO_ALTO-alien.getTamano().y);<br />
}<br />
<br />
}<br />
<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<br/><br />
<br/><br />
<br/><br />
Como temos definido o noso xogo (MVC) agora é moi sinxelo engadir novas formas de control (acelerómetro, gráfico, touchpad,...) xa que o único que temos que facer é controlar na clase que ten a interface cando se preme o control e chamar ó método presionarTecla coa 'tecla' pulsada.<br />
<br />
<br/><br />
<br/><br />
<br />
-----<br />
'''TAREFA 2.8.A A FACER:''' Esta parte está asociada á realización dunha tarefa. <br />
-----<br />
<br />
<br/><br />
<br />
===Tarefas avanzadas===<br />
<br /><br />
<br />
-----<br />
'''TAREFA AVANZADA OPTATIVA:''' Esta parte está asociada á [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Acelerometro#Exemplo_de_c.C3.B3digo realización dunha tarefa avanzada: Acelerómetro/Compás].<br />
-----<br />
<br/><br />
-----<br />
'''TAREFA AVANZADA OPTATIVA:''' Esta parte está asociada á [http://manuais.iessanclemente.net/index.php?title=LIBGDX_Xestion_Eventos_GestureListener realización dunha tarefa avanzada: Interface GestureListener].<br />
-----<br />
<br/><br />
-----<br />
'''TAREFA AVANZADA OPTATIVA:''' Esta parte está asociada á [http://manuais.iessanclemente.net/index.php?title=LIBGDX_TouchPad realización dunha tarefa avanzada: TochPad (joystick)].<br />
-----<br />
<br />
<br />
<br />
<br />
<br />
<br/> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2014).</div>Angelfg