/* BouncingBallSimpleFX.java Copyright (c) Kari Laitinen http://www.naturalprogramming.com/ 2014-12-18 File created. 2014-12-29 Last modification. This program has a Bouncer but it can't rotate or explode. A better program is BouncingBallFX.java. */ import javafx.animation.* ; // AnimationTimer, etc. import javafx.util.Duration; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.*; // Arc, Circle, etc. import javafx.geometry.* ; // Point2D, etc. import javafx.stage.Stage; class Bouncer extends Circle { // bouncer_velocity specifies the number of pixels the object // will be moved in a single movement operation. double bouncer_velocity = 4.0 ; // bouncer_direction is an angle in radians. This angle specifies // the direction where the bouncer will be moved next. double bouncer_direction = Math.random() * Math.PI * 2 ; Rectangle bouncing_area ; public Bouncer( Point2D given_position, Color given_color, Rectangle given_bouncing_area ) { super( given_position.getX(), given_position.getY(), 64, given_color ) ; bouncing_area = given_bouncing_area ; } public void shrink() { // The if-construct ensures that the ball does not become // too small. if ( getRadius() > 5 ) { setRadius( getRadius() - 3 ) ; } } public void enlarge() { setRadius( getRadius() + 3 ) ; } public void move() { // In the following statement a minus sign is needed when the // y coordinate is calculated. The reason for this is that the // y direction in the graphical coordinate system is 'upside down'. setCenterX( getCenterX() + bouncer_velocity * Math.cos(bouncer_direction ) ) ; setCenterY( getCenterY() - bouncer_velocity * Math.sin(bouncer_direction ) ) ; // Now, after we have moved this bouncer, we start finding out whether // or not it has hit a wall or some other obstacle. If a hit occurs, // a new direction for the bouncer must be calculated. // The following four if constructs must be four separate ifs. // If they are replaced with an if - else if - else if - else if // construct, the program will not work when the bouncer enters // a corner in an angle of 45 degrees (i.e. Math.PI / 4). if ( getCenterY() - getRadius() <= bouncing_area.getY() ) { // The bouncer has hit the northern 'wall' of the bouncing area. bouncer_direction = 2 * Math.PI - bouncer_direction ; } if ( getCenterX() - getRadius() <= bouncing_area.getX() ) { // The western wall has been reached. bouncer_direction = Math.PI - bouncer_direction ; } if ( ( getCenterY() + getRadius() ) >= ( bouncing_area.getY() + bouncing_area.getHeight() ) ) { // Southern wall has been reached. bouncer_direction = 2 * Math.PI - bouncer_direction ; } if ( ( getCenterX() + getRadius() ) >= ( bouncing_area.getX() + bouncing_area.getWidth() ) ) { // Eastern wall reached. bouncer_direction = Math.PI - bouncer_direction ; } } } public class BouncingBallSimpleFX extends Application { static final int SCENE_WIDTH = 800 ; static final int SCENE_HEIGHT = 680 ; AnimationTimer animation_timer ; public void start( Stage stage ) { Group group_for_balls = new Group() ; stage.setTitle( "BouncingBallSimpleFX.java" ) ; Scene scene = new Scene( group_for_balls, SCENE_WIDTH, SCENE_HEIGHT ) ; scene.setFill( Color.LIGHTYELLOW ) ; Rectangle bouncing_area = new Rectangle( 0, 0, SCENE_WIDTH, SCENE_HEIGHT ) ; Bouncer ball_on_screen = new Bouncer( new Point2D( SCENE_WIDTH / 2, SCENE_HEIGHT / 2 ), Color.RED, bouncing_area ) ; group_for_balls.getChildren().add( ball_on_screen ) ; stage.setScene( scene ) ; stage.show() ; animation_timer = new AnimationTimer() { public void handle(long l) { ball_on_screen.move() ; } }; animation_timer.start() ; } public static void main( String[] command_line_parameters ) { launch( command_line_parameters ) ; } } /* NOTES: The following were useful pages to develop this program: https://docs.oracle.com/javase/8/javafx/api/javafx/geometry/Point2D.html http://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Circle.html http://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Rectangle.html */