MAJOR COMMIT. big refactor(did it with AI help). no changes in game logic, just moved things around.

This commit is contained in:
Carlo 2025-11-10 11:02:50 +01:00
parent 3c03c8a31e
commit a988017110
23 changed files with 438 additions and 321 deletions

26
Makefile Normal file
View file

@ -0,0 +1,26 @@
CC = gcc
CFLAGS = -Wall -Wextra -Iinclude -std=c11
LDFLAGS = -lncurses
SRC = $(wildcard src/*.c)
OBJ = $(patsubst src/%.c, build/%.o, $(SRC))
TARGET = build/space_shooter
all: $(TARGET)
build:
mkdir -p build
build/%.o: src/%.c | build
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): $(OBJ) | build
$(CC) $(OBJ) -o $@ $(LDFLAGS)
clean:
rm -rf build
run: all
./$(TARGET)
.PHONY: all clean run

View file

@ -4,4 +4,4 @@
> cd space-shooter/ > cd space-shooter/
> gcc -o /build/shooter src/main.c src/gui.c -lncurses > make

BIN
build/game.o Normal file

Binary file not shown.

BIN
build/gui.o Normal file

Binary file not shown.

BIN
build/input.o Normal file

Binary file not shown.

BIN
build/logic.o Normal file

Binary file not shown.

BIN
build/main.o Normal file

Binary file not shown.

BIN
build/objects.o Normal file

Binary file not shown.

BIN
build/space_shooter Executable file

Binary file not shown.

BIN
build/utils.o Normal file

Binary file not shown.

9
include/game.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef GAME_H
#define GAME_H
#include "objects.h"
/* Run the main game. Returns 0 on clean exit. */
int game_run(void);
#endif /* GAME_H */

View file

@ -2,23 +2,26 @@
#define GUI_H #define GUI_H
#include <ncurses.h> #include <ncurses.h>
#include <stdio.h> #include "objects.h"
#include <string.h> #include "utils.h"
// Aspect constatnts /* color pair ids for gui.c */
#define TEXTLINES 4 enum {
#define BORDERLINES 2 ENEMY_PAIR = 1,
TITLE_PAIR,
GMOVR_PAIR,
BONUS_PAIR,
WINSC_PAIR
};
#define ENEMY_PAIR 1 /* initialization and screens */
#define BONUS_PAIR 2 void init_colors(void);
#define TITLE_PAIR 3
#define GMOVR_PAIR 4
#define WINSC_PAIR 5
void init_colors();
void print_menu(WINDOW* win); void print_menu(WINDOW* win);
void print_gameover(WINDOW* win); void print_gameover(WINDOW* win);
void print_win_screen(WINDOW* win); void print_win_screen(WINDOW* win);
/* status bar (draws into stdscr or another window) */
void print_status_bar(WINDOW* main_win, int y, int x, struct status game_status);
#endif /* GUI_H */
#endif

18
include/input.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef INPUT_H
#define INPUT_H
#include <ncurses.h>
#include "objects.h"
#include "utils.h"
/* Process a single key code and apply to game state.
Returns 1 if game should continue, 0 if quit (player inactive). */
int process_input(int input,
int *pause,
int *auto_shoot,
struct game_obj *player,
struct game_obj bullets[],
int bullet_attivi,
int *next_bullet);
#endif /* INPUT_H */

16
include/logic.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef LOGIC_H
#define LOGIC_H
#include "objects.h"
#include "utils.h"
#include <ncurses.h>
/* Logic functions used by the game loop */
void update_bullets(struct game_obj bullets[]);
void handle_collisions(struct game_obj bullets[], struct game_obj enemies[], struct status *game_status, WINDOW *win);
void spawn_enemies(struct game_obj enemies[], int width);
void update_enemies(struct game_obj enemies[], struct status *game_status, int height, WINDOW *win);
void count_bullets(const struct game_obj bullets[], int *bullet_attivi, int *next_bullet, struct status *game_status);
#endif /* LOGIC_H */

