Octubre 16, 2014, 04:59:54 PM Ultima modificación: Octubre 16, 2014, 05:22:34 PM por PedroRenaut
Hola amigos...
Hasta ahora siempre creí que las instancias de objetos solapaban a otros con un DEPTH superior ... pero en lo que respecta a la deteccion de eventos (en este caso el click del mouse), acabo de descubrir que no funciona como yo pensaba... me explico.

En el archivo adjunto teneis el ejemplo que me ha generado dos grandes dudas, que espero, alguien me pueda resolver.

Introduccion:
El ejemplo (Dudas.gmx) consta de 8 objetos.
Cada boton A,B,1,2,3 y wall mostrará al pulsarlo un mensaje de texto diciendo quien es.
Open quita la instancia de obj_wall y Close pone la instancia de obj_wall tapando los botones 1,2 y 3.
Sabiendo que el DEPTH de los objetos es el siguiente:

0       obj_wall y obj_A
100   todos los demás.

1 - ¿Porque si pulsamos en la interseccion de A con B nos muestra los dos mensajes?... ¿Como consigo que solo se muestre el mensaje del objeto de menor depth sin que reaccione el que hay debajo?
*Lógicamente sin tener que modificar lo que hubiese en un depth superior (por debajo).
2 - Del mismo modo, cuando pulsas close y obj_wall tapa los tres botones ocurre lo mismo ... si pulsas una zona que coincida con un boton, tu pulsacion es recibida tanto por el obj_wall como por el propio boton que está debajo... ¿Porque? ... ¿Como tapar de forma efectiva?

En espera de vuestra aportaciones ... recibid un cordial saludo.
"Hay dos maneras de diseñar software: una es hacerlo tan simple que sea obvia su falta de deficiencias, y la otra es hacerlo tan complejo que no haya deficiencias obvias"
-- C.A.R. Hoare
"Controlar la complejidad es la esencia de la programación"
-- Brian Kernigan
"La función de un buen software es hacer que lo complejo aparente ser simple"
-- Grady Booch
"La programación es una carrera entre los desarrolladores, intentando construir mayores y mejores programas a prueba de idiotas, y el universo, intentanto producir mayores y mejores idiotas. Por ahora va ganando el Universo"
-- Rich Cook

Amigo lastima q estoy en el trabajo y no tenego el gm aqui!
Pero lo de las intersecciones se puede arreglar con las mascaras de colisión y lo de que tapa un objeto a otro quizás se puede hacer con el un if deth>other.deth

Creo q puede funcionar asi (lógicamente bien estructurado)  esq como te digo estoy respondiendo desde mi celular! Cuando llegue a casa te ayudo mas
PURA VIDA



El porqué es bastante sencillo: Porque los eventos de GMS son democráticos y no discriminan objetos. Si consultas la documentación de los eventos del mouse
http://docs.yoyogames.com/source/dadiospice/000_using%20gamemaker/events/mouse%20event.html
no hay nada que indique que el evento tiene un orden de ejecución o prioridad basado en la profundidad del objeto.

Asignaste un evento de mouse a los objetos A y B. Cuando se hace click sobre esos objetos, GM detecta que ambos poseen un evento de mouse y ejecuta el código correspondiente de cada objeto. Esto, si se piensa bien, es la manera correcta en que deben funcionar los eventos, y si uno de ellos no se ejecutara (a pesar de que el objeto tuviera un evento totalmente válido) sería un fallo bastante incongruente por parte de GM

GM es obediente y ejecuta el evento de mouse en el momento que debe, sin hacer ni más ni menos que lo que dice el código: "si se me presiona, dibujo un mensaje en pantalla". Si quieres que se muestre un solo mensaje (GM no tiene manera de saber esto originalmente), tienes que ser específico e implementar el código que haga que sólo se muestre el mensaje del objeto con menor profundidad.


Cita de: penumbra en Octubre 16, 2014, 09:38:17 PM
El porqué es bastante sencillo: Porque los eventos de GMS son democráticos y no discriminan objetos. Si consultas la documentación de los eventos del mouse
http://docs.yoyogames.com/source/dadiospice/000_using%20gamemaker/events/mouse%20event.html
no hay nada que indique que el evento tiene un orden de ejecución o prioridad basado en la profundidad del objeto.

