Nessa postagem vamos criar o efeito Metaballs e iremos seguir o mesmo código explicado pelo MESTRE Shiffman no vídeo abaixo, mas iremos aplicar em JavaFX. Sugiro você ver o vídeo, ler o artigo sobre escrita de pixels com JavaFX e tentar fazer por você mesmo. Se não conseguir, em seguida você pode ver o código que criamos como exemplo.
Nosso simples projeto
Como vocês viram, o Shiffman usa Processing,a linguagem de programação mais bacana para criarmos efeitos visuais. A boa notícia é que tudo que fazemos com Processing podemos fazer com JavaFX. A versão original de Processing, na verdade, é baseada em Java (com versões para JavaScript e Python). Logo, tudo que você vê ele fazendo você consegue fazer também e em Java, ou seja, você se diverte e ainda exercita o uso de uma linguagem de mercado.
O nosso programa vai ter duas pequenas classes, veja o código e a seguir um vídeo que fiz explicando. Se tiver dúvidas você pode perguntar no nosso grupo ou nos comentários
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Blob { | |
double posX, posY; | |
double velX, velY; | |
double raio; | |
public Blob(double x, double y) { | |
super(); | |
this.posX = x; | |
this.posY = y; | |
this.raio = 200; | |
velX = Main.random.nextFloat() * 10; | |
velY = Main.random.nextFloat() * 10; | |
} | |
public void update() { | |
posX += velX; | |
posY += velY; | |
if(posX < 0 || posX > Main.WIDTH) { | |
velX *= -1; | |
} | |
if(posY < 0 || posY > Main.HEIGHT) { | |
velY *= -1; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static java.lang.Math.pow; | |
import static java.lang.Math.sqrt; | |
import java.util.Random; | |
import javafx.animation.KeyFrame; | |
import javafx.animation.Timeline; | |
import javafx.application.Application; | |
import javafx.scene.Scene; | |
import javafx.scene.canvas.Canvas; | |
import javafx.scene.canvas.GraphicsContext; | |
import javafx.scene.layout.StackPane; | |
import javafx.scene.paint.Color; | |
import javafx.stage.Stage; | |
import javafx.util.Duration; | |
public class Main extends Application { | |
public static final float WIDTH = 600; | |
public static final float HEIGHT = 400; | |
int COLOR_MODES = 7; | |
public static Random random = new Random(); | |
Blob[] blobs = new Blob[12]; | |
public static void main(String[] args) { | |
launch(); | |
} | |
int selectedColorMode = 1; | |
boolean inverter = false; | |
private Canvas canvas; | |
@Override | |
public void start(Stage stage) throws Exception { | |
canvas = new Canvas(WIDTH, HEIGHT); | |
for (int i = 0; i < blobs.length; i++) { | |
blobs[i] = new Blob(random.nextFloat() * WIDTH, random.nextFloat() * HEIGHT); | |
} | |
canvas.setOnMouseClicked(e -> { | |
if (e.isControlDown()) | |
inverter = !inverter; | |
else if (selectedColorMode > COLOR_MODES) | |
selectedColorMode = 1; | |
else | |
selectedColorMode++; | |
}); | |
stage.setTitle("MetaBalls example with JavaFX"); | |
stage.show(); | |
stage.setScene(new Scene(new StackPane(canvas), WIDTH, HEIGHT)); | |
KeyFrame frame = new KeyFrame(Duration.millis(100), e -> draw()); | |
Timeline timeline = new Timeline(frame); | |
timeline.setCycleCount(Timeline.INDEFINITE); | |
timeline.play(); | |
} | |
private void draw() { | |
GraphicsContext ctx = canvas.getGraphicsContext2D(); | |
ctx.clearRect(0, 0, WIDTH, HEIGHT); | |
for (int x = 0; x < WIDTH; x++) { | |
for (int y = 0; y < HEIGHT; y++) { | |
int total = 0; | |
for (Blob blob : blobs) { | |
double d = distance(x, y, blob.posX, blob.posY); | |
total += 15 * (blob.raio / d); | |
} | |
if (total > 255) | |
total = 255; | |
Color color = selectColor(total); | |
ctx.getPixelWriter().setColor(x, y, color); | |
} | |
} | |
for (int i = 0; i < blobs.length; i++) { | |
blobs[i].update(); | |
} | |
} | |
private Color selectColor(int total) { | |
int inverso = 255; | |
if (inverter) { | |
inverso = 255 % total; | |
} | |
Color color = Color.rgb(total, total, total); | |
switch (selectedColorMode) { | |
case (1): | |
color = Color.rgb(total, total, total); | |
break; | |
case (2): | |
color = Color.rgb(total, total, inverso); | |
break; | |
case (3): | |
color = Color.rgb(total, inverso, total); | |
break; | |
case (4): | |
color = Color.rgb(total, inverso, inverso); | |
break; | |
case (5): | |
color = Color.rgb(inverso, total, total); | |
break; | |
case (6): | |
color = Color.rgb(inverso, total, inverso); | |
break; | |
case (7): | |
color = Color.rgb(inverso, inverso, total); | |
} | |
return color; | |
} | |
private double distance(double x, double y, double x2, double y2) { | |
return sqrt(pow(x2 - x, 2) + pow(y2 - y, 2)); | |
} | |
} |
Conclusão
E está aberta a temporada de efeitos especiais no JavaFX! Vamos criar coisas baseadas nos vídeos do Shiffman. Em breve voltamos com mais novidades.
Nenhum comentário:
Postar um comentário