Receive any Keyboard input and use with Switch statement on Unity - c#

I don't want to use if statement. For simplicity and performance I want to use switch case and execute that method. I want all the keyboard Input to get detected. But is there any method that will pass any key press information?
My current approach is :
// Update is called once per frame
void Update()
{
char a = Input.GetKey();//anything like this method?
switch (a)
{
case 'a':
//print'';
break;
case 'b':
//print'';
break;
default:
break;
}
}
How can I achieve this any key press information detection without if statement?

Best Solution - Use Input.inputString
You may use Input.inputString to catch the keyboard input entered in the last frame as a string.
void Update()
{
//get the input
var input = Input.inputString;
//ignore null input to avoid unnecessary computation
if (!string.IsNullOrEmpty(input))
//logic related to the char pressed
Debug.Log("Pressed char: " + Input.inputString);
}
Other solutions
Foreach Loop
You might use foreach loop approach, like suggested in other answers, but it is not as performant. Foreach allocates more memory and must check against all possible keys (it is also less readable).
If you do not care about time and memory performance, then you might follow this answer. It uses the foreach loop approach and create a reusable interface.
OnGUI
Finally you could catch the Event.current (that is a unityGUI Event), like explained in this answer, but doing so you would rely on the OnGUI method. This method has the worst performance.

foreach(KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKey(kcode))
Debug.Log("KeyCode down: " + kcode);
}
Also you can cache the value of Enum.GetValues(typeof(KeyCode)) for optimization.

I've not used Unity, however, I understand your problem and I am a C# developer.
From a quick search I have found someone on Unity forums with a similar problem to you. Here is the thread https://answers.unity.com/questions/1520939/check-if-there-is-a-keyboard-input.html.
if (Input.anyKeyDown)
{
Event e = Event.current;
if (e.isKey)
{
Debug.Log("Current Key is : " + e.keyCode.ToString());
}
}
The code above (from the Unity forum link) enables you to detect input.anyKeyDown (keyboard and mouse). Then you can filter the mouse detections by checking if the input was only a keyboard input with e.isKey
Here is documentation for KeyCode. This also includes all the properties available to it (many keyboard related properties that you can potential check against).
For example (not tested):
Event e = Event.current;
if (e.isKey)
{
Debug.Log("Current Key is : " + e.keyCode.ToString());
if(e.keyCode == KeyCode.A) //checks if the keycode returned equals the 'A' key
{
// Do something
}
}
EDIT: As mentioned by the other answer you can try Input.inputString. According to the documentation insputString contains "Only ASCII characters". So for example you could do something like this in the 'Update' method if letters was what you were only looking to check.
void Update()
{
//get the input
var input = Input.inputString;
//ignore null input to avoid unnecessary computation
if (!string.IsNullOrEmpty(input))
{
switch(input)
{
case 'a': break;
case 'b': break;
}
}
}
Hope this can help.

Related

Execute specific blocks of code based on which key on the keyboard is pressed

I am very new to the programming world and recently dove into c#. I don't want to waste your time so I'll get right to it. I wanted to create a program just to test my knowledge, and thought I could attempt to execute specific blocks of code based on which key on the keyboard is pressed by the user. I tried doing this by creating an event handler that contained if statements, but then realized I didn't know how to have the event handler active in the program.
For example, and as you can see in the below snippet, after the WriteLine in Line 5 lets say I wanted to raise the EventKeyPress event so that it waits for user input and reads the key they have pressed and reacts accordingly, how would I do that?
Again, I'm almost a complete beginner and have searched around for explanations about event handlers for hours and still can't wrap my head around what I am supposed to do or if I am even using the event handler correctly. Thanks in advance!
static void Main();
{
if (search == "Ball")
{
Console.WriteLine("Press enter to exit or backspace to return to the search bar")
// RIGHT HERE
}
else
{
Console.WriteLine("Sorry, I don't recognize {0}", search);
}
void EventKeyPress(object sender, KeyPressEventArgs e)
{
for (int i = 0; i < 1;)
{
if (e.KeyChar == (char)Keys.Enter)
{
// exit app
}
else if (e.KeyChar == (char)Keys.Back)
{
// go back to search
}
else
{
i = 0; // error
}
}
}
}
So, you're asking for something that involves Threading which is not a beginner thing to accomplish at all. The best way to do this for a beginner is to ask for a prompt, then accept as an input. For example.
Console.WriteLine("Hello, what's your name?");
string nameStr = Console.ReadLine();
Console.WriteLine($"Hello, {nameStr}");
You can then use your variable and apply it to an if/while or whatever kind of conditional.
if (nameStr == "Matt"){
//Do This Code.
}
Once you have that code, add a sequential method that will ask the user to return to the main menu or whatever you want it to do.
Main.ReturnMenu(); //Or whatever you want to use.