Asignaste un evento de mouse a los objetos A y B. Cuando se hace click sobre esos objetos, GM detecta que ambos poseen un evento de mouse y ejecuta el código correspondiente de cada objeto. Esto, si se piensa bien, es la manera correcta en que deben funcionar los eventos, y si uno de ellos no se ejecutara (a pesar de que el objeto tuviera un evento totalmente válido) sería un fallo bastante incongruente por parte de GM

GM es obediente y ejecuta el evento de mouse en el momento que debe, sin hacer ni más ni menos que lo que dice el código: "si se me presiona, dibujo un mensaje en pantalla". Si quieres que se muestre un solo mensaje (GM no tiene manera de saber esto originalmente), tienes que ser específico e implementar el código que haga que sólo se muestre el mensaje del objeto con menor profundidad.

Ya probé con uno que hice yo y pasa también lo mismo en el  :GM8:.

amigo aqui esta tus problemas resueltos  ;) ;) ;) ;)

miralo y me dices que te parece!!!!
PURA VIDA



#5 Octubre 17, 2014, 09:58:55 AM Ultima modificación: Octubre 17, 2014, 10:06:55 AM por PedroRenaut
En primer lugar daros las gracias a todos por las aportaciones que estais enviando.

Quiero primeramente discrepar de lo que ha dicho Penumbra...
CitarEsto, si se piensa bien, es la manera correcta en que deben funcionar los eventos, y si uno de ellos no se ejecutara (a pesar de que el objeto tuviera un evento totalmente válido) sería un fallo bastante incongruente por parte de GM
... No estoy deacuerdo ... en ningun lenguaje visual (VBasic, Gambas o C++) al pulsar sobre un objeto detonas los que haya debajo ... de modo que el que esté en primer plano es el único que recibiría dicha pulsación. Imagina el boton de disparo de misiles... está debajo de una tapa de plastico transparente ... si esta cerrada ¿que pulsas fisicamente? ... ¿El boton percibe que pulsas la tapa? ... No.
Lo incongruente es lo contrario (pienso yo) pero si es asi en GameMaker ... pues así habrá que aprenderlo.  ;)

Con respecto a la solucion de Ocarina, está francamente muy bien, porque hace un control de pulsación que, mediante condicionamiento comparativo de profundidad permite que solo se ejecute el mensaje del objeto apropiado.

Lamentablemente no cubre totalmente el problema.
Supongamos que estoy desarrollando un script/funcion/clase que al insertarlo en un proyecto, al llamarlo me muestre un anuncio solapando la propia aplicacion que lo llamó ... De modo que el concepto es tapar lo que se vé y poner lo que desees.

Si "Tapar" en los terminos que estoy necesitando no es posible del mismo modo que en otros lenguajes OOP ... entonces significaria que hay que modificar y/o condicionar todos los objetos que vayan a quedar debajo (según la solucion de Ocarina)... y eso no sería nada práctico desde un punto de vista programatico y mucho menos en el concepto de Programación Orientada a Servicios.

Creo que si no se puede hacer tal y como expongo, la única solucion práctica sería descartar o sustituir el concepto "Tapar" por ir a una room propia, quizas con un screenshot de la pantalla anterior para usarla de background de dicha room ... de este modo creo que se podría simular lo que digo sin afectar a la app en la que uses el script/funcion/clase. (Aunque surjen otros inconvenientes)

Si, es una solucion pero no es nada óptima o depurada ... de modo que seguire dandole vueltas.

Gracias de nuevo a to2
"Hay dos maneras de diseñar software: una es hacerlo tan simple que sea obvia su falta de deficiencias, y la otra es hacerlo tan complejo que no haya deficiencias obvias"
-- C.A.R. Hoare
"Controlar la complejidad es la esencia de la programación"
-- Brian Kernigan
"La función de un buen software es hacer que lo complejo aparente ser simple"
-- Grady Booch
"La programación es una carrera entre los desarrolladores, intentando construir mayores y mejores programas a prueba de idiotas, y el universo, intentanto producir mayores y mejores idiotas. Por ahora va ganando el Universo"
-- Rich Cook