31
include/objects.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef OBJECTS_H
#define OBJECTS_H
#include "utils.h"
/* speed, game_obj, status definitions */
struct speed {
int slowness;
int count;
};
struct game_obj {
char symbol;
int x, y;
int active;
struct speed y_speed;
};
struct status {
int lives;
int score;
int top_score;
int remaining_bullets;
};
/* constructors / initializers */
void init_player(struct game_obj *player, int win_width, int win_height);
void init_bullets(struct game_obj bullets[]);
void init_enemies(struct game_obj enemies[]);
#endif /* OBJECTS_H */

18
include/utils.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef UTILS_H
#define UTILS_H
/* Window/constants shared across modules */
#define DELAY 30000
#define ENEMY_N 5
#define BULLET_N 3
#define LIVES_N 5
#define WIN_PTS 100
#define WIDTH 52
#define HEIGHT 30
#define MIN_COLS 110
#define TEXTLINES 4
#define BORDERLINES 2
#endif /* UTILS_H */

127
src/game.c Normal file
View file

@ -0,0 +1,127 @@
#include "../include/game.h"
#include "../include/gui.h"
#include "../include/input.h"
#include "../include/logic.h"
#include "../include/objects.h"
#include "../include/utils.h"
#include <ncurses.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
/* main game runner */
int game_run(void) {
WINDOW *game_window = NULL;
int height, width, win_startx, win_starty;
char *pause_msg = "PAUSA: premi q per uscire dal gioco...";
int pause = 0;
int auto_shoot = 0;
struct game_obj player = {};
int input = 0;
struct status game_status = {};
game_status.top_score = 0;
game_status.score = 0;
game_status.lives = LIVES_N;
game_status.remaining_bullets = BULLET_N;
struct game_obj bullet[BULLET_N] = {};
int bullet_attivi = 0;
int next_bullet = -1;
struct game_obj enemy[ENEMY_N] = {};
/* seed */
srand((unsigned)time(NULL));
/* Dimensioni finestra di gioco */
height = HEIGHT;
width = WIDTH - (WIDTH%4);
win_startx = (COLS - width)/2;
win_starty = (LINES - height)/2;
if(COLS < MIN_COLS || LINES < HEIGHT) {
printf("Gioco terminato.\nSchermo troppo piccolo\n");
return 0;
}
/* show menu */
print_menu(stdscr);
getch();
werase(stdscr);
mvprintw(1, 1, "p per pausa, q per uscire");
refresh();
/* create windows */
game_window = newwin(height, width, win_starty, win_startx);
nodelay(game_window, TRUE);
keypad(game_window, TRUE);
box(game_window, 0, 0);
wrefresh(game_window);
/* setup objects */
init_player(&player, width, height);
init_bullets(bullet);
init_enemies(enemy);
while (player.active) {
input = wgetch(game_window);
if (!process_input(input, &pause, &auto_shoot, &player, bullet, bullet_attivi, &next_bullet)) {
player.active = 0;
break;
}
if (!pause) update_bullets(bullet);
if (!pause) handle_collisions(bullet, enemy, &game_status, stdscr);
if (!pause && game_status.score >= WIN_PTS) {
player.active = 0;
print_win_screen(stdscr);
break;
}
if (!pause) spawn_enemies(enemy, width);
if (!pause) update_enemies(enemy, &game_status, height, stdscr);
if (!pause && game_status.lives <= 0) {
player.active = 0;
print_gameover(stdscr);
break;
}
count_bullets(bullet, &bullet_attivi, &next_bullet, &game_status);
/* draw */
werase(game_window);
box(game_window, 0, 0);
if (pause) {
wattron(game_window, A_REVERSE);
mvwprintw(game_window, height/2, (width - (int)strlen(pause_msg)) / 2, "%s", pause_msg);
wattroff(game_window, A_REVERSE);
} else {
mvwprintw(game_window, player.y, player.x, "%c", player.symbol);
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);
wattron(game_window, COLOR_PAIR(ENEMY_PAIR));
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);
wattroff(game_window, COLOR_PAIR(ENEMY_PAIR));
print_status_bar(stdscr, win_starty, (win_startx + width), game_status);
}
wrefresh(game_window);
usleep(DELAY);
}
if (game_window) delwin(game_window);
/* note: no endwin(), no curs_set(1) here */
return 0;
}

