I have a problem with a program that uses forks. I have to do a simple game where I have 2 spaceships, one controlled by the user (only up and down) and one by the computer (which bounces every time it touches an edge). Each spaceship must be controlled by a different process. In addition to the ships it must be possible to shoot (bullet controlled by another process). I realized everything, the only problem is that I don't understand why the user-controlled spaceship doesn't fire, can someone tell me where am I wrong?
#include <stdio.h>
#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#define SHOOT 32 /*Sparare */
#define UP 65 /* Cursore sopra */
#define DW 66 /* Cursore sotto */
#define MAXX 80 /* Dimensione dello schermo di output (colonne) */
#define MAXY 20 /* Dimensione dello schermo di output (righe) */
#define DELAY 80000 /* Ritardo nel movimento delle vespe (da adattare) */
/* Prototipi funzioni adoperate */
void Enemy(int pipeout);
void Spaceship(int pipeout);
void Area(int pipein);
void Proiettile(int pipeout, int x, int y);
/* Struttura adoperata per veicolare le coordinate */
struct position {
char c; /* Identificatore dell'entità che invia i dati */
int x; /* Coordinata X */
int y; /* Coordinata Y */
};
/*
----------------------------------------------------------------------
Funzione principale del programma
----------------------------------------------------------------------
*/
int main()
{
int p[2]; /* Descrittori pipe */
int pidN; /* Pid 'Enemy' */
int pidA; /* Pid 'Spaceship' */
initscr(); /* Inizializza schermo di output */
noecho(); /* Imposta modalità della tastiera */
curs_set(0); /* Nasconde il cursore */
pipe(p); /* Creazione pipe */
/* Creo il primo processo figlio 'Enemy' */
pidN = fork();
/* Se il pid == 0 -> si tratta del processo 'Enemy' */
if(pidN==0) {
/* ed eseguo quindi la relativa funzione di gestione */
close(p[0]); /* chiusura del descrittore di lettura */
Enemy(p[1]); /* invocazione funzione nemico */
}
else {
/* Altrimenti sono ancora nel processo padre e creo il processo 'Spaceship' */
pidA=fork();
/* Se il pid == 0 -> si tratta del processo 'Spaceship' */
if(pidA==0) {
/* Visualizzo L'Spaceship nella posizione iniziale */
mvprintw(MAXY/2,0,"#");
/* ed eseguo quindi la relativa funzione di gestione */
close(p[0]); /* chiusura del descrittore di lettura */
Spaceship(p[1]); /* invocazione funzione astronave */
}
else {
/* Sono ancora nel processo padre */
close(p[1]); /* chiusura del descrittore di scrittura */
Area(p[0]); /* invocazione funzione area */
}
}
/* Termino i processi Spaceship e Enemy */
kill(pidN,1);
kill(pidA,1);
/* Ripristino la modalità di funzionamento usuale */
endwin();
/* Termino il gioco ed esco dal programma */
printf("\n\n\nGAME OVER\n\n\n");
return 0;
}
/*
----------------------------------------------------------------------
Funzione 'Enemy'
----------------------------------------------------------------------
*/
void Enemy(int pipeout)
{
struct position enemy;
//int deltax; /* Spostamento orizzontale */
int deltay=1; /* Spostamento verticale */
enemy.x = MAXX; /* Coordinata X iniziale */
enemy.y = MAXY/2; /* Coordinata Y iniziale */
enemy.c ='$'; /* Carattere identificativo */
/* Comunico le coordinate iniziali al processo padre */
write(pipeout,&enemy,sizeof(enemy));
while(1){
/* Se supero area Y schermo inverto il movimento */
if(enemy.y + deltay < 1 || enemy.y + deltay > MAXY){
deltay = -deltay;
}
/* Movimento Y */
enemy.y += deltay;
/* Comunico le coordinate correnti al processo padre */
write(pipeout,&enemy,sizeof(enemy));
/* Inserisco una pausa per rallentare il movimento */
usleep(DELAY);
}
}
/*
----------------------------------------------------------------------
Funzione 'Spaceship' - Movimento tramite i tasti cursore
----------------------------------------------------------------------
*/
void Spaceship(int pipeout)
{
struct position apos;
int p[2];
apos.x = 0; /* Coordinata X iniziale */
apos.y = MAXY/2; /* Coordinata Y iniziale */
apos.c='#'; /* Carattere identificativo astronave*/
int pidP;
/* Comunico al processo padre le coordinate iniziali dell'astronave */
write(pipeout,&apos,sizeof(apos));
/* Lettura dei tasti cursore */
while(1)
{
char c;
c = getch();
if (c==UP && apos.y > 0){
apos.y-=1;
}
if(c==DW && apos.y < MAXY - 1){
apos.y+=1;
}
if(c==SHOOT) {
pidP = fork();
if(pidP==0) {
flash();
mvprintw(apos.y+1,apos.x,"-");
refresh();
/* ed eseguo quindi la relativa funzione di gestione */
close(pipeout); /* chiusura del descrittore di lettura */
Proiettile(pipeout,apos.x,apos.y); /* invocazione funzione proiettile */
}
}
/* Comunico al processo padre le coordinate dell'astronave */
write(pipeout,&apos,sizeof(apos));
}
kill(pidP,1);
}
/*
----------------------------------------------------------------------
Funzione relativa al processo di visualizzazione e controllo
----------------------------------------------------------------------
*/
void Area(int pipein)
{
struct position enemy, spaceship, dato_letto, proiettile;
int collision=0;
do {
// Leggo dalla pipe /
read(pipein,&dato_letto,sizeof(dato_letto));
switch((char) dato_letto.c){
case '$': // Enemy /
// Cancello il precedente carattere visualizzato /
mvaddch(enemy.y,enemy.x,' ');
// Aggiorno le coordinate relative alla nuova posizione /
enemy=dato_letto;
break;
case '#' :
// Spaceship /
// Cancello il precedente carattere visualizzato /
mvaddch(spaceship.y,spaceship.x,' ');
// Aggiorno le coordinate relative alla nuova posizione /
spaceship=dato_letto;
break;
case '-' :
// Proiettile/
// Cancello il precedente carattere visualizzato /
mvaddch(proiettile.y,proiettile.x,' ');
// Aggiorno le coordinate relative alla nuova posizione /
proiettile=dato_letto;
break;
}
//if(enemy.x != 1 || enemy.y !=0 )
mvaddch(dato_letto.y,dato_letto.x,dato_letto.c);
refresh();
/* Il ciclo si ripete finchè le vite del contadino terminano */
} while(!collision);
}
void Proiettile(int pipeout,int x, int y)
{
struct position proiettile;
int pidP=getpid();
int deltax=1;
proiettile.x = x; /* Coordinata X iniziale */
proiettile.y = y; /* Coordinata Y iniziale */
proiettile.c='-';
write(pipeout,&proiettile,sizeof(proiettile));
while(1){
/* Se supero area X schermo inverte il movimento */
if(proiettile.x + deltax > MAXX){
//CHIUDI PROCESSO
kill(pidP,1);
}
/* Movimento X */
proiettile.x += deltax;
/* Comunico le coordinate correnti al processo padre */
write(pipeout,&proiettile,sizeof(proiettile));
/* Inserisco una pausa per rallentare il movimento */
usleep(DELAY);
}
}
This looks awfully suspicious:
close(pipeout); /* chiusura del descrittore di lettura */ Proiettile(pipeout,apos.x,apos.y); /* invocazione funzione proiettile */
The forked child closes file descriptor pipeout
, but then passes it to function Proiettile()
, which attempts to communicate with the other processes by writing to it. It's not clear to me why you're closing the FD, but that combination obviously won't work for the process running Proiettile()
to communicate anything.
I note that if you were properly checking the return values of your system calls, especially your write()
calls, then your program could have told you about the problem itself. Also, there are other issues here around the (lack of) protocol by which your various processes are communicating, and the risk of being torpedoed by partial writes and reads, but those are not what you asked about.