How to solve a IndexOutOfRange made by the user?

I'm still new to programming, so every time i get an exeption i try to rewrite code so it is avoided. However in this case i see no way to work around it.
I have a textbox that the user uses to imput commands. The string(imput) is then split after the first space.
private void tbxMainImput_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
string commandText = tbxMainImput.Text.ToLower();
string[] commandTextSplitted = commandText.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
ReadTextboxImput(commandTextSplitted);
tbxMainImput.ResetText();
e.SuppressKeyPress = true; //anoying beep is removed :)
}
}
this splitted string commandTextSplitted is being used by a switch method ReadTextboxImput
private void ReadTextboxImput(string[] imput)
{
switch (imput[0])
{
//some other cases
case "attack":
StartCombat(imput[1]); //trows exeption if user only types one word
break;
}
}
If a player only types one word, imput[1] doesnt exist, and an IndexOutOfRange exeption is cast(as it should). However the exeption seems unavoidable. the player can type one word and press enter...
so ive been trying some things to check for the exeption and then break out of the code but it doesnt seem to work. The msdn website isn't realy beginners friendly, and all i found on stackoverflow where people asking to find where the error came from. witch i know.
So far i have tried:
case "attack":
if (imput[1] == null) //(imput[1] == system.IndexOutOfRange) doesnt make sense but i had to try
{
rtbOutput.AppendText("Yes yes. Attack nothing...");
break;
}
StartCombat(imput[1]);
break;
i made a method that uses try and catch that worked, but it just detected the error, i wasn't able to do anything with it(like return a false, or something)
Any help would be apreciated.
you can check if the array length is > 1 instead of imput[1] == null
if (imput.Length > 1){
rtbOutput.AppendText("Yes yes. Attack nothing...");
break;
}
StartCombat(imput[1]);
break;

Process is terminated due to StackOverflowExeption - C#

I have this problem with my code I cant fix.
I am making a quiz, but the questions mustnt be asked twice so I avoided that, but when it runs out of options it crashes.
It also could be the code after it, but I dont think so.
Here is my code:
private static void chooseQuestion()
{
Random randomQuestion = new Random();
int returnValue = randomQuestion.Next(1, 3);
switch (returnValue)
{
case 1:
if (randomValues.questionOneChosen != 1)
{
questionOne();
}else
{
chooseQuestion();
}
break;
case 2:
if (randomValues.questionTwoChosen != 1)
{
questionTwo();
}else
{
chooseQuestion();
}
break;
}
endQuiz();
}
and here is what is after it:
private static void endQuiz()
{
Console.Clear();
Console.WriteLine();
text.centered("You completed the QUIZ, well done!");
Console.WriteLine();
text.centeredWrite("Press ENTER to go back to the menu");
string input = Console.ReadLine();
if (input == "")
{
Menu.main();
}else
{
endQuiz();
}
}
If you need more code to help me, please ask me.
Thanks in advance!
A StackOverflowException on StackOverflow, nice!
Does Menu.main() end up calling chooseQuestion()?
When a function is called, a new entry on the stack is created with room for all its local variables and the address to return to when it returns. If a function calls itself (recursive call), its original stack entry is not released. If it calls itself often enough without returning, the stack will eventually run out of room and give this exception. Having said that, the stack is pretty big - I think the default is 1 megabyte - so you need a lot of recursive calls to exhaust it.
You've got two functions which both call themselves. If they do it often enough, you'll run out of stack space. Just replace the recursive calls with a loop. Here's your first function:
private static void chooseQuestion()
{
bool endQuizChosen = false;
while ( !endQuizChosen ) {
Random randomQuestion = new Random();
int returnValue = randomQuestion.Next(1, 3);
// ... the rest of the function ...
endQuizChosen = endQuiz();
}
}
and edit endQuiz() to not call itself but to return true if user wants to stop and false if they want to go on.
Your chooseQuestion method's logic goes like this:
a. Pick a 1 or 2, randomly
b. If 1, and I haven't asked question 1 yet, show question 1
c. if 1, and I have asked question 1, go to step (a)
d. repeat (b) and (c) for question 2
...
once you answer both questions, you try to get another random question. But there are no more questions available. So you recurse into an exception.
Don't write your logic this way. Use a collection, and remove the item from the collection after you've shown that question. When the collection is empty, you're done.
This is never getting set.
randomValues.questionOneChosen
So whatever it is, if it's not 1 or 2 the method is going to call itself again. It's probably always zero.

Something is wrong with my code

