用java写
时间: 2023-12-30 15:05:16 浏览: 54
好的,以下是一个可能的Java实现,用到了JavaFX图形库:
```java
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioClip;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BalloonPop extends Application {
private static final int WINDOW_WIDTH = 500;
private static final int WINDOW_HEIGHT = 500;
private static final int BALLOON_MIN_RADIUS = 20;
private static final int BALLOON_MAX_RADIUS = 40;
private static final double MIN_TIME_BETWEEN_BALLOONS = 0.0;
private static final double MAX_TIME_BETWEEN_BALLOONS = 2.0;
private static final double BALLOON_SPEED_FACTOR = 50.0;
private static final double POP_ANIMATION_DURATION = 0.2;
private static final int GREEN_BALLOON_SCORE = 10;
private static final int RED_BALLOON_SCORE = -50;
private static final int MISSED_BALLOON_SCORE = -10;
private static final int INITIAL_SCORE = 100;
private static final String POP_SOUND_FILE = "pop.wav";
private Canvas canvas;
private GraphicsContext gc;
private Label scoreLabel;
private Label timeLabel;
private Timeline timeline;
private Random random;
private List<Balloon> balloons;
private AudioClip popSound;
private boolean gameOver;
private double timeElapsed;
private int score;
@Override
public void start(Stage primaryStage) throws Exception {
canvas = new Canvas(WINDOW_WIDTH, WINDOW_HEIGHT);
gc = canvas.getGraphicsContext2D();
scoreLabel = new Label("Score: " + INITIAL_SCORE);
timeLabel = new Label("Time: 0.00s");
BorderPane root = new BorderPane();
root.setCenter(canvas);
root.setTop(new StackPane(scoreLabel));
root.setBottom(new StackPane(timeLabel));
BorderPane.setMargin(canvas, new Insets(10));
BorderPane.setMargin(scoreLabel, new Insets(10));
BorderPane.setMargin(timeLabel, new Insets(10));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Balloon Pop");
primaryStage.setResizable(false);
primaryStage.show();
canvas.addEventHandler(MouseEvent.MOUSE_CLICKED, this::handleMouseClick);
random = new Random();
balloons = new ArrayList<>();
popSound = new AudioClip(getClass().getResource(POP_SOUND_FILE).toExternalForm());
timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.getKeyFrames().add(new KeyFrame(Duration.millis(16), this::update));
timeline.play();
}
private void handleMouseClick(MouseEvent event) {
if (gameOver) {
return;
}
Point2D clickPos = new Point2D(event.getX(), event.getY());
List<Balloon> poppedBalloons = new ArrayList<>();
for (Balloon balloon : balloons) {
if (balloon.contains(clickPos)) {
balloon.pop();
poppedBalloons.add(balloon);
popSound.play();
}
}
for (Balloon poppedBalloon : poppedBalloons) {
poppedBalloon.popNeighbors();
}
updateScore();
}
private void update(ActionEvent event) {
if (gameOver) {
return;
}
double timeBetweenBalloons = random.nextDouble() * (MAX_TIME_BETWEEN_BALLOONS - MIN_TIME_BETWEEN_BALLOONS) + MIN_TIME_BETWEEN_BALLOONS;
double speed = timeElapsed / 10.0 + 1.0;
double yVelocity = random.nextDouble() * BALLOON_SPEED_FACTOR + speed * BALLOON_SPEED_FACTOR;
if (random.nextDouble() < 0.5) {
balloons.add(new Balloon(random.nextDouble() * (WINDOW_WIDTH - 2 * BALLOON_MAX_RADIUS) + BALLOON_MAX_RADIUS, -BALLOON_MAX_RADIUS, random.nextInt(BALLOON_MAX_RADIUS - BALLOON_MIN_RADIUS + 1) + BALLOON_MIN_RADIUS, Color.GREEN, yVelocity, timeBetweenBalloons));
} else {
balloons.add(new Balloon(random.nextDouble() * (WINDOW_WIDTH - 2 * BALLOON_MAX_RADIUS) + BALLOON_MAX_RADIUS, -BALLOON_MAX_RADIUS, random.nextInt(BALLOON_MAX_RADIUS - BALLOON_MIN_RADIUS + 1) + BALLOON_MIN_RADIUS, Color.RED, yVelocity, timeBetweenBalloons));
}
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
for (Balloon balloon : balloons) {
balloon.update();
balloon.draw(gc);
}
timeElapsed += 0.016;
updateTimeLabel();
updateScore();
checkGameOver();
}
private void updateTimeLabel() {
timeLabel.setText(String.format("Time: %.2fs", timeElapsed));
}
private void updateScore() {
int oldScore = score;
score = INITIAL_SCORE;
for (Balloon balloon : balloons) {
if (balloon.getY() + balloon.getRadius() >= WINDOW_HEIGHT) {
if (balloon.getColor() == Color.GREEN) {
score += MISSED_BALLOON_SCORE;
}
} else if (balloon.isPopped()) {
if (balloon.getColor() == Color.GREEN) {
score += GREEN_BALLOON_SCORE;
} else {
score += RED_BALLOON_SCORE;
}
} else {
score += MISSED_BALLOON_SCORE;
}
}
if (score < 0) {
score = 0;
}
if (score != oldScore) {
scoreLabel.setText("Score: " + score);
}
}
private void checkGameOver() {
if (!gameOver && score == 0) {
gameOver = true;
timeLabel.setText("GAME OVER! Press Space to Restart");
canvas.addEventHandler(MouseEvent.MOUSE_CLICKED, this::handleRestartClick);
}
}
private void handleRestartClick(MouseEvent event) {
if (event.getEventType() == MouseEvent.MOUSE_CLICKED && event.getButton().name().equals("PRIMARY")) {
canvas.removeEventHandler(MouseEvent.MOUSE_CLICKED, this::handleRestartClick);
restart();
}
}
private void restart() {
balloons.clear();
score = INITIAL_SCORE;
scoreLabel.setText("Score: " + score);
timeElapsed = 0;
timeLabel.setText("Time: 0.00s");
gameOver = false;
}
private static class Balloon extends Circle {
private final double yVelocity;
private final double timeBetweenBalloons;
private double timeSinceLastBalloon;
private boolean popped;
private List<Balloon> neighbors;
public Balloon(double centerX, double centerY, double radius, Color color, double yVelocity, double timeBetweenBalloons) {
super(centerX, centerY, radius, color);
this.yVelocity = yVelocity;
this.timeBetweenBalloons = timeBetweenBalloons;
timeSinceLastBalloon = 0;
popped = false;
neighbors = new ArrayList<>();
}
public void update() {
setCenterY(getCenterY() + yVelocity * 0.016);
timeSinceLastBalloon += 0.016;
if (timeSinceLastBalloon >= timeBetweenBalloons) {
timeSinceLastBalloon = 0;
double x = random.nextDouble() * getWidth() + getMinX();
double y = getCenterY() + getRadius() * 2;
if (random.nextDouble() < 0.5) {
neighbors.add(new Balloon(x, y, random.nextInt(BALLOON_MAX_RADIUS - BALLOON_MIN_RADIUS + 1) + BALLOON_MIN_RADIUS, Color.GREEN, yVelocity, timeBetweenBalloons));
} else {
neighbors.add(new Balloon(x, y, random.nextInt(BALLOON_MAX_RADIUS - BALLOON_MIN_RADIUS + 1) + BALLOON_MIN_RADIUS, Color.RED, yVelocity, timeBetweenBalloons));
}
}
}
public void draw(GraphicsContext gc) {
if (!popped) {
gc.setFill(getColor());
gc.fillOval(getCenterX() - getRadius(), getCenterY() - getRadius(), getRadius() * 2, getRadius() * 2);
}
}
public void pop() {
if (!popped) {
popped = true;
}
}
public void popNeighbors() {
if (neighbors.isEmpty()) {
return;
}
List<Balloon> poppedBalloons = new ArrayList<>();
for (Balloon neighbor : neighbors) {
if (!neighbor.isPopped() && intersects(neighbor.getBoundsInLocal())) {
neighbor.pop();
poppedBalloons.add(neighbor);
}
}
for (Balloon poppedBalloon : poppedBalloons) {
poppedBalloon.popNeighbors();
}
}
public boolean isPopped() {
return popped;
}
}
public static void main(String[] args) {
launch(args);
}
}
```
这个实现使用了JavaFX的Canvas和Timeline来实现动画效果,处理鼠标事件来响应玩家的点击操作。具体实现细节请查看注释。
阅读全文