Console.ReadKey() looping by itself in while loop - c#

I have a loop and inside it a switch case which is basicly an user interface which lets people choose yes and now to continue a game with the left and right arrows.
i also added a Console.Beep() to give some feedback to the user. for some reason once the game ends(the game uses the arrows(its snake)) the option yes and no keep switching and i hear beeping about 10 to 20 times and then it stops.
Does anyone know the reason?
this is the code :
while (true)
{
Console.Clear();
Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~\n\n~~~~~~~~You Lost!~~~~~~~~\n\n~~~~~~~~~~~~~~~~~~~~~~~~~\nYour score was: " + SnakeBody.Count);
Console.WriteLine("\nDo you want to continue?\n\n " + (Continue ? ">YES / No" : " Yes / >NO"));
switch (Console.ReadKey().Key)
{
case ConsoleKey.LeftArrow:
if (!Continue)
{
Console.Beep(SoundFrequency, SoundLength);
Continue = true;
}
continue;
case ConsoleKey.RightArrow:
if (Continue)
{
Console.Beep(SoundFrequency, SoundLength);
Continue = false;
}
continue;
case ConsoleKey.Enter:
Console.Beep(SoundFrequency + 200, SoundLength);
if (Continue)
SnakeGame();
break;
default: continue;
}
break;
}

When you press and hold a key, it generates repeating keystrokes with a certain frequency and puts them into an input queue. It looks that when you play your game, you generate a lot of keystrokes this way, your application is unable to process them in time so even when you think you've completed playing, your application still has a lot (about 10 to 20 times as you write) of keys yet to process, that's the reason.

Related

How to allow a user to exit from the Console at any time C# with an input

I am very new to programming in C# so bare with me.
I am currently trying to make a block of code for a BMI Calculator within a menu based Console that allows the user to select from different options and it gives them different results.
I have not completed my code yet but everything has been relatively smooth sailing until I got to the point where I have been told -
"There should also be an option to ’exit‘ or terminate at any stage when the program is running."
I have looked on multiple forums and have tried to find an answer, none of which I have been able to get to work with my code.
I was hoping someone here would be able to help me out and point me in the right direction.
Here is the code I am currently working with.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BMI_Application
{
class Program
{
static void Main(string[] args)
{
bool showMenu = true;
while (showMenu)
{
showMenu = MainMenu();
}
}
private static void Calculator()
{
}
private static bool MainMenu()
{
string bmi = "You have selected the BMI Calculator";
float height;
float weight;
float sum1; // Heightx2
float sum2; // Weight / sum1
Console.WriteLine("Please select an option");
Console.WriteLine("1: BMI Calculator");
Console.WriteLine("2: Membership Rates");
Console.WriteLine("3: Close Menu");
Console.WriteLine("\r\nPlease enter 1, 2 or 3");
Console.WriteLine("\r\nYou can also write 'bye' at any time to leave");
switch (Console.ReadLine())
{
case "1":
Console.Clear();
Console.WriteLine(bmi);
Console.WriteLine("Please enter your Height in Metres");
height = float.Parse(Console.ReadLine());
Console.WriteLine("Please enter your Weight in Kilograms");
weight = float.Parse(Console.ReadLine());
sum1 = height * height;
sum2 = weight / sum1;
Console.WriteLine("Your BMI is : {0}", sum2); // Next part is - based on their BMI Level, writing if they are underweight etc
if (sum2 <= 18.5)
{
Console.WriteLine("Your BMI level indicates that your are 'Underweight' "); // Underweight
}
if (sum2 >= 18.5 && sum2 <= 25)
{
Console.WriteLine("Your BMI level indicates that you are 'Normal' weight"); // Normal
}
if (sum2 >= 25 && sum2 <= 30)
{
Console.WriteLine("Your BMI level indicates that you are 'Overweight' ");// Overweight
}
if (sum2 >= 30)
{
Console.WriteLine("Your BMI level indicates that you are 'Obese' "); // Obese
}
Console.WriteLine("\r\nPress any key to return back to main menu");
Console.ReadKey();
Console.Clear();
return true;
case "2":
Console.Clear();
Console.WriteLine("You have selected the Membership Rates");
Console.WriteLine("What Membership would you like?");
return true;
case "3":
Console.WriteLine("You have selected to close the menu, press any key to continue"); // Terminate
Console.ReadKey();
return false;
case "bye":
Console.WriteLine("Goodbye! Push any key to get out of here!");
Console.ReadKey();
return false;
default:
Console.Clear();
Console.WriteLine("That is not a valid number, please enter 1, 2 or 3"); // Not valid entry
Console.WriteLine(" ");
return true;
}
}
}
}
Any ideas of how I would be able to get a user to exit out of the console by entering the word 'exit' for example?
Thanks very much
So if you want to allow the user to enter a text such as "exit" to quit the program at any stage, then at every point where you read input you need to support this.
The way your code is structured at the moment then this is difficult as you basically have 1 method in your code which is doing everything. And you are actually mixing your "calculator" together with your "menu", which should be separated.
And if you look at your code then you will actually see that you are repeating sections of code multiple times with just slight differences (Writing and reading to/from console).
Instead, you need to structure your code so that you have less repeat of code and instead split this out into separate methods.
This is actually the crux of your program. Because the way your code is structured, you can't easily adapt it to support the new requirement without re-writing it.
Now I'm not going to re-write your code for you, but I will give you hints on one way to partly do this (there are other ways!)
Try and separate out the writing & reading into a separate method. Then you can also check for the word "exit" in a separate method.
So Pseudo code would be like this;
//do something in your method
var inputText = WriteAndGetInput("Please select option 1,2,3\r\nBlah blah blah \r\n");
CheckForExit(inputText);
//If you reach here, then Exit was not entered so carry on with your program and check for your real input.
//Try to use methods as to not repeat code.
//Method to write to console and get input
private static string WriteAndGetInput(string textToOutput)
{
Console.WriteLine(textToOutput);
return Console.ReadLine();
}
//method to check if user typed exit
private static void CheckForExit(string inputText)
{
if (inputText.Equals("exit"))
{
Console.WriteLine("You chose to exit. Goodbye!");
System.Environment.Exit(0);
}
}

