martes, 17 de agosto de 2010

Flash: ActionScript 3 - Error al sumar decimales

El problema
Sí, hijos, sí. Una nueva de las de Flash y para la que aún no he encontrado solución. En esta ocasión la gracia graciosa se ha dado en ActionScript 3, pero creo que más bien es un error de Flash al tratar variables flotantes (decimales).

Por todos es sabido, al menos en el universo que nos ocupa y ajustándonos a las leyes físicas y matemáticas que cercan nuestra vida cotidiana, que 2+2=4. Pero ¡ojo!, Flash se atreve a contradecir a los más sabios de la historia y, es más, hace tambalear las bases de las matemáticas actuales, porque para Flash, 2+2 PUEDE que sea 4. Es como si Flash fuera cuántico.

El error me ha surgido al tratar de ampliar un MovieClip utilizando su propiedad scaleX y scaleY. Simplemente, cada vez que pincho un botón, el MovieClip debe incrementar su scaleX y scaleY en 0.2. En ActionScript 3, las propiedades scaleX y scaleY (como también la propiedad alpha) se miden en valores decimales entre 0 y 1, a diferencia de ActionScript 2 en el que estas propiedades se miden en valores entre 0 y 100. De este modo, cada vez que pincho el botón mencionado, incremento las propiedades scaleY y scaleX en 0.2 con un simple movie.scaleX = movie.scaleY += 0.2.

En principio todo aparenta bien. Todo cambia cuando necesitas recuperar el valor de scaleX o scaleY para realizar comprobaciones porque, según Flash, 1+0.2 es igual a 1.2. Correctísimo. Pero no vayas a pensar que todo va a ir igual de bien, porque 1.2+0.2 es igual a 1.4000000001, y de ahí en adelante arrastra el error hasta el infinito y más allá. No es algo perceptible gráficamente, pero como digo entorpece las comprobaciones.

Pero Flash no se queda ahí, en su afán por contradecir el mundo se aventura más allá, poniendo a prueba nuestros conocimientos matemáticos y nuestra paciencia. Inmerso en este problema se me ocurre intentar redondear, y como Flash no dispone de ninguna función de redondeo con decimales (cosa que aún no me explico, será que mi inteligencia no llega a entender las razones puras e íntegras de Flash), me dispongo a redondear manualmente con la sencilla operación ya famosa entre los que han intentado redondear decimales en Flash:

