I am creating a dialog system on unity where the user has options to select from and either gets a response via a text field or gets more options to choose from.
At first i have 3 options. These 3 options belong to a script and another 2 options belong to another which are both running simultaneously. Each option has an int index(first option = 0 , second option = 1 etc..). I have made it so that if i press on option 1, the index becomes 3 to go to the fourth option.
As i have put everything in Update to wait for key input by user, whenever the user presses Enter, it gets executed from both of the scripts so it enters both statements at once.
Whats happening basically when i select option 1, im getting the response of option 4 instantly because when i press enter it gets executed from both scripts
How can i make it so that when i press enter for option 1 it ignores the other statement please. Screenshots below.
if (Input.GetKey (KeyCode.Return)) {
if (indexConversation == 0) {
Debug.Log("first Option");
// GameObject.Find("Scripts2").SetActive(true);
telResponse.text = "Response 1";
Conv1Controller.Conv1showConversation = true;
indexConversation = 3;
Debug.Log (indexConversation);
} else if (indexConversation == 1) {
Debug.Log("second Option");
telResponse.text = "Response 2";
StartCoroutine(responseTwoFollowedbySix ());
}
else if (indexConversation == 2) {
Debug.Log("third Option");
telResponse.text = "Response 3";
StartCoroutine(responseThreeFollowedbyFourFollowedbySeven ());
}
showConversation = false;
}
The other script (option 4 and 5)
if (Input.GetKey(KeyCode.Return))
{
if (DialogueController.indexConversation == 3)
{
Debug.Log("Fourth Option");
telResponse.text = "Response 4";
}
if (DialogueController.indexConversation == 4)
{
Debug.Log("Option 5");
telResponse.text = "Response 5";
}
//Conv1showConversation = false;
}
Considering your first script has a indexConversation variable and your second script seems to refer to it using DialogueController.indexConversation, I feel like this variable is a public static int one. In this situation you could simply do something like this:
First script
[SerializeField]
private YOUR_OTHER_SCRIPT_CLASS otherScript;
if (Input.GetKey(KeyCode.Return))
{
showConversation = false;
switch(indexConversation)
{
case 0:
Debug.Log("first Option");
telResponse.text = "Response 1";
Conv1Controller.Conv1showConversation = true;
indexConversation = 3;
Debug.Log (indexConversation);
break;
case 1:
Debug.Log("second Option");
telResponse.text = "Response 2";
StartCoroutine(responseTwoFollowedbySix ());
break;
case 2:
Debug.Log("third Option");
telResponse.text = "Response 3";
StartCoroutine(responseThreeFollowedbyFourFollowedbySeven ());
break;
default:
otherScript.ReturnKeyPressed();
break;
}
showConversation = false;
}
Here I added a variable to reference your other script and used a switch instruction to avoid the many if and else if.
Also if the value of indexConversation is not 1, 2 or 3, you ask for your other scrip to do something.
Other script
public void ReturnKeyPressed()
{
switch(DialogueController.indexConversation)
{
case 3:
Debug.Log("Fourth Option");
telResponse.text = "Response 4";
break;
case 4:
Debug.Log("Option 5");
telResponse.text = "Response 5";
break;
default:
break;
}
}
In this script, there is no more if (Input.GetKey(KeyCode.Return)) since the input detection will be made in the first script and send to this script if needed.
P.-S.
As #Programmer said, you should never use OnGUI() for anything else than debugging. This method is really heavy as it's called many times per frame (which is useless) and you can use Unity UI System to work with UI easily.
As #Nabren suggested, if your system is more complexe than this simple case, you should really change the way it's made and have an input manager class that get inputs and send them to the appropriate scripts.
Hope this helps,
You should really think about storing your conversations into a Model that have a link to responses and responses can link to specific "FollowUp" conversation. This way you can write the script as agnostic as possible. You just give it a response and it knows how to handle it. Each response would get its own "ResponseView" Script which takes in a response model and could add button listeners or key listeners for press events and then upon receiving the correct input would load the next conversation using its current response model. Writing specific methods in code to tell your responses where they need to go is very very fragile and will not scale well at all.
Related
I'm making a game. it has a login panel and rememmer me button. i keep the info on regedit. when I click rememmer me button it works and when I start game after click button it gets my info like id and pass but when I start again it deletes my id and pass on regedit. So it get just one time. I couldn't find the problem or fix way. Can you help me? Thank you.
Here is my codes:
void Start()
{
if(PlayerPrefs.GetInt("BeniHatirla")==1)
{
Debug.Log("start "+PlayerPrefs.GetInt("BeniHatirla"));
BeniHatirlaGetir();
}
}
Here is the method ı called in start:
public void BeniHatirlaGetir()
{
isim = PlayerPrefs.GetString("BeniHatirlaIsim");
sifre = PlayerPrefs.GetString("BeniHatirlaSifre");
Debug.Log("kullanici "+isim+sifre);
BeniHatirlaUniSlider.value = 1;
Debug.Log("Ogrenm Durumu"+PlayerPrefs.GetInt("OgrenimDurumuBelirleme"));
switch (PlayerPrefs.GetInt("OgrenimDurumuBelirleme"))
{
case 1:
OrtaOkulKadiTextBox.text = isim.ToString();
OrtaokulKsifreTextBox.text = sifre.ToString();
LoginPanelleri[0].SetActive(true);
break;
case 2:
LiseKadiTextBox.text = isim.ToString();
LiseKsifreTextBox.text = sifre.ToString();
LoginPanelleri[1].SetActive(true);
break;
case 3:
UniversiteKadiTextBox.text = isim.ToString();
UniversiteKsifreTextBox.text = sifre.ToString();
LoginPanelleri[2].SetActive(true);
break;
}
}
And here is the rememmer me button:
public void BeniHatırlaButon()
{
PlayerPrefs.SetInt("BeniHatirla", 1);
switch (PlayerPrefs.GetInt("OgrenimDurumuBelirleme"))
{
case 1:
PlayerPrefs.SetString("BeniHatirlaIsim", OrtaOkulKadiTextBox.text.ToString());
PlayerPrefs.SetString("BeniHatirlaSifre", OrtaokulKsifreTextBox.text.ToString());
break;
case 2:
PlayerPrefs.SetString("BeniHatirlaIsim", LiseKadiTextBox.text.ToString());
PlayerPrefs.SetString("BeniHatirlaSifre", LiseKsifreTextBox.text.ToString());
break;
case 3:
PlayerPrefs.SetString("BeniHatirlaIsim", UniversiteKadiTextBox.text.ToString());
PlayerPrefs.SetString("BeniHatirlaSifre", UniversiteKsifreTextBox.text.ToString());
break;
}
}
If you're running some debugger, it may be missing out on when it actually saves the values to disk. From the documentation for PlayerPrefs:
By default Unity writes preferences to disk during OnApplicationQuit(). In cases when the game crashes or otherwise prematuraly exits, you might want to write the PlayerPrefs at sensible 'checkpoints' in your game. This function will write to disk potentially causing a small hiccup, therefore it is not recommended to call during actual gameplay.
So if you are exiting the application prematurely through debugging it may be that you just need to call PlayerPrefs.Save() right after you try to write the values.
I'm a complete Newbie to the world of programming, yet I really wish to learn a lot as quick as possible and now came up to a problem that I can't find to solute just via researching and "learning- by doing" (Trying around).
Basically I'm trying to work on a small console- based TextAdventure in C Sharp (With VisualStudios) Now I came to a Case- Switch (Offering the User some Options to read and walk through), but I wish to add a Y/N Confirmation in case the User decides to take a different path. For now it's only for the starting point of the story:
Does the User want to go into "The Wilds", "The City", "The Farm". Something as simple as that just in addition: "Are you sure (Y/N)?" leading the No to return the given choices.
Thank you all in advance and stay healthy!
Menu mainMenu = new Menu(prompt, options);
int selectedIndex = mainMenu.Run();
switch (selectedIndex)
{
case 0:
EnterTheWorld();
break;
case 1:
VisitTheMemorial();
break;
case 2:
TakeYourLeave();
break;
default:
break;
}
}
private void TakeYourLeave()
{
WriteLine("\nYou are about to take your leave... Are you sure ? (Y/N)");
ReadKey();
Environment.Exit(0);
}
private void VisitTheMemorial()
{
Clear();
//FILLER//
WriteLine("You may proceed by the press of any button.");
ReadKey(true);
RunMainMenu();
}
private void EnterTheWorld()
{
string prompt = "Where would you like to start your journey?";
string[] options = { "The Slums", "The Wilds", "The City", "The Farm" };
Menu startMenu = new Menu(prompt, options);
int selectedIndex = startMenu.Run();
BackgroundColor = ConsoleColor.White;
switch (selectedIndex)
{
case 0:
ForegroundColor = ConsoleColor.Black;
WriteLine("\n ||Small Description||Are you sure to take this path? (Y/N)");
break;
case 1:
ForegroundColor = ConsoleColor.Green;
WriteLine("\n ||Small Description||Are you sure to take this path? (Y/N)");
break;
case 2:
ForegroundColor = ConsoleColor.Red;
WriteLine("\n ||Small Description||Are you sure to take this path? (Y/N)");
break;
case 3:
ForegroundColor = ConsoleColor.Yellow;
WriteLine("\n ||Small Description|| Are you sure to take this path? (Y/N)");
break;
}
In this case, you need to take care of a few things:
Make sure that the entire switch-statement logic is in a while-loop, as such:
while (True) {
int selectedIndex = mainMenu.Run();
switch (selectedIndex)
{
case 0:
EnterTheWorld();
break;
case 1:
VisitTheMemorial();
break;
case 2:
TakeYourLeave();
break;
default:
break;
}
}
Check with your function if the input given is "No", if such, then immeditely return so your function exits before any navigation
private void VisitTheMemorial()
{
userInput = readKeyFunction();
if (userInput == "no") {
return;
}}
Finally, if the user doesn't select no, just do nothing and let the function go on
It is best to handle the 'Are you sure?' inside the menu.Run(), and return a value to the selectedIndex after the confirmation. Also avoid using while loop at the main flow in this case.
Note: you have to think in a modular way. Consider your Menu class as a module which handles user choice. The main flow does not have to bother about the confirmation by the user, it just have to process the final result of the user.
Another suggestion: Use enums instead of integers wherever possible for multiple choices.
So I'm working on a Switch-Case menu for my program but I'm having multiple issues (I'm probably missing something real obvious here)
So first off I'm trying to implement a while loop to make it possible to return to the menu after executing any of the case methods. However when trying to implement a while loop it doesn't seem to recognise my bool variable for some reason.
Secondly I'm not quite sure how to make it so the user can return to the start menu after they've done what they want to do in the case they've chosen, this probably has a real easy solution, but I just can't find one.
[code]
private string[] säten = new string[24];
private int Antal_passagerare = 0;
public void Run()
{
bool continue = true;
while(continue)
{
string menu = (Console.ReadLine());
int tal = Convert.ToInt32(menu);
switch(tal)
{
case 1:
Add_passagerare;
break;
case 2:
break;
case 3:
break;
}
}
}
[/code]
Your problem is that your local variable name conflicts with the C# keyword (or statement) continue which controls the flow of a loop (e.g. for, foreach, while, etc). Another control flow keyword is break.
You must rename the local variable. But because of the flow control keywords you can drop the local variable (see below). Also use Int32.TryParse to avoid your program from crashing, if the user inputs a non numeric value. In this context you can see the statements continue and break at work:
// Start an infinite loop. Use the break statement to leave it.
while (true)
{
string userInput = Console.ReadLine();
// Quit if user pressed 'q' or 'Q'
if (userInput.Equals("Q", StringComparison.OrdinalIgnoreCase)
{
// Leave the infinite loop
break;
}
// Check if input is valid e.g. numeric.
// If not show message and ask for new input
if (!(int.TryParse(userInput, out int numericInput))
{
Console.WriteLine("Only numbers allowed. Press 'q' to exit.");
// Skip remaining loop and continue from the beginning (ask for input)
continue;
}
switch (numericInput)
{
case 1:
break;
case 2:
Add_passagerare();
break;
case 3:
break;
}
}
I sometimes have myself writing code which requires several layers of if/else statements incorporated into each other (example can be found below).
I was wondering if I could shorten it up a bit, because sometimes I have trees of if/else statements of over 70 lines of code, and they are honestly just filling way too much compared to how many of the lines seem redundant.
Here's an example code:
if (labelGiveTip1.Visible == true)
{
if (labelGiveTip2.Visible == true)
{
labelGiveTip3.Visible = true;
if (labelGiveTip3.Visible == true)
{
Custom_DialogBox.Show("All of your hints for this assignment is used, do you want annother assignmment?", //main text argument
"Error: No more hints", //header argument
"Back", //first button text argument
"Get a new assignment"); //second button text argument
//this is a custom dialog box
result = Custom_DialogBox.result;
switch (result)
{
case DialogResult.Yes:
buttonNextAssignment.PerformClick();
break;
case DialogResult.Cancel:
break;
default:
break;
}
}
}
else
{
labelGiveTip2.Visible = true;
}
}
else
{
labelGiveTip1.Visible = true;
}
In my code I tend to check the false condition first and return ASAP. This approach has helped me over years to reduce deeply nested if else. Other than that try to separate related functionalities in to different methods. The example method provided crams too much of logic into one method. If you have ReSharper, it suggests nice improvements and over a period of time, it becomes a habit.
You may check the negated variant of the condition and use else if conditions to avoid that much nesting. E.g. a simplified version for your code:
if (!labelGiveTip1.Visible)
labelGiveTip1.Visible = true;
else if(!labelGiveTip2.Visible)
labelGiveTip2.Visible = true;
else
{
labelGiveTip3.Visible = true;
Custom_DialogBox.Show("All of your hints for this assignment is used, do you want annother assignmment?", //main text argument
"Error: No more hints", //header argument
"Back", //first button text argument
"Get a new assignment"); //second button text argument
//this is a custom dialog box
result = Custom_DialogBox.result;
switch (result)
{
case DialogResult.Yes:
{
buttonNextAssignment.PerformClick();
break;
}
case DialogResult.Cancel:
{
break;
}
default:
{
break;
}
}
}
It is also unnecessary to write labelGiveTip1.Visible == true or labelGiveTip1.Visible == false when they are already boolean values.
So this loop is my first attempt at changing many things. I'm not sure I'm going about it the right way. This is for a rught/wrong answer game. Each time they answer wrong, the loop is called.
In my head it would go to the if related to numAttempts. So if numAttempts ==4 you would see "Wrong Answer 2 tries left!" But each time until the fifth attempt, when the loop is called it always starts at the top regardless of the numattempts.
To mitigate this I also tried adding numAttempts++ in the message check (wrong) code block.
I like the idea of the four loop, because based on each wrong answer a different image will appear, based on HangmanImage() --not currently defined--
I've tried break and return between the for if statements but it isn't working. Can you help me when the loop is called to start the loop where numAttempts =. EX. start at numAttempts==2? And stop the loop after the specific instance is completed?
I'm new to coding and trying to make it work. I appreciate your Patience if my work is 100% wrong or that I shouldn't have done a four look. reading a book and the web is great, but every now again, especially in the beginning people need guidance. Please take a moment and push me in the right direction.
Thank you for your time.
int numAttempts = (0); // global variable, at the start of the class. This allows the variable to be used anywhere with the current value
int maxAttempts = (5);
static void UpdateImage()
{
for (int numAttempts = 0; numAttempts < 6; numAttempts++)
{
if (numAttempts == (1))
{
MessageBox.Show("Wrong Answer 4 tries left!");
{
// HangmanImage();
}
}
else
if (numAttempts == (2))
{
MessageBox.Show("Wrong Answer 3 tries left!");
{
// HangmanImage();
}
}
else
if (numAttempts == (3))
{
MessageBox.Show("Wrong Answer 2 tries left!");
{
// HangmanImage()
}
}
else
if (numAttempts == (4))
{
MessageBox.Show("Wrong Answer 1 try left!");
{
// HangmanImage()
}
}
else
if (numAttempts == (5))
{
MessageBox.Show("You Lose!");
{
// HangmanImage();
}
}
}
}
Here is a working answer: https://dotnetfiddle.net/Z2BaYs
This is the code. Basically, you use the for loop to keep the game in play until the user either runs out of attempts or answers correctly.
using System;
public class Program
{
public static void Main()
{
var maxAttempts = 5;
var correctAnswer = "Edam";
for(int actualAttempts = 1; actualAttempts <= maxAttempts; ++actualAttempts)
{
Console.WriteLine("What is the only cheese that's made backwards?");
Console.WriteLine("Attempt #" + actualAttempts);
var answer = Console.ReadLine();
if(answer.Equals(correctAnswer))
{
Console.WriteLine("Correct!");
break;
}
switch(actualAttempts)
{
case 1:
Console.WriteLine("Whoa. Nice try.");
break;
case 2:
Console.WriteLine("Nope. Wrong.");
break;
case 3:
Console.WriteLine("Incorrect sir!");
break;
case 4:
Console.WriteLine("Still not the correct answer.");
break;
case 5:
Console.WriteLine("...and your done.");
break;
default :
break;
}
}
}
}
This is some example output/input.
What is the only cheese that's made backwards?
Attempt #1
Cheddar
Whoa. Nice try.
What is the only cheese that's made backwards?
Attempt #2
Mozarella
Nope. Wrong.
What is the only cheese that's made backwards?
Attempt #3
Havarti
Incorrect sir!
What is the only cheese that's made backwards?
Attempt #4
Swiss
Still not the correct answer.
What is the only cheese that's made backwards?
Attempt #5
Edam
Correct!
I can tell that you are doing this for school, so I don't want to give much away. But too your question, you are wanting to keep the same iteration in the loop, if I am understanding you. Just to try and stick to your code, you would need to pass in a variable and return one on the function. Like this
int updateImage(int count)
{
for(count < 6; count++)
{
Do what you need;
}
return count;
}
That way you can pass your iteration in and out of the function. Hope this helps.