How I create and run the instance of the game:
using (Game1 game = new Game1())
{
game.Run();
MessageBox.Show("Game finished");
// A lot of other things that I don't want to do inside the game"
}
If inside the game, at a certain point, I write:
this.Exit();
The Application closes entirely, and the MessageBox is never shown.
How can I just let .Run() return?
Edit: I noticed that clicking onto the "x" of the window while the game is running gives the effect I want
https://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.onexiting.aspx might help, something like this should do your thing (put that in your Game class):
protected override void OnExiting (Object sender, EventArgs args)
{
MessageBox.Show("Game finished");
}
Related
Here, I am looking for a piece of code in the Unity editor that will execute the initial panel of the created package only once when Unity is opened, but this code is executed in the initial frame every time I play Unity and then stop it, and it continuously shows the panel. Gives. I want it to be seen only once when the project is opened.
[InitializeOnLoad]
public class Autorun
{
static Autorun()
{
EditorApplication.update += RunOnce;
}
static void RunOnce()
{
Debug.Log("Once"); // but it will repeat every time I Clicking on play then stop it.
Panel.Init();
EditorApplication.update -= RunOnce;
}
}
Above is the code suggested by the user in Unity Answers, which was chosen as the best answer, but in fact, as I pointed out, it had a problem.
Although it was mentioned in the comment that the second answer in Unity answers solves the problem, after a while I noticed that the panel opens again when saving the code and I could not find a way to block it through another condition in EditorApplication. The solution below is the final method of solving the problem that uses EditorPrefs and I feel it necessary to share this method with you.
internal const string FIRST_TIME = "FIRST_TIME"; // the key
static Autorun()
{
EditorApplication.update += RunOnce;
EditorApplication.quitting += Quit;
}
private static void Quit() => EditorPrefs.DeleteKey(FIRST_TIME);
private static void RunOnce()
{
var firstTime = EditorPrefs.GetBool(FIRST_TIME, true);
Debug.Log(firstTime);
if (firstTime)
{
EditorPrefs.SetBool(FIRST_TIME, false);
if (EditorPrefs.GetBool(Panel.ShowOnStart, true)) Panel.Init();
}
EditorApplication.update -= RunOnce;
}
}
MCVE is below. How do I avoid recursively calling StartGame() and DisplayEndScreen? One way is to loop over StartGame(), but this doesn't seem like an extensible solution, more of a hack. Another solution might be: when the user hits R to restart, return to the main menu and pass in the Enter key as input into the switch statement, somehow.
What's a good solution?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Menu: Press Enter to start the game >>");
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Enter:
StartGame();
break;
// Other Menu Items
}
}
private static void StartGame()
{
// Do Game
DisplayEndScreen(); // NB: This causes recursion! I don't want this.
}
private static void DisplayEndScreen()
{
Console.WriteLine("Game Over! Select an option >> \n\n" +
"R:\tPlay again\n" +
"M:\tReturn to Main Menu\n" +
"Q:\tQuit");
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.R:
StartGame(); // NB: This causes recursion! I don't want this.
break;
// Other Menu Items
}
}
}
}
Calling StartGame() inside StartGame() causes the recursion. The way to avoid it is simply not calling a method inside of itself.
I think the name of the functions are a bit confusing for your program, are you sure 'StartGame' is correctly describing what the function is doing? It seems more likely to be the actual game (game()?) itself. If the name instead was something that tells you that the game is actually running (as it looks like its doing), calling it again would make less sense for you.
Considering running a game, most basic solutions usually looks like this:
bool game = true;
while(game)
{
//game running
if(exit)
{
game = false;
}
}
I am trying to make a main menu in Windows Forms. When you click a label in the form, the XNA game should start playing.
But it didn't work.
my code in the program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace _2DSpaceShooter
{
if WINDOWS || XBOX
static class Program
{
static void Main(string[] args)
{
Application.Run(new MainMenu());
}
}
endif
}
My code in the label click event
private void label1_Click(object sender, EventArgs e)
{
using (Game1 game = new Game1())
{
game.Run();
}
}
Please help me!!!
I am sorry for possible English mistakes (I am not American)
I don't know if you can do it, but if you can one of the simplest way is by using GameComponents. Making your game as a GC enables you to launch multiples parts of it at one time, without having issues with threads.
As #eudabash mentioned in the comment section, you'll need to do the game.Run() in a seperate thread:
Game1 game = new Game1();
Thread thread = new Thread(() =>
{
game.Run();
};
thread.Start();
or, if you're on .Net 4.0 (I think. Or even 3.5)
Game1 game = new Game1();
Task.Factory.StartNew(() =>
{
game.Run();
}
Optionally make 'game' a field in your Form1 class, so you can access it anywhere. Just make sure to only retrieve data from Game, and never edit the UI from within Game. Cross-thread operations and whatnot. If you need to, remember to invoke.
I'm working on porting a game engine from Java to Windows Phone 7 XNA. One thing I'm struggling with is how to create modal dialogs. The dialog is rendered in XNA using SpriteBatch just like everything else, but what I basically want is something like this:
result = Dialog.Ask("Some Question?", DialogButtons.YesNo);
Where Dialog.Ask doesn't return until the user clicks one of the buttons. The only thing I've done to come close is a method to continuously call RunOneFrame() on the game:
private int runLoopCount;
public void BeginRunLoop() {
int runIndex = ++runLoopCount;
while (runLoopCount == runIndex) {
RunOneFrame();
Thread.Sleep(1);
}
}
public void EndRunLoop() {
--runLoopCount;
}
There are a few problems with this:
RunOneFrame is only supposedly for debugging purposes.
Input doesn't work! Calling TouchPanel.GetState() or GamePad.GetState(PlayerIndex.One) doesn't return new values.
Is there any way to initiate a run loop without throwing away the Game class and all it does for initialization? And I don't really know how to do without the Game class anyway, as there is no Main() method in Windows Phone 7 XNA applications. It just goes right into the Game constructor.
What you want to do is to add another 'state', you just have to show dialog until user do not select something... and _modalDialogIsUp bool..
protected override void Update(GameTime gameTime)
{
if (_modalDialogIsUp)
{
// handle only secesary mouse and button clicks
}
else
{
// normal mouse and button clicks
}
}
protected override void Draw(GameTime gameTime)
{
if (_modalDialogIsUp)
{
// draw only modal dialog
}
else
{
// draw game
}
}
I just can't undestang why you so desparatly want exactly modal behavior... is it some kind of new "sync" sect? :)
When a user clicks the X button on a form, how can I hide it instead of closing it?
I have tried this.hide() in FormClosing but it still closes the form.
Like so:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
(via Tim Huffman)
I've commented in a previous answer but thought I'd provide my own. Based on your question this code is similar to the top answer but adds the feature another mentions:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
If the user is simply hitting the X in the window, the form hides; if anything else such as Task Manager, Application.Exit(), or Windows shutdown, the form is properly closed, since the return statement would be executed.
From MSDN:
To cancel the closure of a form, set the Cancel property of the FormClosingEventArgs passed to your event handler to true.
So cancel then hide.
Based on other response, you can put it in your form code :
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
According MSDN, the override is preferred:
The OnFormClosing method also allows derived classes to handle the
event without attaching a delegate. This is the preferred technique
for handling the event in a derived class.
If you want to use the show/hide method I've actually done this myself for a menu structure a game I've recently done... This is how I did it:
Create yourself a button and for what you'd like to do, for example a 'Next' button and match the following code to your program. For a next button in this example the code would be:
btnNext.Enabled = true; //This enabled the button obviously
this.Hide(); //Here is where the hiding of the form will happen when the button is clicked
Form newForm = new newForm(); //This creates a new instance object for the new form
CurrentForm.Hide(); //This hides the current form where you placed the button.
Here is a snippet of the code I used in my game to help you understand what I'm trying to explain:
private void btnInst_Click(object sender, EventArgs e)
{
btnInst.Enabled = true; //Enables the button to work
this.Hide(); // Hides the current form
Form Instructions = new Instructions(); //Instantiates a new instance form object
Instructions.Show(); //Shows the instance form created above
}
So there is a show/hide method few lines of code, rather than doing a massive piece of code for such a simple task.
I hope this helps to solve your problem.
Note that when doing this (several answers have been posted) that you also need to find a way to ALLOW the user to close the form when they really want to. This really becomes a problem if the user tries to shut down the machine when the application is running, because (at least on some OS) this will stop the OS from shutting down properly or efficiently.
The way I solved this was to check the stack trace - there are differences between when the user tries to click the X vs when the system tries to end the application in preparation for shutdown.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StackTrace trace = new StackTrace();
StackFrame frame;
bool bFoundExitCommand = false;
for (int i = 0; i < trace.FrameCount; i++)
{
frame = trace.GetFrame(i);
string methodName = frame.GetMethod().Name;
if (methodName == "miExit_Click")
{
bFoundExitCommand = true;
Log("FormClosing: Found Exit Command ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
if (methodName == "PeekMessage")
{
bFoundExitCommand = true;
Log("FormClosing: Found System Shutdown ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
Log("FormClosing: frame.GetMethod().Name = {0}", LogUtilityLevel.Debug4, methodName);
}
if (!bFoundExitCommand)
{
e.Cancel = true;
this.Visible = false;
}
else
{
this.Visible = false;
}
}
This is the behavior of Modal forms. When you use form.ShowDialog() you are asking for this behavior. The reason for this is that form.ShowDialog doesn't return until the form is hidden or destroyed. So when the form is hidden, the pump inside form.ShowDialog destroys it so that it can return.
If you want to show and hide a form, then you should be using the Modeless dialog model
http://msdn.microsoft.com/en-us/library/39wcs2dh(VS.80).aspx
form.Show() returns immediately, you can show and hide this window all you want and it will not be destroyed until you explicitly destroy it.
When you use modeless forms that are not children of a modal form, then you also need to run a message pump using Application.Run or Application.DoEvents in a loop. If the thread that creates a form exits, then the form will be destroyed. If that thread doesn't run a pump then the forms it owns will be unresponsive.
Edit: this sounds like the sort of thing that the ApplicationContext is designed to solve. http://msdn.microsoft.com/en-us/library/system.windows.forms.applicationcontext.aspx
Basically, you derive a class from ApplicationContext, pass an instance of your ApplicationContext as an argument to Application.Run()
// Create the MyApplicationContext, that derives from ApplicationContext,
// that manages when the application should exit.
MyApplicationContext context = new MyApplicationContext();
// Run the application with the specific context.
Application.Run(context);
Your application context will need to know when it's ok to exit the application and when having the form(s) hidden should not exit the application. When it's time for the app to exit. Your application context or form can call the application context's ExitThread() method to terminate the message loop. At that point Application.Run() will return.
Without knowing more about the heirarchy of your forms and your rules for deciding when to hide forms and when to exit, it's impossible to be more specific.