main()
Function
In the main()
function, we first call the initialization function init()
, and then enter the while()
loop. The loop mainly consists of three parts:
- Check the user's input: If the "w" key or the spacebar is pressed, the bird will move up two rows. If the "q" key is pressed, the game will exit. If the "z" key is pressed, the game will pause.
- Move the bird and redraw it.
- Check if the bird hits the pipes.
Let's take a look at the code:
int main()
{
char ch;
init();
while(1)
{
ch = getch(); // Get keyboard input
if(ch == ' ' || ch == 'w' || ch == 'W') // If spacebar or "w" key is pressed
{
// Move the bird and redraw it
move(bird_y, bird_x);
addch(CHAR_BLANK);
refresh();
bird_y--;
move(bird_y, bird_x);
addch(CHAR_BIRD);
refresh();
// If the bird hits the pipes, end the game
if((char)inch() == CHAR_STONE)
{
set_ticker(0);
sleep(1);
endwin();
exit(0);
}
}
else if(ch == 'z' || ch == 'Z') // Pause
{
set_ticker(0);
do
{
ch = getch();
} while(ch != 'z' && ch != 'Z');
set_ticker(ticker);
}
else if(ch == 'q' || ch == 'Q') // Quit
{
sleep(1);
endwin();
exit(0);
}
}
return 0;
}
In the main()
function, we first initialize the screen, and then receive keyboard input in a loop. If the "w" key or spacebar is pressed, the bird will move up two rows. If the "q" key is pressed, the game will exit. If the "z" key is pressed, the game will pause.
Now let's take a look at the init()
function:
void init()
{
initscr();
cbreak();
noecho();
curs_set(0);
srand(time(0));
signal(SIGALRM, drop);
init_bird();
init_head();
init_wall();
init_draw();
sleep(1);
ticker = 500;
set_ticker(ticker);
}
The init()
function first initializes the screen using functions provided by ncurses
. Then it calls several sub-functions to perform specific initializations. Note that we install a signal handler function drop()
, and set the timer interval.
Let's look at each initialization sub-function.
The init_bird()
function initialized the bird's position:
void init_bird()
{
bird_x = 5;
bird_y = 15;
move(bird_y, bird_x);
addch(CHAR_BIRD);
refresh();
sleep(1);
}
The init_head()
and init_wall()
functions initialize a linked list to store the pipes:
void init_head()
{
Node tmp;
tmp = (node *)malloc(sizeof(node));
tmp->next = NULL;
head = tmp;
tail = head;
}
void init_wall()
{
int i;
Node tmp, p;
p = head;
for(i = 0; i < 5; i++)
{
tmp = (node *)malloc(sizeof(node));
tmp->x = (i + 1) * 19;
tmp->y = rand() % 11 + 5;
p->next = tmp;
tmp->next = NULL;
p = tmp;
}
tail = p;
}
The init_draw()
function initializes the screen:
void init_draw()
{
Node p;
int i, j;
// Traverse the linked list
for(p = head->next; p->next != NULL; p = p->next)
{
// Draw the pipes
for(i = p->x; i > p->x-10; i--)
{
for(j = 0; j < p->y; j++)
{
move(j, i);
addch(CHAR_STONE);
}
for(j = p->y+5; j <= 23; j++)
{
move(j, i);
addch(CHAR_STONE);
}
}
refresh();
sleep(1);
}
}
With this, our flappy_bird game is complete.