Bueno, ahora me permito discrepar con tu opinión.

No creo que el ejemplo que das del botón con tapa de plástico sea válido, porque de la misma manera yo puedo sugerir un comportamiento a la inversa, pero eso no quiere decir que es así como deba funcionar el lenguaje en todos los casos. Por ejemplo, si se quisiera simular una de esas varas con las que se pincha la basura (para recogerla del suelo), pues entonces diría que no es lógico que la vara sólo pueda pinchar la envoltura más arriba, sino que la vara puede pinchar y coger más de una envoltura de un solo pinchazo, y si el lenguaje no se comportara así diría que no es congruente, lo cual no es cierto.

De lo que se trata es que en GM, si le colocas un código (válido) a un evento, no hay ninguna razón para pensar que ese código no deba ejecutarse o para pensar que GM deba adivinar cuándo quiero que se ejecute y cuando no (sin usar condiciones). ¿Por qué? Porque la documentación no indica que la ejecución de los eventos de ratón dependa de la profundidad de un objeto. Y por eso mencioné que el comportamiento es congruente. Si la documentación mencionara una cosa y GML se comportara de manera distinta, entonces sí me atrevería a decir que es incongruente.

Y bueno, creo que una comparación o relación con VB o C++ no tiene caso ya que de entrada, GML no es un lenguaje orientado a objetos: http://gmc.yoyogames.com/index.php?showtopic=591920. Así que muchas soluciones serán distintas (y probablemente) menos óptimas que en aquellos lenguajes o simplemente hay cosas que no es posible hacer.

Pero es difícil no estar de acuerdo con la conclusión que haces al final: si así es en GM, así habrá que aprenderlo.

Creo que no entiendo exactamente tu concepto de tapar, pero si quieres que un objeto no sólo quede por encima del juego, sino que se dibuje más allá de los límites de la ventana del juego (como un pop-up no centrado), entonces no conozco ningún método para hacerlo. No he visto la solución de Ocarina, pero si no hay problema en que el mensaje no salga de los límites de la habitación, sí hay manera de hacer que "una capa" obstruya la visión de lo que hay debajo sin necesidad de usar una habitación extra (supongo, porque repito que probablemente no entiendo al 100% cómo funciona eso que llamas tapar).


Es más sencillo si abres el ejemplo y lo vés en acción. Si no estamos en dos contextos distintos de conversacion. ;D
"Hay dos maneras de diseñar software: una es hacerlo tan simple que sea obvia su falta de deficiencias, y la otra es hacerlo tan complejo que no haya deficiencias obvias"
-- C.A.R. Hoare
"Controlar la complejidad es la esencia de la programación"
-- Brian Kernigan
"La función de un buen software es hacer que lo complejo aparente ser simple"
-- Grady Booch
"La programación es una carrera entre los desarrolladores, intentando construir mayores y mejores programas a prueba de idiotas, y el universo, intentanto producir mayores y mejores idiotas. Por ahora va ganando el Universo"
-- Rich Cook

Cita de: PedroRenaut en Octubre 17, 2014, 09:58:55 AM
En primer lugar daros las gracias a todos por las aportaciones que estais enviando.

Quiero primeramente discrepar de lo que ha dicho Penumbra...
CitarEsto, si se piensa bien, es la manera correcta en que deben funcionar los eventos, y si uno de ellos no se ejecutara (a pesar de que el objeto tuviera un evento totalmente válido) sería un fallo bastante incongruente por parte de GM
... No estoy deacuerdo ... en ningun lenguaje visual (VBasic, Gambas o C++) al pulsar sobre un objeto detonas los que haya debajo ... de modo que el que esté en primer plano es el único que recibiría dicha pulsación. Imagina el boton de disparo de misiles... está debajo de una tapa de plastico transparente ... si esta cerrada ¿que pulsas fisicamente? ... ¿El boton percibe que pulsas la tapa? ... No.
Lo incongruente es lo contrario (pienso yo) pero si es asi en GameMaker ... pues así habrá que aprenderlo.  ;)
Visual Basic es un lenguaje que trabaja con formularios. Game Maker con juegos. La condición de que el evento pertinente se active es que el mouse esté sobre un pixel opaco del sprite del objeto, y que se haga click. No importa si por casualidad justo resulta haber algo tapándolo o dibujado arriba.

