Escolar Documentos
Profissional Documentos
Cultura Documentos
JavaFX
Transformações, animações e efeitos visuais
Lançamento 8
E50479-01
Março 2014
E50479-01
Copyright © 2011, 2014, Oracle e/ou suas afiliadas. Todos os direitos reservados.
Este software e a documentação relacionada são fornecidos sob um contrato de licença contendo restrições de uso e
divulgação e são protegidos por leis de propriedade intelectual. Exceto conforme expressamente permitido em seu contrato de
licença ou permitido por lei, você não pode usar, copiar, reproduzir, traduzir, transmitir, modificar, licenciar, transmitir, distribuir,
exibir, executar, publicar ou exibir qualquer parte, de qualquer forma, ou por qualquer meio.
A engenharia reversa, desmontagem ou descompilação deste software, a menos que exigido por lei para
interoperabilidade, é proibida.
As informações aqui contidas estão sujeitas a alterações sem aviso prévio e não são garantidas como isentas de erros. Se
você encontrar algum erro, informe-nos por escrito.
Se este for um software ou documentação relacionada entregue ao governo dos EUA ou a qualquer pessoa licenciando-o
em nome do governo dos EUA, o seguinte aviso é aplicável:
USUÁRIOS FINAIS DO GOVERNO DOS EUA: Os programas da Oracle, incluindo qualquer sistema operacional, software
integrado, quaisquer programas instalados no hardware e/ou documentação, entregues aos usuários finais do governo dos
EUA são "software de computador comercial" de acordo com o Regulamento de Aquisição Federal aplicável e agência-
regulamentos complementares específicos. Assim, o uso, duplicação, divulgação, modificação e adaptação dos programas,
incluindo qualquer sistema operacional, software integrado, quaisquer programas instalados no hardware e/ou documentação,
estará sujeito aos termos de licença e restrições de licença aplicáveis aos programas . Nenhum outro direito é concedido ao
governo dos EUA.
Este software ou hardware é desenvolvido para uso geral em uma variedade de aplicativos de gerenciamento de
informações. Ele não foi desenvolvido ou destinado ao uso em quaisquer aplicações inerentemente perigosas, incluindo
aplicações que possam criar risco de ferimentos pessoais. Se você usar este software ou hardware em aplicativos
perigosos, será responsável por tomar todas as medidas apropriadas de proteção contra falhas, backup, redundância e
outras medidas para garantir seu uso seguro. A Oracle Corporation e suas afiliadas se isentam de qualquer responsabilidade
por quaisquer danos causados pelo uso deste software ou hardware em aplicativos perigosos.
Oracle e Java são marcas registradas da Oracle e/ou de suas afiliadas. Outros nomes podem ser marcas registradas de seus
respectivos proprietários.
Intel e Intel Xeon são marcas comerciais ou marcas registradas da Intel Corporation. Todas as marcas comerciais SPARC
são usadas sob licença e são marcas comerciais ou marcas registradas da SPARC International, Inc. AMD, Opteron, o
logotipo AMD e o logotipo AMD Opteron são marcas comerciais ou marcas registradas da Advanced Micro Devices. UNIX é
uma marca registrada do The Open Group.
Este software ou hardware e documentação podem fornecer acesso ou informações sobre conteúdo, produtos e serviços de
terceiros. A Oracle Corporation e suas afiliadas não são responsáveis e se isentam expressamente de todas as garantias de
qualquer tipo com relação a conteúdo, produtos e serviços de terceiros. A Oracle Corporation e suas afiliadas não serão
responsáveis por quaisquer perdas, custos ou danos incorridos devido ao seu acesso ou uso de conteúdo, produtos ou
serviços de terceiros.
Machine Translated by Google
Conteúdo
iii
Machine Translated by Google
5 Aplicando Efeitos
Efeito de Mistura ....................................... ................................................ ......................................... 5-1
Efeito Bloom ................................................. ................................................ ............................................. 5-2
Efeitos de desfoque .............................................. ................................................ ................................................ 5 -3
Borrão de caixa ................................................. ................................................ ......................................... 5-3
Desfoque de movimento ....................................... ................................................ ......................................... 5-4
Desfoque Gaussiano ....................................... ................................................ ......................................... 5-5
A Xylophone.java
4
Machine Translated by Google
Prefácio
Público
Este documento destina-se a desenvolvedores JavaFX.
Acessibilidade da Documentação
Para obter informações sobre o compromisso da Oracle com a acessibilidade, visite
o site do Programa de Acessibilidade da Oracle em http://www.oracle.com/pls/topic/
lookup?ctx=acc&id=docacc.
Documentos relacionados
Para obter mais informações, consulte os seguintes documentos no conjunto de documentação
Convenções
As seguintes convenções de texto são usadas neste documento:
Convenção Significado
negrito O tipo negrito indica elementos gráficos da interface do usuário associados a uma
ação ou termos definidos no texto ou no glossário.
v
Machine Translated by Google
Convenção Significado
itálico O tipo itálico indica títulos de livro, ênfase ou variáveis de espaço reservado para os
quais você fornece valores específicos.
vi
Machine Translated by Google
Parte I
Parte IAplicando transformações no JavaFX
1
1Visão Geral das Transformações
Apresentando Transformações
Uma transformação muda o lugar de um objeto gráfico em um sistema de coordenadas
de acordo com certos parâmetros. Os seguintes tipos de transformações são suportados no
JavaFX:
ÿ Tradução
ÿ Rotação
Nota: Normalmente, não use a classe Affine diretamente, mas, em vez disso,
use as transformações específicas Translate, Scale, Rotate ou Shear.
Apresentando Transformações
efeito bidimensional (2-D), você pode especificar apenas as coordenadas x e y. Se você deseja
criar um efeito 3D, especifique todas as três coordenadas.
Para poder ver objetos 3-D e efeitos de transformação no JavaFX, os usuários devem habilitar
a câmera em perspectiva.
Embora conhecer os conceitos subjacentes possa ajudá-lo a usar o JavaFX com mais eficiência,
você pode começar a usar as transformações estudando o exemplo fornecido com este
documento e tentando diferentes parâmetros de transformação. Para obter mais informações
sobre classes, métodos ou recursos adicionais específicos, consulte a documentação da API.
Neste documento, um aplicativo Xylophone é usado como exemplo para ilustrar todas as
transformações disponíveis. Você pode baixar seu código-fonte clicando no link
transforms.zip.
2
2 Tipos e Exemplos de Transformação
Tradução
A transformação de translação desloca um nó de um lugar para outro ao longo de um dos eixos
em relação à sua posição inicial. A posição inicial da barra do xilofone é definida pelas
coordenadas x, y e z. No Exemplo 2–1, os valores de posição inicial são especificados pelas
variáveis xStart, yPos e zPos . Algumas outras variáveis são adicionadas para simplificar os
cálculos ao aplicar diferentes transformações. Cada compasso do xilofone é baseado em um
dos compassos de base. O exemplo então traduz as barras de base com diferentes
deslocamentos ao longo dos três eixos para localizá-los corretamente no espaço.
// Base1
Cubo base1Cube = new Cube(1.0, new Color(0.2, 0.12, 0.1, 1.0), 1.0); base1Cube.setTranslateX(xStart
+ 135); base1Cube.setTranslateZ(yPos+20.0); base1Cube.setTranslateY(11.0);
Rotação
A transformação de rotação move o nó em torno de um ponto de pivô especificado da
cena. Você pode usar o método rotate da classe Transform para executar a rotação.
Dimensionamento
mousePosX = me.getX();
mousePosY = me.getY();
mouseDeltaX = mousePosX - mouseOldX;
mouseDeltaY = mousePosY - mouseOldY; if
(me.isAltDown() && me.isShiftDown() &&
me.isPrimaryButtonDown())
{ cam.rz.setAngle(cam.rz.getAngle() - mouseDeltaX);
}
else if (me.isAltDown() && me.isPrimaryButtonDown())
{ cam.ry.setAngle(cam.ry.getAngle() - mouseDeltaX);
cam.rx.setAngle(cam.rx.getAngle() + mouseDeltaY);
}
else if (me.isAltDown() && me.isSecondaryButtonDown()) {
escala dupla = cam.s.getX(); double
newScale = escala + mouseDeltaX*0.01;
cam.s.setX(novaEscala); cam.s.setY(novaEscala);
cam.s.setZ(novaEscala);
}
else if (me.isAltDown() && me.isMiddleButtonDown()) {
cam.t.setX(cam.t.getX() + mouseDeltaX);
cam.t.setY(cam.t.getY() + mouseDeltaY);
}
}
});
Observe que o ponto de pivô e o ângulo definem o ponto de destino para o qual a imagem é
movida. Calcule cuidadosamente os valores ao especificar o ponto de pivô. Caso contrário, a imagem
pode aparecer onde não deveria estar. Para obter mais informações, consulte a documentação da API.
Dimensionamento
A transformação de dimensionamento faz com que um nó pareça maior ou menor, dependendo do fator
de dimensionamento. A escala altera o nó para que as dimensões ao longo de seus eixos sejam
multiplicadas pelo fator de escala. Semelhante às transformações de rotação, as transformações de
dimensionamento são aplicadas em um ponto pivô. Esse ponto de pivô é considerado o ponto em torno
do qual ocorre o escalonamento.
Tosquia
No aplicativo Xylophone, você pode dimensionar o xilofone usando o mouse enquanto pressiona Alt
e o botão direito do mouse. A transformação de escala é usada para ver a escala.
Tosquia
Uma transformação de cisalhamento gira um eixo para que o eixo x e o eixo y não sejam mais
perpendiculares. As coordenadas do nó são deslocadas pelos multiplicadores especificados.
No aplicativo Xilofone, você pode cortar o xilofone arrastando o mouse enquanto mantém pressionada
a tecla Shift e pressionando o botão esquerdo do mouse.
Múltiplas Transformações
O exemplo 2–5 mostra várias transformações aplicadas a um objeto para criar uma barra de
xilofone.
Arquivos de aplicativos
Código fonte
ÿ Xilofone.java
Projetos NetBeans ÿ
transformações.zip
parte II
Parte IICriando Transições e Linha do Tempo
Animações
Este tutorial contém informações que você pode usar para criar animação em JavaFX e contém os capítulos a
seguir.
ÿ Transições
ÿ Interpoladores O
capítulo Tree Animation Example contém uma descrição do exemplo Tree Animation e fornece algumas
dicas e truques sobre animação em JavaFX.
Machine Translated by Google
Machine Translated by Google
3
3 Noções básicas de animação
A animação em JavaFX pode ser dividida em animação de linha do tempo e transições. Este capítulo fornece
exemplos de cada tipo de animação.
Transições
As transições em JavaFX fornecem os meios para incorporar animações em uma linha de tempo interna. As
transições podem ser compostas para criar várias animações que são executadas em paralelo ou sequencialmente.
Consulte as seções Transição Paralela e Transição Sequencial para obter detalhes. As seções a seguir fornecem alguns
exemplos de animação de transição.
Transição Fade
O exemplo 3–1 mostra um trecho de código para uma transição de esmaecimento aplicada a um retângulo.
Primeiro, um retângulo com cantos arredondados é criado e, em seguida, uma transição de esmaecimento é aplicada a
ele.
...
FadeTransition ft = new FadeTransition(Duration.millis(3000), rect1); ft.setFromValue(1.0);
ft.setToValue(0.1); ft.setCycleCount(Timeline.INDEFINITE); ft.setAutoReverse(true); ft.play();
Transição de caminho
Uma transição de caminho move um nó ao longo de um caminho de uma extremidade à outra em um determinado
tempo.
O exemplo 3–2 mostra um trecho de código para uma transição de caminho aplicada a um retângulo.
A animação é invertida quando o retângulo atinge o final do caminho. No código, primeiro é criado um
retângulo com cantos arredondados e, em seguida, uma nova animação de caminho é criada e aplicada
ao retângulo.
...
Caminho caminho = new
Caminho(); path.getElements().add(new MoveTo(20,20));
path.getElements().add(new CubicCurveTo(380, 0, 380, 120, 200, 120)); path.getElements().add(new
CubicCurveTo(0, 120, 0, 240, 380, 240)); PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(4000)); pathTransition.setPath(caminho);
pathTransition.setNode(rectPath);
pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_ TANGENT);
pathTransition.setCycleCount(Timeline.INDEFINITE); pathTransition.setAutoReverse(true);
pathTransition.play();
Transição Paralela
Uma transição paralela executa várias transições simultaneamente.
O exemplo 3–3 mostra o trecho de código para a transição paralela que executa as transições de
fade, translação, rotação e dimensionamento aplicadas a um retângulo.
rectParallel.setArcHeight(15);
rectParallel.setArcWidth(15);
rectParallel.setFill(Color.DARKBLUE);
rectParallel.setTranslateX(50);
rectParallel.setTranslateY(75);
...
FadeTransition fadeTransition =
new FadeTransition(Duration.millis(3000), rectParallel);
fadeTransition.setFromValue(1.0f);
fadeTransition.setToValue(0.3f);
fadeTransition.setCycleCount(2);
fadeTransition.setAutoReverse(true);
TranslateTransition translateTransition =
new TranslateTransition(Duration.millis(2000), rectParallel);
translateTransition.setFromX(50);
translateTransition.setToX(350);
translateTransition.setCycleCount(2);
translateTransition.setAutoReverse(true); RotateTransition
rotateTransition =
novo RotateTransition(Duration.millis(3000), rectParallel);
rotaTransition.setByAngle(180f);
rotaTransition.setCycleCount(4);
rotaTransition.setAutoReverse(true);
ScaleTransition scaleTransition =
new ScaleTransition(Duration.millis(2000), rectParallel);
scaleTransition.setToX(2f);
scaleTransition.setToY(2f);
scaleTransition.setCycleCount(2);
scaleTransition.setAutoReverse(true);
Transição sequencial
Uma transição sequencial executa várias transições uma após a outra.
O exemplo 3–4 mostra o código para a transição sequencial que é executada uma após a
outra. Esmaecer, traduzir, girar e dimensionar as transições que são aplicadas a um retângulo.
...
FadeTransition fadeTransition =
new FadeTransition(Duration.millis(1000), rectSeq);
fadeTransition.setFromValue(1.0f);
fadeTransition.setToValue(0.3f);
fadeTransition.setCycleCount(1);
fadeTransition.setAutoReverse(true);
TranslateTransition translateTransition =
new TranslateTransition(Duration.millis(2000), rectSeq);
translateTransition.setFromX(50);
translateTransition.setToX(375);
translateTransition.setCycleCount(1);
translateTransition.setAutoReverse(true);
RotateTransition rotateTransition =
novo RotateTransition(Duration.millis(2000), rectSeq);
rotaTransition.setByAngle(180f); rotaTransition.setCycleCount(4);
rotaTransition.setAutoReverse(true);
ScaleTransition scaleTransition =
novo ScaleTransition(Duration.millis(2000), rectSeq);
scaleTransition.setFromX(1);
scaleTransition.setFromY(1);
scaleTransition.setToX(2);
scaleTransition.setToY(2);
scaleTransition.setCycleCount(1);
scaleTransition.setAutoReverse(true);
sequencialTransition.play();
Para obter mais informações sobre animação e transições, consulte a documentação da API e a
seção Animação no projeto Ensemble no SDK.
Uma animação é orientada por suas propriedades associadas, como tamanho, localização e cor,
etc. A linha de tempo fornece a capacidade de atualizar os valores de propriedade ao longo da
progressão do tempo. JavaFX suporta animação de quadro-chave. Na animação de quadro-
chave, as transições de estado animadas da cena gráfica são declaradas por instantâneos
iniciais e finais (quadros-chave) do estado da cena em determinados momentos. O sistema pode
executar automaticamente a animação. Ele pode parar, pausar, retomar, reverter ou repetir o
movimento quando solicitado.
O exemplo 3–5 mostra o trecho de código para a animação básica da linha de tempo.
O JavaFX fornece os meios para incorporar eventos que podem ser acionados durante a reprodução
da linha do tempo. O código no Exemplo 3–6 altera o raio do círculo no intervalo especificado e KeyFrame
aciona a transição aleatória do círculo na coordenada x da cena.
//linha do tempo
principal private Linha do tempo linha
do tempo; temporizador AnimationTimer privado;
p.getChildren().add(stack); palco.show();
//Você pode adicionar uma ação específica quando cada quadro é iniciado.
timer = new AnimationTimer() {
@Sobrepor
public void handle(long l) {
text.setText(i.toString()); i++;
};
//cria um keyValue com fábrica: dimensionando o círculo 2 vezes KeyValue keyValueX = new
KeyValue(stack.scaleXProperty(), 2); KeyValue keyValueY = new KeyValue(stack.scaleYProperty(),
2);
i = 0;
}
};
timeline.play();
Interpoladores
timer.start();
}
}
}
Interpoladores A
interpolação define as posições do objeto entre os pontos inicial e final do movimento.
Você pode usar várias implementações integradas da classe Interpolator ou pode
implementar seu próprio Interpolator para obter um comportamento de interpolação personalizado.
Interpoladores embutidos
O JavaFX fornece vários interpoladores embutidos que você pode usar para criar diferentes
efeitos em sua animação. Por padrão, JavaFX usa interpolação linear para calcular as coordenadas.
...
final Timeline timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE); linha do
tempo.setAutoReverse(true); Valor-chave final kv = novo Valor-
chave(rectBasicTimeline.xProperty(), 300,
Interpolator.EASE_BOTH);
KeyFrame final kf = new KeyFrame(Duration.millis(500), kv); linha do tempo.getKeyFrames().add(kf);
timeline.play();
Interpoladores
personalizados Além dos interpoladores integrados, você pode implementar seu próprio interpolador
para obter um comportamento de interpolação personalizado. Um exemplo de interpolador
customizado consiste em dois arquivos java. O exemplo 3–8 mostra um interpolador personalizado
usado para calcular a coordenada y para a animação. O exemplo 3–9 mostra o trecho de código da
animação em que o AnimationBooleanInterpolator é usado.
Arquivos de aplicativos
Arquivos de aplicativos
Projetos NetBeans
ÿ animações.zip
4
Exemplo de Animação 4Tree
Este capítulo fornece detalhes sobre o exemplo de animação de árvore. Você aprenderá como
todos os elementos da cena foram criados e animados.
Projeto e Elementos
O projeto Tree Animation consiste em vários arquivos. Cada elemento, como folhas, folhas de
grama e outros, são criados em classes separadas. A classe TreeGenerator cria uma árvore de
todos os elementos. A classe Animator contém todas as animações, exceto a animação de grama
que reside na classe GrassWindAnimation .
ÿ Grama
Cada elemento é animado à sua maneira. Algumas animações são executadas em paralelo e outras são
executadas sequencialmente. A animação de crescimento da árvore é executada apenas uma vez, enquanto a
animação de mudança de estação é definida para ser executada infinitamente.
Grama
Grama
Esta seção descreve como a grama é criada e animada.
Criando grama
No exemplo de animação de árvore, a grama, mostrada na Figura 4–3 , consiste em
lâminas de grama separadas, cada uma das quais é criada usando Path e adicionada
à lista. Cada lâmina é então curvada e colorida. Um algoritmo é usado para
randomizar a altura, a curva e a cor das lâminas e distribuí-las no "solo". Você pode
especificar o número de lâminas e o tamanho do "solo" coberto com grama.
lâmina pública() {
Grama
getTransforms().addAll(Transform.translate(x, y));
curve1.yProperty().bind(new DoubleBinding() {
{
super.bind(curve1.xProperty());
}
@Sobrepor
protegido double computeValue() {
curve1.xProperty().bind(new DoubleBinding() {
{
super.bind(fase);
}
@Sobrepor
protegido double computeValue() {
return (h/4) + ((cos(phase.get() + (x + 400.) * PI/1600 +
rand) + 1) / 2.) * (-3. / 4) * h;
}
});
}
}
Vários algoritmos são usados para fazer o movimento parecer natural. Por exemplo, o topo de
cada lâmina é movido em um círculo em vez de uma linha reta, e a curva lateral da lâmina faz
com que pareça que ela se dobra com o vento. Números aleatórios são adicionados para
separar cada movimento da lâmina.
Árvore
setCycleCount(Animation.INDEFINITE);
setInterpolator(Interpolator.LINEAR);
setCycleDuration(animationTime); for (Lâmina: lâminas) {
lâmina.fase.bind(fase);
}
}
@Sobrepor
interpolação nula protegida(fração dupla) { phase.set(frac * 2 * PI);
}
}
Árvore
Esta seção explica como a árvore mostrada na Figura 4–4 é criada e animada.
Galhos
A árvore consiste em galhos, folhas e flores. Folhas e flores são desenhadas nos
galhos superiores da árvore. Cada geração de ramificação consiste em três ramificações
(uma ramificação superior e duas laterais) extraídas de uma ramificação pai. Você pode
especificar o número de gerações no código usando o NUMBER_OF_BRANCH_GENERATIONS
passado no construtor de TreeGenerator na classe Main. O exemplo 4–3 mostra o código
na classe TreeGenerator que cria o tronco da árvore (ou o ramo raiz) e adiciona três ramos
para as gerações seguintes.
Árvore
ramos de retorno;
}
Para tornar a árvore mais natural, cada ramificação da geração filha cresce em um ângulo em
relação à ramificação pai, e cada ramificação filho é menor que a pai. O ângulo da criança é
calculado usando valores aleatórios. O exemplo 4–4 fornece um código para criar ramificações
filhas.
interruptor (tipo)
{ caixa TOP:
transY = parentBranch.length; comprimento
= parentBranch.length * 0,8;
locAngle.set(getRandom(10)); quebrar;
caso ESQUERDA:
caso DIREITA:
transY = parentBranch.length - getGaussianRandom(0,
parentBranch.length, parentBranch.length / 10, parentBranch.length / 10);
locAngle.set(getGaussianRandom(35, 10) * (Type.LEFT == type ? 1 :
-1));
if ((0 > globalAngle.get() || globalAngle.get() > 180) && profundidade <
4) {
length = parentBranch.length * getGaussianRandom(0.3, 0.1); } outro {
Árvore
criadas nos ramos superiores. Como as folhas são criadas ao mesmo tempo que os galhos da árvore, as
folhas são dimensionadas para 0 por leaf.setScaleX(0) e leaf.setScaleY(0) para ocultá-las antes que a árvore
cresça, conforme mostrado no Exemplo 4– 5. O mesmo truque é usado para esconder as folhas quando elas
caem. Para criar uma aparência mais natural, as folhas têm tons de verde ligeiramente diferentes. Além disso,
a cor da folha muda dependendo da localização da folha; os tons mais escuros são aplicados nas folhas
localizadas abaixo do meio da copa das árvores.
Color color = new Color(random() * 0.5, random() * 0.5 + 0.5, 0, 1); if (parentBranch.globalH < 400
&& random() < 0.8) { //folha inferior é
mais escura
} setFill(cor);
}
}
As flores são criadas na classe Flower e depois adicionadas aos galhos superiores da árvore na classe
TreeGenerator. Você pode especificar o número de pétalas em uma flor. As pétalas são elipses distribuídas
em círculo com algumas sobreposições. Semelhante à grama e às folhas, as pétalas das flores são coloridas
em diferentes tons de rosa.
Crescimento de
uma árvore A animação de crescimento de uma árvore é executada apenas uma vez, no início do
exemplo de animação de árvore. O aplicativo inicia uma animação de transição sequencial para aumentar as
ramificações uma geração após a outra, conforme mostrado no Exemplo 4–7. Inicialmente, o comprimento é
definido como 0. O tamanho e o ângulo do ramo raiz são especificados na classe TreeGenerator . Atualmente
cada geração é cultivada durante dois segundos.
Árvore
new SequentialTransition(pauseTransition,
branchGrowingAnimation));
}
return sameDepthBranchAnimation;
}
Como todas as ramificações são calculadas e criadas simultaneamente, elas podem aparecer na cena
como pontos. O código apresenta alguns truques para ocultar as linhas antes que elas cresçam. No
exemplo, o código duration.one milisecond pausa a transição por um tempo imperceptível. No Exemplo 4–
9, o código base.setStrokeWidth(0) define a largura das ramificações como 0 antes do início da animação
de crescimento para cada geração.
if (profundidade < 5)
{ base.setStrokeLineJoin(StrokeLineJoin.ROUND);
base.setStrokeLineCap(StrokeLineCap.ROUND);
}
base.setStrokeWidth(0);
}
}
A animação do vento da árvore é semelhante à animação do movimento da grama, mas é mais simples
porque apenas o ângulo dos galhos muda. Para fazer com que o movimento da árvore pareça natural, o
ângulo de dobra é diferente para diferentes gerações de galhos. Quanto maior a geração do galho (ou seja,
quanto menor o galho), mais ele se curva. O exemplo 4–10 fornece código para animação de vento.
Árvore
} return springAnimation;
}
Depois que todos os galhos da árvore estiverem crescidos, as folhas começarão a aparecer conforme
indicado no Exemplo 4–12.
Exemplo 4–12 Transição paralela para iniciar a animação de primavera e mostrar folhas
private Transition animateSpring(List<Leaf> folhagem, List<Blade> grama) {
ParallelTransition springAnimation = new ParallelTransition(); for (lâmina final da lâmina:
grama) {
springAnimation.getChildren().add(new FillTransition(GRASS_BECOME_GREEN_ DURATION, lâmina,
Árvore
leafageAppear.setToY(1);
springAnimation.getChildren().add(leafageAppear); }
return springAnimation; }
Quando todas as folhas estiverem visíveis, as flores começam a aparecer conforme mostrado no
Exemplo 4–13. A transição sequencial é usada para mostrar as flores gradualmente. O atraso no
aparecimento da flor é definido no código de transição sequencial do Exemplo 4–13. As flores aparecem
apenas na copa das árvores.
floresAppearAndFallDown.getChildren().add(novo
SequentialTransition(new SequentialTransition(flowerAppear,
fakeFallDownAnimation(pétala))));
}
}
return floresAppearAndFallDown;
}
Assim que todas as flores aparecem na tela, suas pétalas começam a cair. No código do Exemplo
4–14, as flores são duplicadas e o primeiro conjunto delas é ocultado para ser mostrado posteriormente.
ellipse.setFill(petalOld.getFill()); } outro {
elipse.setFill(cor);
}
ellipse.setRotate(petalOld.getRotate()); elipse.setOpacity(0);
elipse de retorno;
}
As pétalas de flores copiadas começam a cair no chão uma a uma, conforme mostrado no Exemplo 4–15.
As pétalas desaparecem após cinco segundos no chão. A trajetória de queda de uma pétala não é uma
linha reta, mas sim uma curva senoidal calculada, de modo que as pétalas parecem estar girando enquanto
caem.
Arquivos de aplicativos
nó -> {
node.setScaleX(0);
node.setScaleY(0);
});
A próxima mudança de estação começa quando todas as flores desaparecem de cena. As folhas
e a grama ficam amarelas, e as folhas caem e desaparecem. O mesmo algoritmo usado no Exemplo 4–
15 para fazer as pétalas das flores caírem é usado para mostrar as folhas que caem. O código no
Exemplo 4–16 habilita a animação de outono.
toYellow.setDelay(Duração.segundos(1 * random()));
gramaBecomeYellowAnimation.getChildren().add(toYellow); }
outono.getChildren().addAll(grassBecomeYellowAnimation, novo
SequentialTransition(yellowLeafage, dissappearLeafage)); retorno outono;
}
Depois que todas as folhas desaparecem do chão, a animação da primavera começa colorindo a
grama de verde e mostrando as folhas.
Arquivos de aplicativos
Projetos NetBeans
ÿ tree_animation.zip
Parte III
Parte IIICriando efeitos visuais
ÿ Efeito Bloom
ÿ Efeitos de desfoque
ÿ Reflexão
ÿ Efeito de iluminação
ÿ Efeito de perspectiva ÿ
5
5Aplicando efeitos
Este tutorial descreve como usar efeitos visuais para aprimorar a aparência de seu aplicativo
JavaFX.
Todos os efeitos estão localizados no pacote javafx.scene.effect e são subclasses da classe Effect .
Para obter mais informações sobre classes, métodos ou recursos adicionais específicos, consulte a
documentação da API.
Efeito de Mistura
Blend é um efeito que combina duas entradas usando um dos modos de mesclagem predefinidos.
nó sendo renderizado (uma entrada superior) ÿ Tudo abaixo do nó (uma entrada inferior)
ÿ Se o grupo tiver o modo de mesclagem padrão, tudo abaixo do grupo será incluído, recursivamente
usando essa mesma regra.
Um modo de mesclagem define a maneira pela qual os objetos são misturados. Por exemplo, na
Figura 5–1, você pode ver exemplos de alguns modos de mesclagem aplicados a um círculo
agrupado com um quadrado.
Efeito Bloom
O exemplo 5–1 mostra um trecho de código para o efeito de mesclagem no aplicativo de amostra.
r.setY(50);
r.setWidth(50);
r.setHeight(50);
r.setFill(Color.BLUE);
Efeito Bloom
O efeito bloom faz com que as partes mais brilhantes de uma imagem pareçam brilhar, com
base em um limite configurável. O limite varia de 0,0 a 1,0. Por padrão, o limite é definido como 0,3.
O exemplo 5–2 mostra um trecho de código do aplicativo de exemplo que está usando o efeito bloom.
g.setCache(verdadeiro); //
g.setEffect(new Bloom()); Bloom bloom
= new Bloom(); bloom.setThreshold(1.0);
g.setEffect(bloom); g.getChildren().add(r);
g.getChildren().add(t);
g.setTranslateX(350);
retornar g;
}
efeitos de desfoque
Desfoque são efeitos comuns que podem ser usados para fornecer mais foco aos objetos selecionados.
Com o JavaFX, você pode aplicar boxblur, motion blur ou gaussian blur.
Borrão de caixa
O BoxBlur é um efeito de desfoque que usa um kernel de filtro de caixa simples, com tamanhos
configuráveis separadamente em ambas as dimensões que controlam a quantidade de desfoque
aplicado a um objeto e um parâmetro de iterações que controla a qualidade do desfoque resultante.
nó estático boxBlur() {
Texto t = new Texto();
t.setText("Texto embaçado!");
t.setFill(Color.RED);
t.setFont(Font.font("null", FontWeight.BOLD, 36)); t.setX(10); t.setY(40);
t.setEffect(bb);
t.setTranslateX(300);
t.setTranslateY(100);
retornar t;
}
Desfoque de movimento
Um efeito de desfoque de movimento usa um desfoque gaussiano, com raio e ângulo configuráveis para
criar o efeito de um objeto em movimento.
O exemplo 5–4 mostra um trecho de código que cria um efeito de desfoque de movimento com raio definido
como 15 e ângulo definido como 45 no aplicativo de amostra.
Efeito Sombra
t.setEffect(mb);
t.setTranslateX(300);
t.setTranslateY(150);
retornar t;
}
Desfoque gaussiano
O desfoque gaussiano é um efeito que usa um algoritmo gaussiano com um raio configurável para
desfocar objetos.
O exemplo 5–5 mostra um trecho de código que desfoca o texto usando o efeito de desfoque gaussiano.
Efeito Sombra Uma sombra projetada é um efeito que renderiza uma sombra do conteúdo ao qual é aplicada.
Você pode especificar a cor, o raio, o deslocamento e alguns outros parâmetros da sombra.
Efeito Sombra
Palco de palco;
Cena da cena;
@Sobrepor
public void start(Stage stage) { stage.show();
content.add(dropShadow());
palco.setScene(cena);
}
Nó estático dropShadow() {
Grupo g = new Grupo();
ds1.setColor(Cor.CORAL);
g.getChildren().add(t);
g.getChildren().add(c); retornar g;
}
public static void main(String[] args) { Application.launch(args);
}
}
Dica:
A Figura 5–7 mostra texto simples e o mesmo texto com o efeito de sombra interna aplicado.
t.setTranslateX(300);
t.setTranslateY(300);
retornar t;
}
Reflexão
A reflexão é um efeito que renderiza uma versão refletida do objeto abaixo do objeto real.
A Figura 5–8 mostra um reflexo aplicado ao texto. Use o método setFraction para especificar
a quantidade de reflexão visível.
Palco de palco;
Cena da cena;
t.setEffect(r);
t.setTranslateY(400);
retornar t;
Efeito de iluminação
}
public static void main(String[] args) { Application.launch(args);
}
}
Efeito de iluminação
O efeito de iluminação simula uma fonte de luz brilhando no conteúdo fornecido, que pode ser usado
para dar a objetos planos uma aparência tridimensional mais realista.
content.add(iluminação());
palco.setScene(cena);
Efeito de perspectiva
t.setY(10.0f);
t.setTextOrigin(VPos.TOP);
t.setEffect(l);
t.setTranslateX(0);
t.setTranslateY(320);
retornar t;
}
public static void main(String[] args) { Application.launch(args);
}
}
Efeito de perspectiva
O efeito de perspectiva cria um efeito tridimensional de um objeto bidimensional.
Uma transformação de perspectiva pode mapear qualquer quadrado para outro quadrado,
preservando a retidão das linhas. Ao contrário das transformações afins, o paralelismo das
linhas na origem não é necessariamente preservado na saída.
Nota: Este efeito não ajusta as coordenadas dos eventos de entrada ou quaisquer métodos que
medem a contenção em um nó. O clique do mouse e os métodos de contenção são indefinidos
se um efeito de perspectiva for aplicado a um nó.
O exemplo 5–10 é um trecho de código do aplicativo de amostra que mostra como criar um
efeito de perspectiva.
pt.setLrx(210.0f);
pt.setLry(60.0f);
pt.setLlx(10.0f);
pt.setLly(90.0f);
g.setEffect(pt);
g.setCache(verdadeiro);
r.setY(10.0f);
r.setWidth(280.0f);
r.setHeight(80.0f);
r.setFill(Color.DARKBLUE);
g.getChildren().add(r);
g.getChildren().add(t); retornar g;
Na Figura 5–12, o efeito de reflexo é usado como uma entrada para o efeito de sombreamento, o que
significa que primeiro o retângulo é refletido pelo efeito de reflexo e, em seguida, o efeito de sombreamento
é aplicado ao resultado.
Palco de palco;
Cena da cena;
content.add(chainEffects());
palco.setScene(cena);
rect.setY(20.0f);
ds.setInput(reflexão);
rect.setEffect(ds);
retornar reto;
}
Arquivos de aplicativos
}
}
Para obter mais informações sobre classes, métodos ou recursos adicionais específicos, consulte
a documentação da API.
Arquivos de aplicativos
Projetos NetBeans
ÿ visual_effects.zip
Arquivos de aplicativos
Parte IV
Parte IV Código Fonte para as Transformações,
Tutorial de Animações e Efeitos Visuais
A tabela a seguir lista os aplicativos de demonstração neste documento com seus arquivos de
código-fonte associados.
Projeto NetBeans
Tutorial Código fonte Arquivo
A
AXylophone.java
* A redistribuição e uso em fontes e formas binárias, com ou sem * modificação, são permitidos
desde que as seguintes condições
* são atendidas:
*
*
- As redistribuições do código-fonte devem manter o aviso de direitos autorais acima, esta
*
lista de condições e a seguinte isenção de responsabilidade.
*
- As redistribuições em formato binário devem reproduzir o aviso de direitos autorais acima,
*
esta lista de condições e a seguinte isenção de responsabilidade na documentação e/ou
*
outros materiais fornecidos com a distribuição.
* - Nem o nome do Oráculo nem os nomes de seus
*
colaboradores podem ser usados para endossar ou promover produtos derivados deste
*
software sem permissão prévia específica por escrito.
*
* ESTE SOFTWARE É FORNECIDO PELOS DETENTORES DOS DIREITOS AUTORAIS E COLABORADORES
* "COMO ESTÁ" E QUAISQUER GARANTIAS EXPRESSAS OU IMPLÍCITAS, INCLUINDO, MAS NÃO
* LIMITADO ÀS GARANTIAS IMPLÍCITAS DE COMERCIABILIDADE E ADEQUAÇÃO PARA
* UM PROPÓSITO ESPECÍFICO SÃO REJEITADOS. EM NENHUM CASO OS DIREITOS AUTORAIS
* O PROPRIETÁRIO OU OS COLABORADORES SERÃO RESPONSÁVEIS POR QUALQUER COISA DIRETA, INDIRETA, INCIDENTAL,
* DANOS ESPECIAIS, EXEMPLARES OU CONSEQUENTES (INCLUINDO, MAS NÃO
* LIMITADO À AQUISIÇÃO DE BENS OU SERVIÇOS SUBSTITUTOS; PERDA DE USO,
* DADOS OU LUCROS; OU INTERRUPÇÃO DE NEGÓCIOS) DE QUALQUER CAUSA E DE QUALQUER
* TEORIA DA RESPONSABILIDADE, SEJA EM CONTRATO, RESPONSABILIDADE ESTRITA OU ILÍCITO
* (INCLUINDO NEGLIGÊNCIA OU OUTROS) DECORRENTES DE QUALQUER FORMA DO USO
* DESTE SOFTWARE, MESMO SE AVISADO DA POSSIBILIDADE DE TAIS DANOS. */
Código
pacote xilofone;
Xilofone.java A-1
Machine Translated by Google
mousePosX duplo;
mousePosY duplo;
duplo mouseOldX; duplo
mouseOldY; mouseDeltaX
duplo;
mouseDeltaY duplo;
camOffset.getChildren().add(cam); resetCam();
cena.setCamera(new PerspectiveCamera());
novo
AudioClip(Xylophone.class.getResource("audio/Note3.wav").toString()); final AudioClip bar4Note =
novo
AudioClip(Xylophone.class.getResource("audio/Note4.wav").toString()); final AudioClip bar5Nota =
novo
AudioClip(Xylophone.class.getResource("audio/Note5.wav").toString()); final AudioClip bar6Nota =
novo
AudioClip(Xylophone.class.getResource("audio/Note6.wav").toString()); final AudioClip bar7Nota =
novo
AudioClip(Xylophone.class.getResource("audio/Note7.wav").toString()); final AudioClip bar8Nota =
novo
AudioClip(Xylophone.class.getResource("audio/Note8.wav").toString());
// Base1
Cubo base1Cube = new Cube(1.0, new Color(0.2, 0.12, 0.1, 1.0), 1.0);
base1Cube.setTranslateX(xStart + 135);
base1Cube.setTranslateZ(yPos+20.0);
base1Cube.setTranslateY(11.0);
base1Cube.setScaleX(barWidth*11.5);
base1Cube.setScaleZ(10.0);
base1Cube.setScaleY(barDepth*2.0);
// Base2
Cubo base2Cube = new Cube(1.0, new Color(0.2, 0.12, 0.1, 1.0), 1.0);
base2Cube.setTranslateX(xStart + 135);
base2Cube.setTranslateZ(yPos-20.0);
base2Cube.setTranslateY(11.0);
base2Cube.setScaleX(barWidth*11.5);
base2Cube.setScaleZ(10.0);
base2Cube.setScaleY(barDepth*2.0);
// Bar1
Cubo bar1Cube = new Cube(1.0, Color.PURPLE, 1.0);
bar1Cube.setTranslateX(xStart + 1*xOffset); bar1Cube.setTranslateZ(yPos);
bar1Cube.setScaleX(barWidth); bar1Cube.setScaleZ(100.0);
bar1Cube.setScaleY(barDepth);
// Bar2
Xilofone.java A-3
Machine Translated by Google
// Compasso3
// Bar4
Cubo bar4Cube = new Cube(1.0, Color.GREEN, 1.0);
bar4Cube.setTranslateX(xStart + 4*xOffset);
bar4Cube.setTranslateZ(yPos); bar4Cube.setScaleX(barWidth);
bar4Cube.setScaleZ(85.0);
bar4Cube.setScaleY(barDepth);
// Compasso5
// Bar6
Cubo bar6Cube = new Cube(1.0, Color.YELLOW, 1.0);
bar6Cube.setTranslateX(xStart + 6*xOffset); bar6Cube.setTranslateZ(yPos);
bar6Cube.setScaleX(barWidth); bar6Cube.setScaleZ(75.0);
bar6Cube.setScaleY(barDepth);
// Compasso7
bar7Cube.setScaleZ(70.0);
bar7Cube.setScaleY(barDepth);
// Compasso8
bar1Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar1Note.play(); }
});
bar2Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar2Note.play(); }
});
bar3Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar3Note.play(); }
});
bar4Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar4Note.play(); }
});
bar5Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar5Note.play(); }
});
bar6Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar6Note.play(); }
});
bar7Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar7Note.play(); }
});
bar8Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { bar8Note.play(); }
});
retânguloGroup.setScaleX(2.5);
retânguloGroup.setScaleY(2.5);
retânguloGroup.setScaleZ(2.5);
cam.getChildren().add(rectangleGroup);
frameCam(palco, cena);
cena.setOnMousePressed(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { mousePosX =
me.getX(); mousePosY = me.getY(); mouseOldX
= me.getX(); mouseVelhoY = me.getY(); //
System.out.println("scene.setOnMousePressed"
+ eu);
}
});
cena.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Sobrepor
public void handle(MouseEvent me) { mouseOldX =
mousePosX; mouseVelhoY = mousePosY;
mousePosX = me.getX(); mousePosY = me.getY();
mouseDeltaX = mousePosX - mouseOldX;
mouseDeltaY = mousePosY - mouseOldY; if
(me.isAltDown() && me.isShiftDown() &&
me.isPrimaryButtonDown()) {
Xilofone.java A-5
Machine Translated by Google
}
else if (me.isAltDown() && me.isSecondaryButtonDown()) {
escala dupla = cam.s.getX(); double
newScale = escala + mouseDeltaX*0.01; cam.s.setX(novaEscala);
cam.s.setY(novaEscala);
cam.s.setZ(novaEscala);
}
else if (me.isAltDown() && me.isMiddleButtonDown()) {
double tx = cam.t.getX(); double ty
= cam.t.getY(); cam.t.setX(tx +
mouseDeltaX);
cam.t.setY(ty + mouseDeltaY);
}
}
});
cena.setOnKeyPressed(new EventHandler<KeyEvent>() { @Override
shear.setX(0.0);
shear.setY(0.0);
}
if (KeyCode.F.equals(ke.getCode())) { frameCam(palco,
cena); shear.setX(0.0);
shear.setY(0.0);
}
if (KeyCode.SPACE.equals(ke.getCode())) { if
(stage.isFullScreen()) {
stage.setFullScreen(false);
frameCam(palco, cena); } outro {
stage.setFullScreen(true);
frameCam(palco, cena);
}
}
}
});
palco.setScene(cena);
palco.show();
}
//================================================ =========================
// CubeSystem.frameCam //
============================================= ==============================
public void frameCam(fase final do palco, cena final da cena) {
setCamOffset(camOffset, cena);
// cam.resetTSP();
setCamPivot(cam);
setCamTranslate(cam);
setCamScale(câmera, cena);
}
//================================================ =========================
// CubeSystem.setCamOffset //
============================================= ==============================
public void setCamOffset(final Cam camOffset, cena final da cena) {
largura dupla = cena.getWidth(); altura dupla
= cena.getHeight(); camOffset.t.setX(largura/2.0);
camOffset.t.setY(altura/2.0);
}
//================================================ =========================
// definirCamScale
//================================================ =========================
public void setCamScale(final Cam cam, cena final da cena) { final Bounds bounds =
cam.getBoundsInLocal(); final duplo pivotX = limites.getMinX() + limites.getWidth()/
2; final duplo pivôY = limites.getMinY() + limites.getHeight()/2; final duplo pivotZ =
limites.getMinZ() + limites.getDepth()/2;
Fatorescala = FatorescalaX;
}
cam.s.setX(scaleFactor);
cam.s.setY(scaleFactor);
cam.s.setZ(scaleFactor);
}
//================================================ =========================
// setCamPivot
//================================================ =========================
public void setCamPivot(final Cam cam) {
limites limites limites = cam.getBoundsInLocal(); final duplo pivotX
= limites.getMinX() + limites.getWidth()/2; final duplo pivôY = limites.getMinY() +
limites.getHeight()/2; final duplo pivotZ = limites.getMinZ() + limites.getDepth()/2;
cam.p.setX(pivotX);
Xilofone.java A-7
Machine Translated by Google
cam.p.setY(pivotY);
cam.p.setZ(pivotZ);
cam.ip.setX(-pivotX);
cam.ip.setY(-pivotY);
cam.ip.setZ(-pivotZ);
}
//================================================ =========================
// setCamTranslate
//================================================ =========================
public void setCamTranslate(câmera da câmera final) {
limites limites limites = cam.getBoundsInLocal(); final duplo pivotX
= limites.getMinX() + limites.getWidth()/2; final duplo pivôY = limites.getMinY() +
limites.getHeight()/2; cam.t.setX(-pivotX); cam.t.setY(-pivotY);
cam.p.setX(0.0);
cam.p.setY(0.0);
cam.p.setZ(0.0);
cam.ip.setX(0.0);
cam.ip.setY(0.0);
cam.ip.setZ(0.0);
cam.p.setX(pivotX);
cam.p.setY(pivotY);
cam.p.setZ(pivotZ);
cam.ip.setX(-pivotX);
cam.ip.setY(-pivotY);
cam.ip.setZ(-pivotZ);
}
// Face traseira
// face inferior
Rectangle bottomFace = new Rectangle(tamanho,tamanho);
bottomFace.setFill(color.deriveColor(0.0, 1.0, (1 - 0.4*sombra), 1.0)); bottomFace.setTranslateX(-0,5*tamanho);
bottomFace.setTranslateY(0);
bottomFace.setRotationAxis(Girar.X_AXIS);
bottomFace.setRotate(90);
// face direita
Retângulo face direita = new Rectangle(tamanho,tamanho);
rightFace.setFill(color.deriveColor(0.0, 1.0, (1 - 0.3*sombra), 1.0)); facedireita.setTranslateX(-1*tamanho);
facedireita.setTranslateY(-0,5*tamanho); facedireita.setRotationAxis(Girar.Y_AXIS);
facedireita.setRotate(90);
// faceesquerda
leftFace.setTranslateY(-0,5*tamanho);
leftFace.setRotationAxis(Rotate.Y_AXIS);
leftFace.setRotate(90);
// TopFace
Face superior do retângulo = new Rectangle(tamanho,tamanho);
topFace.setFill(color.deriveColor(0.0, 1.0, (1 - 0.1*sombra), 1.0)); topFace.setTranslateX(-0,5*tamanho);
topFace.setTranslateY(-1*tamanho); topFace.setRotationAxis(Girar.X_AXIS); topFace.setRotate(90);
// frontal
FrontFace do retângulo = new Rectangle(tamanho,tamanho);
frontFace.setFill(cor);
frontFace.setTranslateX(-0,5*tamanho);
frontFace.setTranslateY(-0,5*tamanho);
frontFace.setTranslateZ(-0,5*tamanho);
}
}
}
}
Xilofone.java A-9
Machine Translated by Google