Suspenders-and-Belt GUIs: generic Yes/No screen

Started by RocketGirl, Wed 07/12/2005 22:13:41

Previous topic - Next topic

RocketGirl

I have to admit, I'm deeply confused, now. I've been trying to make a GUI system work all morning and I'm just running into way too many half-right solutions that don't work at all.

See, I'm trying to put together the standard idiot-proofing most games have:

"Are you sure? (Y/N)"

But I'd like to make it generic, so if the player has elected to start a new game or quit the game entirely, they get the same "Are you sure?" GUI.
There must be something wrong with my methodology, because I'm very very very confused and nothing I try has worked.

I think first and foremost, I'm confused by GUI controls. What is the difference between a GUI button's script name and a GUI button's Left-Click name? Becaue the script name seems to have no relevance whatsoever to ANYTHING, which the Left-Click script seems to be an actual function within the game's script. The manual just dismisses all the GUI button controls as "self-explanatory" which, I'm sorry, they're not.
And when a script is called by clicking on a GUI button, the function looks like this:

function GUIbutton (GUIControl *control, MouseButton button);

But GUIControl, *control, MouseButton, and button are never used by any of the functions I've seen in the script, so what good do they do? Why are they there at all? I've scoured the docs for n explanation, but all I've really found is the section on pointers, which only sort of describes what *control is, but not why one might use it in a GUI button's function.

And I'm really not sure if any of that is relevant to what I'm trying to do.

Here's what I'm trying to do:

When the player clicks on, say, the New Game button, which is on the GUI called gNewquit (the New Game, Quit Game, and Cancel buttons are on that GUI), I turn off the gNewquit.Visible variable, turn on the gBelt.Visible variable (gBelt is the Suspenders-and-Belt GUI, the one that asks if you're sure; idiot-proofing for mis-clicks) and...that's where I'm stuck.

I've tried setting up a variable that is supposed to be modified by the choice the player makes on gBelt, but because the new_game_Click function isn't paused by opening the gBelt GUI, if conditional statement that checks that variable goes off right away before the player can pick on gBelt, and so nothing gets resolved.

I've thought about passing a variable to gBelt that tells it which GUI the player just came from and make whatever is supposed to happen do so within gBelt (which is why I was wondering if the (GUIControl *control, MouseButton button) part might be important), but I'm not sure if that's the right way to go. I would like the GUI the player was on before gBelt to become Visible again if the player chooses to Cancel from gBelt, which is another reason why knowing gBelt's parent GUI is important. Plus, handling what happens in gBelt would make the function no longer generic.

Unfortunately, the screens that come up with QuitGame(1); aren't available to look at in any script I've come across, so I can't look at those to unravel this.

Can anyone help me out here? I know this is doable, I've seen it in other AGS games...

Thanks.
May the Force be with you

Akumayo

Instead of using a GUI, like you, I prefer to use a simple display message, and let the player push the 'y' key for yes, and any other key for no.Ã,  Like so:
Code: ags

Display("Press the 'y' key for yes, tap any other key for no.");
if (IsKeyPressed(89) == 1) {Ã,  //if they pressed 'y'
Ã,  Ã,  //script for pressing 'y'
}
"Power is not a means - it is an end."

RocketGirl

Well, that could be done, but I'd really like to do this with a GUI.

And even if I didn't, how do I make that generic so it then passes the result to the function the player just came from? I mean, half the point is making this so I don't have forty-eleven versions of the same "Yes/No" question popping up in different functions...
May the Force be with you

Akumayo

In the beginning of your global script, create a function:
Code: ags

function YesOrNo() {
Ã,  Display("Press the 'y' key for yes, tap any other key for no.");
Ã,  if (IsKeyPressed(89) == 1) {Ã,  //if they pressed 'y'
Ã,  Ã,  return 1;
Ã,  }
Ã,  else {
Ã,  Ã,  return 0;
Ã,  }
}


In your script header:
Code: ags

import function YesOrNo();


Then in the script you're using the yes/no in:
Code: ags

Display("Start a new game?");
int startnew;
startnew = YesOrNo();
if (startnew == 1) {
Ã,  //do stuff for yes
}
if (startnew == 0) {
Ã,  //do stuff for no
}
Ã, 

-Regards, Akumayo
"Power is not a means - it is an end."

Candle

Thanks for the tip Akumayo.
Going to save this for later  :=

Akumayo

 :)  It's an easy shortcut for lazy people like me!
