-
Notifications
You must be signed in to change notification settings - Fork 0
5 difficulty levels added for issue #96 #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@coderabbitai full review |
✅ Actions performedFull review triggered. |
WalkthroughThis update introduces a difficulty management system to the project, including a new Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DinosaurMenu
participant GameSettings
participant GreenDinoComponent
participant Difficulty
User->>DinosaurMenu: Selects difficulty from combo box
DinosaurMenu->>GameSettings: setDifficultyLevel(level)
GameSettings->>Difficulty: Create new Difficulty instance
GreenDinoComponent->>GameSettings: getInstance()
GreenDinoComponent->>GameSettings: getDifficulty()
GameSettings->>Difficulty: Return Difficulty instance
GreenDinoComponent->>Difficulty: getSpeed()/getAngleOffset()
Difficulty-->>GreenDinoComponent: Returns speed/angle for game logic
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (5)
src/main/java/com/dinosaur/dinosaurexploder/model/Difficulty.java (1)
5-27
: Well-structured Difficulty class with room for improvement.The class effectively encapsulates difficulty parameters (speed and angle offsets) with clean getters. However, consider these improvements:
- Replace the assertion with a proper exception:
- assert max > min; + if (max <= min) { + throw new IllegalArgumentException("Maximum angle offset must be greater than minimum angle offset"); + }
- Add JavaDoc comments to document the class purpose and method behaviors:
+/** + * Encapsulates game difficulty parameters including movement speed and projectile angle range. + */ public class Difficulty { private final double speed; private final double minAngleOffset; private final double maxAngleOffset; private final Random random = new Random(); + /** + * Creates a difficulty configuration with specified parameters. + * + * @param speed The movement speed for this difficulty + * @param min The minimum angle offset for projectiles in degrees + * @param max The maximum angle offset for projectiles in degrees + * @throws IllegalArgumentException if max is not greater than min + */ public Difficulty(double speed, double min, double max) {src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java (1)
59-68
: Add missing getter for difficultyLevel.The class has a getter for
difficulty
but is missing a getter fordifficultyLevel
.public Difficulty getDifficulty() { return difficulty; } + public int getDifficultyLevel() { + return difficultyLevel; + } + public void setDifficultyLevel(int level) { this.difficultyLevel = level; difficulty = createDifficulty(); }src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java (3)
100-103
: Avoid hard‑coding image path – reuse a constantThe texture path is duplicated here while similar paths live in
GameConstants
.
This increases the risk of typos or future drift.-ImageView imageView = createImageView("assets/textures/dinomenu.png", 300, 400); +ImageView imageView = createImageView(GameConstants.GREENDINO_IMAGEPATH /* or introduce DINOMENU constant */, 300, 400);Consider adding a
DINOMENU_IMAGEPATH
constant toGameConstants
and referencing it to keep all resource paths in one place.
117-118
: Stop menu music when quitting to release audio resources cleanlyExiting the application without stopping the media player can keep native audio handles open on some platforms.
-quitButton.setOnAction(event -> fireExit()); +quitButton.setOnAction(event -> { + mainMenuSound.stop(); + fireExit(); +});Minor, but prevents potential “application still using audio device” warnings.
126-140
: Improve image loading fallback & error signallingReturning a blank
ImageView
on anyIOException
hides the root cause and leaves an empty UI element that might go unnoticed.} catch (IOException e) { - e.printStackTrace(); - return new ImageView(); + // Log once through FXGL’s logger, then propagate as unchecked to fail fast. + FXGL.getLogger(getClass()).error("Failed to load resource: {}", path, e); + throw new UncheckedIOException(e); }Fail‑fast behavior surfaces broken resource packaging during development instead of silently degrading in production.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.idea/misc.xml
(1 hunks)src/main/java/com/dinosaur/dinosaurexploder/model/Difficulty.java
(1 hunks)src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java
(1 hunks)src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java
(3 hunks)src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java
(1 hunks)src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java (1)
src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java (1)
GameSettings
(3-69)
src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java (2)
src/main/java/com/dinosaur/dinosaurexploder/model/GameSettings.java (1)
GameSettings
(3-69)src/main/java/com/dinosaur/dinosaurexploder/model/GameConstants.java (1)
GameConstants
(11-44)
🔇 Additional comments (2)
src/main/java/com/dinosaur/dinosaurexploder/model/LifeComponent.java (1)
42-42
: Corrected comment typo for clarity.Updating “eachother” to “each other” improves readability and maintains professional code comments.
.idea/misc.xml (1)
11-11
: Check Java language level configuration.The
languageLevel
attribute has been changed to "JDK_X", which appears to be a placeholder rather than a valid Java version. Meanwhile, the project JDK name is still set to "19". This inconsistency might cause compilation or IDE configuration issues.If this was an intentional change to make the project more portable, consider using a more standard approach such as setting the language level to match the project JDK or using a specific version like "JDK_19".
public class GameSettings { | ||
// Declare private static instance of the class | ||
private static GameSettings instance; | ||
|
||
// Global variables | ||
private int difficultyLevel; | ||
private Difficulty difficulty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Singleton implementation lacks thread safety.
The singleton pattern is implemented properly for single-threaded scenarios, but lacks thread safety for multi-threaded environments.
Consider using the initialization-on-demand holder idiom for thread-safe lazy initialization:
public class GameSettings {
- // Declare private static instance of the class
- private static GameSettings instance;
+ // Private static holder class for lazy initialization
+ private static class InstanceHolder {
+ private static final GameSettings INSTANCE = new GameSettings();
+ }
// Global variables
private int difficultyLevel;
private Difficulty difficulty;
Then update the getInstance()
method:
// Public static method to provide access to the instance
public static GameSettings getInstance() {
- if (instance == null) {
- instance = new GameSettings();
- }
- return instance;
+ return InstanceHolder.INSTANCE;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
public class GameSettings { | |
// Declare private static instance of the class | |
private static GameSettings instance; | |
// Global variables | |
private int difficultyLevel; | |
private Difficulty difficulty; | |
public class GameSettings { | |
// Private static holder class for lazy initialization | |
private static class InstanceHolder { | |
private static final GameSettings INSTANCE = new GameSettings(); | |
} | |
// Global variables | |
private int difficultyLevel; | |
private Difficulty difficulty; | |
// Public static method to provide access to the instance | |
public static GameSettings getInstance() { | |
return InstanceHolder.INSTANCE; | |
} | |
// ... other methods ... | |
} |
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add input validation and improve difficulty configurations.
The createDifficulty()
method handles unknown difficulty levels with an exception, but the input is not validated in the setter.
- Add validation in
setDifficultyLevel
:
public void setDifficultyLevel(int level) {
+ if (level < 1 || level > 5) {
+ throw new IllegalArgumentException("Difficulty level must be between 1 and 5");
+ }
this.difficultyLevel = level;
difficulty = createDifficulty();
}
- Consider using constants for difficulty parameters to improve readability:
+ // Difficulty constants
+ private static final double[] DIFFICULTY_SPEEDS = {1.0, 2.0, 2.5, 2.5, 3.0};
+ private static final double[] MIN_ANGLE_OFFSETS = {90, 90, 90, 22.5, 45};
+ private static final double[] MAX_ANGLE_OFFSETS = {90, 90, 90, 112.5, 135};
+
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!");
+ if (difficultyLevel < 1 || difficultyLevel > 5) {
+ throw new IllegalArgumentException("Unknown difficulty level!");
}
- return new Difficulty(speed, min, max);
+ int index = difficultyLevel - 1;
+ return new Difficulty(
+ DIFFICULTY_SPEEDS[index],
+ MIN_ANGLE_OFFSETS[index],
+ MAX_ANGLE_OFFSETS[index]
+ );
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
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 void setDifficultyLevel(int level) { | |
if (level < 1 || level > 5) { | |
throw new IllegalArgumentException("Difficulty level must be between 1 and 5"); | |
} | |
this.difficultyLevel = level; | |
difficulty = createDifficulty(); | |
} | |
// Difficulty constants | |
private static final double[] DIFFICULTY_SPEEDS = {1.0, 2.0, 2.5, 2.5, 3.0}; | |
private static final double[] MIN_ANGLE_OFFSETS = {90, 90, 90, 22.5, 45}; | |
private static final double[] MAX_ANGLE_OFFSETS = {90, 90, 90, 112.5, 135}; | |
private Difficulty createDifficulty() { | |
if (difficultyLevel < 1 || difficultyLevel > 5) { | |
throw new IllegalArgumentException("Unknown difficulty level!"); | |
} | |
int index = difficultyLevel - 1; | |
return new Difficulty( | |
DIFFICULTY_SPEEDS[index], | |
MIN_ANGLE_OFFSETS[index], | |
MAX_ANGLE_OFFSETS[index] | |
); | |
} |
public Difficulty difficulty = GameSettings.getInstance().getDifficulty(); | ||
private final LocalTimer timer = FXGL.newLocalTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Difficulty should be dynamically accessed, not stored.
The current implementation initializes the difficulty field only once, which means it won't reflect changes to the difficulty level during gameplay.
- public Difficulty difficulty = GameSettings.getInstance().getDifficulty();
+ // Don't store the difficulty directly, access it when needed
private final LocalTimer timer = FXGL.newLocalTimer();
Committable suggestion skipped: line range outside the PR's diff.
Vec2 direction = Vec2.fromAngle(entity.getRotation() + difficulty.getAngleOffset()); | ||
spawn("basicEnemyProjectile", | ||
new SpawnData(center.getX() + 50 +3, center.getY()) | ||
new SpawnData(center.getX(), center.getY()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Access current difficulty settings dynamically.
Similar to the issue with movement speed, the angle offset calculation should also dynamically access the current difficulty settings.
- Vec2 direction = Vec2.fromAngle(entity.getRotation() + difficulty.getAngleOffset());
+ Vec2 direction = Vec2.fromAngle(entity.getRotation() + GameSettings.getInstance().getDifficulty().getAngleOffset());
spawn("basicEnemyProjectile",
new SpawnData(center.getX(), center.getY())
The change to use entity's center position for spawning projectiles is a good improvement over the previous offset approach.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
Vec2 direction = Vec2.fromAngle(entity.getRotation() + difficulty.getAngleOffset()); | |
spawn("basicEnemyProjectile", | |
new SpawnData(center.getX() + 50 +3, center.getY()) | |
new SpawnData(center.getX(), center.getY()) | |
Vec2 direction = Vec2.fromAngle( | |
entity.getRotation() + GameSettings.getInstance().getDifficulty().getAngleOffset() | |
); | |
spawn("basicEnemyProjectile", | |
new SpawnData(center.getX(), center.getY()) |
@@ -24,7 +24,7 @@ public class GreenDinoComponent extends Component implements Dinosaur{ | |||
*/ | |||
@Override | |||
public void onUpdate(double ptf) { | |||
entity.translateY(verticalSpeed); | |||
entity.translateY(difficulty.getSpeed()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update to dynamically access difficulty settings.
Since the difficulty field is initialized only once and won't update when changed in GameSettings, you should directly access the current difficulty.
- entity.translateY(difficulty.getSpeed());
+ entity.translateY(GameSettings.getInstance().getDifficulty().getSpeed());
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
entity.translateY(difficulty.getSpeed()); | |
entity.translateY(GameSettings.getInstance().getDifficulty().getSpeed()); |
Media media = new Media(getClass().getResource(GameConstants.MAINMENU_SOUND).toExternalForm()); | ||
mainMenuSound = new MediaPlayer(media); | ||
mainMenuSound.play(); | ||
mainMenuSound.setCycleCount(MediaPlayer.INDEFINITE); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against missing audio resource to avoid NPE at startup
getResource()
may return null
if the WAV file is not on the runtime class‑path.
Attempting toExternalForm()
on a null
URL throws a NullPointerException
, which crashes the menu before it appears.
-Media media = new Media(getClass().getResource(GameConstants.MAINMENU_SOUND).toExternalForm());
+URL url = getClass().getResource(GameConstants.MAINMENU_SOUND);
+if (url == null) {
+ throw new IllegalStateException(
+ "Main‑menu sound not found on class‑path: " + GameConstants.MAINMENU_SOUND);
+}
+Media media = new Media(url.toExternalForm());
Fail fast with a descriptive exception (or log + fallback) so the problem can be diagnosed instead of surfacing as a generic NPE later.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
Media media = new Media(getClass().getResource(GameConstants.MAINMENU_SOUND).toExternalForm()); | |
mainMenuSound = new MediaPlayer(media); | |
mainMenuSound.play(); | |
mainMenuSound.setCycleCount(MediaPlayer.INDEFINITE); | |
URL url = getClass().getResource(GameConstants.MAINMENU_SOUND); | |
if (url == null) { | |
throw new IllegalStateException( | |
"Main‑menu sound not found on class‑path: " + GameConstants.MAINMENU_SOUND); | |
} | |
Media media = new Media(url.toExternalForm()); | |
mainMenuSound = new MediaPlayer(media); | |
mainMenuSound.play(); | |
mainMenuSound.setCycleCount(MediaPlayer.INDEFINITE); |
ComboBox<String> 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)); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace String
‑based ComboBox with typed values & drop debug print
The difficulty picker currently holds String
s, which forces an unnecessary Integer.parseInt()
and leaves room for runtime format errors.
A typed combo box eliminates parsing, and the System.out
debug line should be removed (or replaced with proper logging).
-ComboBox<String> difficultyBox = new ComboBox<>();
-difficultyBox.getItems().addAll("1", "2", "3", "4", "5");
-difficultyBox.setValue("1");
+ComboBox<Integer> difficultyBox = new ComboBox<>();
+difficultyBox.getItems().addAll(1, 2, 3, 4, 5);
+difficultyBox.setValue(1);
...
-difficultyBox.valueProperty().addListener((observable, oldValue, newValue) -> {
- System.out.println("Selected Difficulty: " + newValue);
- GameSettings.getInstance().setDifficultyLevel(Integer.parseInt(newValue));
+difficultyBox.valueProperty().addListener((obs, oldVal, newVal) ->
+ GameSettings.getInstance().setDifficultyLevel(newVal)
);
Benefits: type‑safety, one less parse, and a cleaner console.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
ComboBox<String> 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)); | |
}); | |
ComboBox<Integer> difficultyBox = new ComboBox<>(); | |
difficultyBox.getItems().addAll(1, 2, 3, 4, 5); | |
difficultyBox.setValue(1); | |
difficultyBox.valueProperty().addListener((obs, oldVal, newVal) -> | |
GameSettings.getInstance().setDifficultyLevel(newVal) | |
); |
👉 Checklist
✍ Description of the Pull Request
Difficulty.java
andGameSettings.java
addedGreenDinoComponent.java
andDinosaurMenu.java
modified🔗 Issue link
Summary by CodeRabbit
New Features
Improvements
Bug Fixes