Initial commit, for 2024/2025 students
This commit is contained in:
parent
59e5da3dd5
commit
7ceadb7ebd
65
pom.xml
Normal file
65
pom.xml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>de.techfak</groupId>
|
||||||
|
<artifactId>Part14</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.0</version>
|
||||||
|
<name>Part14</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<javafx.version>21.0.2</javafx.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- JavaFX dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-controls</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-base</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-graphics</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-media</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>${basedir}/src</sourceDirectory>
|
||||||
|
<plugins>
|
||||||
|
<!-- Compiler plugin -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
369
src/asteroids/AsteroidsApplication.java
Normal file
369
src/asteroids/AsteroidsApplication.java
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
package asteroids;
|
||||||
|
|
||||||
|
import javafx.animation.AnimationTimer;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.scene.shape.Shape;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class AsteroidsApplication extends Application {
|
||||||
|
public static final int WIDTH = 800;
|
||||||
|
public static final int HEIGHT = 600;
|
||||||
|
private GameController controller;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage stage) {
|
||||||
|
GameView view = new GameView();
|
||||||
|
GameModel model = new GameModel(); // Initialize GameModel with no controller
|
||||||
|
controller = new GameController(view, model); // Pass the model to the controller
|
||||||
|
|
||||||
|
model.setController(controller); // Set the controller in the model after initialization
|
||||||
|
controller.startGameLoop(); // Start the game loop after everything is initialized
|
||||||
|
|
||||||
|
stage.setTitle("Asteroids!");
|
||||||
|
stage.setScene(view.getScene());
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch(AsteroidsApplication.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameModel {
|
||||||
|
private final List<Asteroid> asteroids = new ArrayList<>();
|
||||||
|
private final List<Projectile> projectiles = new ArrayList<>();
|
||||||
|
private final Ship ship;
|
||||||
|
private final AtomicInteger points = new AtomicInteger();
|
||||||
|
private boolean isGameOver = false; // Game Over state
|
||||||
|
private GameController controller; // Reference to the controller
|
||||||
|
|
||||||
|
public GameModel() {
|
||||||
|
ship = new Ship(AsteroidsApplication.WIDTH / 2, AsteroidsApplication.HEIGHT / 2);
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
asteroids.add(new Asteroid(new Random().nextInt(AsteroidsApplication.WIDTH / 3), new Random().nextInt(AsteroidsApplication.HEIGHT)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter for controller
|
||||||
|
public void setController(GameController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ship getShip() { return ship; }
|
||||||
|
public List<Asteroid> getAsteroids() { return asteroids; }
|
||||||
|
public List<Projectile> getProjectiles() { return projectiles; }
|
||||||
|
public AtomicInteger getPoints() { return points; }
|
||||||
|
public boolean isGameOver() { return isGameOver; }
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
if (isGameOver) return; // Stop updates when game over
|
||||||
|
|
||||||
|
ship.move();
|
||||||
|
asteroids.forEach(Asteroid::move);
|
||||||
|
projectiles.forEach(Projectile::move);
|
||||||
|
|
||||||
|
checkCollisions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCollisions() {
|
||||||
|
List<Projectile> toRemoveProjectiles = new ArrayList<>();
|
||||||
|
List<Asteroid> toRemoveAsteroids = new ArrayList<>();
|
||||||
|
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
for (Projectile projectile : projectiles) {
|
||||||
|
if (currentTime - projectile.getSpawnTime() > 200 && projectile.collide(ship)) {
|
||||||
|
gameOver();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Asteroid asteroid : asteroids) {
|
||||||
|
if (projectile.collide(asteroid)) {
|
||||||
|
toRemoveProjectiles.add(projectile);
|
||||||
|
toRemoveAsteroids.add(asteroid);
|
||||||
|
points.addAndGet(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Asteroid asteroid : asteroids) {
|
||||||
|
if (asteroid.collide(ship)) {
|
||||||
|
gameOver();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the view in the controller
|
||||||
|
toRemoveAsteroids.forEach(asteroid -> asteroids.remove(asteroid));
|
||||||
|
toRemoveProjectiles.forEach(projectile -> projectiles.remove(projectile));
|
||||||
|
|
||||||
|
if (!toRemoveAsteroids.isEmpty() || !toRemoveProjectiles.isEmpty()) {
|
||||||
|
controller.updateViewAfterCollisions(toRemoveAsteroids, toRemoveProjectiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void gameOver() {
|
||||||
|
isGameOver = true; // End the game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GameView {
|
||||||
|
private final Pane pane;
|
||||||
|
private final Text scoreText;
|
||||||
|
private final Scene scene;
|
||||||
|
private final Text gameOverText;
|
||||||
|
|
||||||
|
public GameView() {
|
||||||
|
pane = new Pane();
|
||||||
|
pane.setPrefSize(AsteroidsApplication.WIDTH, AsteroidsApplication.HEIGHT);
|
||||||
|
|
||||||
|
scoreText = new Text(10, 20, "Points: 0");
|
||||||
|
pane.getChildren().add(scoreText);
|
||||||
|
|
||||||
|
gameOverText = new Text(AsteroidsApplication.WIDTH / 2 - 50, AsteroidsApplication.HEIGHT / 2, "Game Over!");
|
||||||
|
gameOverText.setVisible(false);
|
||||||
|
pane.getChildren().add(gameOverText);
|
||||||
|
|
||||||
|
scene = new Scene(pane);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scene getScene() { return scene; }
|
||||||
|
public Pane getPane() { return pane; }
|
||||||
|
public Text getScoreText() { return scoreText; }
|
||||||
|
|
||||||
|
public void addGameObject(Character obj) {
|
||||||
|
pane.getChildren().add(obj.getCharacter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeGameObject(Character obj) {
|
||||||
|
pane.getChildren().remove(obj.getCharacter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameOverVisible(boolean visible) {
|
||||||
|
gameOverText.setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameController {
|
||||||
|
private final GameView view;
|
||||||
|
private final GameModel model;
|
||||||
|
private final Map<KeyCode, Boolean> pressedKeys = new HashMap<>();
|
||||||
|
private AnimationTimer gameLoop;
|
||||||
|
private long lastShotTime = 0;
|
||||||
|
|
||||||
|
public GameController(GameView view, GameModel model) {
|
||||||
|
this.view = view;
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
view.addGameObject(model.getShip());
|
||||||
|
model.getAsteroids().forEach(view::addGameObject);
|
||||||
|
|
||||||
|
view.getScene().setOnKeyPressed(event -> pressedKeys.put(event.getCode(), true));
|
||||||
|
view.getScene().setOnKeyReleased(event -> pressedKeys.put(event.getCode(), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startGameLoop() {
|
||||||
|
gameLoop = new AnimationTimer() {
|
||||||
|
@Override
|
||||||
|
public void handle(long now) {
|
||||||
|
if (model.isGameOver()) {
|
||||||
|
gameLoop.stop();
|
||||||
|
view.setGameOverVisible(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputs();
|
||||||
|
spawnAsteroids();
|
||||||
|
model.update();
|
||||||
|
updateView();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gameLoop.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleInputs() {
|
||||||
|
if (model.isGameOver()) return;
|
||||||
|
|
||||||
|
if (pressedKeys.getOrDefault(KeyCode.LEFT, false)) model.getShip().turnLeft();
|
||||||
|
if (pressedKeys.getOrDefault(KeyCode.RIGHT, false)) model.getShip().turnRight();
|
||||||
|
if (pressedKeys.getOrDefault(KeyCode.UP, false)) model.getShip().accelerate();
|
||||||
|
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (pressedKeys.getOrDefault(KeyCode.SPACE, false) && model.getProjectiles().size() < 3
|
||||||
|
&& currentTime - lastShotTime > 200) {
|
||||||
|
lastShotTime = currentTime;
|
||||||
|
double shipAngle = Math.toRadians(model.getShip().getCharacter().getRotate());
|
||||||
|
double spawnX = model.getShip().getX() + Math.cos(shipAngle) * 15;
|
||||||
|
double spawnY = model.getShip().getY() + Math.sin(shipAngle) * 15;
|
||||||
|
|
||||||
|
Projectile projectile = new Projectile(spawnX, spawnY, System.currentTimeMillis());
|
||||||
|
projectile.getCharacter().setRotate(model.getShip().getCharacter().getRotate());
|
||||||
|
model.getProjectiles().add(projectile);
|
||||||
|
projectile.accelerate();
|
||||||
|
|
||||||
|
view.addGameObject(projectile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnAsteroids() {
|
||||||
|
if (Math.random() < 0.005) {
|
||||||
|
Asteroid asteroid = new Asteroid(Math.random() * AsteroidsApplication.WIDTH, 0);
|
||||||
|
if (!asteroid.collide(model.getShip())) {
|
||||||
|
model.getAsteroids().add(asteroid);
|
||||||
|
view.addGameObject(asteroid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateView() {
|
||||||
|
view.getScoreText().setText("Points: " + model.getPoints().get());
|
||||||
|
|
||||||
|
List<Projectile> toRemove = new ArrayList<>();
|
||||||
|
for (Projectile projectile : model.getProjectiles()) {
|
||||||
|
if (projectile.getX() < 0 || projectile.getX() > AsteroidsApplication.WIDTH ||
|
||||||
|
projectile.getY() < 0 || projectile.getY() > AsteroidsApplication.HEIGHT) {
|
||||||
|
toRemove.add(projectile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toRemove.forEach(projectile -> {
|
||||||
|
model.getProjectiles().remove(projectile);
|
||||||
|
view.removeGameObject(projectile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateViewAfterCollisions(List<Asteroid> removedAsteroids, List<Projectile> removedProjectiles) {
|
||||||
|
// Handle view updates here
|
||||||
|
removedAsteroids.forEach(asteroid -> view.removeGameObject(asteroid));
|
||||||
|
removedProjectiles.forEach(projectile -> view.removeGameObject(projectile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Character {
|
||||||
|
protected final Polygon character;
|
||||||
|
protected double x, y, velocityX, velocityY;
|
||||||
|
|
||||||
|
public Character(Polygon shape, double x, double y) {
|
||||||
|
this.character = shape;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.velocityX = 0;
|
||||||
|
this.velocityY = 0;
|
||||||
|
this.character.setTranslateX(x);
|
||||||
|
this.character.setTranslateY(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move() {
|
||||||
|
x += velocityX;
|
||||||
|
y += velocityY;
|
||||||
|
|
||||||
|
// Wrap around screen horizontally
|
||||||
|
if (x < 0) x += AsteroidsApplication.WIDTH;
|
||||||
|
if (x > AsteroidsApplication.WIDTH) x -= AsteroidsApplication.WIDTH;
|
||||||
|
|
||||||
|
// Wrap around screen vertically
|
||||||
|
if (y < 0) y += AsteroidsApplication.HEIGHT;
|
||||||
|
if (y > AsteroidsApplication.HEIGHT) y -= AsteroidsApplication.HEIGHT;
|
||||||
|
|
||||||
|
character.setTranslateX(x);
|
||||||
|
character.setTranslateY(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean collide(Character other) {
|
||||||
|
Shape collisionArea = Shape.intersect(this.character, other.getCharacter());
|
||||||
|
return !collisionArea.getBoundsInLocal().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Polygon getCharacter() {
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
public void setX(double x) {
|
||||||
|
this.x = x;
|
||||||
|
character.setTranslateX(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(double y) {
|
||||||
|
this.y = y;
|
||||||
|
character.setTranslateY(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Ship extends Character {
|
||||||
|
public Ship(double x, double y) {
|
||||||
|
super(new Polygon(-10, -10, 20, 0, -10, 10), x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void turnLeft() {
|
||||||
|
character.setRotate(character.getRotate() - 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void turnRight() {
|
||||||
|
character.setRotate(character.getRotate() + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accelerate() {
|
||||||
|
double angle = Math.toRadians(character.getRotate());
|
||||||
|
velocityX += Math.cos(angle) * 0.1;
|
||||||
|
velocityY += Math.sin(angle) * 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Asteroid extends Character {
|
||||||
|
public Asteroid(double x, double y) {
|
||||||
|
super(new PolygonFactory().createPolygon(), x, y);
|
||||||
|
Random rnd = new Random();
|
||||||
|
velocityX = rnd.nextDouble() - 0.5;
|
||||||
|
velocityY = rnd.nextDouble() - 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Projectile extends Character {
|
||||||
|
private final long spawnTime; // Track when the projectile was created
|
||||||
|
|
||||||
|
public Projectile(double x, double y, long spawnTime) {
|
||||||
|
super(new Polygon(2, -2, 2, 2, -2, 2, -2, -2), x, y);
|
||||||
|
this.spawnTime = spawnTime; // Store the spawn time
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accelerate() {
|
||||||
|
double angle = Math.toRadians(character.getRotate());
|
||||||
|
velocityX = Math.cos(angle) * 3;
|
||||||
|
velocityY = Math.sin(angle) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSpawnTime() {
|
||||||
|
return spawnTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PolygonFactory {
|
||||||
|
public Polygon createPolygon() {
|
||||||
|
Random rnd = new Random();
|
||||||
|
double size = 10 + rnd.nextInt(10);
|
||||||
|
Polygon polygon = new Polygon();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
double angle = 2 * Math.PI * i / 5;
|
||||||
|
polygon.getPoints().addAll(size * Math.cos(angle), size * Math.sin(angle));
|
||||||
|
}
|
||||||
|
return polygon;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user