(Racing cars) Rewrite Programming Exercise 15.29 using a thread to control car r
ID: 3777743 • Letter: #
Question
(Racing cars) Rewrite Programming Exercise 15.29 using a thread to control
car racing. Compare the program with Programming Exercise 15.29 by setting
the delay time to 10 in both programs. Which one runs the animation faster?
Here's the code from 15.29
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Exercise extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
CarPane carPane = new CarPane(600, 200);
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(10), e -> carPane.moveCar(1)));
timeline.setCycleCount(carPane.getOneCycleDuration());
timeline.play();
timeline.setOnFinished(e -> {
carPane.reset();
timeline.play();
});
// Buttons pause, resume, increase, decrease
Button pause = new Button("Pause");
pause.setOnAction(e -> timeline.pause());
Button resume = new Button("Resume");
resume.setOnAction(e -> timeline.play());
Button increase = new Button("Increase");
increase.setOnAction(e -> {
timeline.setRate(timeline.getCurrentRate() + 1);
});
Button decrease = new Button("Decrease");
decrease.setOnAction(e -> {
if (timeline.getCurrentRate() <= 0)
return;
timeline.setRate(timeline.getCurrentRate() - 1);
});
HBox hButtons = new HBox(pause, resume, increase, decrease);
hButtons.setSpacing(10);
hButtons.setAlignment(Pos.CENTER);
hButtons.setPadding(new Insets(5, 5, 5, 5));
BorderPane borderPane = new BorderPane(carPane, null, null, hButtons, null);
borderPane.setOnKeyPressed(e -> {
switch (e.getCode()) {
case UP:
increase.fire();
break;
case DOWN:
decrease.fire();
break;
}
});
primaryStage.setScene(new Scene(borderPane));
primaryStage.setTitle("Moving Car");
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
private class CarPane extends Pane {
private double w; // pane width
private double h; // pane height
// left Tire x,y and radius
private double leftTireX; // left tire is the car's drawing start point
private double leftTireY;
private double tireRadius;
Circle[] tires = new Circle[2]; // Index 0, 1 = left and right tire
Polyline cover = new Polyline();
ObservableList<Double> points;
Rectangle base;
private CarPane(double width, double height) {
// Get width height and measurements for the left tire (starting
// point)
w = width;
h = height;
leftTireX = w * 0.2;
leftTireY = h * 0.9;
tireRadius = h * 0.1;
// set MIN and MAX width
setMinWidth(w);
setMinHeight(h);
setMaxWidth(w);
setMaxHeight(h);
reset(); // draws and adjusts car to starting position
}
public void reset() {
if (points != null)
points.clear();
getChildren().clear();
drawCar();
moveCar(tireRadius * 13 * -1);
}
public void drawCar() {
for (int i = 0; i < tires.length; i++) {
tires[i] = new Circle(leftTireX + (i * 4 * tireRadius), leftTireY, tireRadius);
tires[i].setStroke(Color.BLACK);
tires[i].setFill(Color.TRANSPARENT);
}
double baseX = tires[0].getCenterX() - tires[0].getRadius() * 3;
double baseY = tires[0].getCenterY() - tires[0].getRadius() * 3;
base = new Rectangle(baseX, baseY, tireRadius * 10, tireRadius * 2);
base.setFill(Color.TRANSPARENT);
base.setStroke(Color.BLACK);
// draw the car's top cover
double startX = base.getX() + tireRadius * 2;
double startY = base.getY();
double currentX = startX;
double currentY = startY;
points = cover.getPoints();
double distance = tireRadius * 2;
points.addAll(currentX, currentY); // start point
currentX += distance;
currentY -= distance;
points.addAll(currentX, currentY); // up right
currentX += distance;
points.addAll(currentX, currentY); // right
currentX += distance;
currentY += distance;
points.addAll(currentX, currentY); // down right
points.addAll(startX, startY); // connect to starting point
cover.setFill(Color.BLUE);
getChildren().addAll(tires);
getChildren().add(base);
getChildren().add(cover);
}
private void moveCar(double distance) {
// tires
for (Circle c : tires) {
c.setCenterX(c.getCenterX() + distance);
}
base.setX(base.getX() + distance);
for (int i = 0; i < points.size(); i += 2) {
points.set(i, points.get(i) + distance);
}
}
public int getOneCycleDuration() {
return (int) w;
}
}
}
Explanation / Answer
RaceCars.java
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Line;
import javafx.scene.layout.Pane;
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
public class RaceCars extends Application{
/*public static void main(String[] args){
}*/
private int screenWidth = 800;
private int screenHeight = 400;
/*private double moveRate = 20;
private double position = 0;*/
@Override
public void start(Stage primaryStage){
Pane pane = new Pane();
Car raceCar = new Car();
//raceCar.reposition(moveRate);
pane.getChildren().add(raceCar.getBody());
pane.getChildren().add(raceCar.getWheel1());
pane.getChildren().add(raceCar.getWheel2());
pane.getChildren().add(raceCar.getCabin());
EventHandler<ActionEvent> eventHandler = e->{
pane.getChildren().clear();
//position += moveRate;
raceCar.reposition();
pane.getChildren().add(raceCar.getBody());
pane.getChildren().add(raceCar.getWheel1());
pane.getChildren().add(raceCar.getWheel2());
pane.getChildren().add(raceCar.getCabin());
};
Timeline animation = new Timeline(
new KeyFrame(Duration.millis(10), eventHandler));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play();
Scene scene = new Scene(pane, screenWidth, screenHeight);
primaryStage.setTitle("RaceCar");
primaryStage.setScene(scene);
primaryStage.show();
}
class Car{
private Polygon cabin = null;
private Rectangle body = null;
private double bodyHeight = 10;
private double bodyWidth = 50;
private Circle wheel1 = null;
private Circle wheel2 = null;
private double wheelRadius = 5;
private ObservableList<Double> list = null;
private double moveRate = 20;
private double position = 0;
//Create the car at the starting point
public Car(){
this.reset();
}
public Rectangle getBody(){
return body;
}
public Polygon getCabin(){
return cabin;
}
public Circle getWheel1(){return wheel1;}
public Circle getWheel2(){return wheel2;}
public void reposition(){
position += moveRate;
if(position + bodyWidth >= screenWidth){
this.reset();
}
else{
//Create the cabin
cabin = new Polygon();
list = cabin.getPoints();
double centerX = (bodyWidth / 2) + position, centerY = (screenHeight - 20);
double radius = Math.min(bodyWidth, bodyHeight) * 0.90;
for(int i = 0; i < 4; i++){
list.add(centerX + radius * Math.cos(2* i * Math.PI / 6));
list.add(centerY - radius * Math.sin(2 * i * Math.PI/6));
}
//Create the body
body = new Rectangle(position, screenHeight - 20, bodyWidth, bodyHeight);
//Create the wheels
wheel1 = new Circle((bodyWidth/4) + position, screenHeight - 5, 5);
wheel2 = new Circle((3*bodyWidth/4) + position, screenHeight - 5, 5);
}
}
//Reset the position of the car to the start
public void reset(){
position = 0;
this.reposition();
}
}
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.