PDA

Ver la versión completa : [Fenix] Enemigo esta al alcance de disparo?



Aiken
22/08/2009, 14:35
hola,

hay alguna forma elegante en fenix de comprobar si hay algun enemigo dentro del alcance de tiro?

Se me ocurre, mirar todos los enemigos, y calcular las distancias de las coordenadas x,y de ambos sprites, pero lo mismo hay alguna forma elegante en fenix de hacerlo.


En el caso de hacerlo con x,y ... que habria que hacer lo de la hipotenusa al cuadrado? que rendimiento tendria eso? calcular en cada frame de esa forma la distancia entre cada sprite con todos los demas puede ser un poco cargante no?

Aiken

loixartx
22/08/2009, 14:51
A mí no se me ocurre otra que ir mirando las coordenadas.
Dependiendo del angulo de disparo de tu personaje yo me haría una funcion que comprobara si el enemigo está en el área de disparo y la lanzaría cada 10frames o asi.

otto_xd
22/08/2009, 14:52
hola,

hay alguna forma elegante en fenix de comprobar si hay algun enemigo dentro del alcance de tiro?

Se me ocurre, mirar todos los enemigos, y calcular las distancias de las coordenadas x,y de ambos sprites, pero lo mismo hay alguna forma elegante en fenix de hacerlo.


En el caso de hacerlo con x,y ... que habria que hacer lo de la hipotenusa al cuadrado? que rendimiento tendria eso? calcular en cada frame de esa forma la distancia entre cada sprite con todos los demas puede ser un poco cargante no?

Aiken

No me hagas mucho caso, pero si hay alguna forma de comprobar colisiones de distintos objetos, pinta un cuadrado o un triangulo que salgan desde donde quieras al campo de tiro, y comprueba si existe colision entre el area del poligono y el enemigo.

No se si se podra hacer directamente, pero sino, con saber las coordenadas de las aristas del poligono y del enemigo, podrias hacerlo mas rapido que con teoremas matematicos, no?

swapd0
22/08/2009, 15:17
Puedes acelerar un poco los calculos si tienes dividida la pantalla en cuadrados de NxN, guardando una lista con los objetos que entren en cada cuadrado, asi solo tienes mirar en los cuadrados que estan proximos a la posicion que te interese.

Lo malo es que tendras que actualizar en cada frame esta lista.
Lo bueno es que mientras mas objetos tengas que comprobar mas rendimiento te dara respecto al normal.

< - >

No me hagas mucho caso, pero si hay alguna forma de comprobar colisiones de distintos objetos, pinta un cuadrado o un triangulo que salgan desde donde quieras al campo de tiro, y comprueba si existe colision entre el area del poligono y el enemigo.

No se si se podra hacer directamente, pero sino, con saber las coordenadas de las aristas del poligono y del enemigo, podrias hacerlo mas rapido que con teoremas matematicos, no?

Es mas rapido usando el producto vectoria o escalar, segun lo que necesites comprobar. Ya que solo son un par de multiplicaciones con una suma, pintar un poligono lleva muchos mas calculos (rasterizar, clip, dibujar)

Aiken
22/08/2009, 15:24
No me hagas mucho caso, pero si hay alguna forma de comprobar colisiones de distintos objetos, pinta un cuadrado o un triangulo que salgan desde donde quieras al campo de tiro, y comprueba si existe colision entre el area del poligono y el enemigo.

uhmm ... esta podria ser la forma elegante. que la zona de ataque sea un sprite oculto y comprobar si hay colision con alguno otro sprite del tipo enemigo.

Aiken

< - >

Puedes acelerar un poco los calculos si tienes dividida la pantalla en cuadrados de NxN, guardando una lista con los objetos que entren en cada cuadrado, asi solo tienes mirar en los cuadrados que estan proximos a la posicion que te interese.

Lo malo es que tendras que actualizar en cada frame esta lista.


Ya tengo una especie de cuadricula invisible para otros temas y la podria aprovechar, pero era por si habia alguna forma elegante con precision de pixel, que la verdad la precision me da un poco igual, solo era por si ya existia pues menos que programar.




