Limites de instrucciones en los metodos de java para Android

Iniciado por Desiresportal, 10 Octubre 2018, 18:27 PM

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

Desiresportal

Hace ya bastante tiempo desarrollé una version de pruebas de mi motor de juegos para Android. La idea era comprobar la viabilidad de desarrollar un motor de juegos en Android Studio cuyo funcionamiento fuese muy similar al que ya logré en C++ o en javascript.

Por supuesto encontré algunos obstaculos y algunas capacidades extra que por ejemplo javascript no me podía ofrecer (al menos en entorno web).

Una de las partes que me chocó fue hacer una funcion (o metodo) tan larga que me saltó el siguiente mensaje al compilarlo: "I/art: Method exceeds compiler instruction limit: 17940 in boolean miFuncion(int)". Al parecer no salta siempre. Solo cuando la funcion supera cierto punto en la ejecucion de sus instrucciones.

Al final el juego se ejecuta, pero hay ciertas instrucciones de la funcion que jamas llegarán a cumplir su objetivo. ¿Alguna sugerencia? ¿Alguna que no implique hacer un conjunto de funciones mas pequeñas y complicar mas aún el codigo fuente?

Supongo que se puede configurar el compilador para no tener ese limite ya que si se tratase de un error propiamente dicho ni siquiera me daría el juego compilado.

Debo añadir que en lugar de crear clases y metodos me lié a hacerlo todo con un solo script y como consecuencia tengo un codigo fuente de mas de 5000 lineas que a Android Studio le cuesta un poco procesar con un Core i3 para colorear las fuentes y demas. ¿Eso puede ser un problema? Aunque la programacion podría considerarse que no esta orientada a objetos, el funcionamiento del motor es simple ya que funciona casi como una maquina de estados. Me basé en OpenGL ya que así lo veia mas facil.

En resumen: me alarma mucho que una funcion larga impida el correcto funcionamiento del juego final. ¿Hay alguna forma de evitarlo? ¿Alguna que sea facil, no implique dividir la funcion en funciones mas pequeñas y que tampoco implique crear un proceso en segundo plano?

Un saludo y gracias.

Serapis

#1
Divídelo al menos en una decena de funciones... aunque el propio código, debiera determinar cuantas. Pero que sean manejables.

Puedes seguir teniendo una función pública y el resto las defines privadas, de modo que solo sean llamadas desde tu función pública (si es ese el caso).

Sin embargo, no entiendo que si es un motor de juegos, deba tener una única función.
Probablemente en la llamada deba recibir muchos parámetros y al caso podrías pasar la mayoría a propiedades donde verificas que su valor sea aceptable... luego que se invoque la función solo revisas si hay conformidad con las propiedades recibidas antes de ejecutar la función. Esa revisión podría recaer en otra función que debuelva un buleano, para saber si puede continuar o debe abortar (porque algo falla en los parámetros), ...también toda la funcionalidad extra de señalar el error y la causa podría delegarse a una función aparte (la misma que verifica, por ejemplo).

También cuesta entender que se supone que esperas que un posible usuario deba entender que hace tu motor de juegos si solo contiene una única función.

El caso es que diviendo tu función en varias, tendrás más probabilidades de que no alcances límites que establezca el compilador en su tabla de símbolos...
Un modo de paliar límites en variables en agruparlas en estructuras, arrays, etc... según convenga al caso...
Por ejemplo si tienes variables como estas: int Rojo, int verdeManzana, int ocre, int marino, int lila... mejor una enumeración de tipo color, luego basta una sola variable que recibe el valor  que a cada momento se precise.

...en realidad particionar dicha función en varias (aunque no recurras a más de una clase) lejos de complicar el código debería facilitar su simplicidad. Aunque sean funciones espagueti, será siempre mejor que una macro función espagueti.

De todos modos si pones un puñado de líneas (pongamos 100), uno puede hacerse idea del típo de codificación que estás haciendo y orientar con más precisión el camino a tomar...

