Ending an application(game) and exit or and start a new one - javafx-8

So how does one end an application/game on a button click and exit as if the window red close symbol (X) has been clicked on or better still
how does one end the current application and without closing the whole window / stage starts a new one ?
so for example we have something like
public class Main extends Application
{
public Scene scene ;
private parent createContent()
{
// root pane, nodes and everything is here
//which makes up the game
//return root;
}
#Override
public void start(Stage stage)
{
scene = new Scene(createContent());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {launch(args); }
}
So at the end of the current game, the user should be giving the option to start a new game or to exit the application completely by clicking on buttons. If he should click on exit game then the game should close as if he has pressed on the window red x close symbol.
If the user should click on start a new game, then the prefered behavior will be for method
private parent createContent()
to start all over again, but of course all stages and nodes created in the previous calls of createContent() should be eliminated..
How can this be done?

I have the similar workflow in my project and I implemented the next way.
Register a handler for OnCloseRequest:
stage.setOnCloseRequest(windowEvent -> appToBeClosed(stage, windowEvent));
Below methods to show a dialog with a question. Only if an user decided to stay you should consume the current window event and do something otherwise the application will be closed:
private void appToBeClosed(Stage notUsedStage, WindowEvent windowEvent) {
if (hasNotSavedEvents()) {
final Optional<ButtonType> userResponse = alertAboutNotSavedChangedEvents(
"alert.changed.header", "alert.changed.content");
if (userResponse.isPresent() && userResponse.get() == ButtonType.NO) {
windowEvent.consume();
}
}
}
private Optional<ButtonType> alertAboutNotSavedChangedEvents(String headerResourceKey,
String contentResourceKey) {
final Alert alert = new Alert();
// TODO prepare alert as you wish...
return alert.showAndWait();
}
I hope the main idea is clear and you will be able to adopt it to your project.
Let me know your questions.

Related

After pause menu score doesn't work anymore

does anyone know how to fix this? In my unity game when I go to pause menu and then continue playing, my scoreboard stops updating. I have two scoreboards, one in game and one in pause menu. The one in pause menu works well and updates but the one in game freezes after once visited in pause menu.
Here is my pausecodes and codes to add money (score):
public void PauseGame()
{
Time.timeScale = 0;
}
public void UnPauseGame()
{
Time.timeScale = 1;
}
}
if (collision.gameObject.tag == "Respawn") // When player lifts fish up
{
Destroy(this.gameObject);
// TODO: Player gets money (points) when this happens
textManager.instance.AddMoney();
Debug.Log("Add money");
}
public class textManager : MonoBehaviour
{
public static textManager instance;
public Text moneyText;
public int money;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
Data data = SaveSystem.LoadData();
money = data.balance;
moneyText.text = "Balance: " + money.ToString() + " $";
}
public void AddMoney()
{
money = money + 10;
moneyText.text = "Balance: " + money.ToString() + " $";
SaveSystem.SaveData(this);
}
public int findMoney()
{
return money;
}
}
Please ask more info if needed.
I have tried to delete the one scoreboard in pause menu and after that the in-game pause menu started working right, but I would like to have still that other scoreboard too.
if (collision.gameObject.tag == "Respawn") // When player lifts fish up
{
// TODO: Player gets money (points) when this happens
textManager.instance.AddMoney();
Debug.Log("Add money");
Destroy(this.gameObject);
}
As I said this is the fix for what you posted as for the pause unpause problem you have to post the actual code where you do the pause unpause behavior so can people help you out my friend. As for what you posted what you've been doing is destroying the script just before excuting the call to textManager.instance.AddMoney(); and this will never run in the order you set in your code.
The scope of a static field is global, this means there can only be one.
Your textManager (side note: a classes first letter has to be upper case) is certainly attached to multiple GameObjects, once to the object displaying the score in the scene UI and once to a UI element in the pause menu.
As soon as you pause your game the first time, the TextManager attached to the object in the pause menu will run Awake() and the instance (please capitalise your properties as well) will be overriden and the reference to the ingame TextManager gets discarded.
The sloppy fix is re-initializing the ingame TextManager when you unpause the game, assigning it to be the Instance again. I'd not recommend doing that though.
The better solution is to implement an event on the player that gets triggered when the score changes and making the player instance a Singleton object since there will be only one player in all circumstances.
The UI elements displaying the score can then subscribe to this event in OnEnable() and unsubscribe in OnDisable() (do not forget to unsubscribe from events).
Addendum: You should not destroy your object before all code has been executed. Your code will still work because of how things are managed on the C++ layer of Unity, but it is definitely bad practice.

How do I make the Scoreboard on the side not be visible when the Debug HUD is open?

