I'm trying to have an "o" move down independent from user input. I plan on using user input for another object. Without the if statement, "o" will increase and go down. With a getch, the "o" moves only when there's an input.
while(1) {
clear(); // Clear the screen of all
// previously-printed characters
mvprintw(y, x, "o"); // Print our "ball" at the current xy position
int ch = getch(); //THE PROBLEM
// Move the player's ship left or right based on user input, currently controls the "o" IKNOW. IT's JUST TESTING. THAT"S BESIDES THE PROBLEM
if (ch == 'a') x--;
else if(ch == 'd') x ;
else if(ch == 'q') break;// quit option i
refresh();
usleep(DELAY);
// Shorter delay between movements
y ; // Advance the ball down
}
I tried different loops, putting the movement part into a different function, but I still require the movement to be in the while loop. I've been told the while(1) is for every 1 frame, but the output seems to be stuck on requiring an input to progress to the next frame. How could I move "o" independently?
CodePudding user response:
Read the edit
I'm keeping the original answer because it may be useful to someone with a similar problem that doesn't need multithreading.
I don't know exactly what you're trying to achieve, but hopefully this gets you a little closer to your goal. Really, all you need to do is add a timeout
of DELAY
milliseconds at the top of your main function.
This works, however it is perhaps not ideal -- the ship goes down 1 line every time the a/d keys are pressed. You can reverse this by adding a 'continue' after the if (ch == 'a'/'d') x--/ ; // continue;
(by reverse I mean "not move down at all when the a d keys are pressed")
This could be the behaviour you want, however a possibly better? solution could be to use multithreading (pthreads on *nix systems and I guess the Win32 API could do the same on Windows). I tried this, however you might need to do some more research because I couldn't get it working after a few minutes of trying (the ncurses library might not like multithreading or maybe I was doing something wrong [probably the latter]) (again, see edit).
#include <ncurses.h>
const int DELAY = 1000;
int x = 0;
int y = 0;
int main() {
initscr();
timeout(DELAY);
for (;;) {
clear();
mvprintw(y, x, "o");
int ch = getch();
if (ch == 'a') x--;
else if (ch == 'd') x ;
else if (ch == 'q') return 0;
y ;
}
return 0;
}
Hope this helps!
EDIT/UPDATE: I got the threaded version working
So, I have no idea why threads didn't work before, but now I have a working program that has none of the problems of the previous versions:
#include <ncurses.h>
#include <pthread.h>
#include <unistd.h>
const int DELAY = 1000000;
int x = 0;
int y = 0;
pthread_mutex_t y_mutex;
void *inc_y(void* ptr) {
for (;;) {
pthread_mutex_lock(&y_mutex);
y ;
pthread_mutex_unlock(&y_mutex);
usleep(DELAY);
}
}
void *draw(void* ptr) {
initscr();
timeout(1);
for (;;) {
int ch = getch();
if (ch == 'a') x--;
else if (ch == 'd') x ;
else if (ch == 'q') return 0;
clear();
mvprintw(y, x, "o");
}
}
int main() {
pthread_mutex_init(&y_mutex, NULL);
pthread_t inc_y_thread, draw_thread;
pthread_create(&inc_y_thread, NULL, inc_y, NULL);
pthread_create(&draw_thread, NULL, draw, NULL);
pthread_join(inc_y_thread, NULL);
pthread_join(draw_thread, NULL);
pthread_mutex_destroy(&y_mutex);
return 0;
}
Note that although I am not experienced with C multithreading and the mutex for y
may not be strictly necessary, however I think that it would be to make sure that while draw
is reading the y
variable, it is not also being written to.
CodePudding user response:
delaymove
will increment the row on a one second delay.
manualmove
will modify row and col based on user input. Arrow keys may be used as well as a
, d
, w
or x
.
These functions are called in a loop.
timeout
sets the milliseconds that getch
will wait for an input before returning ERR
.
#include <stdio.h>
#include <ncurses.h>
#include <time.h>
#define DELAY 1.0
#define BILLION 1E9
void delaymove ( int *x, int *y) {
static struct timespec start;
static double delay = 0.0;
struct timespec stop;
double elapsed;
if ( delay < .0001) {
clock_gettime ( CLOCK_REALTIME, &start);
delay = DELAY;
}
clock_gettime ( CLOCK_REALTIME, &stop);
elapsed = stop.tv_sec - start.tv_sec;
elapsed = ( stop.tv_nsec - start.tv_nsec) / BILLION;
if ( elapsed < delay) {
return;//if delay is still in effect
}
clock_gettime ( CLOCK_REALTIME, &start);
(*x);
}
int manualmove ( int *x, int *y) {
int ch = 0;
ch = getch(); // if no input before timeout, ch will be ERR
switch ( ch) {
case ERR:
break;
case 1:
while ( getch() != 1) {} //resume with another ctrl a
break;
case 'q':
return 1;
case KEY_LEFT:
case 'a':
if ( *y > 0) {
--(*y);
}
break;
case KEY_RIGHT:
case 'd':
(*y);
break;
case KEY_UP:
case 'w':
if ( *x > 0) {
--(*x);
}
break;
case KEY_DOWN:
case 'x':
(*x);
break;
}
return 0;
}
int main ( void) {
int row = 0;
int col = 0;
int rw = 0;
int cl = 0;
int r = 0;
int c = 0;
initscr ( );
noecho ( );
timeout ( 20); // milliseconds getch waits for a character
keypad ( stdscr, TRUE);
curs_set ( 0); // hide cursor
getmaxyx ( stdscr, row, col);
rw = 0;
cl = col / 2;
while(1)
{
r = rw;
c = cl;
delaymove ( &rw, &cl);
if ( manualmove ( &rw, &cl)) {
break;
}
if ( rw > row - 4) {
rw = row - 4;
}
if ( cl > col - 2) {
cl = col - 2;
}
move ( r, c);
printw ( " ");
move ( rw, cl);
printw ( "o");
refresh ( );
}
endwin ( );
return 0;
}