Es mas rapido usando el producto vectoria o escalar, segun lo que necesites comprobar. Ya que solo son un par de multiplicaciones con una suma, pintar un poligono lleva muchos mas calculos (rasterizar, clip, dibujar)

creo que elimine los conceptos producto vectoria/escalar de mi memoria de largo plazo, asi que tendria que buscar info :D pero de momento voy a probar las otras opciones.

Aiken

SplinterGU
22/08/2009, 16:31
funcion get_dist

DWORD GET_DIST(INT proceso)

Descripción

Devuelve la distancia desde el proceso actual hasta el proceso cuyo código identificador se le pasa como parámetro.

Si el proceso ha definido su variable local RESOLUTION es importante que el proceso hasta el que se quiere obtener la distancia la tenga definida al mismo valor, si el valor de dicha variable difiere en ambos procesos, el resultado carecerá de sentido.

Aiken
22/08/2009, 18:23
funcion get_dist
DWORD GET_DIST(INT proceso)
Descripción
Devuelve la distancia desde el proceso actual hasta el proceso cuyo código identificador se le pasa como parámetro.


que hariamos sin ti, jeje. :brindis:
no creo que tenga muchos enemigos pero consume muchos recursos la funcion?
la distancia que devuelve que son pixeles de distancia entre los centros de ambos procesos?

Aiken

SplinterGU
22/08/2009, 18:54
consume nada... es un simple calculo... muy costoso es usar collision... distancia en pixels entre el punto de control 0 (centro) de ambos...
hay otras mas con dist, get_distx, get_disty, y alguna que otra mas... no recuerdo ahora de memoria...

Hokutoy
22/08/2009, 19:18
Aiken yo te recomiendo que intentes hacer-lo como dice SlinterGU. Veo que estamos haciendo proyectos parecidos (para el concurso de TD? jejeje) y la opcion que yo había usado es la de el "sprite oculto" de forma circular en modo de radar para saber si un enemigo pisa la zona y así saber si está a tiro. La idea es buena y funciona pero a la que tengas unos cuantos procesos checkeando constantemnente colisiones la wiz lo nota y mucho (en el Pc va de lujo eso sí) y se ralentiza que da gusto.
En cuanto acabe de escribir esto voy a intentar modificar mi codigo para usar la formula de SpliterGU... ya te contaré a ver que tal me ha ido.

Saludos

Drumpi
22/08/2009, 20:35
¡¡¡Leches!!! se me ha adelantado Splinter :D:D:D

La función Get_dist usa una raiz cuadrada para el cálculo, así que piensa cuanto tarda C en hacer una raiz. Puedes hacerlo mediante código Fenix/Bennu, pero al ser interpretado tarda como mínimo el doble (debe interpretar las operaciones antes de hacerla.
Sin embargo, collision comprueba PIXEL POR PIXEL si dos gráficos se superponen y no usan pixel transparente. Es muchísimo más lento.

Hokutoy
22/08/2009, 20:37
Weno ya he modificado el código... la verdad es que es mas sencillo de lo que me parecia en un principio. Te pego el código que he usado yo... aunque soy un principiante puede que te sea de ayuda.



Loop
repeat
who=get_id(type enemigo);
if (who<>0) distancia=GET_DIST(who); end
if distancia<80; break; end
until who==0;

if (distancia=<80 and who>0) angle=get_angle(who); break; else frame; end

end


No hay mucho que comentar pero el primer bloque "pasa lista" a todos los procesos enemigos y mide su distancia hasta el "prota". Si la distancia es menor de 80 pixeles o lo que sea (alcance del radar en mi ejemplo) el bucle se rompe y la variable Who almacena la ID del enemigo que ha invadido el radar.
La última linea sirve para obtener el angulo del enemigo detectado para que puedas dispara-le o lo que necesites.

Saludetes
PD: No me importa ayudar a la "competencia"... ya que al final ganamos todos. :brindis::

Drumpi
22/08/2009, 20:54
Em... Deberías corregirlo. Hacer Get_dist con valor who==0 podría dar problemas: desde falsos valores hasta el cierre del juego

Hokutoy
22/08/2009, 21:10
Em... Deberías corregirlo. Hacer Get_dist con valor who==0 podría dar problemas: desde falsos valores hasta el cierre del juego

No te he acabado de entender.
El valor Who (que recoge las Id de los procesos enemigos) solo vale 0 en una ocasion... cuando no existe ningun proceso del tipo enemigo o cuando se ha acabado de "pasar lista".

O eso he entendido yo al leer la documentacion.

Aunque si me lo explicas mejor te lo agradeceré.

PD: Por cierto... en la Wiz el rendimiento con este metodo me ha mejorado enormemente.

Editado: Ahhh! vale ahora te he captado jejeje. Ahora lo modifico. Gracias!!!

Aiken
22/08/2009, 21:45
Aunque si me lo explicas mejor te lo agradeceré.


creo que se refiere a que el repeat...until primero ejecuta y luego comprueba.
pero creo que el if (who<>0) soluciona el problema, supongo que habras editado la respuesta a posteriori.

PD. para ser "principiante" el codigo que has puesto esta bien estruturado, supongo que te refieres a "principiante con fenix" no? :)

