使用叉子的微型游戏

Micro game using forks

我对使用分叉的程序有疑问。 我必须做一个简单的游戏,其中我有 2 艘宇宙飞船,一艘由用户控制(仅上下),另一艘由计算机控制(每次触及边缘时都会反弹)。 每艘宇宙飞船都必须由不同的进程控制。 除了船只之外,还必须可以射击(子弹由另一个进程控制)。 我明白了,唯一的问题是我不明白为什么用户控制的飞船不发射,谁能告诉我我哪里错了?

#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);
  }

  } 

这看起来非常可疑:

                    close(pipeout); /* chiusura del descrittore di lettura */
                    Proiettile(pipeout,apos.x,apos.y); /* invocazione funzione proiettile */

分叉的子进程关闭文件描述符 pipeout,但随后将其传递给函数 Proiettile(),该函数尝试通过写入它来与其他进程通信。我不清楚你为什么要关闭 FD,但这种组合显然不适用于进程 运行 Proiettile() 来传达任何信息。

我注意到,如果您正确地检查了系统调用的 return 值,尤其是 write() 调用,那么您的程序可能会告诉您问题本身。此外,这里还有其他问题围绕(缺乏)您的各种进程进行通信的协议,以及被部分写入和读取鱼雷攻击的风险,但这些不是您所问的。