Wednesday, June 29, 2011

JavaFX 2.0 "Avoid The Red Balls"

In a comment to my article „JavaFX avoid the red balls“ i was pointed to JavaFX 2.0. The greatest difference between JavaFX 1.x and 2.0 is that in 2.0 you can write your applications now in Java. The support for JavaFX-Script has been completely dropped. Therefore I ported my application from 1.x to 2.0.

JavaFX is very powerful in creating user interfaces with emphasis on look and feel and design. I was able to port my App without any greater issues. Most of the code was usable as it was I just had to change the syntax. The greatest difference was the use of “AnimationTimer“ instead of “timeline”. The new version and the source code (as a netbeans project) is available here. Here is the JavaFX 2.0 code:
/*
 * Copyright 2011, Benny Gächter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jfxtest;

import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import java.util.Random;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventType;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.effect.BoxBlur;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;

/**
 *
 * @author Benny Gächter
 */
public class JFXTest extends Application implements EventHandler {

    static int APP_WIDTH = 800;
    static int APP_HEIGHT = 600;
    double mouseX = 0.0;
    double mouseY = 0.0;
    Random random = new java.util.Random();
    int state = 1;
    int counter = 0;
    double currentRuntime;
    Rectangle player;
    long lastUpdate = 0;
    long startTime = 0;
    final Group balls = new Group();
    Group root = null;
    AnimationTimer timer = null;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
 Application.launch(JFXTest.class, args);
    }

    @Override
    public void start(Stage primaryStage) {
 primaryStage.setTitle("Red Balls JavaFX 2.0");
 lastUpdate = System.currentTimeMillis();

 root = new Group();
 Scene scene = new Scene(root, APP_WIDTH, APP_HEIGHT, Color.WHITE);
 scene.addEventHandler(EventType.ROOT, this);

 player = new Rectangle(20, 20, Color.BLACK);

 root.getChildren().add(player);


 for (int i = 0; i < 15; i++) {
     MyCircle ball = new MyCircle(15, Color.RED);
     ball.setStrokeType(StrokeType.OUTSIDE);
     ball.setStroke(Color.DARKRED);
     ball.setStrokeWidth(4);
     ball.setCenterX(random.nextInt(APP_WIDTH - 15));
     ball.setCenterY(random.nextInt(APP_HEIGHT - 15));

     if (random.nextInt(100) % 2 == 0) {
  ball.setVx(1);
     }
     if (random.nextInt(100) % 2 == 0) {
  ball.setVy(1);
     }
     balls.getChildren().add(ball);
     balls.setEffect(new BoxBlur(2, 2, 1));
 }

 root.getChildren().add(balls);
 startTime = System.currentTimeMillis();

 final Label time = new Label("Time :");
 time.setLayoutX(50);
 time.setLayoutY(20);
 time.setScaleX(2);
 time.setScaleY(2);
 time.setScaleZ(2);
 root.getChildren().add(time);

 timer = new AnimationTimer() {

     @Override
     public void handle(long l) {
  if (state == 1) {
      if (System.currentTimeMillis() > lastUpdate + 20) {
   lastUpdate = System.currentTimeMillis();
   time.setText("Time : " + (System.currentTimeMillis() - startTime) / 1000 + " s");
   for (Node ball : balls.getChildren()) {
       MyCircle AI = (MyCircle) ball;

       //bounce from walls
       if (AI.getCenterX() + AI.getVx() < 15) {
    AI.vx = -AI.vx;
       }
       if (AI.getCenterX() + AI.vx > APP_WIDTH - 15) {
    AI.vx = -AI.vx;
       }

       if (AI.getCenterY() + AI.vy < 15) {
    AI.vy = -AI.vy;
       }
       if (AI.getCenterY() + AI.vy > APP_HEIGHT - 15) {
    AI.vy = -AI.vy;
       }


       if (AI.getCenterX() >= mouseX && AI.getCenterX() <= mouseX + 10) {
    if (AI.getCenterY() + 15 >= mouseY - 10
     && AI.getCenterY() - 15 <= mouseY) {
        AI.vy = -AI.vy;
        state = 2;
    }
       } else if (AI.getCenterY() >= mouseY - 10
        && AI.getCenterY() <= mouseY) {
    if (AI.getCenterX() + 15 >= mouseX
     && AI.getCenterX() - 15 <= mouseX + 10) {
        AI.vx = -AI.vx;
        state = 2;

    }
       }
       //calculate new position
       AI.setCenterX(AI.getCenterX() + AI.vx);
       AI.setCenterY(AI.getCenterY() + AI.vy);

       //increase speed
       AI.vx = AI.vx * 1.002;
       AI.vy = AI.vy * 1.002;
   }
      }
  } else {
      this.stop();
      setGameoverScreen();
  }
     }
 };
 timer.start();

 primaryStage.setScene(scene);

 primaryStage.setVisible(true);

    }

    public void setGameoverScreen() {
 final Button restart = new Button();
 restart.setText("Restart");
 restart.setLayoutX(APP_WIDTH / 2);
 restart.setLayoutY(APP_HEIGHT / 2);
 restart.setScaleZ(4);
 restart.setScaleX(4);
 restart.setScaleY(4);
 root.getChildren().add(restart);

 restart.setOnAction(new EventHandler() {

     @Override
     public void handle(ActionEvent e) {
  for (Node ball : balls.getChildren()) {
      MyCircle buf = (MyCircle) ball;
      buf.setCenterX(random.nextInt(APP_WIDTH - 15));
      buf.setCenterY(random.nextInt(APP_HEIGHT - 15));

      if (random.nextInt(100) % 2 == 0) {
   buf.setVx(1);
      } else {
   buf.setVx(-1);
      }
      if (random.nextInt(100) % 2 == 0) {
   buf.setVy(1);
      } else {
   buf.setVy(-1);
      }
  }

  root.getChildren().remove(restart);
  state = 1;
  timer.start();
  startTime = System.currentTimeMillis();

     }
 });
    }

    public void handle(Event event) {
 if (event instanceof MouseEvent) {
     MouseEvent e = (MouseEvent) event;
     mouseX = e.getX();
     mouseY = e.getY();

     if (mouseX > APP_WIDTH - 20) {
  mouseX = APP_WIDTH - 20;
     }
     if (mouseY > APP_HEIGHT - 20) {
  mouseY = APP_HEIGHT - 20;
     }
     if (mouseX < 0) {
  mouseX = 1;
     }
     if (mouseY < 0) {
  mouseY = 1;
     }

     player.setX(mouseX);
     player.setY(mouseY);
 }
    }

    class MyCircle extends Circle {

 public double vy;
 public double vx;

 public MyCircle(double centerX, double centerY, double radius, Paint fill) {
     super(centerX, centerY, radius, fill);
     setVel();
 }

 public MyCircle(double centerX, double centerY, double radius) {
     super(centerX, centerY, radius);
     setVel();
 }

 public MyCircle() {
     setVel();
 }

 public MyCircle(double radius, Paint fill) {
     super(radius, fill);
     setVel();
 }

 public MyCircle(double radius) {
     super(radius);
     setVel();
 }

 public double getVx() {
     return vx;
 }

 public void setVx(int vx) {
     this.vx = vx;
 }

 public double getVy() {
     return vy;
 }

 public void setVy(int vy) {
     this.vy = vy;
 }

 private void setVel() {
     vx = -1;
     vy = -1;
 }
    }
}

0 Kommentare:

Post a Comment