Un interesante artículo que describe como desarrollar aplicaciones con el mejor rendimiento posible en aparatos móviles, usando JavaFX Script:
- Evitar bindings innecesarios
- Mantener el scenegraph lo más pequeño posible
- Usar Integer en vez de Number
- Usar figuras simples en vez de imágenes
- Usar funcionalidad de pre-escalado
- Usar background loading ("descarga de fondo")
- Usar funciones de clase Sequences
Aquí está el artículo completo. Más adelante revisaré cada recomendación, para compartir los "descubrimientos" ;)
http://java.sun.com/developer/technicalArticles/javafx/mobile/
Mostrando entradas con la etiqueta animacion. Mostrar todas las entradas
Mostrando entradas con la etiqueta animacion. Mostrar todas las entradas
viernes, 8 de mayo de 2009
jueves, 16 de abril de 2009
Un detalle para obtener una mejor performance
Este detalle (junto con incluir canSkip:true en los timelines asociados a animaciones o transiciones gráficas de algún tipo) puede hacer una gran diferencia en la performance gráfica de JavaFX.
Tengo un CustomNode cuyo contenido son unos nodos almacenados en una secuencia:
Digamos que se necesita reemplazar con frecuencia los nodos en objs y que tengo una función que realiza este trabajo:
Como muestra el video, eso es ineficiente. Al estar enlazado el contenido de objs con el contenido del componente e ir cambiando el contenido de objs, se va gatillando trabajo para refrescar el componente.
Es más eficiente crear una secuencia temporal y traspasar al final todos los nodos a la secuencia asociada al componente:
Habría que probar si esto también es aplicable cuando se realizan cambios a los elementos en la secuencia (y no sólo cuando estos se reemplazan). Es probable que ocurra lo mismo, porque al actualizar uno a uno los elementos, es muy probable que también se vaya gatillando trabajo parcial, mientras si se reemplaza toda la secuencia de una vez, ese trabajo debería ocurrir una sóla vez... ¿?
Tengo un CustomNode cuyo contenido son unos nodos almacenados en una secuencia:
public class myComponent extends CustomNode {
var objs:Node[];
public override function create(): Node {
Group {
content: bind objs
};
};
}
Digamos que se necesita reemplazar con frecuencia los nodos en objs y que tengo una función que realiza este trabajo:
function paint():Void {
delete objs;
for (element in someGroup) {
...
insert newNode into objs;
...
}
}
Como muestra el video, eso es ineficiente. Al estar enlazado el contenido de objs con el contenido del componente e ir cambiando el contenido de objs, se va gatillando trabajo para refrescar el componente.
Es más eficiente crear una secuencia temporal y traspasar al final todos los nodos a la secuencia asociada al componente:
function paint():Void {
var tmpObjs:Node[];
for (element in someGroup) {
...
insert newNode into tmpObjs;
...
}
objs = tmpObjs;
}
Habría que probar si esto también es aplicable cuando se realizan cambios a los elementos en la secuencia (y no sólo cuando estos se reemplazan). Es probable que ocurra lo mismo, porque al actualizar uno a uno los elementos, es muy probable que también se vaya gatillando trabajo parcial, mientras si se reemplaza toda la secuencia de una vez, ese trabajo debería ocurrir una sóla vez... ¿?
Etiquetas:
animacion,
animaciones,
como,
fps,
frames,
grafica,
grafico,
graphic,
how to,
javafx,
per second,
performance,
por segundo,
problema,
rendimiento,
resolver,
solucion,
velocidad
domingo, 29 de marzo de 2009
Por qué incluir canSkip:true en los timelines
Este video muestra la diferencia en el rendimiento de las animaciones gráficas con y sin canSkip:true. Es recomendable incluir este parametro en los KeyFrame que alteran valores (values:) asociados a animaciones y efectos (cambio de posiciones, variación de sombras, difuminado, etc... cualquier efecto o movimiento gradual).
Una persona del grupo JavafxProgramming creo una aplicación Flex que luego replicó en JavaFX. Su problema era el rendimiento de JavaFX, que hacia su aplicación inutilizable. Pidió consejos al foro, pero nada funcionó... hasta que incluyó el canSkip:true en los timelines... recién ahí la aplicación funcionó como debía.
Quizás sería bueno que Sun incluyera el canSkip con true como valor por defecto. Esto puede terminar desprestigiando la plataforma.
En todo caso, sería bueno que todos comparta este detalle o lo tengan muy presente al momento de usar los timelines o de tener problemas con el rendimiento.
Una persona del grupo JavafxProgramming creo una aplicación Flex que luego replicó en JavaFX. Su problema era el rendimiento de JavaFX, que hacia su aplicación inutilizable. Pidió consejos al foro, pero nada funcionó... hasta que incluyó el canSkip:true en los timelines... recién ahí la aplicación funcionó como debía.
Quizás sería bueno que Sun incluyera el canSkip con true como valor por defecto. Esto puede terminar desprestigiando la plataforma.
En todo caso, sería bueno que todos comparta este detalle o lo tengan muy presente al momento de usar los timelines o de tener problemas con el rendimiento.
miércoles, 4 de febrero de 2009
JavaFX + Phys2D : JavaFX aprende sobre física (ojo, no solo ciencia)
Phys2D es una excelente API de física, que no solo sirve para simular descabellados experimentos de cientificos encerrados en sus laboratorios o estudiantes queriendo experimentar lo aprendido en clases, esta API es excelente para desarrollar JUEGOS. Si, porque con ella puedes hacer que los elementos del juego se comporten como elementos reales, que se deslicen por pendientes, reboten o se comporten de manera elástica, aceleren, frenen o colisionen.
Lo mejor es que es código abierto... para más información, visita el sitio web de Phys2D
Este ejemplo comprende tres archivos:
1) la biblioteca de Phys2D, que debe estar incluida en los libraries del proyecto (y que incluyo en el directorio lib).
2) una clase que describe EL MODELO de elementos en la simulación... en este caso, incluye una BASE (o anchor, ancla en inglés... que es el elemento fijo en la parte superior), un RESORTE, una masa y un trozo rigido que lo une a la segunda masa. En otras palabras, es un péndulo doble que cuelga por un resorte. OJO: Porque el modelo es una CLASE JAVA... así que de pasada pueden ver lo simple que es integrar Java + JavaFX Script.
3) la animación en JavaFX, que incluye un Timeline para generar los cálculos y el código que pinta los elementos dependiendo de las coordenadas recibidas desde el modelo físico. Bastante simple, como verán... pero no menos sofisticado.
Descarga el projecto Netbeans 6.5. DOWNLOAD the Netbeans project, here!
Lo mejor es que es código abierto... para más información, visita el sitio web de Phys2D
Este ejemplo comprende tres archivos:
1) la biblioteca de Phys2D, que debe estar incluida en los libraries del proyecto (y que incluyo en el directorio lib).
2) una clase que describe EL MODELO de elementos en la simulación... en este caso, incluye una BASE (o anchor, ancla en inglés... que es el elemento fijo en la parte superior), un RESORTE, una masa y un trozo rigido que lo une a la segunda masa. En otras palabras, es un péndulo doble que cuelga por un resorte. OJO: Porque el modelo es una CLASE JAVA... así que de pasada pueden ver lo simple que es integrar Java + JavaFX Script.
3) la animación en JavaFX, que incluye un Timeline para generar los cálculos y el código que pinta los elementos dependiendo de las coordenadas recibidas desde el modelo físico. Bastante simple, como verán... pero no menos sofisticado.
Descarga el projecto Netbeans 6.5. DOWNLOAD the Netbeans project, here!
sábado, 31 de enero de 2009
JavaFX: ¿Cuantas bolitas? (test de rendimiento gráfico)
Este ejercicio contiene 3 controles de barra que permiten ajustar:
1) El número de bolas rebotando en la ventana;
2) La transparencia de las bolas;
3) El radio de las bolas.
Cada nueva bola que se agrega, lo hace con un efecto (cambia el radio un par de veces) y luego continua rebotando entre los márgenes de la ventana. Si se aumenta el tamaño de la ventana, el area de desplazamiento aumenta, si se reduce, las bolas que se encuentran más alla del nuevo margen, regresan al centro de la ventana.
Un area de texto muestra el número de bolas en la ventana, el porcentaje de transparencia y el radio de los círculos.
Una instrucción importante es "canSkip:true", en el Timeline que actualiza la posicion de las bolas (y que por lo tanto, las redibuja). Esta instrucción evita que la CPU se sobrecargue de trabajo y solo realiza la actualización de las bolas si hay capacidad de procesamiento disponible. Intenten con unas 200 bolas y quiten el canSkip y veran como el programa se "pega".
Archivo Maix.fx
Archivo element.fx
1) El número de bolas rebotando en la ventana;
2) La transparencia de las bolas;
3) El radio de las bolas.
Cada nueva bola que se agrega, lo hace con un efecto (cambia el radio un par de veces) y luego continua rebotando entre los márgenes de la ventana. Si se aumenta el tamaño de la ventana, el area de desplazamiento aumenta, si se reduce, las bolas que se encuentran más alla del nuevo margen, regresan al centro de la ventana.
Un area de texto muestra el número de bolas en la ventana, el porcentaje de transparencia y el radio de los círculos.
Una instrucción importante es "canSkip:true", en el Timeline que actualiza la posicion de las bolas (y que por lo tanto, las redibuja). Esta instrucción evita que la CPU se sobrecargue de trabajo y solo realiza la actualización de las bolas si hay capacidad de procesamiento disponible. Intenten con unas 200 bolas y quiten el canSkip y veran como el programa se "pega".
Archivo Maix.fx
package howmany;
import javafx.scene.*;
import javafx.stage.Stage;
import javafx.ext.swing.SwingSlider;
import javafx.scene.layout.VBox;
import javafx.scene.text.*;
// si cambia tamaño de la ventana
// reposiciona los circulos mas alla del margen
var maxX=250.0 on replace { circles.resetPos() };
var maxY=250.0 on replace { circles.resetPos() };
// seleccion numero de bolas
var selector = SwingSlider {
minimum: 0
maximum: 100
value: 0
vertical: false
};
// transparencia de las bolas
var transparency = SwingSlider {
minimum: 0
maximum: 100
value: 50
vertical: false
};
// radio de las bolas
var radius = SwingSlider {
minimum: 0
maximum: 40
value: 20
vertical: false
};
// texto para desplegar valores
var total = Text {
font: Font { size: 18 }
textOrigin:TextOrigin.TOP;
};
// componente que contiene los circulos
var circles = element {
balls:bind selector.value;
radius:bind radius.value;
level:bind transparency.value / 100.0;
display: total
maxX:bind maxX
maxY:bind maxY
};
Stage {
// si cambia tamaño de la ventana
// actualiza variables con dimensiones
width: bind maxX with inverse
height: bind maxY with inverse
scene: Scene { content: [
circles,
VBox { content: [
selector,
transparency,
radius,
total ]
} ]
}
}
Archivo element.fx
package howmany;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.animation.*;
import java.lang.Math;
// clase que extiende circulos
class ball extends Circle {
// "sobreescribe" los parametros del circulo normal,
// de manera de tener los valores en la nueva clase
override var stroke = null;
override var fill = Color.RED;
override var centerX = 100;
override var centerY = 100;
override var radius = 10;
override var scaleX;
override var scaleY;
public var incx;
public var incy;
// mueve el circulo en los incrementos de la instancia
function move():Void {
centerX += incx;
centerY += incy;
if (centerX<0 or centerX>maxX) then
incx = -incx;
if (centerY<0 or centerY>maxY) then
incy = -incy;
};
// efecto para cuando crea el circulo
// cambia un par de veces de tamaño (como rebote)
var dropIn = Timeline {
repeatCount:5
autoReverse:true
keyFrames: [
at (0s) { scaleX => 2.0; scaleY => 2.0 }
at (0.3s) { scaleX => 1.0; scaleY => 1.0 }
]
};
// al crear el circulo, dispara el efecto de rebote
postinit {
dropIn.play();
};
};
// clase que contiene a todos los circulos
public class element extends CustomNode {
public var balls = 50.0;
public var display = Text { };
public var maxX;
public var maxY;
// si cambia la transparencia
public var level = 1.0 on replace {
// actualiza la opacidad de todos los circulos
for (obj in objs) obj.opacity = level; };
// si cambia el radio
public var radius = 10.0 on replace {
// actualiza el radio de todos los circulos
for (obj in objs) obj.radius = radius; };
// arreglo que contiene todos los circulos
var objs:ball[];
// colores que asigna a los circulos
var colors:Color[]=[
Color.RED, Color.BLUE, Color.YELLOW,
Color.PURPLE, Color.CYAN];
var i=0;
// agrega nuevo circulo al componente
function addBall():Void {
var ix=Math.random()*15 - 7;
var iy=Math.random()*15 - 7;
var circ = ball {
centerX:maxX/2
centerY:maxY/2
incx: ix
incy:iy
radius:radius
fill: colors[i mod sizeof colors]
opacity:level
};
insert circ into objs;
};
// crea el componente con los circulos
override function create():Node {
// chequea si debe agregar o quitar circulos
Timeline {
repeatCount:Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0.2s
action: function():Void {
display.content=
"{sizeof objs} / {(level*100) as Integer}% / {radius}";
if (sizeof objs < balls) then {
addBall();
i++;
}
if (sizeof objs > balls) then
delete objs[0];
}
}
]
}.play();
// mueve los circulos
Timeline {
repeatCount:Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0.04s
// para evitar que se sobrecargue de trabajo
canSkip: true
action: function():Void {
for (obj in objs)
obj.move();
}
}
]
}.play();
// retorna el componente con los circulos
Group {
content: bind objs
};
};
// reposicion los circulos si excende el margen
public function resetPos():Void {
for (obj in objs) {
var pos = obj.boundsInScene;
if (pos.maxX > maxX) then
obj.centerX = maxX/2 ;
if (pos.maxY > maxY) then
obj.centerY = maxY/2 ;
}
};
}
Etiquetas:
ajuste,
animacion,
animation,
barra,
control,
controles,
grafico,
graficos,
graphics,
java,
javafx,
performace,
rendimiento,
resize,
slider,
tamaño,
transparencia,
transparency,
ventana,
windows
miércoles, 28 de enero de 2009
Mi primer juego en JavaFX: Alunizaje
Al juego le falta un par de detalles, como que la nave aparezca inicialmente en cualquier area de la pantalla. Por ahora aparece al centro a una velocidad y dirección aleatoria. También me falta agregar que la "base" de alunizaje tenga una posición aleatoria y que detecte cuando aterriza fuera de ella. Son detalles menores que quizas hasta puedes terminar tú.
El juego usa 4 teclas. La barra de espacio, para encender el motor principal. Las teclas de flecha hacia izquierda y derecha, que encienden los motos auxiliares para inclinar el módulo, y la tecla con la flecha hacia arriba, que enciende el piloto automático, para frenar la rotación del módulo (automáticamente).
Está bastante realista, los retrocohetes se encienden cuando corresponde y dejan de operar cuando no hay mas combustible. También incluye alarmas visuales y sonoras para cuando se excede la velocidad de aterrizaje, la inclinación del módulo es incorrecta cuando esta cerca de alunizar o cuando el combustible baja de 1/3 del estanque.
Me resultó entretenido hacer este juego y también descubrir LO INCREIBLEMENTE SIMPLE que es desarrollar cosas bastante decentes en tan poco tiempo (el grueso estaba operando en un par de horas... ¡y eso que estoy aprendiendo JavaFX script!).
La facilidad de incluir gráficos desde Adobe Illustrator sin duda es una ventaja inmensa. Especialmente, porque puede ser reemplazada por el trabajo de un diseñador más experto, sin necesidad de tocar el código de JavaFX script ya desarrollado. De hecho, con poco trabajo adicional podría agregarse multiples "skins" o apariencias al juego... escenarios de distintos planetas y naves por ejemplo (pudiendo relocalizar las alarmas, botones, formas de la nave, motores, entorno, etc).
El proyecto Netbeans 6.5 completo está disponible aquí (código fuente, gráfica, sonidos, etc).
El código requiere que esté incluida la libreria JavaFX FXD 1.0 en el proyecto.
El juego usa 4 teclas. La barra de espacio, para encender el motor principal. Las teclas de flecha hacia izquierda y derecha, que encienden los motos auxiliares para inclinar el módulo, y la tecla con la flecha hacia arriba, que enciende el piloto automático, para frenar la rotación del módulo (automáticamente).
Está bastante realista, los retrocohetes se encienden cuando corresponde y dejan de operar cuando no hay mas combustible. También incluye alarmas visuales y sonoras para cuando se excede la velocidad de aterrizaje, la inclinación del módulo es incorrecta cuando esta cerca de alunizar o cuando el combustible baja de 1/3 del estanque.
Me resultó entretenido hacer este juego y también descubrir LO INCREIBLEMENTE SIMPLE que es desarrollar cosas bastante decentes en tan poco tiempo (el grueso estaba operando en un par de horas... ¡y eso que estoy aprendiendo JavaFX script!).
La facilidad de incluir gráficos desde Adobe Illustrator sin duda es una ventaja inmensa. Especialmente, porque puede ser reemplazada por el trabajo de un diseñador más experto, sin necesidad de tocar el código de JavaFX script ya desarrollado. De hecho, con poco trabajo adicional podría agregarse multiples "skins" o apariencias al juego... escenarios de distintos planetas y naves por ejemplo (pudiendo relocalizar las alarmas, botones, formas de la nave, motores, entorno, etc).
El proyecto Netbeans 6.5 completo está disponible aquí (código fuente, gráfica, sonidos, etc).
El código requiere que esté incluida la libreria JavaFX FXD 1.0 en el proyecto.
sábado, 17 de enero de 2009
JavaFX: Clases de clases... y dos Scene alternadas
Este ejemplo crea una clase que hace rotar un círculo. Luego, crea una nueva clase que utiliza varias instancias de la primera clase para hacer rotar varios círculos dentro del nuevo objeto. Finalmente, crea varias instancias de este último tipo de objeto y los pone en dos Scene que luego alterna... es decir, es un Stage con dos Scene.
package experimentroam;
import javafx.stage.Stage;
import javafx.animation.*;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
// clase basica que dibuja circulo moviendose formando un cuadrado
class myObject extends CustomNode {
var x:Number;
var y:Number;
public var ix=0;
public var iy=0;
public var dx=100;
public var dy=100;
public var radius=40;
public var color=Color.RED;
var roamingtimeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
at(0s) { x => ix+radius; y => iy+radius }
at(0.3s) { x => dx-radius; y => iy+radius }
at(0.6s) { x => dx-radius; y => dy-radius }
at(0.9s) { x => ix+radius; y => dy-radius }
at(1.2s) { x => ix+radius; y => iy+radius }
]
};
// mensaje desplegado (compuesto por texto y rectangulo a su alrededor)
override protected function create():Node {
roamingtimeline.play();
Group {
content: [
Circle {
centerX: bind x
centerY: bind y
radius: bind radius
fill: bind color
}
]
}
};
};
// clase compuesta por objetos de la clase precedente
class myBigObject extends CustomNode {
var fig:myObject=myObject{
ix: 0
iy: 0
radius:55
dx:250
dy:250
color:Color.PURPLE
}
var fig2:myObject=myObject{
ix: 40
iy: 40
radius:40
dx:210
dy:210
color:Color.RED
}
var fig3:myObject=myObject{
ix: 80
iy: 80
radius:30
dx:170
dy:170
color:Color.GREEN
}
var fig4:myObject=myObject{
ix: 120
iy: 120
radius:20
dx:130
dy:130
color:Color.BLUE
}
var fig5:myObject=myObject{
ix: 160
iy: 160
radius:10
dx:90
dy:90
color:Color.YELLOW
}
var fig6:myObject=myObject{
ix: 190
iy: 190
radius:5
dx:60
dy:60
color:Color.ORANGE
}
override protected function create():Node {
Group {
content: [
fig,
fig2,
fig3,
fig4,
fig5,
fig6
]
}
};
}
// instancia de clase compuesta
var bigFig:myBigObject=myBigObject{};
// instancia de clase compuesta desplazada en la pantalla
var bigFig2:myBigObject=myBigObject{
translateX:250
translateY:0
};
// instancia de clase compuesta desplazada en la pantalla
var bigFig3:myBigObject=myBigObject{
translateX:250
translateY:250
};
// instancia de clase compuesta desplazada en la pantalla
var bigFig4:myBigObject=myBigObject{
translateX:0
translateY:250
};
var myScene:Scene=Scene {
fill:Color.BLACK
content: [
bigFig,
bigFig2,
bigFig3,
bigFig4
]
};
var myScene2:Scene=Scene {
fill:Color.BLACK
content: [
bigFig,
bigFig3,
]
};
var scenes=[myScene, myScene2];
var activeScene:Integer;
Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
at(0s) { activeScene => 0 }
at(1s) { activeScene => 1 }
]
}.play();
Stage {
title: "Application title"
width: 500+16
height: 500+36
scene: bind scenes[activeScene]
}
Etiquetas:
animacion,
animation,
clase,
clases,
class,
classes,
component,
componente,
compound,
compuestos,
español,
javafx,
objects. object,
spanish
sábado, 6 de diciembre de 2008
JavaFX: La rueda de la fortuna
Este ejemplo genera una "rueda" de colores de distinta intensidad y que gira... el ejemplo original viene incluido con Netbeans 6.5, yo sólo le agregué el giro. Pueden modificar la velocidad del giro cambiando el tiempo en el Timeline (0.5s, o medio segundo para una vuelta completa).
Básicamente, lo único que agregué fue un rotate: bind angle; asociado a la rueda ya generada incluida en la escena (Scene) y una "linea de tiempo" (Timeline) que incrementa el ángulo entre 0º y 360º, en el tiempo especificado. Una vez que llega a 360º, comienza por el ángulo 0º. Así queda la impresión que la ruega gira indefinidamente.

