diff --git a/.idea/misc.xml b/.idea/misc.xml
index dc377ec..44185bb 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -8,5 +8,5 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/Difficulty.java b/src/main/java/com/dinosaur/dinosaurexploder/model/Difficulty.java
new file mode 100644
index 0000000..6916c04
--- /dev/null
+++ b/src/main/java/com/dinosaur/dinosaurexploder/model/Difficulty.java
@@ -0,0 +1,27 @@
+package com.dinosaur.dinosaurexploder.model;
+
+import java.util.Random;
+
+public class Difficulty {
+ private final double speed;
+ private final double minAngleOffset;
+ private final double maxAngleOffset;
+ private final Random random = new Random();
+
+ public Difficulty(double speed, double min, double max) {
+ assert max > min;
+ this.speed = speed;
+ this.minAngleOffset = min;
+ this.maxAngleOffset = max;
+ }
+ public double getSpeed() {
+ return speed;
+ }
+
+ public double getAngleOffset() {
+ if (minAngleOffset == maxAngleOffset) {
+ return minAngleOffset;
+ }
+ return minAngleOffset + (maxAngleOffset - minAngleOffset) * random.nextDouble();
+ }
+}
diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java b/src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java
new file mode 100644
index 0000000..67bf8c9
--- /dev/null
+++ b/src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java
@@ -0,0 +1,69 @@
+package com.dinosaur.dinosaurexploder.model;
+
+public class GameSettings {
+ // Declare private static instance of the class
+ private static GameSettings instance;
+
+ // Global variables
+ private int difficultyLevel;
+ private Difficulty difficulty;
+
+ // Private constructor to prevent instantiation from other classes
+ private GameSettings() {
+ difficultyLevel = 1;
+ difficulty = createDifficulty();
+ }
+
+ private Difficulty createDifficulty() {
+ double speed, min, max;
+ switch (difficultyLevel) {
+ case 1:
+ speed = 1.0;
+ min = 90;
+ max = 90;
+ break;
+ case 2:
+ speed = 2.0;
+ min = 90;
+ max = 90;
+ break;
+ case 3:
+ speed = 2.5;
+ min = 90;
+ max = 90;
+ break;
+ case 4:
+ speed = 2.5;
+ min = 22.5;
+ max = 112.5;
+ break;
+ case 5:
+ speed = 3.0;
+ min = 45;
+ max = 135;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown difficulty level!");
+ }
+ return new Difficulty(speed, min, max);
+ }
+
+ // Public static method to provide access to the instance
+ public static GameSettings getInstance() {
+ if (instance == null) {
+ instance = new GameSettings();
+ }
+ return instance;
+ }
+
+ // Getters and setters for the global variables
+
+ public Difficulty getDifficulty() {
+ return difficulty;
+ }
+
+ public void setDifficultyLevel(int level) {
+ this.difficultyLevel = level;
+ difficulty = createDifficulty();
+ }
+}
diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java b/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java
index f644f51..f24450e 100644
--- a/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java
+++ b/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java
@@ -14,8 +14,8 @@
* This class extends Component and Implements the Dinosaur Classes and Handles the Shooting and Updating the Dino
*/
public class GreenDinoComponent extends Component implements Dinosaur{
- double verticalSpeed = 1.5;
- private LocalTimer timer = FXGL.newLocalTimer();
+ public Difficulty difficulty = GameSettings.getInstance().getDifficulty();
+ private final LocalTimer timer = FXGL.newLocalTimer();
/**
* Summary :
* This method runs for every frame like a continues flow , without any stop until we put stop to it.
@@ -24,7 +24,7 @@ public class GreenDinoComponent extends Component implements Dinosaur{
*/
@Override
public void onUpdate(double ptf) {
- entity.translateY(verticalSpeed);
+ entity.translateY(difficulty.getSpeed());
//The dinosaur shoots every 2 seconds
if (timer.elapsed(Duration.seconds(1.5)) && entity.getPosition().getY() > 0)
@@ -41,9 +41,9 @@ public void onUpdate(double ptf) {
public void shoot() {
FXGL.play(GameConstants.ENEMYSHOOT_SOUND);
Point2D center = entity.getCenter();
- Vec2 direction = Vec2.fromAngle(entity.getRotation() +90);
+ Vec2 direction = Vec2.fromAngle(entity.getRotation() + difficulty.getAngleOffset());
spawn("basicEnemyProjectile",
- new SpawnData(center.getX() + 50 +3, center.getY())
+ new SpawnData(center.getX(), center.getY())
.put("direction", direction.toPoint2D() )
);
}
diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java b/src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java
index 28016a1..4cf306c 100644
--- a/src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java
+++ b/src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java
@@ -39,7 +39,7 @@ public void onUpdate(double ptf)
lifeText.setFill(Color.RED);
lifeText.setFont(Font.font(GameConstants.ARCADECLASSIC_FONTNAME, 20));
- // Adjusting Hearts with respect to text and eachother
+ // Adjusting Hearts with respect to text and each other
test1.setLayoutY(10);
test2.setLayoutY(10);
test3.setLayoutY(10);
diff --git a/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java b/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java
index 8075ee3..0d929d5 100644
--- a/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java
+++ b/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java
@@ -4,164 +4,143 @@
import com.almasb.fxgl.app.scene.MenuType;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.scene.Scene;
-import com.almasb.fxgl.ui.FontType;
import com.dinosaur.dinosaurexploder.model.GameConstants;
+import com.dinosaur.dinosaurexploder.model.GameSettings;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
import javafx.scene.control.Button;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
-import java.io.InputStream;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.geometry.Pos;
-import javafx.scene.control.Label;
-import javafx.scene.control.Slider;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.layout.Region;
+
import java.io.FileNotFoundException;
-import java.util.Objects;
-import javafx.scene.layout.StackPane;
+import java.io.IOException;
+import java.io.InputStream;
public class DinosaurMenu extends FXGLMenu {
- private MediaPlayer mainMenuSound;
+ private final MediaPlayer mainMenuSound;
public DinosaurMenu() {
super(MenuType.MAIN_MENU);
+ // Initialize background music
Media media = new Media(getClass().getResource(GameConstants.MAINMENU_SOUND).toExternalForm());
mainMenuSound = new MediaPlayer(media);
mainMenuSound.play();
mainMenuSound.setCycleCount(MediaPlayer.INDEFINITE);
+ // Create the background
var bg = new Rectangle(getAppWidth(), getAppHeight(), Color.BLACK);
- var title = FXGL.getUIFactoryService().newText(GameConstants.GAME_NAME, Color.LIME, FontType.MONO, 35);
+ // Create buttons
var startButton = new Button("Start Game");
var quitButton = new Button("Quit");
+ // Create volume slider and label
Slider volumeSlider = new Slider(0, 1, 1);
volumeSlider.setBlockIncrement(0.01);
-
- volumeSlider.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/styles/styles.css")).toExternalForm());
-
- //Sets the volume label
Label volumeLabel = new Label("100%");
- volumeSlider.valueProperty().addListener(new ChangeListener() {
- @Override
- public void changed(ObservableValue extends Number> observable, Number oldValue, Number newValue) {
- mainMenuSound.setVolume(newValue.doubleValue());
- volumeLabel.setText(String.format("%.0f%%", newValue.doubleValue() * 100));
- }
+ volumeSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
+ mainMenuSound.setVolume(newValue.doubleValue());
+ volumeLabel.setText(String.format("%.0f%%", newValue.doubleValue() * 100));
});
+ ComboBox difficultyBox = new ComboBox<>();
+ difficultyBox.getItems().addAll("1", "2", "3", "4", "5");
+ difficultyBox.setValue("1");
- try {
-
- //Using InputStream for efficient fetching of images
- InputStream menuImage = getClass().getClassLoader().getResourceAsStream("assets/textures/dinomenu.png");
- if (menuImage == null) {
- throw new FileNotFoundException("Resource not found: assets/textures/dinomenu.png");
- }
- InputStream muteButton = getClass().getClassLoader().getResourceAsStream("assets/textures/silent.png");
- if (muteButton == null) {
- throw new FileNotFoundException("Resource not found: assets/textures/silent.png");
- }
- InputStream soundButton = getClass().getClassLoader().getResourceAsStream("assets/textures/playing.png");
- if (soundButton == null) {
- throw new FileNotFoundException("Resource not found: assets/textures/playing.png");
- }
-
- // image for dino in main menu
- Image image = new Image(menuImage);
- ImageView imageView = new ImageView(image);
- imageView.setFitHeight(250);
- imageView.setFitWidth(200);
- imageView.setX(200);
- imageView.setY(190);
- imageView.setPreserveRatio(true);
-
- //adding image to manually mute music
- Image mute = new Image(muteButton);
-
-
- Image audioOn = new Image(soundButton);
- ImageView imageViewPlaying = new ImageView(audioOn);
- imageViewPlaying.setFitHeight(50);
- imageViewPlaying.setFitWidth(60);
- imageViewPlaying.setX(470);
- imageViewPlaying.setY(20);
- imageViewPlaying.setPreserveRatio(true);
-
-
- startButton.setMinSize(50, 50);
- startButton.setPrefSize(140,60);
-
- quitButton.setMinSize(140, 60);
+ difficultyBox.valueProperty().addListener((observable, oldValue, newValue) -> {
+ System.out.println("Selected Difficulty: " + newValue);
+ GameSettings.getInstance().setDifficultyLevel(Integer.parseInt(newValue));
+ });
- title.setTranslateY(100);
- title.setTranslateX(getAppWidth() / 2 - 145);
+ // Set uniform size for buttons and dropdowns
+ startButton.setPrefSize(200, 50);
+ quitButton.setPrefSize(200, 50);
- startButton.setTranslateY(400);
- startButton.setTranslateX(getAppWidth() / 2 - 50);
- startButton.setStyle("-fx-font-size:20");
+ difficultyBox.setPrefSize(200, 50);
- quitButton.setTranslateY(500);
- quitButton.setTranslateX(getAppWidth() / 2 - 50);
- quitButton.setStyle("-fx-font-size:20");
+ startButton.setStyle("-fx-font-size: 18px;");
+ quitButton.setStyle("-fx-font-size: 18px;");
+ difficultyBox.setStyle("-fx-font-size: 18px;");
- BorderPane root = new BorderPane();
- root.setTop(title);
- BorderPane.setAlignment(title, Pos.CENTER);
+ // Set volume slider width
+ volumeSlider.setPrefWidth(150);
+ // Create root layout container
+ BorderPane root = new BorderPane();
+ root.setPrefSize(getAppWidth(), getAppHeight());
- BorderPane volumePane = new BorderPane();
- volumePane.setLeft(volumeLabel);
- BorderPane.setAlignment(volumeLabel, Pos.CENTER);
- volumePane.setCenter(volumeSlider);
- volumeSlider.setStyle("-fx-padding: 10px;");
- volumeSlider.setTranslateY(25);
- volumeSlider.setTranslateX(10);
- volumeLabel.setTranslateX(20);
- volumeLabel.setTranslateY(20);
- volumeLabel.setStyle("-fx-text-fill: #61C181;");
+ // Top layout for title, difficulty, and volume
+ VBox settingsBox = new VBox(10, new Label("Difficulty:"), difficultyBox);
+ settingsBox.setAlignment(Pos.TOP_LEFT);
+ settingsBox.setPadding(new Insets(10));
+ HBox volumeBox = new HBox(10, volumeLabel, volumeSlider);
+ volumeBox.setAlignment(Pos.TOP_RIGHT);
+ volumeBox.setPadding(new Insets(10));
+ BorderPane topPane = new BorderPane();
+ topPane.setLeft(settingsBox);
+ topPane.setRight(volumeBox);
- root.setCenter(volumePane);
- root.setBottom(new BorderPane(startButton, null, quitButton, null, null));
- BorderPane.setAlignment(startButton, Pos.CENTER);
- BorderPane.setAlignment(quitButton, Pos.BOTTOM_CENTER);
+ root.setTop(topPane);
+ // Center layout for dinosaur image
+ ImageView imageView = createImageView("assets/textures/dinomenu.png", 300, 400);
+ StackPane centerPane = new StackPane(imageView);
+ centerPane.setAlignment(Pos.CENTER);
+ root.setCenter(centerPane);
- startButton.setOnAction(event -> {
- fireNewGame();
- mainMenuSound.stop();
- });
+ // Bottom layout for buttons
+ VBox buttonBox = new VBox(20, startButton, quitButton);
+ buttonBox.setAlignment(Pos.CENTER);
+ buttonBox.setPadding(new Insets(10));
+ root.setBottom(buttonBox);
- imageViewPlaying.setOnMouseClicked(mouseEvent -> {
- if (mainMenuSound.isMute()){
- mainMenuSound.setMute(false); //False later
- imageViewPlaying.setImage(audioOn);
- } else {
- mainMenuSound.setMute(true);
- imageViewPlaying.setImage(mute);
- }
- });
+ // Set button actions
+ startButton.setOnAction(event -> {
+ fireNewGame();
+ mainMenuSound.stop();
+ });
- quitButton.setOnAction(event -> fireExit());
+ quitButton.setOnAction(event -> fireExit());
+ // Add everything to the scene
+ getContentRoot().getChildren().addAll(bg, root);
+ }
- getContentRoot().getChildren().addAll(
- bg, title, startButton, quitButton, imageView, imageViewPlaying, volumeLabel, volumeSlider
- );
- }
- catch (FileNotFoundException e){
- System.out.println("File not found" + e.getMessage());
+ /**
+ * Helper method to create an ImageView with specific width and height.
+ */
+ private ImageView createImageView(String path, double width, double height) {
+ try (InputStream stream = getClass().getClassLoader().getResourceAsStream(path)) {
+ if (stream == null) {
+ throw new FileNotFoundException("Resource not found: " + path);
+ }
+ Image image = new Image(stream);
+ ImageView imageView = new ImageView(image);
+ imageView.setFitWidth(width);
+ imageView.setFitHeight(height);
+ imageView.setPreserveRatio(true);
+ return imageView;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new ImageView();
}
}
+
+
@Override
public void onEnteredFrom(Scene prevState) {
super.onEnteredFrom(prevState);