Aiken

< - >

Editado: Ahhh! vale ahora te he captado jejeje. Ahora lo modifico. Gracias!!!

Ups! lo has puesto en negrita para que se viera mejor, y a sido peor porque lo he confundido con la firma :D

PD. Para cuando ese Streets of Rage Tactics? :) creo que ya te lo dije, pero siento un poco de hype por el :)
Aiken

Hokutoy
22/08/2009, 22:02
No la verdad es que soy principiante en cualquier cosa. Fenix es lo primero que he tocado en programación.
El codigo me ha quedado bien estructurado pero debe ser a que estoy de vacaciones y estoy relajado jejeje.
El Sor Tactics fue un proyecto demasiado ambicioso para la poca experiencia que tenia cuando empezé co él... El codigo es tan enmarañado que tengo que rehacerlo de 0. Aún guardo el codigo con un par de personajes y unos cuantos enemigos con simple IA que va de vicio en la GP32 jejeje. Pero como es un proyecto que tengo bastante claro pienso hacerlo en cuanto tenga mas habilidad. Seguro.

Saludos!

Aiken
22/08/2009, 23:06
Pero como es un proyecto que tengo bastante claro pienso hacerlo en cuanto tenga mas habilidad. Seguro.
Saludos!

si necesitas ayuda avisa, me encantaria ver un Sor Tactics ;)
Aiken

< - >

La última linea sirve para obtener el angulo del enemigo detectado para que puedas dispara-le o lo que necesites.


tened cuidado pues get_angle parece que puede devolver angulos positivos o negativos, que es muy util e interesante pero si no lo tienes en cuenta tambien puedes pillarte los dedos ;)

Aiken

Drumpi
23/08/2009, 04:31
Da igual que los ángulos sean positivos o negativos, fuera de 0 a 360º las cosas se repiten. El único problema a tener en cuenta son las comparaciones porque es posible que nunca obtengas ángulos>180º


Respecto al código, yo decía de hacer algo así

loop
who=get_id(type enemigo);
while (who!=0)
distancia=GET_DIST(who);
if distancia<80; break; end
who=get_id(type enemigo);
end //while

if (distancia=<80 and who>0) angle=get_angle(who); break; else frame; end

end

Porque como tu lo has puesto haces dos comprobaciones idénticas.
De todas maneras, os puede interesar la función EXISTS


INT EXISTS ( INT id )
Esta función devuelve 1 (cierto) si el proceso cuyo identificador recibe como parámetro sigue en ejecución (esto es, no ha sido eliminado de memoria, ni marcado para matar mediante una función como SIGNAL. Es posible pasarle como parámetro un tipo de proceso obtenido mediante la instrucción TYPE, en cuyo caso devolverá 1 si hay en memoria al menos un proceso del tipo indicado. En caso de no encontrar ningún proceso, EXISTS devolverá 0.

Parámetros:
INT id: Identificador de un proceso, o bien un tipo de proceso obtenido mediante la instrucción TYPE.

Por cierto, si te animas a seguir con el SoR Tactics, ánimo. Aqui está el soporte técnico cada 24h :D

Hokutoy
23/08/2009, 13:49
si necesitas ayuda avisa, me encantaria ver un Sor Tactics ;)
Aiken

