space-shooter/main.c

251 lines
7.1 KiB
C
Raw Normal View History

2025-11-07 13:00:48 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ncurses.h>
#include <time.h>
#define DELAY 30000
#define ENEMY_N 5
#define BULLET_N 3
#define MIN_WIDTH 52
#define MIN_HEIGHT 30
struct speed {
int slowness;
int count;
};
struct game_obj {
char symbol;
int x, y;
int active;
struct speed y_speed;
};
/************** FUNZIONI GUI ***************/
void print_menu(WINDOW* win) {
mvwprintw(win, 1, 1, "BENVENUTO IN SPACE SHOOTER!\n");
mvwprintw(win, 2, 1, "Premi un tasto qualsiasi per giocare...");
refresh();
getch();
return;
}
int main() {
/************ VARIABILI **************/
WINDOW *game_window;
int height, width, win_startx, win_starty;
char *pause_msg = "PAUSA: premi q per uscire dal gioco...";
int pause = 0;
int max_height;
int max_width;
2025-11-07 13:37:00 +01:00
int auto_shoot = 0;
2025-11-07 13:00:48 +01:00
// Giocatore
struct game_obj player = {};
int input;
// Proiettile
struct game_obj bullet[BULLET_N] = {};
int bullet_attivi = 0;
int next_bullet = 0;
// Nemici
struct game_obj enemy[ENEMY_N] = {};
/**************** INIZIALIZZAZIONE ***************/
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
curs_set(0);
srand(time(NULL));
// "menu"
print_menu(stdscr);
mvprintw(3, 1, "p per pausa, q per uscire");
refresh();
// Dimensioni finestra di gioco
max_height = LINES - 10;
max_width = COLS - 10;
// Schermo troppo piccolo ?
if(max_width < MIN_WIDTH || max_height < MIN_HEIGHT) {
delwin(game_window);
curs_set(1);
endwin();
printf("Gioco terminato.\n");
printf("Schermo troppo piccolo \n");
return 0;
}
// calcolo delle misure della finestra
height = max_height;
width = MIN_WIDTH < max_width ? MIN_WIDTH - (MIN_WIDTH%4) : (max_width) - ((max_width)%4);
win_startx = (COLS - width)/2;
win_starty = (LINES - height)/2;
// Crea la finestra di gioco
game_window = newwin(height, width, win_starty, win_startx);
nodelay(game_window, TRUE); // input non bloccante
keypad(game_window, TRUE);
box(game_window, 0, 0);
wrefresh(game_window);
// setup giocatore
player.symbol = 'A';
player.x = width / 2;
player.y = height - 2;
player.active = 1;
// setup proiettili
for(int i = 0; i < BULLET_N; i++) {
bullet[i].symbol = '*';
bullet[i].active = 0;
}
// setup dei nemici
for(int i = 0; i < ENEMY_N; i++) {
enemy[i].symbol = 'Q';
enemy[i].active = 0;
enemy[i].y_speed.slowness = 7;
enemy[i].y_speed.count = 0;
}
//********************* GAME LOOP ***********************/
while (player.active) {
// TODO if pausa all'inizio e continue
input = wgetch(game_window);
// Gestione input
if (input == KEY_RIGHT && !pause && player.x < width - 2) {
player.x += 2;
} else if (input == KEY_LEFT && !pause && player.x > 2) {
player.x -= 2;
2025-11-07 13:37:00 +01:00
} else if (!auto_shoot && input == ' ' && bullet_attivi < BULLET_N && !pause) {
2025-11-07 13:00:48 +01:00
bullet[next_bullet].x = player.x;
bullet[next_bullet].y = player.y - 1;
bullet[next_bullet].active = 1;
} else if (input == 'p') {
pause = !pause;
} else if (input == 'q') {
player.active = 0;
2025-11-07 13:37:00 +01:00
} else if (input == 'g') {
auto_shoot= !auto_shoot;
}
if (auto_shoot && bullet_attivi < BULLET_N && !pause) {
bullet[next_bullet].x = player.x;
bullet[next_bullet].y = player.y - 1;
bullet[next_bullet].active = 1;
2025-11-07 13:00:48 +01:00
}
// Aggiorna proiettile
for(int i = 0; i< BULLET_N; i++) {
if (bullet[i].active && !pause) {
bullet[i].y--;
}
if (bullet[i].y < 1) {
bullet[i].active = 0;
}
}
// Collisioni 1
for(int j = 0; j < BULLET_N; j++) {
if(bullet[j].active && !pause) {
for(int i = 0; i < ENEMY_N; i++) {
if(bullet[j].x == enemy[i].x && bullet[j].y == enemy[i].y) {
enemy[i].active = 0;
bullet[j].active = 0;
// TODO aggiorna punteggio
}
}
}
}
// Spawna nemici
for(int i = 0; !pause && i < ENEMY_N; i++) {
if(!enemy[i].active && !pause) {
enemy[i].y = 2;
enemy[i].x = (rand()%((width-4)/2))*2 + 2;
enemy[i].active = 1;
break;
}
}
// Aggiorna posizione nemici
for(int i = 0; !pause && i < ENEMY_N; i++) {
if(enemy[i].active && !pause) {
enemy[i].y_speed.count++;
if(enemy[i].y_speed.count > enemy[i].y_speed.slowness) {
enemy[i].y++;
enemy[i].y_speed.count = 0;
}
if(enemy[i].y > height - 2) {
enemy[i].active = 0;
// TODO aggiorna punteggio
}
}
}
// Collisioni 2
for(int j = 0; j < BULLET_N; j++) {
if(bullet[j].active && !pause) {
for(int i = 0; i < ENEMY_N; i++) {
if(bullet[j].x == enemy[i].x && bullet[j].y == enemy[i].y) {
enemy[i].active = 0;
bullet[j].active = 0;
// TODO aggiorna punteggio
}
}
}
}
// Conteggio proiettili
bullet_attivi = 0;
next_bullet = -1;
for (int i = 0; i < BULLET_N; i++) {
if (bullet[i].active) {
bullet_attivi++;
} else if (i < next_bullet || next_bullet == -1) {
next_bullet = i;
}
}
// Disegna scena
werase(game_window);
box(game_window, 0, 0);
if (pause) {
wattron(game_window, A_REVERSE);
mvwprintw(game_window, height/2, (width - strlen(pause_msg)) / 2, "%s", pause_msg);
wattroff(game_window, A_REVERSE);
} else {
// Giocatore
mvwprintw(game_window, player.y, player.x, "%c", player.symbol);
// Proiettile
for(int i = 0; i < BULLET_N; i++) {
if (bullet[i].active) mvwprintw(game_window, bullet[i].y, bullet[i].x, "%c", bullet[i].symbol);
}
// Nemici
for(int i = 0; i < ENEMY_N; i++) {
if (enemy[i].active) mvwprintw(game_window, enemy[i].y, enemy[i].x, "%c", enemy[i].symbol);
}
}
wrefresh(game_window);
usleep(DELAY);
}
/***************** CHIUSURA *****************/
delwin(game_window);
curs_set(1);
endwin();
printf("Gioco terminato.\n");
return 0;
2025-11-07 13:37:00 +01:00
}