diff --git a/README.md b/README.md index 088323f..ec2dd58 100644 --- a/README.md +++ b/README.md @@ -43,34 +43,37 @@ object-oriented, GUI programming, advanced GUI and Web programming using Java... ____ + ## How to Contribute ### _Coding Guidelines_ + - #### Solution must use Java 8 SE, as this is the version used by the book. - - #### Every solution should have a java file containing a public main method for testing it. - - #### Naming convention is: ExerciseCC_EE.java where CC is the chapter number and EE is the exercise number. - - #### The public Exercise class containing the main method must include a JavaDoc comment on the class with original exercise question. - - #### Each solution should be its own self-contained program with minimal dependencies on other files. If you need multiple files please create a package for the exercise. - - #### ch_XX/exercise22_07/Exercise22_07.java - - #### This allows us to utilize the Exercise Checking Tool [Exercise Checking Tool](https://liveexample.pearsoncmg.com/CheckExercise/faces/CheckExercise.xhtml?chapter=1&programName=Exercise01_01) to verify solutions. + - #### Every solution should have a java file containing a public main method for testing it. + - #### Naming convention is: ExerciseCC_EE.java where CC is the chapter number and EE is the exercise number. + - #### The public Exercise class containing the main method must include a JavaDoc comment on the class with original exercise question. + - #### Each solution should be its own self-contained program with minimal dependencies on other files. If you need multiple files please create a package for the exercise. + - #### ch_XX/exercise22_07/Exercise22_07.java + - #### This allows us to utilize the Exercise Checking Tool [Exercise Checking Tool](https://liveexample.pearsoncmg.com/CheckExercise/faces/CheckExercise.xhtml?chapter=1&programName=Exercise01_01) to verify solutions. - ### Example exercise solution: + ```java package ch_01; + /** -* 1.1 (Display three messages) Write a program that displays Welcome to Java, -* Welcome to Computer Science, and Programming is fun. - */ - public class Exercise01_01 { - public static void main(String[] args) { - System.out.println("Welcome to Java"); - System.out.println("Welcome to Computer Science"); - System.out.println("Programming is fun"); - } + * 1.1 (Display three messages) Write a program that displays Welcome to Java, + * Welcome to Computer Science, and Programming is fun. + */ +public class Exercise01_01 { + public static void main(String[] args) { + System.out.println("Welcome to Java"); + System.out.println("Welcome to Computer Science"); + System.out.println("Programming is fun"); + } } ``` - ### Pull requests: - _When to use Pull Requests_ @@ -156,10 +159,8 @@ Indicates 100% completion of all exercises for that chapter 14 - JavaFx Basics complete-check-img
  • Chapter 15 - - Event-Driven Programming and Animations -
    -Exercises Needed: 33 -
    + - Event-Driven Programming and Animations complete-check-img +

  • Chapter 16 - JavaFx UI Controls and Multimedia diff --git a/ch_15/Exercise15_33.java b/ch_15/Exercise15_33.java new file mode 100644 index 0000000..d643edb --- /dev/null +++ b/ch_15/Exercise15_33.java @@ -0,0 +1,226 @@ +package ch_15; + +import javafx.animation.PathTransition; +import javafx.application.Application; +import javafx.collections.ObservableList; +import javafx.geometry.Point2D; +import javafx.scene.Scene; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Line; +import javafx.scene.shape.Polyline; +import javafx.stage.Stage; +import javafx.util.Duration; + +import java.util.ArrayList; +import java.util.List; + +/** + * ***15.33 (Game: bean-machine animation) Write a program that animates the bean + * machine introduced in Programming Exercise 7.21. The animation terminates + * after ten balls are dropped, as shown in Figure 15.36b and c. + */ +public class Exercise15_33 extends Application { + + @Override + public void start(Stage primaryStage) { + double WIDTH = 400; + double HEIGHT = 400; + BeanMachinePane pane = new BeanMachinePane(WIDTH, HEIGHT, 8); + Scene scene = new Scene(pane, WIDTH, HEIGHT); + primaryStage.setScene(scene); + primaryStage.setResizable(false); + primaryStage.setTitle(getClass().getName()); + primaryStage.show(); + playAnimation(pane); + } + + static void playAnimation(BeanMachinePane pane) { + /* Drop 10 balls */ + for (int i = 0; i < 10; i++) { + pane.dropBall(); + } + } + + static class BeanMachinePane extends Pane { + private final int numberOfPins; + private final int numberOfSlots; + + double ballRadius; + + Line[] outlineShape; + Line outlineShapeBaseLine; + Line[] slotVerticalLines; + Circle[] pins; + + List droppedBalls = new ArrayList<>(); + + double spaceBallDropDelaySeconds = 0.5; + + public BeanMachinePane(double width, double height, int numberOfSlots) { + setWidth(width); + setHeight(height); + this.numberOfSlots = numberOfSlots; + this.numberOfPins = getNumberOfPins(numberOfSlots); + buildStaticShapes(); + getChildren().add(outlineShapeBaseLine); + getChildren().addAll(outlineShape); + getChildren().addAll(slotVerticalLines); + getChildren().addAll(pins); + } + + public void dropBall() { + ballDropAnimation(); + } + + private void ballDropAnimation() { + /* Draw ball in the center flask shape opening */ + double flaskOpeningCenterX = getDropStartPtX(); + /* Draw ball just ABOVE flask shape opening */ + ballRadius = pins[0].getRadius(); + Circle ball = new Circle(flaskOpeningCenterX, + outlineShape[5].getEndY() - ballRadius - 20, + ballRadius, + Color.RED); + Polyline polyline = createRandomPath(ball); + PathTransition path = new PathTransition(Duration.seconds(4), polyline, ball); + path.setDelay(Duration.seconds(spaceBallDropDelaySeconds)); + spaceBallDropDelaySeconds += 1.5; + getChildren().addAll(polyline); + getChildren().addAll(ball); + droppedBalls.add(ball); + path.play(); + } + + private double getDropStartPtX() { + return outlineShapeBaseLine.getStartX() + + (outlineShapeBaseLine.getEndX() + - outlineShapeBaseLine.getStartX()) / 2; + } + + + private Line getBaseLineShape(double paneWidth, double paneHeight) { + /* Horizontal line at the bottom of the machine (Y value does not change) */ + double baseLineYValue = paneHeight * 0.8; + double baseLineStartXValue = paneWidth * 0.2; + double baseLineEndXValue = paneWidth * 0.8; + return new Line(baseLineStartXValue, baseLineYValue, baseLineEndXValue, baseLineYValue); + + } + + + /** + * @param slots the number of slots in the bean machine + * @return the number of pins in the bean machine + */ + int getNumberOfPins(int slots) { + int numPins = 0; + do { + slots--; + numPins += slots; + } while (slots > 1); + + return numPins; + } + + private void buildStaticShapes() { + double paneWidth = getWidth(); + double paneHeight = getHeight(); + outlineShapeBaseLine = getBaseLineShape(paneWidth, paneHeight); + double distance = (outlineShapeBaseLine.getEndX() - outlineShapeBaseLine.getStartX()) / numberOfSlots; + pins = new Circle[numberOfPins]; + int index = 0; + for (int i = 1; i < numberOfSlots; i++) { + double x = outlineShapeBaseLine.getStartX() + (i * distance * 0.50) + distance / 2; + double y = outlineShapeBaseLine.getStartY() - (distance * i) - distance / 2; + for (int j = 0; j < numberOfSlots - i; j++) { + pins[index++] = new Circle(x, y, paneWidth * 0.012, Color.BLUE); + x += distance; + } + } + + distance = distance + (distance / 2) - pins[0].getRadius(); + slotVerticalLines = new Line[numberOfSlots - 1]; + for (int i = 0; i < numberOfSlots - 1; i++) { + double x1 = pins[i].getCenterX() + pins[i].getRadius() * Math.sin(Math.PI); + double y1 = pins[i].getCenterY() - pins[i].getRadius() * Math.cos(Math.PI); + slotVerticalLines[i] = new Line(x1, y1, x1, y1 + distance); + + } + + outlineShape = new Line[6]; + outlineShape[0] = new Line( + outlineShapeBaseLine.getEndX(), outlineShapeBaseLine.getEndY(), + outlineShapeBaseLine.getEndX(), outlineShapeBaseLine.getEndY() - distance); + outlineShape[1] = new Line( + outlineShapeBaseLine.getStartX(), outlineShapeBaseLine.getStartY(), + outlineShapeBaseLine.getStartX(), outlineShapeBaseLine.getStartY() - distance); + + for (int i = 2; i < 4; i++) { + double x = pins[pins.length - i].getCenterX(); + double y = pins[pins.length - i].getCenterY() - distance; + outlineShape[i] = + new Line(x, y, outlineShape[i - 2].getEndX(), outlineShape[i - 2].getEndY()); + } + + for (int i = 4; i < outlineShape.length; i++) { + outlineShape[i] = + new Line( + outlineShape[i - 2].getStartX(), + outlineShape[i - 2].getStartY(), + outlineShape[i - 2].getStartX(), + outlineShape[i - 2].getStartY() - (distance * 0.6) + ); + } + } + + private Polyline createRandomPath(Circle ball) { + Polyline polyLine = new Polyline(); + polyLine.setFill(Color.TRANSPARENT); + polyLine.setStroke(Color.TRANSPARENT); + ObservableList pathPoints = polyLine.getPoints(); + Point2D startPoint = new Point2D(ball.getCenterX(), ball.getCenterY()); + double nextX = startPoint.getX(); // Set current X to ball's center X starting position + double nextY = startPoint.getY(); // Set current Y to ball's center Y starting position + pathPoints.addAll(nextX, nextY); + + while (nextY < outlineShapeBaseLine.getStartY() - ball.getRadius()) { + nextY += 1; // Move ball down on Y axis to simulate falling + /* Re-calculate random path until it does not pass through a static shape */ + nextX = getRandomX(nextX); + while (collideWithPins(nextX, nextY) || collideWithOutline(nextX, nextY)) { + nextX = getRandomX(nextX); + } + pathPoints.addAll(nextX, nextY); + } + + return polyLine; + } + + private boolean collideWithOutline(double nextX, double nextY) { + return false; + } + + private boolean collideWithPins(double nextX, double nextY) { + for (Circle pin : pins) { + if (pin.contains(nextX, nextY + ballRadius)) { + return true; + } + } + return false; + } + + private double getRandomX(double currentX) { + double random = Math.random(); + if (random < 0.5) { + currentX -= 1; + } else { + currentX += 1; + } + return currentX; + } + + + } +}