< - >


tened cuidado pues get_angle parece que puede devolver angulos positivos o negativos, que es muy util e interesante pero si no lo tienes en cuenta tambien puedes pillarte los dedos ;)

Aiken

Mis pruebas con el get_angle me han enseñado que (no se si es correcto o un bug... pero en mi codigo funciona así):

Si todos los angulos posibles son 360º. Y partimos que la derecha es el angulo 0. Arriba es 90000, a la izquierda 180000, abajo 270000 y, he aquí la cuestión, el ultimo cuarto lo devuelve siempre en negativo por lo que va desde el -90000 (que equivale al 270000) hasta el 0 de la derecha.

El porque es así no lo sé... quizá es un BUG del Fenix?

PD: Gracias a tí y a Drumpi por la ayuda/apoyo al Sor... seguro que la usaré.
PD: Luego pruebo tu sugerencia Drumpi. Hay que depurar el codigo al maximo o se acaba perdiendo rendimiento por todas partes jeejej

Drumpi
23/08/2009, 14:41
Si no recuerdo mal, el rango de valores que da Fenix es desde -179º hasta 180º, por eso a la izquierda te da positivo y abajo negativo. Si en lugar de a la derecha exactamente estuviera un grado más hacia abajo lo verías en negativo.

Hokutoy
23/08/2009, 20:36
Aprovecho el hilo para preguntar alguna cosa.
Como la resolución de la wiz es paupérrima para juegos tipo tower defense ya que o usas graficos enanos o las pantallas te quedan muy pequeñas he decidido crear un scroll para poder usar pantallas de juego mas grandes.

El problema es el sigüiente... tengo un proceso enemigo que sigue su ruta marcada que esta integrado en el scroll con CTYPE=C_SCROLL así yo puedo alejarme de ellos con un proceso "camara" y ellos siguen su ruta aunque mueva la camara lejos de ellos. Perfecto.
El tema es que encima de la cada proceso enemigo muestro la vida que le queda mediante:
ID_LIFE=WRITE_VAR(id_fnt,x,y,4,life);

Lo problematico es que los numeros que aparecen encima (id_life) cuando hago scroll moviendo la camara y alejandome de los enemigos estos numeros tambien se mueven quedando fueran del scroll... como si CTYPE=C_SCROLL no fuera con ellos.

Hay alguna manera de obligar a id_life a quedarse dentro de un scroll?

editado: ***** esto me esta costando mas de lo que pensaba... ahora tengo el mismo problema con el puntero que se mueve gracias al uso de mouse.x etc... No hay manera de hacer que se mueva al mover el scroll... aunque este al final del mapa al usar el puntero siempre devuelve un valor dentro del 320x240 nunca el valor relativo al mapa scrolleado.

Sigo intentando...

PD: Me explico fatal [wei]

< - >
Weno ya lo he arreglado todo... me ha llevado su tiempo la verdad pero solo eran chorradas jejeje
Lo del ID_LIFE=WRITE_VAR(id_fnt,x,y,4,life); era facil. No recordaba que el movimiento de este "texto lo marcaba un MOVE_TEXT así que con:
MOVE_TEXT(ID_LIFE,x-scroll[0].x0,y-scroll[0].y0); los numeros se quedan en su sitio.

Para el tema del puntero del mouse es algo parecido... cuando quiero obtener sus cordenadas en el plano de scroll solo tengo que:
X=mouse.x+scroll[0].X0;
Y=mouse.y+scroll[0].y0;

Pues ya está!

Yo voy escribiendo mis divagaciones en el hilo por si a alguien le sirve de ayuda.

Saludos!

Drumpi
24/08/2009, 04:48
Señores, atentos porque Hokutoy acaba de resolver por si mismo uno de los problemas más comunes con los scrolls.

Primero un aplauso :)




Y ahora saquen sus cuadernos de notas importantes y anotenlo.

