hugoruscitti/pilas

View on GitHub
data/manual/eventos/index.json

Summary

Maintainability
Test Coverage
{
    "content": "<h1 id=\"eventos-conexiones-y-respuestas\">Eventos, conexiones y respuestas</h1>\n<p>En el desarrollo de videojuegos es muy importante\npoder comunicarse con el usuario. Lograr que los\npersonajes del juego puedan interactuar con \u00e9l y\nexista una fuerte interacci\u00f3n.</p>\n<p>En pilas usamos una estrategia llamada <code>eventos, conexiones\ny respuestas</code>, no solo porque es muy sencilla de usar, sino\ntambi\u00e9n porque es una soluci\u00f3n conocida y muy utilizada\nen otros lugares como en la web.</p>\n<h2 id=\"que-es-un-evento\">\u00bfQue es un Evento?</h2>\n<p>Los eventos representan algo que esperamos que ocurra\ndentro de un juego, por ejemplo un <code>click</code> del mouse, la\n<code>pulsaci\u00f3n</code> de una tecla, el <code>cierre</code> de la\nventana o la <code>colisi\u00f3n</code> entre un enemigo y nuestro\nprotagonista.</p>\n<p>Lo interesante de los eventos, es que pueden ocurrir en\ncualquier momento, y generalmente no lo controlamos, solamente\nlos escuchamos y tomamos alguna respuesta predefinida.</p>\n<p>Pilas representa a los eventos como objetos, y nos brinda\nfunciones para ser avisados cuando un evento ocurre e incluso\nemitir y generar eventos nuevos.</p>\n<p>Veamos algunos ejemplos:</p>\n<h2 id=\"conectando-la-emision-de-eventos-a-funciones\">Conectando la emisi\u00f3n de eventos a funciones</h2>\n<p>Los <code>eventos</code> no disparan ninguna acci\u00f3n autom\u00e1tica, nosotros\nlos programadores somos los que tenemos que elegir los\neventos importantes y elegir que hacer al respecto.</p>\n<p>Para utilizar estas se\u00f1ales, tenemos que vincularlas a funciones, de\nforma que al emitirse la se\u00f1al podamos ejecutar c\u00f3digo.</p>\n<h3 id=\"la-funcion-conectar\">La funci\u00f3n <code>conectar</code></h3>\n<p>La funci\u00f3n <code>conectar</code> nos permite conectar una se\u00f1al de\nevento a un m\u00e9todo o una funci\u00f3n.</p>\n<p>De esta forma, cada vez que se emita una determinada\nse\u00f1al, se avisar\u00e1 a todos los objectos que hallamos\nconectado.</p>\n<p>Por ejemplo, si queremos que un personaje se mueva\nen pantalla siguiendo la posici\u00f3n del puntero\ndel mouse, tendr\u00edamos que escribir algo como\nesto:</p>\n<pre><code class=\"python\">import pilasengine\n\npilas = pilasengine.iniciar()\n\nmono = pilas.actores.Mono()\n\ndef mover_mono_a_la_posicion_del_mouse(evento):\n    mono.x = evento.x\n    mono.y = evento.y\n\npilas.eventos.mueve_mouse.conectar(mover_mono_a_la_posicion_del_mouse)\n\n# O puedes utilizar el m\u00e9todo abreviado del actor.\nmono.mueve_mouse(mover_mono_a_la_posicion_del_mouse)\n\npilas.ejecutar()\n</code></pre>\n\n<p>Es decir, la se\u00f1al de evento que nos interesa es <code>mueve_mouse</code> (que se emite\ncada vez que el usuario mueve el mouse). Y a esta se\u00f1al le conectamos\nla funci\u00f3n que buscamos ejecutar cada vez que se mueva el mouse.</p>\n<p>Ten en cuenta que pueden existir tantas funciones conectadas a una se\u00f1al como\nquieras.</p>\n<p>Las coordenadas que reporta el mouse son relativas al escenario y no\nde la ventana. Por lo tanto puedes asignar directamente el valor\nde las coordenadas del mouse a los actores sin efectos colaterales\ncon respecto a la c\u00e1mara.</p>\n<h2 id=\"observando-a-los-eventos-para-conocerlos-mejor\">Observando a los eventos para conocerlos mejor</h2>\n<p>Como puedes ver en la funci\u00f3n <code>mover_mono_a_la_posicion_del_mouse</code>, hemos\ndefinido un par\u00e1metro llamado <code>evento</code> y accedimos a sus valores\n<code>x</code> e <code>y</code>.</p>\n<p>Cada evento tiene dentro un conjunto de valores que nos resultar\u00e1\nde utilidad conocer. En el caso del movimiento de mouse usamos\n<code>x</code> e <code>y</code>, pero si el evento es la pulsaci\u00f3n de una tecla, seguramente\nvamos a querer saber exactamente qu\u00e9 tecla se puls\u00f3.</p>\n<p>Entonces, una forma f\u00e1cil y simple de conocer el estado de un\nobjeto es imprimir directamente su contenido, por ejemplo, en\nla funci\u00f3n de arriba pod\u00edamos escribir:</p>\n<pre><code>def mover_mono_a_la_posicion_del_mouse(evento):\n    print evento\n</code></pre>\n<p>y en la ventana de nuestra computadora tendr\u00edamos que ver\nalgo as\u00ed:</p>\n<pre><code>{'y': 2.0, 'x': -57.0, 'dx': 0.0, 'dy': -1.0}\n</code></pre>\n<p>donde claramente podemos ver todos los datos que vienen asociados\nal evento.</p>\n<p>Por \u00faltimo, ten en cuenta que este argumento <code>evento</code>, en realidad,\nes un diccionario de python como cualquier otro, solo\nque puedes acceder a sus valores usando sentencias c\u00f3mo\n<code>diccionario.clave</code> en lugar de <code>diccionario['clave']</code>.</p>\n<h2 id=\"desconectando-senales\">Desconectando se\u00f1ales</h2>\n<p>Las se\u00f1ales se desconectan por cuenta propia cuando dejan de existir\nlos objetos que le conectamos. En la mayor\u00eda de los casos podemos\nconectar se\u00f1ales y olvidarnos de desconectarlas, no habr\u00e1 problemas,\nse deconectar\u00e1n solas.</p>\n<p>De todas formas, puede que quieras conectar una se\u00f1al, y por\nalg\u00fan motivo desconectarla. Por ejemplo si el juego cambia\nde estado o algo as\u00ed...</p>\n<p>Si ese es tu caso, simplemente as\u00edgnale un identificador \u00fanico\nal manejador de la se\u00f1al y luego usa la funci\u00f3n <code>desconectar_por_id</code> indicando\nel identificador.</p>\n<p>Por ejemplo, las siguientes sentencias muestran eso:</p>\n<pre><code>pilas.eventos.mueve_mouse.conectar(imprimir_posicion, id='drag')\npilas.eventos.mueve_mouse.desconectar_por_id('drag')\n</code></pre>\n<p>En la primera sentencia conect\u00e9 la se\u00f1al del evento a una funci\u00f3n y le di\nun valor al argumento <code>id</code>. Este valor ser\u00e1 el identificador\nde ese enlace. Y en la siguiente linea se utiliz\u00f3 el identificador\npara desconectarla.</p>\n<h2 id=\"listado-de-todos-los-eventos-existentes\">Listado de todos los eventos existentes</h2>\n<table>\n<thead>\n<tr>\n<th><strong>Evento</strong></th>\n<th><strong>Parametros</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>mueve_camara</td>\n<td>x, y, dx, dy</td>\n</tr>\n<tr>\n<td>mueve_mouse</td>\n<td>x, y, dx, dy</td>\n</tr>\n<tr>\n<td>click_de_mouse</td>\n<td>boton, x, y</td>\n</tr>\n<tr>\n<td>termina_click</td>\n<td>boton, x, y</td>\n</tr>\n<tr>\n<td>mueve_rueda</td>\n<td>delta</td>\n</tr>\n<tr>\n<td>pulsa_tecla</td>\n<td>codigo, texto</td>\n</tr>\n<tr>\n<td>suelta_tecla</td>\n<td>codigo, texto</td>\n</tr>\n<tr>\n<td>pulsa_tecla_escape</td>\n<td></td>\n</tr>\n<tr>\n<td>cuando_actualiza</td>\n<td></td>\n</tr>\n<tr>\n<td>pulsa_boton</td>\n<td>numero</td>\n</tr>\n<tr>\n<td>mueve_pad</td>\n<td>x, y, x1, y1</td>\n</tr>\n</tbody>\n</table>\n<h2 id=\"consultado-senales-conectadas\">Consultado se\u00f1ales conectadas</h2>\n<p>Durante el desarrollo es \u00fatil poder observar qu\u00e9\neventos se han conectado a funciones.</p>\n<p>Una forma de observar la conexi\u00f3n de los eventos\nes pulsar la tecla <code>F6</code>. Eso imprimir\u00e1 sobre\nconsola los nombres de las se\u00f1ales conectadas\njunto a las funciones.</p>\n<h2 id=\"creando-tus-propios-eventos\">Creando tus propios eventos</h2>\n<p>Si tu juego se vuelve mas complejo y hay interacciones entre\nvarios actores, puede ser una buena idea hacer que exista algo\nde comunicaci\u00f3n entre ellos usando eventos.</p>\n<p>Veamos c\u00f3mo crear un evento:</p>\n<p>Primero tienes que crear un objeto que represente a tu evento\ny darle un nombre:</p>\n<pre><code>evento = pilas.evento.Evento(\"Nombre\")\n</code></pre>\n<p>luego, este nuevo objeto <code>evento</code> podr\u00e1 ser utilizado como\ncanal de comunicaci\u00f3n: muchos actores podr\u00e1n <code>conectarse</code> para\nrecibir alertas y otros podr\u00e1n <code>emitir</code> alertas:</p>\n<pre><code class=\"python\">def ha_ocurrido_un_evento(datos_evento):\n    print &quot;Hola!!!&quot;, datos_evento\n\nevento.conectar(ha_ocurrido_un_evento)\n\n# En otra parte...\nevento.emitir(argumento1=123, argumento2=123)\n</code></pre>\n\n<p>Cuando se emite un evento se pueden pasar muchos argumentos, tantos\ncomo se quiera. Todos estos argumentos llegar\u00e1n a la funci\u00f3n de\nrespuesta en forma de diccionario.</p>\n<p>Por ejemplo, para este caso, cuando llamamos al m\u00e9todo <code>evento.emitir</code>,\nel sistema de eventos ir\u00e1 autom\u00e1ticamente a ejecutar la funci\u00f3n <code>ha_ocurrido_un_evento</code>\ny \u00e9sta imprimir\u00e1::</p>\n<pre><code>Hola!!! {argumento1: 123, argumento2: 123}\n</code></pre>\n<h2 id=\"referencias\">Referencias</h2>\n<p>El concepto que hemos visto en esta secci\u00f3n se utiliza\nen muchos sistemas. Tal vez el mas conocido de estos es\nla biblioteca <code>GTK</code>, que se utiliza actualmente para construir\nel escritorio <code>GNOME</code> y <code>Gimp</code> entre otras aplicaciones.</p>\n<p>El sistema de se\u00f1ales que se utiliza en pilas es una\nadaptaci\u00f3n del siguiente sistema de eventos:</p>\n<p>http://stackoverflow.com/questions/1092531/event-system-in-python</p>\n<p>Anteriormente us\u00e1bamos parte del c\u00f3digo del sistema <code>django</code>, pero\nluego de varios meses lo reescribimos para que sea mas sencillo\nde utilizar y no tenga efectos colaterales con los m\u00e9todos y\nel m\u00f3dulo <code>weakref</code>.</p>\n<p>Si quieres obtener mas informaci\u00f3n sobre otros sistemas de\neventos te recomendamos los siguientes documentos:</p>\n<ul>\n<li>http://pydispatcher.sourceforge.net/</li>\n<li>http://www.mercurytide.co.uk/news/article/django-signals/</li>\n<li>http://www.boduch.ca/2009/06/sending-django-dispatch-signals.html</li>\n<li>http://docs.djangoproject.com/en/dev/topics/signals/</li>\n</ul>\n", 
    "url": "/eventos/", 
    "language": "en", 
    "title": "Eventos conexiones y respuestas"
}