I'm working on a 1.16.5 Minecraft client-side mod and I am trying to get the scoreboard to be invisible when the Debug HUD is visible. I have a basic mixin to the scoreboard's rendering function but I need to be able to check for whether the DebugHud is visible or not.
Code:
#Mixin(InGameHud.class)
public class MScoreboardHUD {
#Inject(at = #At("HEAD"), method = "renderScoreboardSidebar")
private void init(CallbackInfo info) {
// soon
}
}
Answer
Using MinecraftClient.options.debugEnabled will tell you whether the F3 menu is active.
Final Code
This uses client as the MinecraftClient object, and info.cancel() to cancel the scoreboard render
#Mixin(InGameHud.class)
public class MScoreboardHUD {
#Inject(at = #At("HEAD"), method = "renderScoreboardSidebar")
private void init(CallbackInfo info) {
if (client.options.debugEnabled) {
info.cancel();
}
}
}

Unity, I have problem with DontDestroyOnLoad to keep tracking in different scence

im new in unity and i have a problem
I am making a game that have 2 scence(Main Menu Scence and Game Scence), i put my music on Main Menu scence. I make a empty game object and i attach audio source there(music) , and i also attach script like this :
First script
public static KeepTheMusicOn Instance;
void Awake()
{
if (!Instance)
Instance = this;
else
Destroy(this.gameObject);
DontDestroyOnLoad(this.gameObject);
}
With that script i can keep music play in second scence wihtout restart the music, and in the main menu scence i have settings that have button to mute the music , the button will run my second script .
Second Script:
public AudioSource mainMusic;
public void Update()
{
DontDestroyOnLoad(mainMusic);
}
public void MusicOnOff()
{
if (mainMusic.isPlaying)
{
mainMusic.Pause();
}
else
{
mainMusic.UnPause();
}
}
My problem is when i start the game so im in my main menu scence i can mute the music with the button, but when i go to game scence and i back to menu, the button dont do anything.
So that is my problem, i hope anyone can help me. Sorry for my bad english.
Sounds like when switching scenes you destroy the button. When you them go back to the main menu you destroy the duplicate instance of your audio controller thing => references configured in the Button are lost.
In your case since you use a public Singleton anyway you could as well (ab)use it and put a component on the Button itself instead (thus the reference can not get lost) and do something like e.g.
[RequireComponent(typeof(Button))]
public class MusicButton : MonoBehaviour
{
[SerializeField] private Button button;
private void Awake()
{
if(!button) button = GetComponemt<Button>();
// dynamically add the callback
// it won't appear in the editor but get called in onClick
button.onClick.AddListener(OnClicked);
}
private void OnClicked()
{
KeepTheMusicOn.Instance.MusicOnOff();
}
}
If you prefer seeing it in the editor you can ofcourse as well rove it from Awake, make the OnClicked public and reference it in the button's onClick event manually.

Loader during Unity IAP Callback

I want to put loader in between dialog boxes come up for the purchase. What is the way for this?
Because when game player press Buy button, he should require to wait for 5 to 10 second depends on internet speed and server response and this process happed 2 to 3 times because multiple dialogs come up within screen.
So in this case, may be player can leave the screen. I want to put the loader so that game player realise that some processing is running in background, he required to wait for some time.
At present I was following completely this code for Unity IAP setup.
Integrating Unity IAP In Your Game
I assume this is for mobile platform but even if its not still the following can be considered:
Simple solution is to create a full screen Image (UI/Panel) object in your UI to block clicks. I would use Animator component (with triggers) to display this panel in front of other UI when there is a background process running.
public class Loader : MonoBehaviour
{
public static Loader Instance;
Animator m_Animator;
public bool Loading {get; private set;}
void Awake()
{
Instance = this; // However make sure there is only one object containing this script in the scene all time.
}
void Start()
{
//This gets the Animator, which should be attached to the GameObject you are intending to animate.
m_Animator = gameObject.GetComponent<Animator>();
Loading = false;
}
public void Show()
{
Loading = true;
m_Animator.SetBool("Loading", Loading); // this will show the panel.
}
public void Hide()
{
Loading = false;
m_Animator.SetBool("Loading", Loading); // this will hide the panel.
}
}
Then in any script which manipulates UI:
public void BuyButtonClicked()
{
Loader.Instance.Show();
// process time taking stuff
Loader.Instance.Hide();
}
You can also create any kind of loading animation as child of panel object using simple images and animation tool inside Unity (for example rotating animation (use fidget spinner, its cool)).
And in case of Android where user have option to leave screen by pressing OS back button you can prevent going back by checking if any loading is in progress by following example:
// code for back button
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
BackButtonPressed();
}
}
void BackButtonPressed()
{
if(Loader.Instance.Loading)
return;
// use back button event. (For example to leave screen)
}
Hope this helps ;)