Hokutoy
24/08/2009, 16:36
Buenas,
Ahora estoy currando así que no puedo darle mucho al Fenix pero me ha asaltado una duda que con lo poco que he mirado no atino a despejarla.

Pongamos que tengo un FPG (16 BITS) con los graficos de un soldado enemigo, por ejemplo.
Como tengo intencion de usar el mismo enemigo (con los mismos graficos) pero con carácteristicas diferentes me interesa que estos dos enemigos se "diferencien" en solo el color del casco (en el ejemplo el casco es de color verde plano) y quiero crear otro enemigo identico pero con el casco color blanco.

Podria coger los graficos originales, cambiar el color verde por el blanco con el photoshop y crear un nuevo fpg que cargaría junto al otro en la memoria del programa con un ID diferente para cada uno... lo malo es que si quiero crear 10 tipos de soldado diferente voy a tener que cargar 10 fpg en memoria... algo que no me sobra precisamente (logicamente cargando/descargando el que no se use).

Como se trata de modificar un solo color... no existe alguna manera de poder modificar el FPG en "memoria" o en "pantalla" o algo así para aligerar la carga de RAM? El problema que encuentro es qué pasará cuando quiera que aparezcan en pantalla el soldado con casco verde y el soldado con casco blanco a la vez? Se puede lograr? Si me paso a los 8bits y sus paletas (algo que odio por cierto) es más facil de conseguir?

Gracias!

Aiken
24/08/2009, 16:52
Si me paso a los 8bits y sus paletas (algo que odio por cierto) es más facil de conseguir?
Gracias!

mariquita, los hombres usan 8bits y paletas :D

lo unico que se me ocurre, es que tengas por un lado el cuerpo del soldado, que es igual para todos, y por otro lado 10 cabezas clonadas de diferentes colores.

Pero creo que al final sera casi peor ... creo que gastaras la misma memoria o mas que con lo normal de cargar y descargar los sprites que uses o no.

a no ser que algun guru nos ilumine y nos diga que existe alguna forma de modificar el proceso de dibujado de un proceso para que imprima los dos trozos superpuestos sin utilizar memoria intermedia para unirlos.

Aiken

hardyx
24/08/2009, 18:53
Hombre si fueran 500 soldados de colores diferentes si, pero 10 tipos sólo no creo que merezca la pena liarla para ahorrar memoria. No soy experto en Fénix pero creo que la solución sería recorrer el gráfico con map_get_pixel / map_put_pixel y cambiar un color determinado por otro distinto.

Drumpi
24/08/2009, 19:36
Mmmm, el famoso efecto Megaman pero sin perder los datos...
Bueno, se me ocurre, para empezar, que uses la característica de cargar diversas paletas en un modo 16/32bits. Es algo que aun no he probado y no se cómo va, no recuerdo si puedes asignar una paleta a un proceso (creo que si) o a un FPG. En el segundo caso hay funciones para clonar FPGs en memoria (clone_fpg, o clone_map).
Otra opción es esa: coger los gráficos, clonarlos y cambiarles los pixels como dice hardyx.
Y tambien está la opción "sencilla" que es usar los blendops: una blendop es una tabla de conversión de colores para los modos de 16bits con muchas funciones posibles (se pueden ver algunos ejemplos en la demo técnica) pero requiere bastante memoria (256KB por tabla, si no recuerdo mal) y bastante rendimiento (un par de tablas en un juego a 800x600 me ha hecho volver al menu en GP2X).

Así al pronto, no se me ocurren más ideas, pero lo más sencillo y útil es lo de las múltiples paletas... pero no me preguntes a mi como va.

Hokutoy
24/08/2009, 20:08
Gracias chicos. Iré probando a ver que conclusion saco. Aunque si la memoria usada al cargar 10 fpg es la misma que al cargar 1 y crear 9 más al vuelo... pues casi que cargo 10 fpg que el photoshop se me da mejor que las paletas... aunque le daré un vistazo a ver que me sale.
El Tema no es diez soldados quietos... sino diez soldados caminando, corriendo, disparando, muriendo... son bastantes frames cada fpg.