Básicamente, lo único que agregué fue un rotate: bind angle; asociado a la rueda ya generada incluida en la escena (Scene) y una "linea de tiempo" (Timeline) que incrementa el ángulo entre 0º y 360º, en el tiempo especificado. Una vez que llega a 360º, comienza por el ángulo 0º. Así queda la impresión que la ruega gira indefinidamente.

package color;
import javafx.scene.Group;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.animation.Timeline;
import javafx.lang.FX;
class ColorWheelNode extends CustomNode {
var segments : Number = 12;
var steps : Number = 6;
var radius : Number = 95;
var stripes : Arc[];
override function create() : Node {
return Group {
content: bind stripes
};
}
init {
// Set radius
var r = radius;
var rStep = radius / steps;
var colors : Color[];
for( i in [1..
segments + 1] ) {
insert Color.rgb( 255, 255, 0 ) into colors;
}
for( i in [0..
steps - 1] ) {
colors[1] = Color.rgb( 255 - ( 255 / steps * i ), 255 - ( 255 / steps * i ), 0 );
colors[2] = Color.rgb( 255 - ( 255 / steps ) * i, ( 255 / 1.5 ) - (( 255 / 1.5 ) / steps ) * i, 0 );
colors[3] = Color.rgb( 255 - ( 255 / steps ) * i, ( 255 / 2 ) - ( ( 255 / 2 ) / steps ) * i, 0 );
colors[4] = Color.rgb( 255 - ( 255 / steps ) * i, ( 255 / 2.5 ) - (( 255 / 2.5 ) / steps ) * i, 0 );
colors[5] = Color.rgb( 255 - ( 255 / steps ) * i, 0, 0 );
colors[6] = Color.rgb( 255 - ( 255 / steps ) * i, 0, ( 255 / 2 ) - (( 255 / 2 ) / steps ) * i );
colors[7] = Color.rgb( 255 - ( 255 / steps ) * i, 0, 255 - ( 255 / steps ) * i );
colors[8] = Color.rgb(( 255 / 2 ) - (( 255 / 2 ) / steps ) * i, 0, 255 - ( 255 / steps ) * i );
colors[9] = Color.rgb( 0, 0, 255 - ( 255 / steps ) * i );
colors[10] = Color.rgb( 0, 255 - ( 255 / steps ) * i, ( 255 / 2.5 ) - (( 255 / 2.5 ) / steps ) * i );
colors[11] = Color.rgb( 0 , 255 - ( 255 / steps ) * i, 0 );
colors[12] = Color.rgb(( 255 / 2 ) - (( 255 / 2 ) / steps ) * i, 255 - ( 255 / steps ) * i, 0 );
for( j in [1..segments] ) {
var c = colors[
j.intValue()];
insert Arc {
centerX: 100,
centerY: 100
radiusX: r ,
radiusY: r
startAngle: 360 / segments * ( segments - j - 0.5)
length: 360 / segments
fill: c
type: ArcType.ROUND
} into stripes;
}
r -= rStep;
}
}
}
var angle:Integer;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: false
keyFrames: [
at (0s) {angle => 0},
at (0.5s) {angle => 360},
]
}.play();
Stage {
scene: Scene {
fill: Color.GRAY
content: ColorWheelNode {
rotate: bind angle;
}
}
width: 216
height: 232
title: "Color Wheel"
}
Suscribirse a:
Entradas (Atom)