questo è il codice del progetto che sarebbe una versione semplificata di space invaders con l utilizzo dei thread e dei semafori per la sincronizzazione. il problema(a parte la schermata disturbata) è che non mi visualizza mai tutti i nemici e dunque il gioco funziona male! poi oltretutto i nemici a volte spariscono riappaiono e si muovono in modo strano.
da compilare con le opzioni -lpthread , -lncurses
#include <stdio.h>
#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include<pthread.h>
#include<semaphore.h>
/* Codice dei tasti da utilizzare per il gioco*/
#define SINISTRA 68
#define DESTRA 67
#define SPARA 32
/* Dimensione dello schermo */
#define MAXX 80
#define MAXY 24
#define DIM_BUFFER 1000000
#define PASSO 1
//Numero di nemici da creare
#define NEMICI 1
/*Numero massimo di missili che si possono lanciare prima che i precedenti siano scomparsi dallo schermo
Deve essere multiplo di 2 perché ne vengono sparati 2 per volta*/
#define MAX_MISSILI 10000
/* Codice da associare ai vari oggetti da mostrare. Devono essere tutti diversi perché
* servono a indicare al controllo da chi arrivano i messaggi
*/
#define TIPO_ASTRONAVE 0
#define TIPO_NEMICO 1
#define TIPO_MISSILE 2
#define TIPO_BOMBA 3
typedef struct pos{
int tipo;
int numero;
int x;
int y;
int passo;
} posizione;
void * astronave(void * arg);
void * missile(void * arg);
void * nemico(void * arg);
void * nemico2(void * arg);
void * nemico3(void * arg);
void * bomba(void * arg);
void * controllo(void * arg);
posizione buffer[DIM_BUFFER]; // buffer condiviso
int inserisci = 0; // variabile che indica le posizioni occupate nel buffer
int preleva = 0; // variabile che indica le posizioni disponibili nel buffer
sem_t presenti, disponibili; // variabili che indicano il valore del semaforo, ovvero la presenza o meno di job disponibili
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // mutex per evitare la race condiction
int flag_tr[NEMICI], flag_su[NEMICI], flag_muori[NEMICI];
int flag_tr2[NEMICI], flag_su2[NEMICI], flag_muori2[NEMICI];
int flag_tr3[NEMICI], flag_su3[NEMICI], flag_muori3[NEMICI];
pthread_t astronave_id, nemico_id[NEMICI], controllo_id;
int main(){
initscr();
noecho();
curs_set(0);
sem_init(&disponibili, 0, DIM_BUFFER); // inizializzazione semaforo disponibili
sem_init(&presenti, 0, 0); // inizializzazione semaforo presenti
int nemici_counter=0, n;
for(n=0;n<NEMICI;n++){//inizializzazione flag comunicazione controllo
flag_tr[n]=0;
flag_su[n]=0;
flag_muori[n]=0;
flag_tr2[n]=0;
flag_su2[n]=0;
flag_muori2[n]=0;
flag_tr3[n]=0;
flag_su3[n]=0;
flag_muori3[n]=0;
}
pthread_create(&astronave_id, NULL, &astronave, NULL);
while(nemici_counter<NEMICI){
if (pthread_create(&nemico_id[nemici_counter], NULL, &nemico, &nemici_counter)!=0){
perror("Errore!");
}else
nemici_counter++;
}
pthread_create(&controllo_id, NULL, &controllo, NULL);
pthread_join(controllo_id, NULL);
getchar();
endwin();
return 0;
}
void * controllo(void * arg){
/*Strutture in cui salvare le posizioni degli oggetti da mostrare*/
posizione valore_letto, astronave;
posizione nemici[NEMICI];
posizione bombe[NEMICI];
posizione missili[MAX_MISSILI];
pthread_t nemico2_id[NEMICI], nemico3_id[NEMICI];
/* Array di flag per lo stato dei missili. Il flag corrispondente a un missile vale 1 se ha colpito un nemico */
int missile_colpito[MAX_MISSILI];
// cont_nem com_nem; //Struttura per inviare messaggi ai nemici
char sch_astronave[4][6] = { //Disegno dell'astronave. Dimensione max: 6x6
{' ', ' ', ' ', 'A', ' ', ' '},
{' ', ' ', '[', 'O', ']', ' '},
{' ', '[', 'O', 'O', ']', ' '},
{'[', 'O', 'O', 'O', 'O', ']'},
};
int a_astronave = 4; //Altezza dell'astronave in caratteri
int l_astronave = 6; //Lunghezza dell'astronave in caratteri
int livello_nemici[NEMICI]; //Fase di vita dei nemici 0: Morto, 1: Primo livello, 2: Secondo livello
int nemici_colpiti[NEMICI], nemici1l_colpiti[NEMICI]; //Array di flag che indicano che il nemico n-simo è appena stato colpito da un missile
int nemici2l_colpiti[NEMICI], nemici3l_colpiti[NEMICI]; //Numero di colpi ricevuti da ciascuna navicella di secondo livello
int len_nem_1 = 3; //Caratteri occupati dal nemico nella sua prima fase
int len_nem_2 = 3; //Caratteri occupati dal nemico nella sua seconda fase
int len_nem_3=3;
int nemici_distrutti = 0; //Tiene il conto dei nemici distrutti. Quando è uguale a max_nemici il giocatore ha vinto
int game_over = 0; //0: Gioco in corso, 1: Perso, 2: Vinto
int i, j, k; //Contatori vari;
//Inizializzazione delle strutture per memorizzare lo stato del gioco
for(i = 0; i < NEMICI; i++){
nemici[i].x = -1;
nemici[i].y = -1;
bombe[i].x = -1;
bombe[i].y = -1;
livello_nemici[i] = 1;
nemici_colpiti[i] = 0;
nemici1l_colpiti[i]=0;
nemici2l_colpiti[i] = 0;
nemici3l_colpiti[i]=0;
}
for(i = 0; i < MAX_MISSILI; i++){
missili[i].x = -1;
missili[i].y = -1;
missile_colpito[i] = 0;
}
astronave.x = -1;
astronave.y = -1;
do{
sem_wait(&presenti);
pthread_mutex_lock(&mutex);
valore_letto = buffer[preleva];
preleva=(preleva+1)%DIM_BUFFER;
sem_post(&disponibili); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
/* CONTROLLO ASTRONAVE */
if (valore_letto.tipo == TIPO_ASTRONAVE){
/* Cancellazione dell'astronave nella posizione precedente */
if (astronave.x >= 0)
for (i = 0; i < a_astronave; i++)
for (j = 0; j < l_astronave; j++)
if(sch_astronave[i][j] != ' ')
mvaddch(astronave.y + i, astronave.x + j, ' ');
astronave = valore_letto;
/* Disegno dell'astronave e controllo di eventuali collisioni con bombe lanciate dai nemici*/
for (i = 0; i < a_astronave; i++)
for (j = 0; j < l_astronave; j++)
if(sch_astronave[i][j] != ' '){
mvaddch(valore_letto.y + i, valore_letto.x + j, sch_astronave[i][j]);
for (k = 0; !game_over && k < NEMICI; k++)
if (bombe[k].y != -1 && valore_letto.y + i == bombe[k].y && valore_letto.x + j == bombe[k].x)
game_over = 1;
}
}
/* FINE CONTROLLO ASTRONAVE */
/* CONTROLLO MISSILI */
if (valore_letto.tipo == TIPO_MISSILE){
if(missili[valore_letto.numero].x >= 0)
/* Cancellazione del missile nella posizione precedente */
mvaddch(missili[valore_letto.numero].y, missili[valore_letto.numero].x, ' ');
missili[valore_letto.numero] = valore_letto;
/* Controlla se ha colpito un nemico
* Se il missile aveva già colpito un nemico, il processo associato è ancora attivo, per cui sta ancora generando
* le coordinate, ma affinché il comportamento sia realistico ci si aspetta che non oltrepassi il nemico
* che ha colpito e quindi viene ignorato.
*/
for (i = 0; !missile_colpito[valore_letto.numero] && i < NEMICI; i++){
/// Se nemico di primo livello Se nemico di primo livello
if (livello_nemici[i] == 1 && valore_letto.y == nemici[i].y){
/* Il missile occupa un carattere, ma il nemico no, quindi si confrontano le coordinate del missile con tutta la lunghezza del nemico */
//for(j=0;!missile_colpito[valore_letto.numero]&&j<max_nemici;j++){
if (nemici1l_colpiti[i] < 2){
/* k rappresenta l'offset per controllare se il missile si trova all'interno della navicella */
for (k = 0; !missile_colpito[valore_letto.numero] && k < len_nem_1; k++)
if (valore_letto.x == nemici[i].x + k){
missile_colpito[valore_letto.numero] = 1;
nemici1l_colpiti[i]++;
nemici_colpiti[i] = 1;
}
/* Se una navicella è stata colpita dal missile, la cancella */
if (missile_colpito[valore_letto.numero])
for(k = 0; k < len_nem_1; k++)
mvaddch(nemici[i].y, nemici[i].x+ k, ' ');
}/// fine se minore di due
}/// Fine if se primo livello
/// se di secondo livello
if (livello_nemici[i] == 2 && valore_letto.y == nemici[i].y){
if (nemici2l_colpiti[i] < 3){
/* k rappresenta l'offset per controllare se il missile si trova all'interno della navicella */
for (k = 0; !missile_colpito[valore_letto.numero] && k < len_nem_2; k++)
if (valore_letto.x == nemici[i].x + k){
missile_colpito[valore_letto.numero] = 1;
nemici2l_colpiti[i]++;
nemici_colpiti[i] = 1;
}
/* Se una navicella è stata colpita dal missile, la cancella */
if (missile_colpito[valore_letto.numero])
for(k = 0; k < len_nem_1; k++)
mvaddch(nemici[i].y, nemici[i].x+ k, ' ');
}/// fine se minore di due
}/// Fine if se secondo livello
//}/**
/** Se il nemico è di terzo livello controlla subito che siano sulla stessa riga */
if (livello_nemici[i] == 3 && valore_letto.y == nemici[i].y){
/* Prima controlla che la navicella non sia già stata distrutta */
if (nemici3l_colpiti[i] < 4){
/* k rappresenta l'offset per controllare se il missile si trova all'interno della navicella */
for (k = 0; !missile_colpito[valore_letto.numero] && k < len_nem_3; k++)
if (valore_letto.x == nemici[i].x + k){
missile_colpito[valore_letto.numero] = 1;
nemici3l_colpiti[i]++;
nemici_colpiti[i] = 1;
}
/* Se una navicella è stata colpita dal missile, la cancella */
if (missile_colpito[valore_letto.numero])
for(k = 0; k < len_nem_2; k++)
mvaddch(nemici[i].y, nemici[i].x+ k, ' ');
}
}/// fine se livello tre
}/// fine for (i = 0; !missile_colpito[valore_letto.numero] && i < max_nemici; i++){
/* Disegno del missile */
if (!missile_colpito[valore_letto.numero]) //Non lo disegna se ha già colpito un nemico
mvaddch(valore_letto.y, valore_letto.x, '^');
else
if (valore_letto.y <= 0 || valore_letto.x >= MAXX || valore_letto.x <= 0)
/* A questo punto, il missile che ha colpito un nemico ha finito la sua corsa ideale verso la fine dello schermo.
* Il suo stato viene ripristinato affinché il prissimo missile con lo stesso numero funzioni.*/
missile_colpito[valore_letto.numero] = 0;
}
/* FINE CONTROLLO MISSILI */
/* CONTROLLO NEMICI */
if (valore_letto.tipo == TIPO_NEMICO){
//cont nem bla bla
/* Non deve disegnarlo se è morto */
int disegna = (livello_nemici[valore_letto.numero] != 0);
if ((livello_nemici[valore_letto.numero] == 1 && nemici_colpiti[valore_letto.numero])){
if(nemici1l_colpiti[valore_letto.numero]==2){
flag_muori[valore_letto.numero]=1;
pthread_create(&nemico2_id[valore_letto.numero], NULL, &nemico2, &valore_letto.numero);
livello_nemici[valore_letto.numero] = 2; /* Il nemico entra nella seconda fase */
disegna = 0;
nemici_colpiti[valore_letto.numero] = 0; /* Reimposta il flag perché serve ad avvertire che almeno una navicella del gruppo è stata colpita */
}
}
if ((livello_nemici[valore_letto.numero] == 2 && nemici_colpiti[valore_letto.numero])){
if(nemici2l_colpiti[valore_letto.numero]==3){
flag_muori2[valore_letto.numero]=1;
pthread_create(&nemico3_id[valore_letto.numero], NULL, &nemico3, &valore_letto.numero);
livello_nemici[valore_letto.numero] = 3; /* Il nemico entra nella terza fase */
disegna = 0;
nemici_colpiti[valore_letto.numero] = 0; /* Reimposta il flag perché serve ad avvertire che almeno una navicella del gruppo è stata colpita */
}
}
/* Controlla se il nemico è stato colpito da un missile. Caso del nemico di terzo livello */
if ((livello_nemici[valore_letto.numero] == 3 && nemici_colpiti[valore_letto.numero])){
if(nemici3l_colpiti[valore_letto.numero]==4){
flag_muori3[valore_letto.numero]=1;
livello_nemici[valore_letto.numero] = 0; /* Il nemico entra nella terza fase */
disegna = 0;
nemici_colpiti[valore_letto.numero] = 0; /* Reimposta il flag perché serve ad avvertire che almeno una navicella del gruppo è stata colpita */
nemici_distrutti++;
}
}/// fineeeee if livello tre