I am making a music maker program in C# (visual studio).
Here is my code:
int accCount = 0;
enum accidental { flat, sharp, none }
accidental thisAcc = accidental.none;
if (keyComboBox.SelectedItem.ToString().Length < 8)
{
MessageBox.Show("Please select a key!");
}
else switch (keyComboBox.SelectedItem.ToString())
{
case "C major - A minor":
accCount = 0; thisAcc = accidental.none;
break;
case "G major - E minor":
accCount = 1; thisAcc = accidental.sharp;
break;
...etc..
}
and so on...This all is included in postButton_click(postButton_Click(object sender, EventArgs e)
But when I click the button, an exception is shown (An unhandled exception of type 'System.StackOverflowException' occurred in Program.exe)And if I select "break", this line is selected:
object key(int count, accidental ac) (here is the cursor){
return key(0, accidental.none);
}
Does anyone know what is wrong?Sorry if this question is not specific enough, just tell me.
Well yes, look at this code (reformatted from your question for readability):
object key(int count, accidental ac)
{
return key(0, accidental.none);
}
That will just invoke the same method... which will invoke the same method... which will invoke the same method etc, until it runs out of stack space.
It's not clear what you intended to return from this method, but you need to stop recursing in this infinite way.
A stackoverflow means that you have some unbound recursion in your application. In English this essentially means you're calling a method again and again.
Can you see how you're calling your method key within itself?

Chip8 Emulator - User Input

I have been writing a chip8 Emulator -- http://en.wikipedia.org/wiki/CHIP-8
I have tested all of the opcodes as well as the graphics calculations and I am now struggling with the user input. I have the following method monitoring user input and altering the registers as needed (When using the chip8 the user input alters the corresponding memory register - E.G. hitting '0' sets the V0 register to 0.
My problem is that I have the following code fetching and calculating each opcode and its operation contained in a while loop. And while this is running my application cannot detect user input. So the ROMS start and just stay locked in place waiting on a register change or user input. It keeps getting stuck in an infinite loop, I tried to implement a global Boolean RUN, and it is not detected after the while loop is initiated. I'm assuming it is out of the scope of the loop, but from what I have read, the keyboard event triggers an interrupt that should be visible from almost anywhere, any Thoughts?
This is what calculates and parses the opcode
private void button1_Click(object sender, EventArgs e)
{
// This will become the run function
do{
for (int i = 0; i < 2; i++)
{
opc[i] = mem[mc]; // fetching the instruction from the memory array
mc++;
}
cibox.Clear(); // Just clearing Debugging text boxes in the UI
pcbox.Clear();
pc++;
pcbox.Text += pc;
cibox.Text += opc[0].ToString("X2") + "-" + opc[1].ToString("X2");
calculations(opc); // Parses the Opcode and does the corresponding operation
}while(run);
}
And this method is controlling the user input...
protected override void OnKeyDown(KeyEventArgs keyEvent) // Listens for Keyboard events! Read More: http://www.geekpedia.com/tutorial53_Getting-input-from-keyboard.html
{
keyPress = true;
//Gets the key code found at keyEvent...
MessageBox.Show("KeyCode: " + keyEvent.KeyCode.ToString());
String register = keyEvent.KeyCode.ToString();
if (register == "Escape")
{
Application.Exit();
run = false;
}
try
{
registerVal = int.Parse(register, System.Globalization.NumberStyles.HexNumber); // Second Nibble! --> Int Format
}
catch (System.ArgumentNullException e)
{
return;
}
catch (System.ArgumentException)
{
return;
}
catch (System.FormatException)
{
return;
}
catch (System.OverflowException)
{
return;
}
if (registerVal >= 208)
{
registerVal = registerVal - 208;
}
if (registerVal <= 15)
{
mem[registerVal] = (byte)registerVal;
}
display(); // Alters UI to display state of registers, etc
}
So I have now tried the Game Loop Idea, but I cannot find a way to make a method in C# that will return a key press. Maybe I am missing something here, but I cannot seem to figure it out!
I also tried another method involving running the CPU calculations in a separate thread, and this is causing a slight delay issue.
I would really like to see an example of a method in C# that returns the value of a key being pressed that I can call within the While loop!
I suggest you set up your emulator's loop like a game loop. You have one global loop which triggers updates to each module in your emulator. In the loop, you call your input (or generic "event") processor, then your opcode/hardware emulation, then your screen update.
Here's some pseudo-code.
while (True):
processInput()
updateCPU()
outputGraphics()
I don't know how the key input works in C#, if it's an asynchronous event trigger (i.e. the "OnKeyDown" method gets called outside of your loop), you can set up "OnKeyDown" to just send the key events to an intermediate event manager, then in "processInput()" you actually resolve the events and use them to update registers on the emulated CPU etc.

Categories