I am trying to make a controller for a game with SDL 2(didn't want to ask on gamedev since it is not a game issue directly) I use SDL_GetKeyboardEvent to see if the navigation arrows are being pressed but it apparently doesn't work, it is supposed to print a value 1 or -1 if one of those keys is pressed but it doesn't it just prints 0 even if I hold the key down for several seconds, it is like it doesn't detect that the key is being pressed. I searched all over the internet and this is how they do it, but it doesn't work for me.
#define SDL_MAIN_HANDLED
#include <stdio.h>
#include "SDL.h"
/* I'll add some code later
so something that isn't used
might be initialized
*/
int main (void)
{
int a = 1;
int x;
int z;
SDL_Event quit;
const Uint8 *keys = SDL_GetKeyboardState(NULL);
SDL_Init(SDL_INIT_VIDEO);
while(a)
{
SDL_PollEvent(&quit);
if(quit.type == SDL_QUIT)
a = 0;
if(keys[SDL_SCANCODE_UP])
z = 1;
else if(keys[SDL_SCANCODE_DOWN])
z = -1;
else
z = 0;
if(keys[SDL_SCANCODE_LEFT])
x = -1;
else if(keys[SDL_SCANCODE_RIGHT])
x = 1;
else
x = 0;
printf("%d, %d\n", x, z);
//This is supposed to print
//x, z values so if up arrow is pressed it will print 0, 1 and if
//down arrow is pressed it will print 0, -1: the same with horizontal ones.
//1 or -1, 1 or -1
}
SDL_Quit();
return 0;
}
Read the documentation: wiki
Note: This function gives you the current state after all events have been processed, so if a key or button has been pressed and released before you process events, then the pressed state will never show up in the SDL_GetKeyboardState() calls
What it means is?
You need to process all events. How? Looping the PollEvent, after the loop (or if you want to check in the loop, check at the end), the SDL_GetKeyboardState is usable.
So, go through the loop, check for keyboards states. Do not forget to always go through the loop before checking for keys
e.g.
while (game)
{
/*! updates the array of keystates */
while ((SDL_PollEvent(&e)) != 0)
{
/*! request quit */
if (e.type == SDL_QUIT)
{
game = false;
}
}
if (keys[SDL_SCANCODE_RIGHT])
std::cout << "Right key";
}
You'll need to create a window with SDL_SetVideoMode to get mouse and keyboard events.
Here is my InputManager update function that updates the user input from the keyboard and mouse. Notice the const_cast needed to be able to update the class variable Uint8* keysArray;. This way, more than one event can be processed at once.
void update() {
SDL_PumpEvents();
// update keyboard state
keysArray = const_cast <Uint8*> (SDL_GetKeyboardState(NULL));
if (keysArray[SDL_SCANCODE_RETURN])
printf("MESSAGE: <RETURN> is pressed...\n");
if (keysArray[SDL_SCANCODE_RIGHT] && keysArray[SDL_SCANCODE_UP])
printf("MESSAGE: Right and Up arrows are pressed...\n");
// update mouse location and button states
SDL_GetMouseState(&x, &y);
getMouseButtonStates();
}
Related
I'm making a whack-a-mole program, and currently I have the setup for the mole to appear and disappear at random; however, while this is all going on I'll need to accept user input in order to "whack" the mole. Is there any way to do this without pausing the loop to wait for the user to input something, and rather have the loop run WHILE scanning for input? my code is below.
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
int main(){
// sets the mole to be initially under_ground
bool above_ground = false;
char mole_presence[1] = {0};
// keeps the mole running as long as the game is in play
while(1){
// while the mole is not above ground, wait until he randomly is
while(above_ground == false){
int r = rand() % 6;
if (r == 5){
printf("a mole has appeared, he's dancing around!\n");
mole_presence[0] = 1;
above_ground = true;
}
else{
printf("%d\n", mole_presence[0]);
sleep(1);
}
}
// while the mole is above ground, he dances until he randomly escapes
while(above_ground == true){
bool escaped = false;
// while he hasn't escaped, continue this loop
while (escaped == false){
int x = rand() % 10;
// if he randomly escapes, break out and show he is no longer above ground
if (x == 5){
printf("he disappeared!\n");
mole_presence[0] = 0;
escaped = true;
}
else{
printf("%d\n", mole_presence[0]);
sleep(1);
}
}
above_ground = false;
}
}
}
I faced the same problem while writing a snake-xenia kind of game. In Windows there is function called _kbhit which can be used to check whether the key is pressed or not. It's prototype is
int _kbhit(void)
Itreturns a nonzero value if a key has been pressed. Otherwise, it returns 0. Read more here : https://msdn.microsoft.com/en-us/library/58w7c94c.aspx
It's not available on linux as there is no conio.h in linux So for linux this answer can help Using kbhit() and getch() on Linux
i need to make somekind of "on-off" button with my project.
when the button not pressed, it supposed to print
stopped
if pressed
started
the problem is, when im not pressin it, it keep printin 'stopped', same when i keep pushin the button. i want it to only print the data once.
more detail, what i need is, the button hold the stay in 'STARTED' position until i press it again.
here is my code
{
int main (void)
int TestM4;
while(1)
{
if (!(PORTJ_IN&PIN1_bm)) //test m4
{
testM4 = 1;
printf("%d\n", testM4);
}
else
{
testM4 = 0;
printf("%d\n", testM4);
}
while(1)
This runs the while loop continuously.
So, it checks the buttons, prints out the statements, and then goes back straightaway to check them again.
To run it only once, remove the while loop altogether, but then the program will end pretty quickly.
Perhaps, look at ways to pause the program.
I don't know all the code, so while(1) could be good or bad code, but you can test as a flag to change it and print once only.
while(1)
{
if (!(PORTJ_IN&PIN1_bm)) //test m4
{
if(testM4 != 1) // status as button up
{
testM4 = 1;
printf("%d\n", testM4);
}
}
else
{
if(testM4 != 0)
{
testM4 = 0;
printf("%d\n", testM4);
}
}
}
I am getting major amounts of input lag when I run my application.
More details:
When I press 'w', 'a', 's', 'd' (My assigned input keys) the object moves however it continues to move for an extended period of time after the key has been released. The source code is below however small parts of the code have been cut out to shorten the questions however if the source code below does not compile I have all of the code up on github.
https://github.com/TreeStain/DodgeLinuxGame.git Thankyou for your time. -Tristan
dodge.c:
#define ASPECT_RATIO_X 2
#define ASPECT_RATIO_Y 1
#define FRAMES_PER_SECOND 60
#include <ncurses.h>
#include "object.h"
#include "render.h"
int main()
{
initscr();
cbreak();
noecho();
nodelay(stdscr, 1);
object objs[1];
object colObj; colObj.x = 10; colObj.y = 6;
colObj.w = 2; colObj.h = 2;
colObj.sprite = '*';
colObj.ySpeed = 1;
colObj.xSpeed = 1;
objs[0] = colObj;
//halfdelay(1);
while (1)
{
char in = getch();
if (in == 'w')
objs[0].y -= objs[0].ySpeed * ASPECT_RATIO_Y;
if (in == 's')
objs[0].y += objs[0].ySpeed * ASPECT_RATIO_Y;
if (in == 'a')
objs[0].x -= objs[0].xSpeed * ASPECT_RATIO_X;
if (in == 'd')
objs[0].x += objs[0].xSpeed * ASPECT_RATIO_X;
render(objs, 1);
napms(FRAMES_PER_SECOND);
}
getch();
endwin();
return 0;
}
render.h:
void render(object obj[], int objectNum);
void render(object obj[], int objectNum) //Takes array of objects and prints them to screen
{
int x, y, i, scrWidth, scrHeight;
getmaxyx(stdscr, scrHeight, scrWidth); //Get terminal height and width
for (y = 0; y < scrHeight; y++)
{
for (x = 0; x < scrWidth; x++)
{
mvprintw(y, x, " ");
}
}
for (i = 0; i < objectNum; i++)
{
int xprint = 0, yprint = 0;
for (yprint = obj[i].y; yprint < obj[i].y + (obj[i].h * ASPECT_RATIO_Y); yprint++)
{
for (xprint = obj[i].x; xprint < obj[i].x + (obj[i].w * ASPECT_RATIO_X); xprint++)
mvprintw(yprint, xprint, "%c", obj[i].sprite);
}
}
refresh();
}
object.h:
typedef struct
{
int x, y, w, h, ySpeed, xSpeed;
char sprite;
}object;
P.S. please feel free to critique my methods and code as I am fairly new at programming and can take all the criticism I can get.
I believe the reason is because getch() will only release one input-character at a time (even if there are many queued up in the input stream) so if they queue up faster than you 'remove' them from the stream, the loop will continue until the queue is emptied even after you release the key. Also, you'll want to go (1000 / FRAMES_PER_SECOND) to get your desired delay-time in milliseconds (this creates 60 frames per second).
Try this in your while loop instead.
while (1)
{
char in;
/* We are ready for a new frame. Keep calling getch() until we hear a keypress */
while( (in = getch()) == ERR) {}
if (in == 'w')
objs[0].y -= objs[0].ySpeed * ASPECT_RATIO_Y;
if (in == 's')
objs[0].y += objs[0].ySpeed * ASPECT_RATIO_Y;
if (in == 'a')
objs[0].x -= objs[0].xSpeed * ASPECT_RATIO_X;
if (in == 'd')
objs[0].x += objs[0].xSpeed * ASPECT_RATIO_X;
render(objs, 1);
/* Clear out any other characters that have been buffered */
while(getch() != ERR) {}
napms(1000 / FRAMES_PER_SECOND);
}
From the top of your loop: while( (in = getch()) == ERR) {} will call getch() rapidly until a keypress is detected. If a keypress isn't detected, getch() will return ERR.
What while(getch() != ERR) {} does is keep calling getch() until all buffered input characters are removed from the queue, then getch() returns ERR and moves on. Then the loop should sleep ~17ms and repeat. These lines should force the loop to only 'count' one keypress every ~17ms, and no more often than that.
See: http://linux.die.net/man/3/getch
Ncurses does not detect key presses and key releases separately. You cannot move an object while a key is being held, and stop immediately after it is released.
The phenomenon you observe results from a ximbination of two factors: an auto-repeating keyboard, and a buffering keyboard driver. That is, the user holds a key, this generates a large amount of key events, and they are buffered by the driver and given to your application as it asks for key presses.
Neither the driver nor keyboard auto-repeat feature are under control of your application. The only thing you can hope to achieve is to process key events faster than they come out of the keyboard. If you want to do this, you have to get rid of napms in your main loop and process key presses as they come, between frame repaints. There are many ways to do that but the most straightforward is to use the timeout function.
timeout (timeToRefresh);
ch = getch();
if (ch == ERR) refresh();
else processKey(ch);
You need to calculate timeToRefresh each time using a real time clock.
What would be the best and easiest(simplest) way to do this..?
I am writing code in C or Capel (Vector CANoe)
I have a switch on a panel which I have designed in Vector CANoe , turns a motor on and off (0 == off and 1 == on) and I want to turn the motor off when it reaches its limit .. to stop the motor burning out ! (we know it has reached its limit when the a sensor says that the limit is reached (sensor = 1 for limit reached and 0 for not reached)
How would I do this?
i want to do something like this
WHILE (clutchMotorPower==1 & sensorClutchDisengaged !=1)
break;
else clutchMotorPower==0
WHILE (clutchMotorPower==1 & sensorClutchEngaged !=1)
break;
else clutchMotorPower==0
I don't know much about the system you're working on, so this is going to be some bare-bones code. Anyway, let's go through this step-by-step.
Assumptions:
button is a variable that is 1 if the button is currently pressed and 0 otherwise.
motor is a variable that we set to 1 to turn the motor on, or 0 to turn it off.
sensor is a variable that is 1 when the sensor is activated, or 0 otherwise
First, we need code to toggle the motor state when the button is pressed. (Assume all code samples are inside a function called from your main loop)
//values of static variables are preserved between function calls
static char bActivateMotor = 0; //1 if we should activate motor, 0 otherwise
static char bButtonHeld = 0; //1 if button was pressed last loop
//(to differentiate between button being held and it being released and pressed again)
if(!button) {
bButtonHeld = 0; //if button is not being pressed, it can't be being held down.
}
if(!bActivateMotor) { //we aren't running the motor
if(button && !bButtonHeld) { //button was pressed this loop (not held from previous loop)
bButtonHeld = 1; //Don't toggle motor state next loop just because button was held down
bActivateMotor = 1; //we should be running the motor
}
else {
motor = 0;
}
}
if(bActivateMotor) { //not else because could be activated this loop
if(button && !bButtonHeld) { //button toggles motor; if we're running, stop.
bButtonHeld = 1;
bActivateMotor = 0;
}
else {
motor = 1;
}
}
Now, the next part is to stop the motor when the sensor has activated:
//values of static variables are preserved between function calls
static char bActivateMotor = 0; //1 if we should activate motor, 0 otherwise
static char bButtonHeld = 0; //1 if button was pressed last loop
//(to differentiate between button being held and it being released and pressed again)
if(!button) {
bButtonHeld = 0; //if button is not being pressed, it can't be being held down.
}
if(!bActivateMotor) { //we aren't running the motor
if(button && !bButtonHeld) { //button was pressed this loop (not held from previous loop)
bButtonHeld = 1; //Don't toggle motor state next loop just because button was held down
bActivateMotor = 1; //we should be running the motor
}
else {
motor = 0;
}
}
if(bActivateMotor) { //not else because could be activated this loop
if(button && !bButtonHeld) { //button toggles motor; if we're running, stop.
bButtonHeld = 1;
bActivateMotor = 0;
}
/////////////////////
// Added Code Here //
/////////////////////
else if(sensor) {
bActivateMotor = 0; //motor will shut off next loop
}
else {
motor = 1;
}
}
With the lack of specifics about your code, it's hard to figure out exactly what difficulties you might be having, but hopefully the algorithm above will be a good starting point.
Problem: Upon spacebar press i need my projectile to fire and continue its life regardless of another press or letting go of the spacebar.
below is both the code adding, updating, and drawing the projectiles. I have tried numerous reworkings of this code but alas am not experienced enough to have found a suitable solution yet.
AddProjectile code below
enter code here
//add projectile if spacebar is pressed
private void AddProjectile(Vector2 position)
{
//i need somthing like this to make bullets autofire on phone
//while (TouchPanel.IsGestureAvailable)
//{
// Projectile projectile = new Projectile();
// projectile.Initialize(GraphicsDevice.Viewport, projectileTexture, position);
// projectiles.Add(projectile);
//}
if (currentKeyboardState.IsKeyDown(Keys.Space) ||
currentGamePadState.Buttons.A == ButtonState.Pressed)
{
Projectile projectile = new Projectile();
projectile.Initialize(GraphicsDevice.Viewport, projectileTexture, position);
projectiles.Add(projectile);
}
}
Update Projectile code below
private void UpdateProjectiles()
{
//update projectiles
for (int i = projectiles.Count - 1; i >= 0; i--)
{
if (currentKeyboardState.IsKeyDown(Keys.Space) ||
currentGamePadState.Buttons.A == ButtonState.Pressed)
{
//adds particle to first projectile but not again until the next fire butotn press
//particleEngine.EmitterLocation = new Vector2(projectiles[i].Position.X, projectiles[i].Position.Y);
projectiles[i].Update();
projectileOn = true;
}
//if projectiles not being fired remove them from the game screen
else
{
projectiles.RemoveAt(i);
}
}
}
the Draw method that draws projectiles to screen
//draw the projectiles
//***********************************************************
//using the if here allows control of projectiles to pass...
//...to the "currentstate of the spacebar (is pressed = fire)
/***/
if (currentKeyboardState.IsKeyDown(Keys.Space) ||
currentGamePadState.Buttons.A == ButtonState.Pressed)
{
for (int i = 0; i < projectiles.Count; i++)
{
projectiles[i].Draw(spriteBatch);
}
}
//remove projectiles and reset
if (currentKeyboardState.IsKeyUp(Keys.Space) ||
currentGamePadState.Buttons.A == ButtonState.Released)
{
UpdateProjectiles();
}
So, this is what i have so far and as stated can get the projectile to worl fine , i just cant get them to continue their life (until a collision or they reach the end of screen) once i let go of the keyboard spacebar.
A quick overview of the problems I see that are causing your isses:
You're checking if keys/buttons are pressed during your add, update, and draw methods.
If a key isn't pressed, you're removing the item during an update and not drawing it during a draw.
To accomplish what I think you're trying to accomplish, I'd do something along these lines (tailored and cleaned up for your needs, of course):
private void Update(GameTime gameTime)
{
// Only add a new projectile if Space or A is pressed
if (currentKeyboardState.IsKeyDown(Keys.Space) ||
currentGamePadState.Buttons.A == ButtonState.Pressed)
{
AddProjectile(); // some method that adds a new projectile to 'projectiles'
}
// Update all existing projectiles, regardless of button press.
// This will allow your projectiles to continue flying after they have been fired.
for (int i = 0; i < projectiles.Count; i++)
{
projectiles[i].Update();
if (projectiles[i].Dead) // check if projectiles[i] is out of bounds or has collided with something
{
projectiles.RemoveAt(i);
i--;
}
}
}
private void Draw(GameTime gameTime)
{
// Draw all existing projectiles, regardless of button press.
for (int i = 0; i < projectiles.Count; i++)
{
projectiles[i].Draw(spriteBatch);
}
}
Your space bar or A button is only used to fire a new projectile. You want that projectile to fly until it hits something or flies off the side of the screen, and it shouldn't depend on whether you have a button pressed in order to do that. Neither should drawing the bullet.
Make sense?