Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 06f6b10

Browse files
Completed Chapter 15
1 parent d23e545 commit 06f6b10

File tree

1 file changed

+226
-0
lines changed

1 file changed

+226
-0
lines changed

‎ch_15/Exercise15_33.java‎

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
package ch_15;
2+
3+
import javafx.animation.PathTransition;
4+
import javafx.application.Application;
5+
import javafx.collections.ObservableList;
6+
import javafx.geometry.Point2D;
7+
import javafx.scene.Scene;
8+
import javafx.scene.layout.Pane;
9+
import javafx.scene.paint.Color;
10+
import javafx.scene.shape.Circle;
11+
import javafx.scene.shape.Line;
12+
import javafx.scene.shape.Polyline;
13+
import javafx.stage.Stage;
14+
import javafx.util.Duration;
15+
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
/**
20+
* ***15.33 (Game: bean-machine animation) Write a program that animates the bean
21+
* machine introduced in Programming Exercise 7.21. The animation terminates
22+
* after ten balls are dropped, as shown in Figure 15.36b and c.
23+
*/
24+
public class Exercise15_33 extends Application {
25+
26+
@Override
27+
public void start(Stage primaryStage) {
28+
double WIDTH = 400;
29+
double HEIGHT = 400;
30+
BeanMachinePane pane = new BeanMachinePane(WIDTH, HEIGHT, 8);
31+
Scene scene = new Scene(pane, WIDTH, HEIGHT);
32+
primaryStage.setScene(scene);
33+
primaryStage.setResizable(false);
34+
primaryStage.setTitle(getClass().getName());
35+
primaryStage.show();
36+
playAnimation(pane);
37+
}
38+
39+
static void playAnimation(BeanMachinePane pane) {
40+
/* Drop 10 balls */
41+
for (int i = 0; i < 10; i++) {
42+
pane.dropBall();
43+
}
44+
}
45+
46+
static class BeanMachinePane extends Pane {
47+
private final int numberOfPins;
48+
private final int numberOfSlots;
49+
50+
double ballRadius;
51+
52+
Line[] outlineShape;
53+
Line outlineShapeBaseLine;
54+
Line[] slotVerticalLines;
55+
Circle[] pins;
56+
57+
List<Circle> droppedBalls = new ArrayList<>();
58+
59+
double spaceBallDropDelaySeconds = 0.5;
60+
61+
public BeanMachinePane(double width, double height, int numberOfSlots) {
62+
setWidth(width);
63+
setHeight(height);
64+
this.numberOfSlots = numberOfSlots;
65+
this.numberOfPins = getNumberOfPins(numberOfSlots);
66+
buildStaticShapes();
67+
getChildren().add(outlineShapeBaseLine);
68+
getChildren().addAll(outlineShape);
69+
getChildren().addAll(slotVerticalLines);
70+
getChildren().addAll(pins);
71+
}
72+
73+
public void dropBall() {
74+
ballDropAnimation();
75+
}
76+
77+
private void ballDropAnimation() {
78+
/* Draw ball in the center flask shape opening */
79+
double flaskOpeningCenterX = getDropStartPtX();
80+
/* Draw ball just ABOVE flask shape opening */
81+
ballRadius = pins[0].getRadius();
82+
Circle ball = new Circle(flaskOpeningCenterX,
83+
outlineShape[5].getEndY() - ballRadius - 20,
84+
ballRadius,
85+
Color.RED);
86+
Polyline polyline = createRandomPath(ball);
87+
PathTransition path = new PathTransition(Duration.seconds(4), polyline, ball);
88+
path.setDelay(Duration.seconds(spaceBallDropDelaySeconds));
89+
spaceBallDropDelaySeconds += 1.5;
90+
getChildren().addAll(polyline);
91+
getChildren().addAll(ball);
92+
droppedBalls.add(ball);
93+
path.play();
94+
}
95+
96+
private double getDropStartPtX() {
97+
return outlineShapeBaseLine.getStartX()
98+
+ (outlineShapeBaseLine.getEndX()
99+
- outlineShapeBaseLine.getStartX()) / 2;
100+
}
101+
102+
103+
private Line getBaseLineShape(double paneWidth, double paneHeight) {
104+
/* Horizontal line at the bottom of the machine (Y value does not change) */
105+
double baseLineYValue = paneHeight * 0.8;
106+
double baseLineStartXValue = paneWidth * 0.2;
107+
double baseLineEndXValue = paneWidth * 0.8;
108+
return new Line(baseLineStartXValue, baseLineYValue, baseLineEndXValue, baseLineYValue);
109+
110+
}
111+
112+
113+
/**
114+
* @param slots the number of slots in the bean machine
115+
* @return the number of pins in the bean machine
116+
*/
117+
int getNumberOfPins(int slots) {
118+
int numPins = 0;
119+
do {
120+
slots--;
121+
numPins += slots;
122+
} while (slots > 1);
123+
124+
return numPins;
125+
}
126+
127+
private void buildStaticShapes() {
128+
double paneWidth = getWidth();
129+
double paneHeight = getHeight();
130+
outlineShapeBaseLine = getBaseLineShape(paneWidth, paneHeight);
131+
double distance = (outlineShapeBaseLine.getEndX() - outlineShapeBaseLine.getStartX()) / numberOfSlots;
132+
pins = new Circle[numberOfPins];
133+
int index = 0;
134+
for (int i = 1; i < numberOfSlots; i++) {
135+
double x = outlineShapeBaseLine.getStartX() + (i * distance * 0.50) + distance / 2;
136+
double y = outlineShapeBaseLine.getStartY() - (distance * i) - distance / 2;
137+
for (int j = 0; j < numberOfSlots - i; j++) {
138+
pins[index++] = new Circle(x, y, paneWidth * 0.012, Color.BLUE);
139+
x += distance;
140+
}
141+
}
142+
143+
distance = distance + (distance / 2) - pins[0].getRadius();
144+
slotVerticalLines = new Line[numberOfSlots - 1];
145+
for (int i = 0; i < numberOfSlots - 1; i++) {
146+
double x1 = pins[i].getCenterX() + pins[i].getRadius() * Math.sin(Math.PI);
147+
double y1 = pins[i].getCenterY() - pins[i].getRadius() * Math.cos(Math.PI);
148+
slotVerticalLines[i] = new Line(x1, y1, x1, y1 + distance);
149+
150+
}
151+
152+
outlineShape = new Line[6];
153+
outlineShape[0] = new Line(
154+
outlineShapeBaseLine.getEndX(), outlineShapeBaseLine.getEndY(),
155+
outlineShapeBaseLine.getEndX(), outlineShapeBaseLine.getEndY() - distance);
156+
outlineShape[1] = new Line(
157+
outlineShapeBaseLine.getStartX(), outlineShapeBaseLine.getStartY(),
158+
outlineShapeBaseLine.getStartX(), outlineShapeBaseLine.getStartY() - distance);
159+
160+
for (int i = 2; i < 4; i++) {
161+
double x = pins[pins.length - i].getCenterX();
162+
double y = pins[pins.length - i].getCenterY() - distance;
163+
outlineShape[i] =
164+
new Line(x, y, outlineShape[i - 2].getEndX(), outlineShape[i - 2].getEndY());
165+
}
166+
167+
for (int i = 4; i < outlineShape.length; i++) {
168+
outlineShape[i] =
169+
new Line(
170+
outlineShape[i - 2].getStartX(),
171+
outlineShape[i - 2].getStartY(),
172+
outlineShape[i - 2].getStartX(),
173+
outlineShape[i - 2].getStartY() - (distance * 0.6)
174+
);
175+
}
176+
}
177+
178+
private Polyline createRandomPath(Circle ball) {
179+
Polyline polyLine = new Polyline();
180+
polyLine.setFill(Color.TRANSPARENT);
181+
polyLine.setStroke(Color.TRANSPARENT);
182+
ObservableList<Double> pathPoints = polyLine.getPoints();
183+
Point2D startPoint = new Point2D(ball.getCenterX(), ball.getCenterY());
184+
double nextX = startPoint.getX(); // Set current X to ball's center X starting position
185+
double nextY = startPoint.getY(); // Set current Y to ball's center Y starting position
186+
pathPoints.addAll(nextX, nextY);
187+
188+
while (nextY < outlineShapeBaseLine.getStartY() - ball.getRadius()) {
189+
nextY += 1; // Move ball down on Y axis to simulate falling
190+
/* Re-calculate random path until it does not pass through a static shape */
191+
nextX = getRandomX(nextX);
192+
while (collideWithPins(nextX, nextY) || collideWithOutline(nextX, nextY)) {
193+
nextX = getRandomX(nextX);
194+
}
195+
pathPoints.addAll(nextX, nextY);
196+
}
197+
198+
return polyLine;
199+
}
200+
201+
private boolean collideWithOutline(double nextX, double nextY) {
202+
return false;
203+
}
204+
205+
private boolean collideWithPins(double nextX, double nextY) {
206+
for (Circle pin : pins) {
207+
if (pin.contains(nextX, nextY + ballRadius)) {
208+
return true;
209+
}
210+
}
211+
return false;
212+
}
213+
214+
private double getRandomX(double currentX) {
215+
double random = Math.random();
216+
if (random < 0.5) {
217+
currentX -= 1;
218+
} else {
219+
currentX += 1;
220+
}
221+
return currentX;
222+
}
223+
224+
225+
}
226+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /