MAJOR COMMIT. big refactor(did it with AI help). no changes in game logic, just moved things around.
This commit is contained in:
parent
3c03c8a31e
commit
a988017110
23 changed files with 438 additions and 321 deletions
26
Makefile
Normal file
26
Makefile
Normal 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
|
||||||
|
|
@ -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
BIN
build/game.o
Normal file
Binary file not shown.
BIN
build/gui.o
Normal file
BIN
build/gui.o
Normal file
Binary file not shown.
BIN
build/input.o
Normal file
BIN
build/input.o
Normal file
Binary file not shown.
BIN
build/logic.o
Normal file
BIN
build/logic.o
Normal file
Binary file not shown.
BIN
build/main.o
Normal file
BIN
build/main.o
Normal file
Binary file not shown.
BIN
build/objects.o
Normal file
BIN
build/objects.o
Normal file
Binary file not shown.
BIN
build/space_shooter
Executable file
BIN
build/space_shooter
Executable file
Binary file not shown.
BIN
build/utils.o
Normal file
BIN
build/utils.o
Normal file
Binary file not shown.
9
include/game.h
Normal file
9
include/game.h
Normal 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 */
|
||||||
|
|
@ -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
18
include/input.h
Normal 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
16
include/logic.h
Normal 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
31
include/objects.h
Normal 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
18
include/utils.h
Normal 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
127
src/game.c
Normal 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;
|
||||||
|
}
|
||||||
33
src/gui.c
33
src/gui.c
|
|
@ -1,4 +1,5 @@
|
||||||
#include "../include/gui.h"
|
#include "../include/gui.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/************** FUNZIONI GUI ***************/
|
/************** FUNZIONI GUI ***************/
|
||||||
|
|
||||||
|
|
@ -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
41
src/input.c
Normal 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
73
src/logic.c
Normal 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);
|
||||||
|
}
|
||||||
295
src/main.c
295
src/main.c
|
|
@ -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
33
src/objects.c
Normal 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
2
src/utils.c
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "utils.h"
|
||||||
|
/* currently no utility functions needed; file exists for future helpers */
|
||||||
Loading…
Add table
Reference in a new issue