movement binding in c++ using ncurses - c++

I can't get this movement binding to work. I'm using the ncurses library, update_ch and oldch are global variables. KEYERR is a macro set to -120 (I just don't handle those keypresses). I'm trying to restrict the player so he can't hold up, down, left, or right, but he has to keep pressing them to move. It's not working, you can still hold the keys down and move. Any suggestions? My logic must be off.
if(update_ch != KEYERR)
{
oldch = update_ch;
}
update_ch = getch();
if(oldch == update_ch)
{
update_ch = KEYERR;
}

I'm trying to restrict the player so
he can't hold up, down, left, or
right, but he has to keep pressing
them to move.
I am pretty sure this isn't possible with curses. If I remember correctly curses only receives characters from a terminal. It doesn't control anything about the process.
Measuring the time between to such readings might give you a hint if the user is holding a key instead of continuously pressing. I mean, when you do a reading, record the following
Key read
Time of read (millisecond precision)
When you read a value, ask the following:
Is it the same as the last key ?
What's the difference between the current time and the time of the last read ?
If it's the same key and the time difference is smaller than some threshold you can decide he's holding the key down.

Related

Debounce user input in c++

we have a project on school, coding a volleyball - match as console application.
We should make input-output for teams and score etc, and bind keys to Team1-score+1, Team2-score-1 etc. That's fine. We use getch() to bind these keys.
My problem: If you for example press R and R is Team1-score+1 and hold this key, it will continue adding the score+1, and we should stop that so you need to press R again if you want to add another point.
I didn't find this solution anywhere!
Can anyone give an example how to fix it?
I am new on coding so I am inexperienced.
Thanks for help guys!
EDIT: I am using Windows 10, important part of my code:
while (true)
{
_kbhit();
char L = _getch();
if (L == 114)
{
score1 = score1 + 1;
}
else if (L == 99)
{
score1 = score1 - 1;
}
else if (L == 117)
{
score2 = score2 + 1;
}
else if (L == 110)
{
score2 = score2 - 1;
}
else if (L == 113)
{
L=="number" is the ascii-code for buttons r,u,c,n,q
getch() operates on stdio which effectively is just a bytestream coming/going from/into the OS. It doesn't have the concept of "key presses/releases". When you keep a key pressed the OS will start to autorepeat the pressed character. To make things worse for your use case, if you keep a key pressed, and then press another key, the key repeats of the first will cease.
Now there are ways to get raw key down/up events, but these involve OS specific programming interfaces; you didn't tell us which OS you're using, so it's a bit of guesswork there. Doing what you want to do in the console is somewhat possible, but it's awkward to use. For Windows see C++ console keyboard events, for Linux see Receiving key press and key release events in Linux terminal applications?
However I strongly suggest you don't even try to implement all that OS level key event interfacing yourself, and instead make use of a cross platform library that offers a framework for doing exactly what you want to do there. One of the most widely used frameworks these days is SDL http://libsdl.org/ – it will move you out of the console though (when it comes to games: good riddance, except if you're working on a rouge-like game).
If you are using the console then most operating systems will wait a second after you press a key before registering that key press again. You can try it now: press a key on your keyboard and see what the response is.
Making sure someone doesn't accidentally press a key twice is a problem that the OS takes care of, because otherwise every application taking keyboard input would need to code their own solution to the problem.
If you want to go further than what the OS does, you can use a timer in your program with the chrono library, and wait n seconds before allowing input to be registered again.

SDL - how to use single button as a switch between "on" and "off"?

Can this be done with SDL ?
What I mean is when you press F1 - "turn on the lights". When you press F1 for a second time - "turn off the lights", and so on.
A solution to this can be to keep a counter for the button and if it is pressed odd number of times - "turn on lights", if it is pressed even number of times - "turn off lights".
But if I have 12 buttons for different functions I don't think that's the optimal way to do it, because I will have to keep different counters for each of these 12 buttons.
Counter are not a bad idea, and I don't think that the optimal way too. If you use an int to do this, it only 4 byte per counter, so it's not that much.
But in my opinion, you can do this with a bool value, when the value is true, the button is active else, it's not. If will simplify your code too, because you will just need to implement a getter for your bool value, and you will be able to use it in your condition. On and off are binary option, because it's 0 or 1, so the bool represent that exactly.
And just for the conception of your software, you can make a class Button that contains that information and you just create an instance for each of your switches.

C++ - DirectSoundBuffer stop playing at specific location - no notifications

I'm using DirectSound's DirectSoundBuffer to play voice data that I am streaming over a network. The nature of voice/speech is that it doesn't necessarily constantly stream (it starts and stops) and it also can come in varying packet sizes (which makes it difficult to predict where the buffer should stop). I keep a StoppingPoint variable that keeps track of where in my buffer I have written up to (it also takes into account the circular nature of this buffer). If the StoppingPoint is reached, I would like to stop playing my buffer. Also, I StoppingPoint would also signify the point at which I'd also like to start writing from.
My buffer
|==============================|--------------------------|
^ ^ ^
| | |
Voice Data Stopping point Old/Garbage
data
Also, I can't use notifications, because in order to use a notification the buffer must be stopped. But in my case, it is very likely for more data to come in as the buffer is playing, thus pushing back my 'StoppingPoint` value.
What I currently have now is a function that is called every frame. This function, amongst other things, is checking where the Play cursor is. If the Play cursor is passed the StoppingPoint location, it stops the buffer, and moves the Play cursor back to the StoppingPoint location. This seems to work ok so far, but as you'd expect, the Play cursor quite often overshoots the StoppingPoint. This means a little bit of old/garbage data is played every time the end of the streamed data is reached.
I'm just curious as to if there is a way to stop playing a DirectSoundBuffer at a specific offset? What I would like is to write data to the buffer, then play, then have it stop precisely at the location described by my StoppingPoint variable without overshooting it.
Note: I haven't included any code because this is more of a high-level solution that I need. My implementation is incredibly straight forward, typical and for the most part it DOES work. I just need a nudge in the right direction to remove the overshooting of my StoppingPoint. Perhaps there is a function I can use? Or some other algorithm that is commonly used to achieve this?
I've come up with a solution, but I'm still interested in any feedback or alternative solutions. I'm not sure if the way I've done it is ok, but it seems to be producing the desired results. Although, my solution feels a little too convoluted...
1) Whenever I write data, I now write at either the Buffer's Write Cursor or the StoppingPoint - whichever is later. This is to avoid stopping, then later writing in that "untouchable" space between the Play Cursor and Write Cursor, whose data has already been dedicated to playback.
DWORD writeCursorOffset = 0;
buffer->GetCurrentPosition(NULL, &writeCursorOffset);
//if write cursor has passed stopping point, then we need to write from there.
//So update m_StoppingPoint to reflect the new writing position.
m_StoppingPoint = m_StoppingPoint > writeCursorOffset ? m_StoppingPoint : writeCursorOffset;
2) I added some silence after every single write, but I left StoppingPoint to point at the end of the actual voice data. Eg.
|==============================|*********|---------------------|
^ ^ ^ ^
| | | |
Voice data Stopping Silence Old/Garbage
Point Data
3) If the Buffer's Play Cursor passed the StoppingPoint, I would then stop playing the buffer. Even if the Play Cursor overshoots here, all it will play is silence.
//error checking removed for demonstration purposes
buffer->Stop();
4) Immediately after stopping I would update StoppingPoint to be equal to the end of the silence. This would ensure that when more speech data comes in, the buffer will not play any silence first.
//don't forget that modulo at the end - circular buffer!
m_StoppingPoint = (m_StoppingPoint + SILENCE_BUFFER_SIZE) % BufferSize;
|==============================|*********|-------------------|
^
|
Move Stopping
Point here
Again, if I've done anything glaringly evil here, please let me know!

How do I make something happen on the screen even without a key being pressed?

I am making Pacman in C++ with the Ncurses library. I am able to move Pacman with my code, but I want to move it so that pacman keeps moving even when I am not pressing any key and when I press another direction key, it changes direction. Right now, the pacman only takes one step when I press a key. Also I have to press a key 2 or 3 times before pacman moves in that direction.
if (ch==KEY_LEFT)
{
int b,row,column;
getyx(stdscr,row,column);
int h;
do // do-whileloop to move the pacman left until it hits the wall
{
column-=1;
mvprintw(row,column,">"); //print the ">" symbol
refresh();
waitf(0.1); //this pauses the game for 0.1sec
attron(COLOR_PAIR(1));
mvprintw(row,column,">");
attroff(COLOR_PAIR(1));
refresh();
waitf(0.1);
mvprintw(row,(b),"O"); //showing the open mouth of pacman
refresh();
waitf(0.1);
attron(COLOR_PAIR(1));a
mvprintw(row,column,"O");
attroff(COLOR_PAIR(1));
h = getch();
}
while(h == KEY_LEFT);
}
right = getch();
loop to move right in an if condition
up = getch();
loop to move up in an if condition
down = getch();
oop for moving down in an if condition.
The standard solution to this is the finite-state machine. The character has six or so possible states: standing, moving up, moving right, moving down, moving left, dead. Rather than a keypress directly moving the character, the keypress should change the character's state.
In such a small application, rather than implementing an incredibly flexible finite-state machine, you may use a very simple implementation as such:
enum PlayerState {
Standing,
MovingUp,
MovingRight,
MovingDown,
MovingLeft,
Dead
};
Then, inside your game loop you can add a very simple state check which then takes the appropriate action for the frame.
switch(state) {
case Standing:
break;
case MovingUp:
player.PositionY += 1;
break;
// ...
}
The last step is to hook input, which depends on your method of retrieving input. Using callbacks, an example is:
void KeyDown(Key k) {
switch(k) {
case UpArrow:
if(state != Dead)
state = MovingUp;
break;
case RightArrow:
if(state != Dead)
state = MovingRight;
// ...
}
}
You can see why in a larger project it would be important to implement a more flexible finite-state machine, but hopefully this example has given you an easy-to-understand idea.
You need an equivalent of kbhit, ie. a non-blocking getch. Which really gives the solution, set O_NONBLOCK on the input. See an example here. Once you have this, simply loop contiguously and just check for the key hit, w/o waiting on actual key press.
Function getch is blocked until some key is pressed. If you don't want to be blocked then call _kbhit before getch too make sure that there is something in input buffer.
EDIT: Take a look at ncurses functions nodelay and cbreak. They enable asynchronous input.
I suggest you take a look at the model-view-controller model, it will help you with this problems and all the other problems that you will have if you continue your program like this.
Edit: shortcut
To move your pacman continuously you will need a separate thread to control it and make it move. Take a look at pthreads for that.
If you keep only the user input in the main run loop of your program, the problem that you have to press the keys a few times will go away too (the problem here is that the processor has to be on the getch() line when you press the key, otherwise it will not be detected.
It is pretty easy
for each direction make 4 function
and inside the function,put in the other 3 direction function which get activated by kbhit.
and put a else statement in which it keeps moving forward if you do not hit a button i.e (!kbhit());
and then put all this in a loop.
If you do this for all the direction functions you should be able to get the desirable outcome.

Using SetKeyboardState along with GetKeyboardState in C++

I don't know how to write a good question here, but, basically, does anyone know where I can possibly find some C++ source code using these to actually set keyboard state? For some reason using it the way MSDN does on Windows 7 doesn't do...anything at all.
Basic code:
PBYTE keyState;
GetKeyboardState(keyState);
...
// Later on when I need to set the keyboard state (key pressed etc) back to original:
SetKeyboardState(keyState);
and ... nothing happens :(
From:
http://www.gamedev.net/community/forums/topic.asp?topic_id=43463
First off, GetKeyboardState() would be the wrong function to use because as Windows has a chance to process keyboard messages (whether you want it too or not) it updates the results of the keyboard's state for the next call to GetKeyboardState().
Here's a little function that I use to get the status of the keyboard's keys. Be carefull though, depending on how fast your main loop is, it may cause problems if you aren't expecting it.
You need to keep track of whether or not a specific key was pressed the last time you called the ReadKeyboard() function. If your loop polls the keyboard 30 times a second, then pressing a key once probably causes the key to be flagged 3 or 4 calls in a row. Rather confusing sometimes. Just thought I'd mention it.
void ReadKeyboard( char* keys )
{
for (int x = 0; x < 256; x++)
keys[x] = (char) (GetAsyncKeyState(x) >> 8);
}