Y por cierto, C++ no es un "lenguaje visual". Cualquier cosa "visual" de C++ a la que te estés refiriendo debe ser algún agregado y de ninguna manera parte del lenguaje.

Te recomiendo que expliques más generalmente qué estás tratando de lograr. No puedo abrir tu ejemplo porque no tengo GMS.
Vim.

Pedro si queres hacer algo asi de tapar entonces vas a tener q condicionar todos tus objetos de botones!

Y wadk y penumbra
En Vb y C++ si se puede hacer juegos yo he echo juegos en ambos lenguajes!
Vb es muy amplio y se puede hacer tanto con formularios y también juegos!  Lo se porque yo he hecho juegos en vb
Y en C++ también he echo juegos y visuales osea con sprites! Aunque no lo creais!
PURA VIDA



Cita de: ocarina en Octubre 17, 2014, 07:18:19 PM
Y wadk y penumbra
En Vb y C++ si se puede hacer juegos yo he echo juegos en ambos lenguajes!
Vb es muy amplio y se puede hacer tanto con formularios y también juegos!  Lo se porque yo he hecho juegos en vb
Y en C++ también he echo juegos y visuales osea con sprites! Aunque no lo creais!

Bueno, pero nadie en el hilo a dicho que GML sea el único lenguaje que sirve para hacer juegos, ni que C++ o VB no sirvan para hacer juegos. Lo único que mencioné es que no sé por qué GML tendría que comportarse como C++/VB cuando GML ni siquiera es un lenguaje orientado a objetos, y aun entre lenguajes orientados a objetos, hay muchas diferencias.

A ver ... no digo como se debe comportar GML sino mas bien intento entender como se "deben" hacer las cosas en él.

La duda es ... Como hacer un objeto que tape por ejemplo un boton y que ese boton no reaccione al click dado que está debajo del elemento que lo tapa... de manera analoga a la realidad.

Supongamos que quiero hacer un script que al llamarlo me sobre impresione un objeto que me atenue la pantalla y todos los elementos que se encuentran en ella. Que al hacerle click desaparezca. Y todo ello sin tener que decirle a los demás que quedan por debajo nada de nada.

Según lo que explicó Penumbra, esto no funciona asi en GML ... de forma que solo se me ocurre la manera "rebuscada" que comenté con anterioridad (en un post anterior) de hacer un snapshot del room y ponerlo de fondo en un nuevo room para simular lo que intento realizar.

Que en su dia realicé en C++ con Allegro y en VBasic ... pero esto no es importante.

Lo que realmente me ha dejado un poco descolocado es el echo de que la profundidad de un objeto o incluso su alfa no provoque una "opacidad" real en lo que respecta a discriminar quien recibe la accion.

Dicho de otro modo ... y si lo he entendido bien ... cuando por ejemplo se hace click con el izquierdo del raton en las coordenadas 100,100 ... todos los objetos que estén en esas coordenadas con evento click izquierdo detectaran dicha pulsacion aunque otros objetos estén "tapándolos" ... es decir ... ¿No ha forma de poner "barreras" entre objetos?

Perdona Wadk ... intentaré explicarlo mejor, aunque es complicado, por lo que acabo de mencionar ... de modo que parece que siempre habrá que discriminar en estos casos con las colisiones.

No deja de chocarme amigos.

Gracias a to2
"Hay dos maneras de diseñar software: una es hacerlo tan simple que sea obvia su falta de deficiencias, y la otra es hacerlo tan complejo que no haya deficiencias obvias"
-- C.A.R. Hoare
"Controlar la complejidad es la esencia de la programación"
-- Brian Kernigan
"La función de un buen software es hacer que lo complejo aparente ser simple"
-- Grady Booch
"La programación es una carrera entre los desarrolladores, intentando construir mayores y mejores programas a prueba de idiotas, y el universo, intentanto producir mayores y mejores idiotas. Por ahora va ganando el Universo"
-- Rich Cook

