I have a very simple program where you can use your W, A, S, D and space keys to shoot. All of the shooting and moving animations work, but I'm not exactly sure how I'd implement a system in which the program is constantly checking if the bullets have touched a node, such as a circle.
I was thinking I could have an ArrayList
to store all the bullets and then use a TimerTask
to check if the bullets have touched a node; but I feel like that would slow down the program, and also the bullet could pass them in the time the TimerTask
is waiting to go again.
Any suggestions would help.
Code: Pastebin
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.animation.*;
import javafx.util.Duration;
public class functionalShooter extends Application {
private String currentDirection = "W";
public static void main(String[] args){ launch(args); }
@Override public void start(Stage stage) throws Exception{
Pane root = new Pane();
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
Circle player = new Circle(10);
player.setLayoutX(300);
player.setLayoutY(200);
Circle other = new Circle(100, 100, 10);
root.getChildren().addAll(player, other);
//key events
scene.setOnKeyPressed(event -> {
switch(event.getCode()){
case A:
player.setLayoutX(player.getLayoutX()-10);
currentDirection = "A";
break;
case D:
player.setLayoutX(player.getLayoutX()+10);
currentDirection = "D";
break;
case W:
player.setLayoutY(player.getLayoutY()-10);
currentDirection = "W";
break;
case S:
player.setLayoutY(player.getLayoutY()+10);
currentDirection = "S";
break;
case SPACE:
if (currentDirection.equals("D")){
Circle newCircle = new Circle(player.getLayoutX()+10, player.getLayoutY(), 5);
root.getChildren().add(newCircle);
shoot(newCircle);
}
else if (currentDirection.equals("A")){
Circle newCircle = new Circle(player.getLayoutX()-10, player.getLayoutY(), 5);
root.getChildren().add(newCircle);
shoot(newCircle);
}
else if (currentDirection.equals("S")){
Circle newCircle = new Circle(player.getLayoutX(), player.getLayoutY()+10, 5);
root.getChildren().add(newCircle);
shoot(newCircle);
}
else {
Circle newCircle = new Circle(player.getLayoutX(), player.getLayoutY()-10, 5);
root.getChildren().add(newCircle);
shoot(newCircle);
}
break;
}
});
}
private void shoot(Circle bullet){
Timeline timeline = new Timeline();
if (currentDirection.equals("D")){
KeyValue start = new KeyValue(bullet.translateXProperty(), 0);
KeyValue end = new KeyValue(bullet.translateXProperty(), 800);
KeyFrame startF = new KeyFrame(Duration.ZERO, start);
KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
timeline.getKeyFrames().addAll(startF, endF);
}
else if (currentDirection.equals("A")){
KeyValue start = new KeyValue(bullet.translateXProperty(), 0);
KeyValue end = new KeyValue(bullet.translateXProperty(), -800);
KeyFrame startF = new KeyFrame(Duration.ZERO, start);
KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
timeline.getKeyFrames().addAll(startF, endF);
}
else if (currentDirection.equals("S")){
KeyValue start = new KeyValue(bullet.translateYProperty(), 0);
KeyValue end = new KeyValue(bullet.translateYProperty(), 800);
KeyFrame startF = new KeyFrame(Duration.ZERO, start);
KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
timeline.getKeyFrames().addAll(startF, endF);
}
else{
KeyValue start = new KeyValue(bullet.translateYProperty(), 0);
KeyValue end = new KeyValue(bullet.translateYProperty(), -800);
KeyFrame startF = new KeyFrame(Duration.ZERO, start);
KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
timeline.getKeyFrames().addAll(startF, endF);
}
timeline.setAutoReverse(false);
timeline.setCycleCount(1);
timeline.play();
}
}
What you need is something that will check for collision every time you draw a frame in your game. A timer would run in a separate thread which could work, but would be much harder to synchronize with the game.
In general, when you must "constantly observe" something in an OO language, the best solution is to use the Observer pattern.
You can check if the
bullet
intersectsother
usingShape.intersect()
in a customInterpolator
supplied to each relevantKeyValue
. The fragment below adds anInterpolator
toshoot()
, but you'll need an identical one for each direction. The implementation is linear, simply returningt
unchanged, but you might also look at this parabolic interpolator. I also madeother
a class variable, accessible toshoot()
. I put a dozen bullets into the air with no perceptible delay. Note that you don't need astart
value: "one will be synthesized using the target values that are current at the time" the animation is played.