MouseDown events are not delivered until MouseUp when a Drag Source is present

I have a mouse listener. It has some code to respond to mouseUp and mouseDown events. This works correctly.
However, as soon as I add a DragSource, my mouseDown event is no longer delivered -- until I release the mouse button!
This is trivial to reproduce - below is a simple program which contains a plain shell with just a mouse listener and a drag listener. When I run this (on a Mac), and I press and hold the mouse button, nothing happens - but as soon as I release the mouse button, I instantly see both the mouse down and mouse up events delivered. If I comment out the drag source, then the mouse events are delivered the way they should be.
I've searched for others with similar problems, and the closest I've found to an explanation is this:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=26605#c16
"If you hook drag detect, the operating system needs to eat mouse events until it determines that you have either dragged or not."
However, I don't understand why that's true -- why must the operating system eat mouse events to determine if I have a drag or not? The drag doesn't start until I have a mouse -move- event with the button pressed.
More importantly: Can anyone suggest a workaround? (I tried dynamically adding and removing my drag source when the mouse is pressed, but then I couldn't get drag & drop to function properly since it never saw the initial key press - and I can't find a way to programmatically initiate a drag.)
Here's the sample program:
package swttest;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SwtTest {
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.addMouseListener(new MouseListener() {
public void mouseUp(MouseEvent e) {
System.out.println("mouseUp");
}
public void mouseDown(MouseEvent e) {
System.out.println("mouseDown");
}
public void mouseDoubleClick(MouseEvent e) {
System.out.println("mouseDoubleClick");
}
});
DragSourceListener dragListener = new DragSourceListener() {
public void dragFinished(DragSourceEvent event) {
System.out.println("dragFinished");
}
public void dragSetData(DragSourceEvent event) {
System.out.println("dragSetData");
}
public void dragStart(DragSourceEvent event) {
System.out.println("dragStart");
}
};
DragSource dragSource = new DragSource(shell, DND.DROP_COPY | DND.DROP_MOVE);
dragSource.addDragListener(dragListener);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
To answer your specific question about why this happens -- on Cocoa we don't consider a drag to have started until the mouse has moved a few pixels. This ensures against 'accidental' drags if you're sloppy with the clicks. On Linux and Win32 the window toolkit can do the drag detection. If you just hold down the button the detection times out and the mouse down is delivered. On Cocoa we have no time out, which is why nothing happens until the drag is detected or a mouse up happens.
That's a lot of detail, but the conclusion is that the behavior is inconsistent, and we should always be able to deliver the mouse down immediately, without waiting for the drag detection to complete.
I don't see a workaround, since this is happening before the Control sees the event.
See this bug which has patches for win32, gtk and cocoa SWT.
I had faced the same problem and found a solution. Once you attach a DragSource to your custom widget, the event loop will be blocked in that widget's mouse down hook and will eat mouse move events to detect a drag. (I've only looked into the GTK code of SWT to find this out, so it may work a little differently on other platforms, but my solution works on GTK, Win32 and Cocoa.) In my situation, I wasn't so much interested in detecting the mouse down event right when it happened, but I was interested in significantly reducing the drag detection delay, since the whole purpose of my Canvas implementation was for the user to drag stuff. To turn off the event loop blocking and built-in drag detection, all you have to do is:
setDragDetect(false);
In my code, I am doing this before attaching the DragSource. As you already pointed out, this will leave you with the problem that you can't initiate a drag anymore. But I have found a solution for that as well. Luckily, the drag event generation is pure Java and not platform specific in SWT (only the drag detection is). So you can just generate your own DragDetect event at a time when it is convenient for you. I have attached a MouseMoveListener to my Canvas, and it stores the last mouse position, the accumulated drag distance and whether or not it already generated a DragDetect event (among other useful things). This is the mouseMove() implementation:
public void mouseMove(MouseEvent e) {
if (/* some condition that tell you are expecting a drag*/) {
int deltaX = fLastMouseX - e.x;
int deltaY = fLastMouseY - e.y;
fDragDistance += deltaX * deltaX + deltaY * deltaY;
if (!fDragEventGenerated && fDragDistance > 3) {
fDragEventGenerated = true;
// Create drag event and notify listeners.
Event event = new Event();
event.type = SWT.DragDetect;
event.display = getDisplay();
event.widget = /* your Canvas class */.this;
event.button = e.button;
event.stateMask = e.stateMask;
event.time = e.time;
event.x = e.x;
event.y = e.y;
if ((getStyle() & SWT.MIRRORED) != 0)
event.x = getBounds().width - event.x;
notifyListeners(SWT.DragDetect, event);
}
}
fLastMouseX = e.x;
fLastMouseY = e.y;
}
And that will replace the built-in, blocking drag detection for you.