Evento Begin Step:
[gml]globalvar mouse_depth,mouse_instance,mouse_clickon;
mouse_depth=99999
mouse_instance=0
mouse_clickon=false[/gml]

Evento Mouse Click:
[gml]globalvar mouse_depth,mouse_instance,mouse_clickon;
if depth<mouse_depth then
{
   mouse_depth=depth
   mouse_instance=id
   mouse_clickon=true
}[/gml]

Evento End Step
[gml]globalvar mouse_depth,mouse_instance,mouse_clickon;
if mouse_clickon then
{
   if mouse_instance.object_index=id then
   {
      //Lo que quieres que pase, aquí
   {
}[/gml]

Todos los código van en el objeto.

Puedes usar la función collision_point, dicha función devuelve la id de la instancia con la que encuentra colisión, en el caso de encontrar varias instancias en la misma posición devuelve la id de la instancia con menor profundidad y menor id.

Esto quiere decir que devuelve el id de la instancia que el GM dibujaría por encima de las demás.

Podrías usar esta función de dos maneras:

if collision_point(mouse_x,mouse_y,all,1,0) == id {
  //Código de click
}


Donde el código de lo que quieras que ocurra con click estaría dentro del if de collision_point, el cual se ejecutaría si la id del objeto es la misma que retorna la función.

O puedes usarla así al principio del código:

if collision_point(mouse_x,mouse_y,all,1,0) != id exit;

Donde el evento de click se terminaría inmediatamente al encontrar que la id de la instancia no es la misma que retorna collision_point. Con este método ni siquiera tienes que ponerlo en el mismo bloque de código que el resto del evento, puedes agregarlo en un bloque aparte al principio del evento.

Ahora bien, entiendo que preferirías que esto fuese automático, para no tener que estar agregando tú esa pieza de código, y puede hacerse, por ejemplo este código:

if mouse_check_button(mb_left){
  mouse_clear(mb_left);
  with(all) {
    if collision_point(mouse_x,mouse_y,object_index,1,0) {
      event_perform(ev_mouse,ev_left_button);
      break;
    }
  }
}


Ese código se usaría en el evento step begin de un objeto en la room, cualquier objeto. Se activa cuando presionas el botón izquierdo del mouse, limpia el estado de dicho botón para evitar que los eventos se ejecuten como normalmente lo harían, y luego busca entre las instancias una con la misma id que la devuelta por collision_point para ejecutar su evento del botón izquierdo del mouse manualmente. Sin embargo esto trae su propios problemas como, por ejemplo, la función que limpia el estado del mouse hace que no se puedan registrar eventos al soltar el botón izquierdo, y el evento del botón presionado solo se ejecuta una vez, en lugar de seguir ejecutándose mientras se siga presionando el botón.

Estos son problemas que se pueden solucionar usando métodos alternos, como eventos de usuario en lugar de eventos de mouse, así no es necesario limpiar el estado del botón del mouse, pero sinceramente me parece que el esfuerzo necesario para hacer una pieza de código que funcione sin ningún problema supera al esfuerzo necesario para copiar y pegar un bloque en los objetos que tienen eventos de mouse.

Dejo un ejemplo, puedes hacerle click a los círculos para cambiarles de color, notaras que, aparte de que los círculos respetan el orden en que están dibujados a la hora de hacer click, solo podrás hacerle click a los círculos que están por encima de instancias barrera.

Gracias a TheSandBoxMKG y a Killer por vuestras soluciones, creo que esa es la solución más optima ... voy a ver el ejemplo que has enviado y a hacer unas cuantas pruebas.

De nuevo... muchas gracias a to2.

Salu2
"Hay dos maneras de diseñar software: una es hacerlo tan simple que sea obvia su falta de deficiencias, y la otra es hacerlo tan complejo que no haya deficiencias obvias"
-- C.A.R. Hoare
"Controlar la complejidad es la esencia de la programación"
-- Brian Kernigan
"La función de un buen software es hacer que lo complejo aparente ser simple"
-- Grady Booch
"La programación es una carrera entre los desarrolladores, intentando construir mayores y mejores programas a prueba de idiotas, y el universo, intentanto producir mayores y mejores idiotas. Por ahora va ganando el Universo"
-- Rich Cook