1.400000001 * 10 = 14.00000001 (Bien!)
Math.round(14.00000001) = 14 (Bien!! Estamos cerca!!)
14/10 = 1.40000001 (FJ%·&/"$%!!!!! ¿CÓMO????)

Increíble pero cierto. Las graciosidades graciosas de Flash no conocen límites.

¿Por qué pasa esto?
Amigo mío, los caminos del señor son inescrutables, y además no deberías osar ni preguntarte por las razones de Flash. Simplemente ocurre. Es como un acto de fe.

Intuyo que el problema radica en que Flash recalcula constantemene el valor de las propiedades scaleY y scaleX en función del tamaño adquirido y el tamaño original. Por ejemplo, si tengo un MovieClip a tamaño natural (con scaleX y scaleY a 1) y decido ampliarlo un 20%, tan sólo tengo que establecer estas propiedades a 1.2. Si más tarde intento recuperar el valor de estas propiedades, creo que Flash lo que hace es medir la anchura y altura del MovieClip actualmente y dividirlas por sus correspondientes medidas iniciales. En teoría esto debería devolver el mismo resultado, es decir, 1.2, pero algo me dice que las ampliaciones en pantalla, al realizarse sobre píxeles, en ocasiones no son exactas, y esa inexactitud es la que provoca que el recálculo de Flash dé erróneo. Por ejemplo, si el MovieClip en cuestión mide 1003 píxeles, al aplicarle la ampiación del 20% su anchura sería de 1203.6 píxeles (¡¡¡ERROR!!! ¡¡¡ERROR!!! NO EXISTE EL MEDIO PÍXEL, las pantallas muestran un píxel entero o si no no lo muestran). Entonces ¿qué pasa con los 0.6 píxeles que sobran? "¡Fácil!" - dice Flash - "¡Lo redondeo para no molestar al programador con engorrosos decimales! ¡¡Qué bueno soy con mis programadores!!" En definitiva, mi MovieClip mide ahora 1204 píxeles, y cuando quiero recuperar el valor de scaleX o scaleY Flash divide sus 1204 entre los 1003 originales, y es ahí cuando se presenta el ejército de decimales.

Todo esto son sólo SUPOSICIONES mías. Un intento de explicar los fenómenos que ocurren en Flash, como un astrónomo intenta saber qué pasa dentro de un agujero negro.

He de aclarar que el intento de redondeo puesto arriba no lo he hecho con valores fijos como en el ejemplo, si no que donde puse 1.40000001 en realidad está la propiedad movie.scaleX. Más concretamente el redondeo lo hacía así:
movie.scaleX = movie.scaleY += 0.2; (En este punto scaleX y scaleY valen 1.400000001)
movie.scaleX = movie.scaleY = Math.round(movie.scaleX * 10) / 10;

¿Cómo se soluciona?
Quien lo sepa que me lo diga, por favor. Yo he tenido que acabar recurriendo a otras variables declarados a mano por mí para hacer las comprobaciones que necesito.

Agradecimientos
Siempre al todopoderoso Flash, por enseñarnos una vez más los misterios que lo componen, por mostrarnos que en lo más hondo de su núcleo el espacio-tiempo se comprime y el tiempo y las matemáticas se dilatan.



viernes, 14 de mayo de 2010

Flash: Actionscript 2.0 - Texto html se desplaza al pasar sobre un link



El problema
Sí. hijos, sí. Una gracia graciosa ya conocida del maravilloso Flash es esa. En ocasiones (prácticamente cuando a Flash le place) los textos html que contienen enlaces se desordenan, se desplazan, desorganizan... no sé cómo decirlo, al pasar por encima con el ratón. Como una imagen vale más que mil palabras, os mando dos para que valga más que dos mil:

Texto sin pasar por encima con el ratón


Texto al pasar por encima con el ratón


He de decir que en mi caso las características del campo de texto son:
  • es html
  • tiene una hoja de estilos externa cargada
  • el texto contiene un con 'tabstops' incluidos.


¿Por qué pasa esto?
¡Buena pregunta! Sólo os puedo decir que el campo de texto mide de ancho aproximadamente lo que mide la imagen que veis. Al pasar por encima en texto se torna naranja e inexplicablemente se dilatan los espacios entre palabras, provocando un feo efecto que obliga al texto a desplazarse una línea por debajo. En teoría ese desplazamiento se debe a que Flash intenta ajustar el texto al ancho del campo de texto que lo contiene. Todos los campos de texto tienen una propiedad en Flash llamada "wordWrap" que por defecto está establecida en "true", y esta propiedad es la que provoca que el texto se ajuste. Ahora, ¿por qué se ajusta cuando se pasa por encima con el ratón si el texto no varía en absoluto en tamaño, alineación...? Expediente X...

¿Cómo se soluciona?
Indicándole a Flash que no ajuste el texto:

texto_txt.wordWrap = false;

Esto es un arma de doble filo. Os servirá siempre y cuando el ancho del texto sea menor que el ancho del campo de texto que lo contiene. Si no es así, el texto desaparecerá por la derecha sin saltar a la línea siguiente.

Agradecimientos
Démosle gracias a Flash por esta utilísima característica que a todos los que la hemos sufrido nos ha hecho tan felices y dichosos. Démosle gracias por documentar tan detalladamente sus bugs, y no obligarnos a probar durante horas distintas soluciones desesperadas y en ocasiones ilógicas hasta dar con la solución.

Gracias a San Google bendito que, aunque esta vez no me ha ayudado, lo ha hecho en tantísimas ocasiones.