如何在javafx中反弹圆圈和其他形状?

时间:2016-08-17 04:56:59

标签: javafx

package application;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {
    private static Canvas canvas;

    private static int clickCount = 0;

    private static int x1 = 0;
    private static int y1 = 0;

    static ArrayList<Circle> circleArr = new ArrayList<Circle>();

    private Timeline timeline;

    @Override
    public void start(Stage primaryStage) {
        try {
            primaryStage.setTitle("Graphics Demo App");

            BorderPane root = new BorderPane();
            Scene scene = new Scene(root, 800, 500);

            canvas = new Canvas(800, 475);
            canvas.setOnMouseClicked(new EventHandler<MouseEvent>() {

                @Override
                public void handle(MouseEvent event) {

                    int x = (int) event.getX();
                    int y = (int) event.getY();

                    if (clickCount % 2 == 0) {
                        x1 = x;
                        y1 = y;
                    } else {
                        int x2 = x;
                        int y2 = y;

                        int r = (int) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

                        int x_corner = x1 - r;
                        int y_corner = y1 - r;

                        Circle c = new Circle(x_corner, y_corner, r);

                        circleArr.add(c);

                        c.drawOn(canvas);

                    }

                    clickCount++;

                }

            });

            GraphicsContext gc = canvas.getGraphicsContext2D();

            gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

            root.setCenter(canvas);

            Button circleButton = new Button("Circle");

            circleButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {

                    // System.out.println("Circle");

                    GraphicsContext gc = canvas.getGraphicsContext2D();

                    gc.setStroke(Color.AQUAMARINE);

                    Random rand = new Random();

                    int x = rand.nextInt((int) canvas.getWidth());
                    int y = rand.nextInt((int) canvas.getHeight());

                    Circle c = new Circle(x, y, 50);

                    c.drawOn(canvas);

                    // gc.strokeOval(x, y, 200, 200);

                }

            });

            Button squareButton = new Button("Square");

            squareButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {
                    // System.out.println("square");

                    GraphicsContext gc = canvas.getGraphicsContext2D();

                    gc.setStroke(Color.AQUAMARINE);

                    Random rand = new Random();

                    int x = rand.nextInt((int) canvas.getWidth());
                    int y = rand.nextInt((int) canvas.getHeight());
                    int w = rand.nextInt((int) canvas.getWidth());
                    int h = rand.nextInt((int) canvas.getHeight());

                    Square s = new Square(x, y, w, h);

                    s.drawOn(canvas);

                    // gc.strokeOval(x, y, 200, 200);
                }

            });

            Button stepButton = new Button("Step");

            stepButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {
                    step();
                }

            });

            Button playButton = new Button("Play");

            playButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {
                    timeline = new Timeline(new KeyFrame(Duration.millis(100), ae -> step()));

                    timeline.setCycleCount(Animation.INDEFINITE);
                    timeline.play();

                }

            });

            Button stopButton = new Button("Stop");

            stopButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {

                    if (timeline != null) {
                        timeline.stop();
                    }

                }

            });

            FlowPane buttonsPane = new FlowPane();
            buttonsPane.setAlignment(Pos.CENTER);

            buttonsPane.getChildren().add(circleButton);
            buttonsPane.getChildren().add(squareButton);

            Button saveButton = new Button("Save");
            Button restoreButton = new Button("Restore");

            restoreButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent e) {
                    restore();
                }

            });

            buttonsPane.getChildren().add(saveButton);
            buttonsPane.getChildren().add(restoreButton);
            buttonsPane.getChildren().add(stepButton);
            buttonsPane.getChildren().add(playButton);
            buttonsPane.getChildren().add(stopButton);

            root.setBottom(buttonsPane);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void step() {
        clearScreen();

        for (Circle c : circleArr) {
            c.step(canvas);
        }
    }

    private static void clearScreen() {
        canvas.getGraphicsContext2D().fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
    }

    public static void main(String[] args) {
        launch(args);
    }

    public static void restore() {
        try {

            // Setting up to read the text file
            FileReader reader = new FileReader("shapes.txt");

            BufferedReader bufferReader = new BufferedReader(reader);

            // Read the first line in the file
            String line = bufferReader.readLine();

            while (line != null && line.trim().length() > 0) {

                String[] parts = line.split(":");
                String left = parts[0];
                String right = parts[1];

                if (left.equals("C")) {
                    String[] components = right.trim().split(" ");

                    int x = Integer.parseInt(components[0]);
                    int y = Integer.parseInt(components[1]);
                    int r = Integer.parseInt(components[2]);
                    Circle c = new Circle(x, y, r);
                    c.drawOn(canvas);
                } else if (left.equals("S")) {
                    System.out.println("This is a square: " + right);
                }
                line = bufferReader.readLine();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

这是圆圈代码: -

package application;

import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

public class Circle {
    int x;
    int y;
    int radius;

    int x_direction = 1;
    int y_direction = 1;
    int dx = 11, dy = 7;

    public Circle(){
    }

    public Circle(int x, int y, int r){
        this.x = x;
        this.y = y;
        this.radius = r;
    }

    public void print(){
        System.out.println("Circle: " + x + " " + y + " " + radius);
    }

    public void drawOn(Canvas canvas){
        GraphicsContext gc = canvas.getGraphicsContext2D();

        gc.setStroke(Color.AQUAMARINE);
        gc.strokeOval(x, y, 2*radius, 2*radius);
    }


    public void step(Canvas canvas){

    x += 5 * x_direction;
    y += 5 * y_direction;


    if (x + radius * 2 > canvas.getWidth()){

    x_direction = x_direction * -1;

    }

    if (y + radius * 2 > canvas.getHeight()){
        y_direction = y_direction * -1;
    }
    if ((x - radius + dx < 0) || (x + radius + dx > canvas.getWidth()))
        dx = -dx;

        if ((y - radius + dy < 0) || (y + radius + dy > canvas.getHeight()))
            dy = -dy;

        // Move the circle.
        x += dx;
        y += dy;

        drawOn(canvas);
    }

1 个答案:

答案 0 :(得分:0)

这是我想出的。由于你没有说出你的问题,我做了一个例子。我没有使用时间线,我只是使用了另一个不断更新的线程。

package helloworld;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Matt on 17/08/16.
 */
public class AnimatedScene extends Application{
    List<AnimatedCircle> circles = new ArrayList<>();
    Canvas custom;
    boolean quit = false;
    @Override
    public void start(Stage primaryStage) throws Exception {

        Group root = new Group();

        custom = new Canvas(600, 600);
        GraphicsContext gc = custom.getGraphicsContext2D();
        createBackground(gc);
        root.getChildren().add(custom);


        circles.add(new AnimatedCircle(50, 50));
        circles.add(new AnimatedCircle(50, 100));
        circles.add(new AnimatedCircle(50, 150));
        circles.add(new AnimatedCircle(50, 200));

        for(AnimatedCircle circle: circles) {
            root.getChildren().add(circle.shape);
        }

                Scene scene = new Scene(root, 600, 600);


        primaryStage.setScene(scene);
        primaryStage.show();

        primaryStage.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, evt->{
            quit=true;
        });
        startMainLoop();
    }

    private void startMainLoop(){
        new Thread(()->{
            Thread.currentThread().setName("bounce loop");
            long time = System.currentTimeMillis();
            int step = (int)(1000.0/60.0);
            while(!(Thread.interrupted()||quit)){
                synchronized (circles) {
                    for(int i = 0; i<circles.size(); i++){
                        for(int j = i+1; j<circles.size(); j++){
                            AnimatedCircle a = circles.get(i);
                            AnimatedCircle b = circles.get(j);
                            double dx = b.cx - a.cx;
                            double dy = b.cy - a.cy;
                            double distance = Math.sqrt(dx*dx + dy*dy);

                            if(distance<a.radius + b.radius){
                                //collision
                                b.vx = dx/distance;
                                b.vy = dy/distance;
                                a.vx = -dx/distance;
                                a.vy = dy/distance;
                            }

                        }
                    }
                    for (AnimatedCircle circle : circles) {
                        circle.update();
                    }
                }
                Platform.runLater(()->{
                    sync();
                });
                try{
                    long nt = System.currentTimeMillis();
                    long wait = step - (nt - time);
                    if(wait>=0) {
                        Thread.sleep(wait);
                        time = nt+wait;
                    } else{
                        time = nt;
                    }

                } catch(InterruptedException exc){
                    //just exit.
                }
            }
        }).start();
    }

    void sync(){
        synchronized (circles){
            GraphicsContext gc = custom.getGraphicsContext2D();
            createBackground(gc);
            for(AnimatedCircle circle: circles){
                circle.sync();

                gc.setFill(new Color(0, 0, 0, 0.2));
                gc.fillOval(circle.cx - circle.radius-15, circle.cy - circle.radius-5, 50, 50);

            }
        }
    }

    void createBackground(GraphicsContext gc){
        gc.setFill(Color.RED);
        RadialGradient gradient = new RadialGradient(
                0, 0, 300, 300, 300, false,
                CycleMethod.NO_CYCLE,
                new Stop(0.0, Color.RED), new Stop(1.0, Color.DARKRED));
        gc.setFill(gradient);
        gc.fillRect(100, 100, 400, 400);
        gc.setFill(new Color(1, 0.2, 0.2, 1));
        gc.fillPolygon(
            new double[]{ 0, 100, 100, 0},
            new double[]{ 0, 100, 500, 600},
            4
        );
        gc.setFill(new Color(1, 0.25, 0.25, 1));
        gc.fillPolygon(
                new double[]{ 0, 100, 500, 600},
                new double[]{ 0, 100, 100, 0},
                4
        );
        gc.setFill(new Color(0.5, 0., 0., 1));
        gc.fillPolygon(
                new double[]{ 500, 600, 600, 500},
                new double[]{ 100, 0, 600, 500},
                4
        );
        gc.setFill(new Color(0.8, 0., 0., 1));
        gc.fillPolygon(
                new double[]{ 0, 100, 500, 600},
                new double[]{ 600, 500, 500, 600},
                4
        );

    }

    public static void main(String[] args){
        launch(args);
    }
}

class AnimatedCircle{
    public Ellipse shape;
    RadialGradient gradient;
    double vx;
    double vy;
    double cx, cy;
    double speed = 5;
    double radius = 25;
    public AnimatedCircle(double x, double y){
        cx = x;
        cy = y;

        vx = 2*(Math.random() - 0.5);
        vy = Math.sqrt(1 - vx*vx);
        if(Math.random()>=0.5){
            vy = -vy;
        }
        shape = new Ellipse(cx, cy, radius, radius);
        final String label = x + ", " + y;
        shape.addEventHandler(MouseEvent.MOUSE_CLICKED, evt->{
            System.out.println(label);
        });
        gradient = new RadialGradient(0, 0, 0.75, 0.6, 1, true, CycleMethod.NO_CYCLE, new Stop(0.0, Color.WHITE), new Stop(1.0, Color.BLACK));
        shape.setFill(gradient);

    }

    void update(){

        double nx = cx + vx*speed;

        if(nx + shape.getRadiusX()>600 || nx - shape.getRadiusX()<0){
            vx = -vx;
            nx = cx;
        }

        double ny = cy + vy*speed;

        if(ny + shape.getRadiusY()>600 || ny - shape.getRadiusY()<0 ){
            vy = -vy;
            ny = cy;
        }

        cy = ny;
        cx = nx;

    }
    public void sync(){
        shape.setCenterX(cx);
        shape.setCenterY(cy);
    }

}

注意事项:

  • 在createBackground中,我完全重绘了背景。在你的清晰方法中,你用最后一个颜料填充所有东西。这并不一定能清除你的背景。
  • 我用两种不同的方法来画球。 1)我使用添加到场景中的椭圆,然后我更新它们的位置。 2)我使用图形画布绘制阴影。

否则,如果你能稍微清理一下你的问题,并解释一下有什么问题可能会修复你的代码。