(C# Monogame) When adding objects to a list, keyboard input lags for a frame

Basically, I have a list of enemy objects and timed events using gameTime.TotalGameTime.TotalSeconds. Every 0.1 seconds it calls upon a method to check for enemy spawns, and if we're at second 2.5 we add an enemy to the enemy list.
Now what happens is that keyboard input lags for a second, for example, if i'm moving continuously to the left, my character will stop for a short period (like 0.1 secs i think) before resuming moving.
I'm using gameTime to check for keyboard input every millisecond, but i've tried not using it too and it still happens. It's also weird because I have code that creates bullet objects every 0.5 seconds if i hold down Z the same way it does with enemies (through adding the object to a list), but that doesn't make it lagg the input
if (elapsedMs > oldElapsedMs + 0.001) //Millisecond update, for movement
{
oldElapsedMs = elapsedMs;
//Keys to be held down.
newState = Keyboard.GetState();
Keys[] pressed_Key = Keyboard.GetState().GetPressedKeys();
for (int i = 0; i < pressed_Key.Length; i++)
{
switch (pressed_Key[i])
{
case Keys.Escape:
this.Exit();
break;
case Keys.Left:
player.tryMoveLeft();
break;
case Keys.Right:
player.tryMoveRight();
break;
case Keys.Up:
player.tryMoveUp();
break;
case Keys.Down:
player.tryMoveDown();
break;
default:
break;
}
}
}
Spawn check code:
//0.1sec Update, spawning code
if (elapsedSpawnTime > oldElapsedSpawnTime + 0.1)
{
oldElapsedSpawnTime = elapsedSpawnTime;
spawnTimer += 1; //Every 0.1 sec add one to spawnTimer. The spawn timer int is what stage.Spawn() uses to check for spawns.
stage.Spawn();
}
my spawning method in my stage class:
public void Spawn()
{
switch (game.spawnTimer) //Each int is 0.1sec
{
//10 spawnTimer = 1 Second
case 40:
case 42:
case 44:
case 46:
game.enemyList.Add(new Enemy(game.enemySprite, 500, 500, 1, true));
break;
default:
break;
}
}
Thanks. If you want to help me but need more info you can add my skype # emil1000123
The code in the screenshot says
( elapsedMs > oldElapsedMs + 0.001 )
The variable names tell that those values are in milliseconds, so are you are checking every 0.001 milliseconds?
It seems that the issue lies in the millisecond update:
if (elapsedMs > oldElapsedMs + 0.001)
So, what happens if it gets at this statement, but havn't passed 1 millisecond yet?
A computer looks at code in ticks, those are way faster than milliseconds, and thus it'll ignore that statement at all, which can result in a tiny lag, depending on your PC's performance and file size (which will increase by adding arrays or lists)
Now, I don't know what you've used in the TryMoveLeft() (ect.) methodes. But I think you're better of my getting rid of the said if-statement. and try to rework the way how you player walks.
Maybe I might give a few tips if I can see how the player.TryMoveRight method looks like.

How does one cycle back to previous options in a C# console application?

To say I'm fresh off the boat would be an understatement. I think this solution is extremely simple for an experienced programmer, but I'm completely new to C# and coding in general, so I apologize if I offend anybody with my utter lack of comprehension. That being said, answers geared towards somebody completely new to coding would be appreciated. Basically, please assume no prior knowledge.
I'm working on a short text adventure as a learning experience. I'm trying to make a dialogue system where the player can choose three dialogue options:
Player says something -> NPC responds -> Player responds to NPC's response -> NPC responds again -> options cycle back to the three initial dialogue options
Player says something -> NPC responds -> options cycle back to the three initial dialogue options
Player ends dialogue -> options return to main dialogue options (which encases the following code)
This is what I've come up with so far:
//Talk to Smith
if (Input == "TALK TO SMITH")
{
{
Console.Clear();
Console.WriteLine("Initial discussion and character introduction");
Console.WriteLine("(Enter the corresponding number with what you want to say)");
Console.WriteLine("What would you like to discuss with Smith?");
}
do
{
correct = 0;
Console.WriteLine("1. Dialogue Option #1");
Console.WriteLine("2. Dialogue Option #2");
Console.WriteLine("3. Dialogue Option #3");
Input = Console.ReadLine().ToUpper();
if (Input == "1")
{
Console.Clear();
dialogue = 1;
correct = 1;
Console.WriteLine("Dialogue Option #1");
Console.WriteLine("Response #1");
Console.WriteLine("1. Dialogue Option #1A");
Console.WriteLine("2. Dialogue Option #1B");
Input = Console.ReadLine().ToUpper();
do
{
if (Input == "1")
{
dialogue = 0;
Console.Clear();
Console.WriteLine("Dialogue Option #1A");
Console.WriteLine("Response #1A");
Console.ReadKey();
correct = 1;
}
if (Input == "2")
{
dialogue = 0;
Console.Clear();
Console.WriteLine("Dialogue Option #1B");
Console.WriteLine("Response #1B");
Console.ReadKey();
correct = 1;
}
} while (correct == 1 && dialogue == 0);
}
if (Input == "2" && dialogue == 0)
{
Console.Clear();
dialogue = 1;
correct = 1;
Console.WriteLine("Response #2");
Input = Console.ReadLine().ToUpper();
}
if (Input == "3")
{
Console.Clear();
dialogue = 1;
correct = 0;
Console.WriteLine("Response #3");
Input = Console.ReadLine().ToUpper();
}
} while (correct == 1 && location == 1);
}
(This is only a part of the game's code, not the entire program itself)
The issue is that once I've chosen options #1A, #1B, or #2 the program does not cycle back to the dialogue with the NPC, but the main menu that I've set up. I've tried multiple methods, but none seem to work.
There's actually a formal concept in Computer Science that maps very well to what you're trying to do: a Finite State Machine.
The idea of a Finite State Machine is that it's a system that has a finite number of States that it can be in, the system is always in exactly one State, and each State contains a certain number of defined Transitions that put the system into a new State.
Dialogue trees are a very good fit for the FSM concept. The initial State of the system is the start of the dialogue, and each of the player's possible responses cause a Transition to a new State. It helps to formally model it like this:
State 0:
MessageBox(NPC001, "Is there anything else you need to know?")
Response "Where is the castle located?":
GotoState 1
Response "What sort of defenses does the castle have?":
GotoState 2
Response "Are we sure the Princess is being held in this castle?":
GotoState 3
Response "No, I think that's all.":
GotoState 4
State 1:
MessageBox(NPC001, "It is located two days' journey to the north, on the other side of the Dark Forest")
GotoState 0
State 2:
MessageBox(NPC001, "The castle is defended by monsters conjured forth by the Sorcerer King. Be sure to bring plenty of healing potions!")
GotoState 0
State 3:
MessageBox(NPC001, "Of course! What do you think this is, a Mario game?")
GotoState 0
State 4:
MessageBox(NPC001, "Farewell, heroes. May the Gods be with you on your journey!")
//no state transition here, so execution of the state machine ends at this point
Translating this outline into actual C# code is left as an exercise to the reader, but the basic idea is that each State is a method on the state machine object, and it continues running one method after another until it executes a method that does not end up telling it what the next State should be. (If you were using Boo, you could define a state machine macro and the outline above could literally be the code of your dialogue tree, but that's a whole other matter.)
Do a bit of research on the theory behind how a Finite State Machine works, and you'll find implementing things like this gets a whole lot easier.
EDIT:
Here's one way to implement a FSM for something like this.
class DialogueTree {
public void Execute()
{
int state = 0;
while (state >= 0)
{
switch (state)
{
case 0:
state = this.State0();
break;
case 1:
state = this.State1();
break;
//and so on
}
}
}
}
Each method would display some dialogue and choices, and return the next state for the state machine to go into based on the choice the player makes. To exit the conversation, a method should return -1. Does that help?
Remember, this is one possible way to do it. There are other implementations, some of which can be better or worse for certain applications of the State Machine concept.
It would require a restructuring of code, in particular to change the "linear" or "if then else" flow into a "display - response" loop.
The next dialog to be shown is captured in a state variable.
In each "display - response" cycle,
A prompt is displayed;
User response is captured;
Changes to program states are made, in order to encode the "knowledge" into the "story line";
The next dialog is chosen.
A simplified sketch of the code would look like this:
/// somewhere else
enum NextDialog
{
Smith,
Anderson,
Finished
}
NextDialog nextDialog = NextDialog.Smith;
while (nextDialog != NextDialog.Finished)
{
NextDialog nextNextDialog;
switch (nextDialog)
{
case NextDialog.Smith:
// Each handler is responsible for:
// (1) printing the prompt
// (2) getting the user response
// (3) converting the user response into state (program variable) changes, as well as determine the next dialog.
// Each handler will need access to object fields;
// these typically do not appear on the arguments list because
// all instance methods can access all object fields.
nextNextDialog = ProcessDialogSmith( ... );
break;
case NextDialog.Anderson:
nextNextDialog = ProcessDialogAnderson( ... );
break;
default:
throw new UnhandledException();
}
nextDialog = nextNextDialog;
}

Console.KeyAvailable is true, but Console.In.Peek() stalls

I'm making the game Snake. It's all working but if you press buttons too quickly it has an unfortunate behavior. Before I started attacking this issue, the code handled a single key press per loop iteration, and if you pressed a key multiple times in a row, it took that many loops before you could change direction.
My initial change was to read all the keys that have been pressed since the last game loop, and only apply the last one. This worked, but really, if I press two keys, I want them both to be applied. What I don't want is for me to be stuck going right because I pressed right three times.
So my next approach was to peek at the next inputted character and see if it's the same as the last one. If so, read it out of the stream, and try again.
My understanding is that Console.KeyAvailable returns true if there is any unread data in the input stream, and Console.In.Peek() returns the first character of data in the input stream, or else hangs until there is data there.
Here's my current code:
private static void UpdateDirection()
{
ConsoleKey key = ConsoleKey.Escape; // dummy key
Dir curDir = s_snakeDir;
lock (s_consoleLock)
{
if (Console.KeyAvailable)
{
key = Console.ReadKey(true).Key;
// ignore multiple key presses of the same direction
while (Console.KeyAvailable)
{
int next = Console.In.Peek();
if (next != (int)key)
{
break;
}
// read and ignore next character
Console.ReadKey(true);
}
}
switch (key)
{
// do stuff...
}
}
}
If I press two keys on the same loop, the game stalls. What happens (as far as I can tell) is it gets to int next = Console.In.Peek(); and waits for the next character.
What I don't understand is why Console.In.Peek() needs to wait. If Console.KeyAvailable is true, then there should be a character in Console.In's stream.
EDIT
I believe I've figured out the issue. Console.In.Peek() is looking for characters, not key presses, and the arrow buttons don't have characters associated with them. So my next question is how to do what I want to do.
I also made a snake multiplayer game (source code here) and i had exact the same poblem:
If somebody presses a key for a while then the direction is set very delayed...
I solved this problem with a keyBuffer and a keyCheck thread:
List<ConsoleKeyInfo> keyBuffer = new List<ConsoleKeyInfo>();
new Thread(() =>
{
while(true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (keyBuffer.Count > 0)
{
if (keyBuffer[keyBuffer.Count - 1] != key)
keyBuffer.Add(key);
}
else
keyBuffer.Add(key);
}
Thread.Sleep(1);
}
}).Start();
while(true)
{
if (keyBuffer.Count>0)
{
switch (keyBuffer[0].Key)
{
//SwitchSomeStuff
}
keyBuffer.RemoveAt(0);
}
//PlayGame
}
There's no conceivable point in not using Console.ReadKey(). You are only interested in the position of the keys to control the snake, not what letter they produce. WASD is ZQSD in France for example. And you get a use out of the cursor keys, you can't do that with Console.Read()

C# console tetris programming. Making the pieces move?

I'm trying to make my first game, a console tetris.
I have a class Block, that contains x and y integers. Then I have a class Piece : List<Block>, and a class Pieces : List<Piece>.
I can already randomly generate pieces, and make them fall one row per second. I still didn't get to collisions detection, but I think that I already know how to work it out later.
The problem is that I don't know how to control the pieces. I've read a bit about keyboard hooking and checked some tetris tutorials, but most of them are for windows forms, which really simplifies events handling and the such.
So... Could you please point me the beginning of the path to controlling the pieces on a console? Thanks!
public class Program
{
static void Main(string[] args)
{
const int limite = 60;
Piezas listaDePiezas = new Piezas(); //list of pieces
bool gameOver = false;
Pieza pieza; //piece
Console.CursorVisible = false;
while (gameOver != true)
{
pieza = CrearPieza(); //Cretes a piece
if (HayColision(listaDePiezas, pieza) == true) //if there's a collition
{
gameOver = true;
break;
}
else
listaDePiezas.Add(pieza); //The piece is added to the list of pieces
while (true) //This is where the piece falls. I know that I shouldn't use a sleep. I'll take care of that later
{
Thread.Sleep(1000);
pieza.Bajar(); //Drop the piece one row.
Dibujar(listaDePiezas); //Redraws the gameplay enviroment.
}
}
}
What you are looking for is non-blocking console input.
Here is an example:
http://www.dutton.me.uk/2009/02/24/non-blocking-keyboard-input-in-c/
Basically, you would check Console.KeyAvailable in your while loop and then move the piece according to what key was pressed.
if (Console.KeyAvailable)
{
ConsoleKeyInfo cki = Console.ReadKey();
switch (cki.Key)
{
case ConsoleKey.UpArrow:
// not used in tetris game?
break;
case ConsoleKey.DownArrow:
// drop piece
break;
case ConsoleKey.LeftArrow:
// move piece left
break;
case ConsoleKey.RightArrow:
// move piece right
break;
}
}
You could use a Low-Level Keyboard Hook as shown here

Categories