Skip to content

feat: allow selecting difficulty in the gameplay menu - #1471

Merged
AlmasB merged 3 commits into
AlmasB:devfrom
jamesmosey:dev
Apr 10, 2026
Merged

feat: allow selecting difficulty in the gameplay menu#1471
AlmasB merged 3 commits into
AlmasB:devfrom
jamesmosey:dev

Conversation

@jamesmosey

Copy link
Copy Markdown
Contributor

Closes #1449

New menu for selecting difficulty in both the main menu and the in-game menu.
Added specific CSS styling to fix the issue of the difficulty choice-box not accepting the general style.
Updated MenuSample.java to showcase the new difficulty menu.
Uses existing gameDifficultyProperty from the ReadOnlyGameSettings class in settings.kt.

@AlmasB AlmasB left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, it looks good. Please can you take a look at the comments

difficultyBox.styleClass.add("fxgl-difficulty-choice-box")

difficultyBox.value = getSettings().gameDifficulty
getSettings().gameDifficultyProperty().bindBidirectional(difficultyBox.valueProperty())

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be the other way around? I'm thinking of a case where the user sets the difficulty in the main menu, then opens the game menu. At this point does the above mean the settings difficulty will rebound to the UI box's value property?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is in the correct order. For example, if the user sets the difficulty in the main menu, that will update getSettings().gameDifficulty. Then later, the game menu creates its own difficultyBox and executes difficultyBox.value = getSettings().gameDifficulty ->bindBidirectional(difficultyBox.valueProperty(), the box will show the same difficulty that was set in the main menu, any changes in either place after that will update the other.

I havent' tested the reverse order, but if the value was bound first and then assigned to one side, the assigned value should still propagate to the other menu because of the bidirectional binding.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, 2 questions:

  1. is createDifficultyMenu() rebuilt on each menu creation or is it built only once and cached? For example, main menu -> game menu -> main menu (at this last step do we still have the same difficultyBox that was created the first time main menu was constructed?)

  2. can one property be bidirectionally bound to multiple objects?

If the answer to question 1 is "no, the menu items are cached rather than rebuilt" and if the answer to question 2 is also "no", then I can see a potential issue:

  • User opens main menu settings difficulty is bound to main menu box
  • User opens game menu settings difficult is bound to game menu box, losing the binding to main menu box. If we change the difficulty here, then at the next step does the difficulty in main menu also change?
  • User opens main menu again...

Are you able to test this scenario and see if it works as expected?

@jamesmosey jamesmosey Apr 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To answer question 1: The createDifficultyMenu() is rebuilt on each menu creation. The bound difficulty value persists as that setting lives outside of the UI controls (settings.kt).

As for question 2: As far as I'm aware the answer is no, but I have just tested it and these were the results:

  • Difficulty is set to 'nightmare' in main menu
  • New game is started, opening game menu shows that the difficulty is still set to 'nightmare'. Difficulty was then changed to 'easy'.
  • Upon leaving the game and returning back to the main menu the difficulty is still set to 'easy'.

Perhaps this is due to the two seperate bidirectional bindings from both the main menu and game menu to the same difficulty property in the settings, allowing the difficulty to persist between each menu type.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, thanks for testing.

I've looked up documentation of Property. Turns out we can have multiple bidirectional bindings. There is a note about weak listeners and garbage collection, but I don't expect any issues if the menu is rebuilt every time.

getSettings().gameDifficultyProperty().bindBidirectional(difficultyBox.valueProperty())

difficultyBox.valueProperty().addListener { _, _, _ ->
switchMenuContentTo(EMPTY)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remind me what this does / why this is needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in hindsight I should've left this in a comment.
Line 367 binds the difficulty option in the UI to the built in difficulty settings. So that when the difficulty is changed through the menu, it changes it in the settings.

The rest of the code adds a listener that reacts whenever the difficulty selection changes, hiding the dropdown menu and returning the user to the previous menu. Which was the alternative to adding a seperate back button somewhere else in the menu, increasing visual clutter. I tested adding a back button but it made more sense to me to keep it so when the difficulty is changed (or in the event of not changing, clicking the already-selected difficulty) returns the user back to the previous menu.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could just leave the user in the same view, i.e. the difficulty menu remains where it is and the user can select the difficult value multiple times. Will this cause an issue do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, it won't cause an issue - it was that way initially during testing. How would you suggest leaving the difficulty menu after the changes have been made? Perhaps when another menu item (options, extras..) is selected, it hides the difficulty choicebox? As opposed to having a back button or something of that sort.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it as is for now. We can always action this separately if users raise an issue.

@AlmasB AlmasB left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks good, thanks for this PR!

@AlmasB
AlmasB merged commit f418525 into AlmasB:dev Apr 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow selecting Difficulty in Gameplay menu

2 participants