View file

@ -1,4 +1,5 @@
#include "../include/gui.h" #include "../include/gui.h"
#include <string.h>
/************** FUNZIONI GUI ***************/ /************** FUNZIONI GUI ***************/
@ -10,7 +11,7 @@ char* title[] =
"# o888 88 888888 88 88 o888 88 88 88 888 88 888 88 88 88 88 #", "# o888 88 888888 88 88 o888 88 88 88 888 88 888 88 88 88 88 #",
"# 088880 88 88 88 888880 088888 088880 08 80 088880 088880 00 088888 88 88o #", "# 088880 88 88 88 888880 088888 088880 08 80 088880 088880 00 088888 88 88o #",
"###########################################################################################################" "###########################################################################################################"
}; };
char menu_desc[] = "BENVENUTO. Premi qualsiasi tasto per giocare..."; char menu_desc[] = "BENVENUTO. Premi qualsiasi tasto per giocare...";
@ -28,7 +29,7 @@ char gameover_desc[] = "HAI PERSO. Premi q per uscire...";
char* win_screen[] = char* win_screen[] =
{ {
"o8 o8 o8888o o8 8o o8 8o o8888o o8 8o", "o8 o8 o8888o o8 8o o8 8o o8888o o8 8o",
"88 o8 88 888 88 88 oo 88 88 88 888o88", "88 o8 88 888 88 88 oo 88 88 88 888o88",
"888 88 888 88 88 88/\\88 88 88 888", "888 88 888 88 88 88/\\88 88 88 888",
"888 088880 088880 8888 088880 88 88" "888 088880 088880 8888 088880 88 88"
}; };
@ -45,76 +46,78 @@ void init_colors() {
} }
void print_menu(WINDOW* win) { void print_menu(WINDOW* win) {
// Ottieni parametri della finestra
int height; int height;
int width; int width;
getmaxyx(win, height, width); getmaxyx(win, height, width);
// Scritta colorata
wattron(win, COLOR_PAIR(TITLE_PAIR)); wattron(win, COLOR_PAIR(TITLE_PAIR));
for(int i = 0; i < (TEXTLINES+BORDERLINES); i++) { for(int i = 0; i < (TEXTLINES+BORDERLINES); i++) {
mvwprintw(win, i+1, (width-(strlen(title[0])))/2, "%s", title[i]); mvwprintw(win, i+1, (width-(strlen(title[0])))/2, "%s", title[i]);
} }
wattroff(win, COLOR_PAIR(TITLE_PAIR)); wattroff(win, COLOR_PAIR(TITLE_PAIR));
// Scritta che blinka
wattron(win, A_BLINK); wattron(win, A_BLINK);
mvwprintw(win, (TEXTLINES+BORDERLINES)+1, (width-(strlen(menu_desc)))/2, "%s", menu_desc); mvwprintw(win, (TEXTLINES+BORDERLINES)+1, (width-(strlen(menu_desc)))/2, "%s", menu_desc);
wattroff(win, A_BLINK); wattroff(win, A_BLINK);
// stampa a video wrefresh(win);
refresh();
return; return;
} }
void print_gameover(WINDOW* win) { void print_gameover(WINDOW* win) {
// Parametri della finestra e pulisci tutto
int height; int height;
int width; int width;
int ch; int ch;
wclear(win); wclear(win);
getmaxyx(win, height, width); getmaxyx(win, height, width);
// Stampa della scritta colorata
wattron(win, COLOR_PAIR(GMOVR_PAIR)); wattron(win, COLOR_PAIR(GMOVR_PAIR));
for(int i = 0; i < TEXTLINES; i++) { for(int i = 0; i < TEXTLINES; i++) {
mvwprintw(win, i+1, (width-(strlen(gameover[0])))/2, "%s", gameover[i]); mvwprintw(win, i+1, (width-(strlen(gameover[0])))/2, "%s", gameover[i]);
} }
wattroff(win, COLOR_PAIR(GMOVR_PAIR)); wattroff(win, COLOR_PAIR(GMOVR_PAIR));
// Stampa della scritta che blinka
wattron(win, A_BLINK); wattron(win, A_BLINK);
mvwprintw(win, TEXTLINES+1, (width-(strlen(gameover_desc)))/2, "%s", gameover_desc); mvwprintw(win, TEXTLINES+1, (width-(strlen(gameover_desc)))/2, "%s", gameover_desc);
wattroff(win, A_BLINK); wattroff(win, A_BLINK);
// Stampa a video e attendi input wrefresh(win);
refresh();
while((ch = wgetch(win)) != 'q'); while((ch = wgetch(win)) != 'q');
return; return;
} }
void print_win_screen(WINDOW* win) { void print_win_screen(WINDOW* win) {
// Parametri della finestra e pulisci tutto
int height; int height;
int width; int width;
int ch; int ch;
wclear(win); wclear(win);
getmaxyx(win, height, width); getmaxyx(win, height, width);
// Stampa della scritta colorata
wattron(win, COLOR_PAIR(WINSC_PAIR)); wattron(win, COLOR_PAIR(WINSC_PAIR));
for(int i = 0; i < TEXTLINES; i++) { for(int i = 0; i < TEXTLINES; i++) {
mvwprintw(win, i+1, (width-(strlen(win_screen[0])))/2, "%s", win_screen[i]); mvwprintw(win, i+1, (width-(strlen(win_screen[0])))/2, "%s", win_screen[i]);
} }
wattroff(win, COLOR_PAIR(WINSC_PAIR)); wattroff(win, COLOR_PAIR(WINSC_PAIR));
// Stampa della scritta che blinka
wattron(win, A_BLINK); wattron(win, A_BLINK);
mvwprintw(win, TEXTLINES+1, (width-(strlen(win_desc)))/2, "%s", win_desc); mvwprintw(win, TEXTLINES+1, (width-(strlen(win_desc)))/2, "%s", win_desc);
wattroff(win, A_BLINK); wattroff(win, A_BLINK);
// Stampa a video e attendi input wrefresh(win);
refresh();
while((ch = wgetch(win)) != 'q'); while((ch = wgetch(win)) != 'q');
return; return;
} }
void print_status_bar(WINDOW* main_win, int y, int x, struct status game_status) {
int status_x = x + 1;
int status_y = y;
status_x++;
mvwprintw(main_win, status_y, status_x, "LIVES:\t%d", game_status.lives);
mvwprintw(main_win, status_y+1, status_x, "SCORE:\t%d", game_status.score);
mvwprintw(main_win, status_y+2, status_x, "TOP SCORE:\t%d", game_status.top_score);
mvwprintw(main_win, status_y+3, status_x, "BULLETS:\t%d", game_status.remaining_bullets);
wrefresh(main_win);
return;
}