Desiresportal

La funcion es simple: teniendo un objeto le quiero aplicar un frame de animacion.

Dado que el motor aún es 2D, la funcion solo recibe el frame a aplicar como argumento y segun la animacion total del objeto hace calculos de interpolacion en todos sus parametros y los aplica para mostrar el frame exigido. Devuelve un booleano para indicar si todo ha ido bien o si algo ha fallado y añade un codigo de error a la lista. Esto ultimo, la gestion de errores por medio de codigos y listas donde se van añadiendo no está listo aún, pero implicarían mas operaciones por funcion y por posible error.

El caso es que las animaciones por ahora solo pueden ser lineales y si añado animaciones curvadas el codigo se va a complicar mas aún.

Quiero hacerlo simple para que llamando una funcion se haga todo. Sino tendría funciones para orientar segun la animacion, para deformar segun la animacion, para mover el UV segun la animacion y eso solo serían tres llamadas en el codigo final cuando con una sería suficiente.

Supongo que puedo dividir las funciones y llamarlas todas una por una con la funcion que tengo ahora. El tema es que no uso funciones publicas y privadas. Eso significa que si hago esas subfunciones me van a aparecer mas sugerencias cuando esté programando el juego que quiera hacer y podría acabar liandome.

De todos modos, fragmentar la funcion general en funciones que despues van a ser llamadas por esta, ¿no supone tambien superar ese limite de instrucciones antes de finalizar la funcion general?

Ahora estoy finalizando un pequeño programa en C++. En cuanto lo termine volveré a tocar Android Studio y pondré a prueba lo de la fragmentacion de las funciones. En cuanto sepa el resultado te comento y si me surgen mas dudas vuelvo a preguntar aqui mismo.

Gracias.

Serapis

Lo ideal sería crear clases, pero si no te apetece al menos, si crear otras funciones que son llamadas exclusivamente desde esa. Por ejemplo, las interpolacones... crea una función para interpolar que recibe como parámetros una imagen o un array de bytes, ancho y alto d eorigen ancho y alto final, método de interpolación, etc... incluso ésta si ofreces varios métodos según calidad, puede llamar invidualmente a ca una que trata un método específico, por ejemplo una bilineal, otra bicúbica, etc...
Lo mismo si quieres trabajar con luces, briilo, contraste, saturación etc... sácalas como funciones.

El compilador tiene una serie de límites, el de variables totales del programa no creo que se supere, pero quizás algún compiador no espere que una sola función alcance 1Mb. (por ejemplo), lo habitual es que una función no supere las 2000 líneas de código, que ya queda una función larga... lo habitual es que esas 2000 líneas sean las que tienen un móulo repartidas entre 15 funciones (por ejemplo)...

No debes considerar que si tu función llama a otras 20 para hacer su tarea suponga una sobrecarga de tiempo. Aunque una llamada a una función supone cierta carga, solo se aprecia su sobrecarga cuando se ejecutan en un bucle largo.

En fin divide tu función en cuestiones funcionales... además a futuro, lo vas a agradecer, porque el mantenimiento o una ampliación luego será más sencillo, y no penoso como creo que te va a resltar.
Al estar dividido en funciones, cada una queda aislada, entra algo y devuelve algo, y el como haga lo que haga a otra función no le importa, los cambios que hagas en ella no atañe al resto mientras siga recibiendo y devolviendo lo mismo que antes... (mantener en vigor sel contrato).
Cuando tienes una macrofunción... un simple cambio, puede suponer que afecte a 300 líneas de código repartidas entre esas miles, tardarás más en localizar cada punto (y asegurarte que no te olvidas de ninguno), que en modificar el propio código.

El tiempo se tiene que perder escribiendo código... no buscando y revisando que un cambio aquí, no afecta allí y allí y allá...

"Divide y vencerás" decían los romanos, en programación eso se traduce sobretodo en productividad....