Noticias

Importante: ¡Si quieres publicar tu juego no olvides leer este tema!

Comunidad Game Maker

Bienvenid@ a la comunidad hispana de Game Maker. Nuestro objetivo es crear videojuegos y dar soporte en castellano de GM. Para mejorar nuestro servicio hemos implantado, como adicion al reglamento general, algunas normas especificas en los subforos más comunes. ¡No olvides informarte antes de participar!.

Autor Tema: Bala que rebote de un enemigo a otro  (Leído 658 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Taki-A

en: Enero 28, 2020, 07:35:06 am
  Hola buenas gente, quisiera implementar el que una bala pueda rebotar de un enemigo a otro y este pueda hacerlo un máximo de veces digamos 3 y que sólo pueda atacar a un enemigo que no haya atacado antes.

Intente esto. Añadi a la bala el instance nearest  y al enemigo una variable golpeado.

Hice que la bala busque al enemigo que no esté golpeado. Pero la bala solo se queda fija en el primer enemigo a demás vuelve a golpear al enemigo que ya golpeó

Para tener una idea de lo que deseo hacer. Me baso en las mecánicas de Jessie de Brawl Star
 Cualquier ayuda es bien merecida.

 

 


No Tienes Permisos Para Dar Puntos
point 0 Puntos

Este tema no recibió puntos.


Desconectado BssString

Respuesta #1 en: Febrero 02, 2020, 01:51:39 am
Hola Taki-A

Eso lo puedes hacer llamando una función "with" desde el proyectil para encontrar al enemigo más cercano.
Si no quieres repetir el enemigo para que cada rebote golpee a un objetivo único, puedes añadir el ID del objeto que ya fue golpeado a una "data structure" e ignorarlo del check. (Creo que así funcionan las balas de Jessie)

Ejemplo de lo que digo.

En el create event del proyectil:
objetivos_golpeados = ds_list_create() //Esto crea una DS_LIST que guardará el ID de los objetivos golpeados para ignorarlos en el check del rebote y colisión

Importante eliminar la DS LIST cuando el proyectil se destruye y cuando se termina la ejecución del Juego (por si cierras el juego antes que el proyectil se destruya).
En el "Game End Event" y en el "Destroy Event"
if ds_exists(objetivos_golpeados,ds_type_list) ds_list_destroy(objetivos_golpeados) //Esto elimina la DS LIST de la memoria
Yo uso GMS1.4 y en lo personal, en el "Game End" event me gusta llamar al destroy event usando "event_perform(ev_destroy,0)", así no tengo que copiar y pegar todo lo que ponga en el Destroy.
En GMS2 se creó el "Clean Up" event para facilitar la destrucción de las Data Structures.

Ahora el rebote. En el evento de colisión del proyectil contra el enemigo:
//Sólo hace algo si el proyectil NO ha colisionado con ese enemigo.
if ds_list_find_index(objetivos_golpeados,other) = -1 { //La palabra "other" es el ID del objeto enemigo con el que el proyectil ha colisionado. Si NO lo encuentra en la DS LIST, la función regresa "-1".
other.hp -= 10//Aqui corres tu línea para causar daño al enemigo, yo usé esta de ejemplo con la variable "hp". Si tu enemigo no tiene la variable "hp" te dará bug.
ds_list_add(objetivos_golpeados,other) //Esto añade ese Enemigo a la Lista de enemigos golpeados.
var next_target = noone //Este será el ID del próximo enemigo a perseguir.
var min_distance = -1 //Esto es simplemente para determinar cuál es el enemigo más cercano.
var _list = objetivos_golpeados
with ( obj_enemy ) if ds_list_find_index(other.objetivos_golpeados,id) = -1 {
if min_distance = -1 { min_distance = point_distance(x,y,other.x,other.y); next_target = id }
else {
var my_distance = point_distance(x,y,other.x,other.y)
if my_distance < min_distance { min_distance = my_distance; next_target = id }
}
}
//Después del With, la variable "next_target" tendrá el ID del enemigo más cercano o "noone" si no encontró ninguno
if next_target != noone {
direction = point_direction(x,y,next_target.x,next_target.y) //Esto le cambia la dirección al proyectil para dirigirse ahora hacia el nuevo enemigo
}
}

He llamado al enemigo "obj_enemy", tú llámalo como le hayas puesto.

Ojo que al usar la función "with" te cambia el Scoping de las variables (no sé como se dice en español... alcance de las variables?) eso quiere decir que todas las variables de instance que uses, no se escriben/leen desde el proyectil, sino que se harán desde el enemigo, incluso la palabra "other" significa el enemigo fuera del With y el proyectil dentro del With.
Las variables locales que declaré con la palabra "var" adelante no se ven afectadas por el Scoping, así que las puede leer cualquier objeto tal como si fuesen variables globales.

Recuerda ponerle un tiempo de duración de vida al proyectil o algún contador de rebotes para que se destruya.

Saludos

 


Desconectado Taki-A

Respuesta #2 en: Febrero 03, 2020, 05:48:22 am
  ante todo muchas gracias por tomarte el tiempo de evaluar mi problemilla, veras provee el codigo y le cambie los valores que me dijiste pero ocurre un problema y es que la bala no se mueve, hasta donde entendi en direction deberia ver la direccion del proximo enemigo no es asi? al crear la bala esta se queda quieta solo genera el daño escrito 

 


Desconectado BssString

Respuesta #3 en: Febrero 03, 2020, 10:40:04 am
Hola Taki-A

El código que coloqué era sólo para cambiar la trayectoria de la bala, no para moverla.

Intenta asignarle una variable "speed" en el create event para que la bala se mueva.

Saludos

 


Desconectado FernandoNavarro

Respuesta #4 en: Febrero 03, 2020, 02:52:00 pm
Hola a todos.

Si creas la bala desde otro objeto, algo como esto:

Spoiler
[...] //Comprobación de dónde mira o algo así
insBullet = instance_create(posicion_en_x, posicion_en_y, objBullet);

//Aquí puedes agregar las variables que necesitará la bala, como daño que hará, velocidad, etcétera.

insBullet.speed = 4.5;

 


Desconectado Taki-A

Respuesta #5 en: Febrero 03, 2020, 03:01:05 pm
Hola Taki-A

El código que coloqué era sólo para cambiar la trayectoria de la bala, no para moverla.

Intenta asignarle una variable "speed" en el create event para que la bala se mueva.

Saludos Eso había pensando en su momento. Ahora al hacerlo golpea a un enemigo, pasa de largo y se pierde en la room. Y si le doy un else para que se destruya. Golpea al primero y se destruye o golpea al primero va por el 2do y pasa de largo sin dañarlo solo lo atraviesa.

 


Desconectado BssString

Respuesta #6 en: Febrero 04, 2020, 04:01:42 pm
Qué rato, yo lo testié y me funcionó perfecto.

Manda tu código para ver cómo lo has dejado y dime en qué objeto y en qué evento has puesto el código.
Con el código puedo ver también el nombre de las variables que usas

 


Desconectado Taki-A

Respuesta #7 en: Febrero 05, 2020, 12:26:37 am
  Estos vienen a ser los cambios que hice al codigo
 //en el evento create de mi objeto obj_esfera_rebote
objetivos_golpeados = ds_list_create()
speed = 7
 
 //en el evento game end y en destroy
if ds_exists(objetivos_golpeados,ds_type_list) ds_list_destroy(objetivos_golpeados) //Esto elimina la DS LIST de la memoria  
 
 //en el evento de colision de obj_esfera_rebote hacia obj_enemigo_general
//tengo que decir que el obj_enemigo_general es un objeto padre
//Sólo hace algo si el proyectil NO ha colisionado con ese enemigo.
if ds_list_find_index(objetivos_golpeados,other) = -1 { //La palabra "other" es el ID del objeto enemigo con el que el proyectil ha colisionado. Si NO lo encuentra en la DS LIST, la función regresa "-1".
other.vida -= (global.ataque_general * 1.25)//Aqui corres tu línea para causar daño al enemigo, yo usé esta de ejemplo con la variable "hp". Si tu enemigo no tiene la variable "hp" te dará bug.
ds_list_add(objetivos_golpeados,other) //Esto añade ese Enemigo a la Lista de enemigos golpeados.
var next_target = noone //Este será el ID del próximo enemigo a perseguir.
var min_distance = -1 //Esto es simplemente para determinar cuál es el enemigo más cercano.
var _list = objetivos_golpeados
with (obj_enemigo_general) if ds_list_find_index(other.objetivos_golpeados,id) = -1 {
if min_distance = -1 { min_distance = point_distance(x,y,other.x,other.y); next_target = id }
else {
var my_distance = point_distance(x,y,other.x,other.y)
if my_distance < min_distance { min_distance = my_distance; next_target = id }
}
}
//Después del With, la variable "next_target" tendrá el ID del enemigo más cercano o "noone" si no encontró ninguno
if next_target != noone {
direction = point_direction(x,y,next_target.x,next_target.y) //Esto le cambia la dirección al proyectil para dirigirse ahora hacia el nuevo enemigo
}
}


 
[/size][/font]
Qué rato, yo lo testié y me funcionó perfecto.

Manda tu código para ver cómo lo has dejado y dime en qué objeto y en qué evento has puesto el código.
Con el código puedo ver también el nombre de las variables que usas

 


Desconectado BssString

Respuesta #8 en: Febrero 05, 2020, 01:30:37 am
Hola Taki-A

Sigo sin entender bien tu problema, probé el código que me pasaste y me funciona perfecto.

Cuando la bala colisiona con cualquiera de los hijos, se cambia de dirección hacia el próximo enemigo más cercano (que no haya tocado antes)
Puse 10 enemigos (5 de un objeto y 5 de otro con un padre en común) y la bala rebotó en los 10 enemigos y a todos los quitó HP, y cuando llegó al décimo enemigo siguió su trayectoria al infinito porque ya no encontró más enemigos NO golpeados para atacar. Para evitar que la bala recorra hasta el infinito, creale una alarma en el "create event" que le de un cierto tiempo de vida, luego en el evento de activación de la alarma destruyes la instancia del proyectil, así ya no viajará hasta el infinito.

Si la bala no está causando daño, primero dibuja en pantalla la variable "vida" de cada enemigo para ver cómo se comporta cuando recibe la bala.

Mi sugerencia es que revises en los objetos hijos si TODOS tienen asignado el "obj_enemigo_general" como padre, si uno de los hijos no tiene asignado ese padre, entonces quedan fuera de la detección.

También revisa que tanto el proyectil como todos los sprites de los objetos hijos tengan una máscara de colisión ya que el check de colisión se hace contra el cuadro de colisión de los sprite.

Ojo que la dirección que gana la bala se calcula en base al punto de origen de los sprites. Si tienes el punto de origen en la coordenada ( 0, 0) puede ser que la bala pase por una parte del Sprite transparente y por eso no te detecta la colisión.

A modo de test, puedes escribir un "show_message" (o un show_debug_message) justo debajo de la línea que le quita vida a los enemigos para que aparezca cada vez que la bala detecta colisión, así sabrás si el problema es que la bala no colisiona u otra cosa.
ejemplo:
Código: [Seleccionar]
show_message("La bala colisiona con: "+object_get_name(other.object_index))
Saludos Cordiales

 


Desconectado Taki-A

Respuesta #9 en: Febrero 05, 2020, 02:40:24 am
disculpa que te insista, pero me pasa lo mismo, que la bala al ser creada se dirige al enemigo mas cercano pero solo impacta en ese(ahora sale el mensaje) y luego sigue su camino al infinito, eso y a veces cuando la bala se crea muy arriba del enemigo mas cercano esta se dirige a su direccion pero solo en X mas no en y asi que le pasa por encima sin dañarlo, probe creando un nuevo proyecto solo el codigo de la bala y el enemigo con la variable, aun asi el problema persiste, quizas problema de version o algo asi  :'( 

 


Desconectado BssString

Respuesta #10 en: Febrero 05, 2020, 02:00:45 pm
Hola Taki-A

1 - Mencionaste que al crear la bala "arriba" del enemigo hace que la bala sólo lo persiga en el eje X y no alcanza a hacer colisión. Eso pasa porque la Bala se dirige hacia las coordenadas de origen del sprite, si tu sprite enemigo tiene el origen en la coordenada (x=0, y=0) obiamente la bala irá hacia ese punto.
Para ir al centro, lo que puedes hacer es cambiar la última línea que te calcula la nueva dirección de la Bala:
Código: [Seleccionar]
direction = point_direction(x,y,next_target.x,next_target.y)Por esta nueva línea:
Código: [Seleccionar]
direction = point_direction(x,y,next_target.x+next_target.sprite_width/2,next_target.y+next_target.sprite_height/2)No es la mejor solución, porque va a variar según el tamaño del sprite, pero si no quieres cambiar la coordenada de origen, puede ser una buena solución parche a ese problema.

2 - Lo otro que comentaste, es que sólo detecta un enemigo y no los demás.
Eso es porque la función "with (obj_enemigo_general)" no los está tomando en cuenta. Comprobaste que todos los objetos enemigos tengan asignado como parent al obj_enemigo_general???
Por alguna razón esa función no los está tomando en cuenta.

Saludos

 


Desconectado Taki-A

Respuesta #11 en: Febrero 05, 2020, 07:36:59 pm
Si exactamente eso verifique, el objeto es hijo del obj_enemigo_general y tiene su sprite centrado.... habra una forma de contactarte para mostrar capturas de lo que pasa en el codigo?
   
Hola Taki-A

1 - Mencionaste que al crear la bala "arriba" del enemigo hace que la bala sólo lo persiga en el eje X y no alcanza a hacer colisión. Eso pasa porque la Bala se dirige hacia las coordenadas de origen del sprite, si tu sprite enemigo tiene el origen en la coordenada (x=0, y=0) obiamente la bala irá hacia ese punto.
Para ir al centro, lo que puedes hacer es cambiar la última línea que te calcula la nueva dirección de la Bala:
Código: [Seleccionar]
direction = point_direction(x,y,next_target.x,next_target.y)Por esta nueva línea:
Código: [Seleccionar]
direction = point_direction(x,y,next_target.x+next_target.sprite_width/2,next_target.y+next_target.sprite_height/2)No es la mejor solución, porque va a variar según el tamaño del sprite, pero si no quieres cambiar la coordenada de origen, puede ser una buena solución parche a ese problema.

2 - Lo otro que comentaste, es que sólo detecta un enemigo y no los demás.
Eso es porque la función "with (obj_enemigo_general)" no los está tomando en cuenta. Comprobaste que todos los objetos enemigos tengan asignado como parent al obj_enemigo_general???
Por alguna razón esa función no los está tomando en cuenta.

Saludos

 


Desconectado BssString

Respuesta #12 en: Febrero 07, 2020, 01:00:55 am
Hola Taki-A

Subí un rar file a mi Google Drive con el proyecto escrito en GMS 1.4

Descárgalo, extraelo, abre tu Game Maker e importalo desde "File > Import".
https://drive.google.com/u/0/uc?id=1Fu-3FKyRnZSuTjMQmPpXbX78asO8TZ8G&export=download

Cree un GIF con un ejemplo de lo que el código hace.
Cuando la bala se crea por primera vez, no hace nada, el código simplemente la genera y hace que se mueva en una cierta dirección.
Cuando la bala colisiona con un enemigo. Primero revisa si ya ha tocado antes a ese enemigo (si lo ha tocado, lo ignora)
Si no lo ha tocado, entonces le causa daño y busca al siguiente enemigo de entre todos los enemigos disponibles que aún no toca, y cambia de dirección hacia el más cercano.
Si ya no quedan más enemgios disponibles, entonces el código no se ejecuta y la bala sigue su curso hacia el infinito.

Cada bala es independiente y hace los checks por sí sola, sin importar cuantas balas hay en la room

Usé 2 objetos enemigo diferente (pintados de colores diferentes) y el check se hace contra un objeto parent y funciona perfecto, a menos que haya entendido mal tu duda y eso no es lo que quieres lograr.

GIF: https://drive.google.com/open?id=1zPr2FCOPcBRgeZbbr4MnO0d4oPEAfh9b

Saludos
« última modificación: Febrero 07, 2020, 01:03:37 am por BssString »