41
src/input.c Normal file
View file

@ -0,0 +1,41 @@
#include "../include/input.h"
#include <ncurses.h>
/* Returns 1 to continue, 0 if quit requested (player inactive). */
int process_input(int input,
int *pause,
int *auto_shoot,
struct game_obj *player,
struct game_obj bullets[],
int bullet_attivi,
int *next_bullet) {
if (input == KEY_RIGHT && !(*pause) && player->x < (WIDTH - 2)) {
player->x += 2;
} else if (input == KEY_LEFT && !(*pause) && player->x > 2) {
player->x -= 2;
} else if (!(*auto_shoot) && input == ' ' && bullet_attivi < BULLET_N && !(*pause)) {
if (*next_bullet != -1) {
bullets[*next_bullet].x = player->x;
bullets[*next_bullet].y = player->y - 1;
bullets[*next_bullet].active = 1;
}
} else if (input == 'p') {
*pause = !(*pause);
} else if (input == 'q') {
/* signal to caller to quit by marking player inactive */
return 0;
} else if (input == 'g') {
*auto_shoot = !(*auto_shoot);
}
if (*auto_shoot && bullet_attivi < BULLET_N && !(*pause)) {
if (*next_bullet != -1) {
bullets[*next_bullet].x = player->x;
bullets[*next_bullet].y = player->y - 1;
bullets[*next_bullet].active = 1;
}
}
return 1;
}