Alguien sabe cuanta RAM libre dispones al usar Fenix?

PD: Como nota curiosa... al hacer scroll en la wiz la "diagonal de la muerte" es muy muy visible. Con el Pollux.set se soluciona por completo pero da un pequeño efecto secundarió de lo mas molesto... al usar la tactil, el cursor que lo representa pierde precision a medida que te desplazas a la derecha de la pantalla. Si pulsas a la izquierda de la pantalla el "cursor" aparece donde debe... si pulsas a la derecha el cursor aparece de 1 a 2 cm hacia la izquierda del punto selecionado. Imagino que será cosa de la ram settings o de algo no sé. Pero el mismo dcb si el pollux no presenta este defecto. Alguna experiencia al respeto?

Drumpi
24/08/2009, 20:28
Tienes la función memory_free() para conocer dicho dato, aunque no se si es fiable, a mi me ha hecho cosas muy raras en el pasado.

Usando la mutipaleta, si se asocia a procesos como creo que se hace, sólo necesitarías un FPG en memoria.

Y de la diagonal de la muerte, eso se escapa de mi radio de acción, pero creo que lo de la pantalla táctil se debe a un problema con el programa de calibrado. Eso lo puedes ver en el foro.

Aiken
24/08/2009, 20:53
en cuanto aparezca la palabra clonar se acabo, pues te ocupara lo mismo que cargar 10fpgs. probablemente lo de la multipaleta es lo unico valido.


ahora que pienso, quizas puedas clonar (y cambiar el color) justo antes de pintar el frame y liberar el clonado justo despues de pintar el frame.

de esa manera solamente tendras en memoria 1 fpg completo+ 1 frame clonado por cada soldadito en pantalla. Que si tienes menos soldaditos en pantalla que frames totales de los 10 fpgs pues estarias ahorrando memoria. Ahora bien, hacerlo justo antes de pintar el frame puede castigar el rendimiento.

Aiken

Hokutoy
24/08/2009, 21:13
Y de la diagonal de la muerte, eso se escapa de mi radio de acción, pero creo que lo de la pantalla táctil se debe a un problema con el programa de calibrado. Eso lo puedes ver en el foro.

Gracias Drumpi miraré lo de la multi paleta a ver que tal.

Lo del calibrado no se debe al mal calibrado de mi wiz... mi wiz esta muy bien calibrada y es muy precisa. Mi juego, ejecutado normalmente no presenta ningún problema de precision. Solo cuando ejecuto mi juego usando el pollux para eliminar la diagonal es cuando la pantalla parece descalibrarse al interactuar con el Fenix. Si la apago vuelve a estar perfectamente calibrada.
Bueno... el tema de la Diagonal tampoco me molesta mucho... no se trata de hacer scroll "nonstop" precisamente.

Saludos

Aiken
24/08/2009, 21:24
Tienes la función memory_free() para conocer dicho dato, aunque no se si es fiable, a mi me ha hecho cosas muy raras en el pasado.


que pasa con esta funcion, que esta en todos los lenguajes pero es raro que no de errores? y resultados raros? no se porque se empeñan en ponerla en todos los lenguajes, si no se puede saber facilmente la memoria libre que no la pongan la funcion.

Aiken

Drumpi
25/08/2009, 00:22
No se, pero en PC va bien. Bueno, siendo sinceros, no lo he probado tan exahustivamente como con la negrita, porque nunca he tenido problemas de quedarme sin memoria. Me extrañaba que, suponiendo los 32MB de RAM que lleva, se me saliera al menu con un FPG de 8MB, así que iba escribiendo en un fichero de texto lo que cargaba y la memoria que iba quedando:
Empezaba diciendo que quedaban menos de 16MB al empezar (puede ser normal, pues la RAM se dividía para cada CPU). No recuerdo exactamente los valores, pero a lo mejor cargaba un fichero de 200KB y perdía un par de megas, luego cargaba 4MB y sólo perdía 300KB...
Puede que sea cosa del sistema, que cargue segun necesidad, pero no tuve más remedio que mantener la carga de ficheros por debajo de 8MB.