"Power is not a means - it is an end."

Ashen

#6
I can't find a link to the seperate module, but ...
Bundled with SSH's SaveLoad Screenshot Module is the YesNo module, which does the same thing. (SSH: if it's not available seperately, can you make it so?)

OK, now everything else:

QuoteWhat is the difference between a GUI button's script name and a GUI button's Left-Click name?

OK, you nailed the Left-Click named thing. The 'Script Name' is exactly that - the name the control is known by in the script. This is used for most of the GUI Control commands (Label.SetText(string text), for example - lblTest.SetText("Cheese."); would change the text on the label with the scriptname lblTest to Cheese.) - check the manual for the full list of all GUI Control commands.

QuoteGUIControl, *control, MouseButton, and button are never used by any of the functions

Firstly, that's two things not four as you've split it with commas - GUI Control *control, which is a pointer to a GUI Control (like the script name), and MouseButton button.
Now, I'll admit I don't know what control does - perhaps someone else can explain it? button returns the mouse button used to click the control, meaning you could do something like:
Code: ags

function btnTest_Click(GUIControl *control, MouseButton button) {
  if (button == eMouseLeft) Display("Left");
  else if (button == eMouseRight) Display("Right");
}

And have a different reaction depending on which button was used. The MouseButton part just means it uses the MouseButton enumerated type (other AGS Built-in Enums, and where they're used) - which if you don't know means it returns a phrase instead of number, to make things easier to track (in this case, eMouseLeft instead of the more ambiguous 1).

QuoteUnfortunately, the screens that come up with QuitGame(1); aren't available to look at in any script I've come across,
No, that's hard-coded in, and you can't get at it. A simple Quit GUI would jusy need 2 buttons -  one for 'Play' that turns itself off (e.g. gQuit.Visible = false;) and one for 'Quit' that runs QuitGame(0);.

I know what you're thinking ... Don't think that.

RocketGirl

#7
Ah-hah! That's part of what I desperately needed to know!

I used to have some experience with coding in Pascal, but that was well over a decade ago. I remember that there was a way to call a function to return a result, but I'd forgotten the syntax, and I wasn't sure if it would be different in AGS anyway since AGS is trying to mimic C++ and not Pascal.

And 'return' is just what I needed for that kinna functionality.

I may still have some difficulty in changing from one GUI to another to get the yes or no results, but you've given me the first step. Thanks!

Quote from: Ashen on Wed 07/12/2005 23:56:34
OK, you nailed the Left-Click named thing. The 'Script Name' is exactly that - the name the control is known by in the script.

Ah! That's what confused me! I was thinking that 'Script Name' meant it was the name of a script rather than the name of the control. My bad, though it is kinna ambiguous.

Quote
QuoteGUIControl, *control, MouseButton, and button are never used by any of the functions

Firstly, that's two things not four as you've split it with commas - GUI Control *control, which is a pointer to a GUI Control (like the script name), and MouseButton button.

Heh, actually, I knew that part, sorta. I mean, there are four things there, really, it's just that there's only two eventual results. All a matter of perspective. I suppose i should have said that I wasn't sure what *control became as a result of GUIControl or something... I d'know. Semantics.

Quote
Now, I'll admit I don't know what control does - perhaps someone else can explain it?

It's my guess that *control points to the button the player just clicked on, in case you need to know it, but I could be wrong.

Quote
button returns the mouse button used to click the control, meaning you could do something like:
Code: ags

function btnTest_Click(GUIControl *control, MouseButton button) {
  if (button == eMouseLeft) Display("Left");
  else if (button == eMouseRight) Display("Right");
}

And have a different reaction depending on which button was used. The MouseButton part just means it uses the MouseButton enumerated type (other AGS Built-in Enums[/i], and where they're used) - which means it returns a phrase instead of number, to make things easier to track (in this case, eMouseLeft instead of the more ambiguous 1).

Okay, that makes sense.

So, hmm...So if I combine this with Akumayo's method, what I'd really do is turn off gNewquit, turn on gBelt, and then run the YesOrNo function described until I get a result that isn't 'null'. Then process that result as normal.

Something like:

Code: ags

function Newquit_Click(GUIControl *control, MouseButton button);
int quitornot;
gNewquit.Visible = false;
gBelt.Visisble = true;
while (quitornot == null) {
YesOrNo(quitornot);}
}


And then have YesOrNo() check GUI clicks rather than keypresses. I might need help figuring that part out, since GUI clicks are handled with separate functions rather than just simple detection...(I'm doing this without AGS in front of me, so I may have that code wrong, but the idea should be sound...)

QuoteA simple Quit GUI would jusy need 2 buttons -  one for 'Play' that turns itself off (e.g. gQuit.Visible = false;) and one for 'Quit' that runs QuitGame(0);.

Yeah, I'm just being more complex than that, trying to have GUI heirarchies or something...

But anyway, this has been a big help! Thanks! :)
May the Force be with you

RocketGirl

Okay, I've got this one figured out. It might be a bit clunky, but it's also really really simple...

Code: ags

// main global script file

//Initial variables
GUI *From;
Button *ToDo;

// ********* What to do when they select OK

function DoIt(){
if (ToDo == truequit) {
QuitGame(0);}
if (ToDo == NewGame) {
RestartGame();}  
}

// *********

// ********* Suspenders and Belt Idiot-proofing

function SandB_cancel_Click(GUIControl *control, MouseButton button){
gBelt.Visible = false;
From.Visible = true;

}  

function SandB_OK_Click(GUIControl *control, MouseButton button){
  gBelt.Visible = false;
  DoIt();
}  

// ******** End Suspenders and Belt

// ******** Quit_Check Menu Items Here

function NewGame_Click(GUIControl *control,  MouseButton button){
  gNewquit.Visible = false;
  gBelt.Visible = true;
  From = gNewquit;
  ToDo = control.AsButton;
}

function truequit_Click(GUIControl *control, MouseButton button) {
  gNewquit.Visible = false;
  gBelt.Visible = true; 
  From = gNewquit;
  ToDo = control.AsButton;
}

function newquit_cancel_Click(GUIControl *control, MouseButton button) {
  gNewquit.Visible = false;
  mouse.UseDefaultGraphic();
  gMain.Visible = true;
}

// ********* Quit_Check end


I had to figure out pointers and how they worked, then I had to figure out what the *control pointer was actually doing and why reading it into another pointer or a variable wasn't working before I hit on this solution.

The *From pointer points to the GUI that the player got to gBelt from so that it could be displayed again if they pressed cancel. The  *ToDo pointer points at the GUI control they clicked on to get to gBelt so that the DoIt() function would know what action to perform after they had clicked on OK.

Maybe there's a more elegant way to do DoIt(), but I haven't found one. I'd prefer to handle that from within the button's Click function to have it all self-contained, but no matter how I racked my brains I couldn't figue that one out. There seems to be no way to make AGS wait for the player to input something on gBelt before continuing the Click functions. Maybe it's just because I was in debug mode or something, but if I made a While loop that did nothing until the player did something, the engine would crash claiming that after some ungodly number of cycles nothing new had happened so AGS assumed it had gotten hung. Annoying.

Regardless, this does get the job done. Now I just need to apply what I've learned to Save/Restore screens, because I'll be damned to Cleveland before I use the built-in ones. Not cuz they stink, cuz they don't, but because they're generic and don't fit in with the visual scheme I'm coming up with for my game.
Though I'd like to suggest in the future that ALL of these screens exist as editable GUIs so the game creators can plug in their own graphics without all this trouble. (That is why I went through all this, to create my own unique GUI scheme rather than use the default. Superficial, I know, but personalizing the GUI is what makes a game stand out as one that actual care and attention was paid to, IMHO)
May the Force be with you

SSH

Once again: solved here...

For a customisable confirm box, try my new DialogBox module
12

SMF spam blocked by CleanTalk