73
src/logic.c Normal file
View file

@ -0,0 +1,73 @@
#include "../include/logic.h"
#include <stdlib.h>
void update_bullets(struct game_obj bullets[]) {
for(int i = 0; i< BULLET_N; i++) {
if (bullets[i].active) {
bullets[i].y--;
if (bullets[i].y < 1) {
bullets[i].active = 0;
}
}
}
}
void handle_collisions(struct game_obj bullets[], struct game_obj enemies[], struct status *game_status, WINDOW *win) {
(void)win; /* kept parameter for parity with original code */
for(int j = 0; j < BULLET_N; j++) {
if(bullets[j].active) {
for(int i = 0; i < ENEMY_N; i++) {
if(enemies[i].active && bullets[j].x == enemies[i].x && bullets[j].y == enemies[i].y) {
enemies[i].active = 0;
bullets[j].active = 0;
game_status->score++;
}
}
}
}
}
void spawn_enemies(struct game_obj enemies[], int width) {
for(int i = 0; i < ENEMY_N; i++) {
if(!enemies[i].active) {
enemies[i].y = 2;
enemies[i].x = (rand()%((width-4)/2))*2 + 2;
enemies[i].active = 1;
enemies[i].y_speed.count = 0;
break;
}
}
}
void update_enemies(struct game_obj enemies[], struct status *game_status, int height, WINDOW *win) {
(void)win;
for(int i = 0; i < ENEMY_N; i++) {
if(enemies[i].active) {
enemies[i].y_speed.count++;
if(enemies[i].y_speed.count > enemies[i].y_speed.slowness) {
enemies[i].y++;
enemies[i].y_speed.count = 0;
}
if(enemies[i].y > height - 2) {
enemies[i].active = 0;
game_status->lives--;
}
}
}
}
/* Recomputes bullet_attivi and next_bullet, and updates remaining_bullets */
void count_bullets(const struct game_obj bullets[], int *bullet_attivi, int *next_bullet, struct status *game_status) {
*bullet_attivi = 0;
*next_bullet = -1;
for (int i = 0; i < BULLET_N; i++) {
if (bullets[i].active) {
(*bullet_attivi)++;
} else {
if (*next_bullet == -1 || i < *next_bullet) {
*next_bullet = i;
}
}
}
game_status->remaining_bullets = BULLET_N - (*bullet_attivi);
}

View file

@ -1,308 +1,25 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ncurses.h> #include <ncurses.h>
#include <time.h>
#include <curses.h> #include "../include/game.h"
#include <menu.h>
#include "../include/gui.h" #include "../include/gui.h"
/************* STATIC DEFINITIONS ************/ int main(void) {
// Game constants
#define ENEMY_N 5
#define BULLET_N 3
#define LIVES_N 5
#define WIN_PTS 100
// Window constants
#define DELAY 30000
#define WIDTH 52
#define HEIGHT 30
#define MIN_COLS 110
/************* GAME STRUCTURES **************/
struct speed {
int slowness;
int count;
};
struct game_obj {
char symbol;
int x, y;
int active;
struct speed y_speed;
};
struct status {
int lives;
int score;
int top_score;
int remaining_bullets;
};
void print_status_bar(WINDOW* main_win, int y, int x, struct status game_status) {
int status_x = x + 1;
int status_y = y;
status_x++;
// lives
mvwprintw(main_win, status_y, status_x, "LIVES:\t%d", game_status.lives);
// score
mvwprintw(main_win, status_y+1, status_x, "SCORE:\t%d", game_status.score);
// top score
mvwprintw(main_win, status_y+2, status_x, "TOP SCORE:\t%d", game_status.top_score);
// bullets
mvwprintw(main_win, status_y+3, status_x, "BULLETS:\t%d", game_status.remaining_bullets);
// refresh window
wrefresh(main_win);
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 auto_shoot = 0;
// Giocatore
struct game_obj player = {};
int input;
// Status
struct status game_status = {};
game_status.top_score = 0;
game_status.score = 0;
game_status.lives = LIVES_N;
game_status.remaining_bullets = BULLET_N;
// Proiettile
struct game_obj bullet[BULLET_N] = {};
int bullet_attivi = 0;
int next_bullet = 0;
// Nemici
struct game_obj enemy[ENEMY_N] = {};
/**************** INIZIALIZZAZIONE ***************/
initscr(); initscr();
cbreak(); cbreak();
noecho(); noecho();
keypad(stdscr, TRUE); keypad(stdscr, TRUE);
curs_set(0); curs_set(0);
srand(time(NULL));
// Colori
init_colors(); init_colors();
// Dimensioni finestra di gioco e controlli game_run();
// calcolo delle misure della finestra
height = HEIGHT;
width = WIDTH - (WIDTH%4);
win_startx = (COLS - width)/2;
win_starty = (LINES - height)/2;
// Schermo troppo piccolo ? /* cleanup terminal */
if(COLS < MIN_COLS || LINES < HEIGHT) {
curs_set(1);
endwin();
printf("Gioco terminato.\n");
printf("Schermo troppo piccolo \n");
return 0;
}
// MENU
print_menu(stdscr);
getch();
werase(stdscr);
mvprintw(1, 1, "p per pausa, q per uscire");
refresh();
// GAME WINDOW
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;
} else if (!auto_shoot && input == ' ' && bullet_attivi < BULLET_N && !pause) {
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;
} 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;
}
// 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;
game_status.score++;
if(game_status.score == WIN_PTS) {
player.active = 0;
print_win_screen(stdscr);
}
}
}
}
}
// 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;
game_status.lives--;
if(game_status.lives == 0) {
player.active = 0;
print_gameover(stdscr);
}
}
}
}
// 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;
game_status.score++;
if(game_status.score == WIN_PTS) {
player.active = 0;
print_win_screen(stdscr);
}
}
}
}
}
// 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;
}
}
game_status.remaining_bullets = BULLET_N - bullet_attivi;
// 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++) {
wattron(game_window, COLOR_PAIR(1));
if (enemy[i].active) mvwprintw(game_window, enemy[i].y, enemy[i].x, "%c", enemy[i].symbol);
wattroff(game_window, COLOR_PAIR(1));
}
// Status Bar
print_status_bar(stdscr, win_starty, (win_startx + width), game_status);
}
wrefresh(game_window);
usleep(DELAY);
}
/***************** CHIUSURA *****************/
delwin(game_window);
curs_set(1); curs_set(1);
endwin(); endwin();
printf("Gioco terminato.\n"); printf("Gioco terminato.\n");
return 0; return 0;
} }

33
src/objects.c Normal file
View file

@ -0,0 +1,33 @@
#include "objects.h"
#include <stdlib.h>
void init_player(struct game_obj *player, int win_width, int win_height) {
player->symbol = 'A';
player->x = win_width / 2;
player->y = win_height - 2;
player->active = 1;
player->y_speed.slowness = 0;
player->y_speed.count = 0;
}
void init_bullets(struct game_obj bullets[]) {
for (int i = 0; i < BULLET_N; i++) {
bullets[i].symbol = '*';
bullets[i].active = 0;
bullets[i].x = 0;
bullets[i].y = 0;
bullets[i].y_speed.slowness = 0;
bullets[i].y_speed.count = 0;
}
}
void init_enemies(struct game_obj enemies[]) {
for (int i = 0; i < ENEMY_N; i++) {
enemies[i].symbol = 'Q';
enemies[i].active = 0;
enemies[i].y_speed.slowness = 7;
enemies[i].y_speed.count = 0;
enemies[i].x = 0;
enemies[i].y = 0;
}
}

2
src/utils.c Normal file
View file

@ -0,0 +1,2 @@
#include "utils.h"
/* currently no utility functions needed; file exists for future helpers */