Blame |
Last modification |
View Log
| RSS feed
/*
* Invaders 2004
* Copyright (C) 2004 Nicola Rialti, Alessandro Vannuccini, Matteo Corsini
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE@. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <kernel/kern.h>
#include <drivers/glib.h>
#include <drivers/keyb.h>
#include <semaphore.h>
#include <stdlib.h>
#include <math.h>
#define YMENU 10
#define XMIN 50
#define XMAX 600
#define YMIN 100
#define YMAX 450
#define VEL 3 // velocità dei nemici
#define VEL_NAVICELLA 6 // velocità della navicella
#define D 10 // raggio dell'astronave invasore
#define ESC 27 // ASCII code of ESCAPE key
#define MAX_ENEMIES 15 // numero massimo di nemici
#define MAX_MISSILE 3 // numero massimo di missili
#define INITIAL_LIFE 3 // numero di vite iniziali
#define HEIGHT_NAV 10 // altezza della navicella
#define COLOR_NAV 4 // colore della navicella
#define LENGTH_NAV 20 // lunghezza della navicella
#define LENGTH_MISSILE 7 // lunghezza del missile
#define ENEMY_CREATOR_PERIOD 400000
#define ENEMY_CREATOR_WCET 100
#define ENEMY_CREATOR_MET 100
#define NAVICELLA_PERIOD 10000
#define NAVICELLA_WCET 500
#define NAVICELLA_MET 500
#define ENEMY_PERIOD 40000 // 25 fps
//#define ENEMY_PERIOD 16666 // 60 fps
#define ENEMY_WCET 1000
#define ENEMY_MET 800
#define MISSILE_PERIOD 40000
#define MISSILE_WCET 500
int num_enemies
; // numero dei nemici che varia a seconda dello schema
int speed
; // velocità dei nemici che varia a seconda dello schema
double tick
= 1.0; /* system tick = 1 ms */
sem_t mutex
;
PID pid
;
/* Struttura con i dati dei nemici */
struct enemy_table
{
int status
; // 0 -> risorsa libera, 1 -> risorsa occupata
int killed
; // 1 -> il nemico è stato ucciso
PID pid
;
WORD x
,y
;
int color
;
} enemy_table
[MAX_ENEMIES
];
struct table
{
int count_enemies
;
int count_missile
;
int score
;
int level
;
int killed
; // 1 -> l'astronave è stata colpita
int life
;
WORD x_center
;
/* semafori di mutua per scrivere nelle strutture condivise */
/* un semaforo per il contatore dei missili, uno per i nemici */
/* uno per la posizione dei nemici */
sem_t mx_missile
; // Semaforo per la struttura condivisa
sem_t mx_navicella
; // semaforo per la posizione della navicella
sem_t mx_enemies
[MAX_ENEMIES
];// Semaforo per le strutture dei nemici
} navicella_table
;
void init_navicella_table
(struct table
*m
)
{
int i
;
sem_init
(&m
->mx_missile
,0,1);
for (i
=0;i
<MAX_ENEMIES
;i
++) {
sem_init
(&m
->mx_enemies
[i
],0,1);
}
m
->count_enemies
= m
->count_missile
= m
->score
= m
->level
= m
->killed
= 0;
m
->life
= INITIAL_LIFE
;
}
void draw_fly
(int x
, int y
, int c
)
{
int b
;
if (!c
)
b
=0;
else
b
=15;
sem_wait
(&mutex
);
grx_disc
(x
, y
, D
, c
);
grx_disc
(x
, y
, D
/3, b
);
grx_disc
(x
+D
*4/5, y
, D
/10, b
);
grx_disc
(x
-D
*4/5, y
, D
/10, b
);
grx_disc
(x
,y
+D
*4/5,D
/10,b
);
grx_disc
(x
,y
-D
*4/5,D
/10,b
);
sem_post
(&mutex
);
}
void draw_navicella
(int x
,int c
)
{
int l
=LENGTH_NAV
;
int h
=HEIGHT_NAV
;
sem_wait
(&mutex
);
grx_line
(x
-LENGTH_NAV
/2,YMAX
,x
+LENGTH_NAV
/2,YMAX
,c
); // base
grx_line
(x
-l
/2,YMAX
,x
-l
/2,YMAX
-h
/2,c
); // parte dx
grx_line
(x
-l
/2,YMAX
-h
/2,x
-l
*7/20,YMAX
-h
,c
);
grx_line
(x
-l
/5,YMAX
-h
/2,x
-l
*7/20,YMAX
-h
,c
);
grx_line
(x
+l
/2,YMAX
,x
+l
/2,YMAX
-h
/2,c
); // parte sx
grx_line
(x
+l
/2,YMAX
-h
/2,x
+l
*7/20,YMAX
-h
,c
);
grx_line
(x
+l
/5,YMAX
-h
/2,x
+l
*7/20,YMAX
-h
,c
);
grx_line
(x
-l
/6,YMAX
-h
/2,x
,YMAX
-h
*5/4,c
);
grx_line
(x
+l
/6,YMAX
-h
/2,x
,YMAX
-h
*5/4,c
);
sem_post
(&mutex
);
}
void draw_missile
(int x
,int y
,int c
)
{
sem_wait
(&mutex
);
grx_line
(x
,y
+LENGTH_MISSILE
/2,x
,y
-LENGTH_MISSILE
/2,c
);
sem_post
(&mutex
);
}
void draw_lifes
(int life
)
{
char s
[15];
sprintf(s
,"Navicelle: %d",life
);
sem_wait
(&mutex
);
grx_text
(" ",XMIN
+300,YMENU
+10, 0, 0);
grx_text
(s
,XMIN
+300,YMENU
+10, 12, 0);
sem_post
(&mutex
);
}
void draw_score
(int score
)
{
char s
[10];
sprintf(s
,"Score: %d",score
);
sem_wait
(&mutex
);
grx_text
(" ",XMIN
+300,YMENU
+20, 0, 0);
grx_text
(s
,XMIN
+300,YMENU
+20, 12, 0);
sem_post
(&mutex
);
}
void end_fun
(KEY_EVT
* k
)
{
sys_end
();
}
TASK missile
(void *arg
)
{
int index
;
int x
, y
;
int oy
;
int dy
;
int col
;
int outy
;
index
= (int)arg
;
sem_wait
(&navicella_table.
mx_navicella);
x
= navicella_table.
x_center; // centro del missile
sem_post
(&navicella_table.
mx_navicella);
y
= oy
= YMAX
-HEIGHT_NAV
-LENGTH_MISSILE
;
dy
= LENGTH_MISSILE
/2;
col
= 2; // colore missile
while (1) {
y
-=dy
;
outy
= (y
<= YMIN
);
/* se il missile è uscito dallo schermo */
/* libero la risorsa */
if (outy
) {
sem_wait
(&navicella_table.
mx_missile);
navicella_table.
count_missile--;
sem_post
(&navicella_table.
mx_missile);
draw_missile
(x
,oy
,0);
break;
}
draw_missile
(x
, oy
, 0);
draw_missile
(x
, y
, col
);
int i
;
/* Confronto la posizione di ogni nemico */
/* con la posizione del missile */
/* per verificare se è stato colpito */
for (i
=0;i
<MAX_ENEMIES
;i
++)
{
sem_wait
(&navicella_table.
mx_enemies[i
]);
if (enemy_table
[i
].
status && !enemy_table
[i
].
killed && +
x
>= enemy_table
[i
].
x-D
&& x
<= enemy_table
[i
].
x+D
&& +
y
>= enemy_table
[i
].
y-D
&& y
<= enemy_table
[i
].
y+D
) {
enemy_table
[i
].
killed=1; // segnalo all'invasore che deve morire
sem_post
(&navicella_table.
mx_enemies[i
]);
draw_missile
(x
, y
, 0);
return NULL
;
}
else
sem_post
(&navicella_table.
mx_enemies[i
]);
}
oy
= y
;
task_endcycle
();
}
return NULL
;
}
void shot
()
{
SOFT_TASK_MODEL m
;
sem_wait
(&navicella_table.
mx_missile);
if (navicella_table.
count_missile<MAX_MISSILE
) {
navicella_table.
count_missile++;
int count
=navicella_table.
count_missile;
sem_post
(&navicella_table.
mx_missile);
soft_task_default_model
(m
);
soft_task_def_level
(m
,0);
soft_task_def_periodic
(m
);
soft_task_def_arg
(m
,(void*)count
-1);
soft_task_def_period
(m
,MISSILE_PERIOD
);
soft_task_def_wcet
(m
, MISSILE_WCET
);
soft_task_def_met
(m
, NAVICELLA_MET
);
soft_task_def_usemath
(m
);
pid
= task_create
("soft_missile", missile
, &m
, NULL
);
task_activate
(pid
);
}
else
sem_post
(&navicella_table.
mx_missile);
}
void hard_shot
()
{
HARD_TASK_MODEL m
;
sem_wait
(&navicella_table.
mx_missile);
if (navicella_table.
count_missile<MAX_MISSILE
) {
navicella_table.
count_missile++;
int count
=navicella_table.
count_missile;
sem_post
(&navicella_table.
mx_missile);
hard_task_default_model
(m
);
hard_task_def_periodic
(m
);
hard_task_def_arg
(m
,(void*)count
-1);
hard_task_def_wcet
(m
, MISSILE_WCET
);
hard_task_def_mit
(m
, NAVICELLA_PERIOD
);
hard_task_def_usemath
(m
);
pid
= task_create
("hard_missile", missile
, &m
, NULL
);
task_activate
(pid
);
}
else
sem_post
(&navicella_table.
mx_missile);
}
void move_right
()
{
int x
,ox
;
sem_wait
(&navicella_table.
mx_missile);
x
=ox
=navicella_table.
x_center;
sem_post
(&navicella_table.
mx_missile);
if (ox
<XMAX
) {
sem_wait
(&navicella_table.
mx_missile);
x
+=VEL_NAVICELLA
;
navicella_table.
x_center=x
;
sem_post
(&navicella_table.
mx_missile);
draw_navicella
(ox
,0);
draw_navicella
(x
,COLOR_NAV
);
}
}
void move_left
()
{
int x
,ox
;
sem_wait
(&navicella_table.
mx_missile);
x
=ox
=navicella_table.
x_center;
sem_post
(&navicella_table.
mx_missile);
if (ox
>XMIN
) {
sem_wait
(&navicella_table.
mx_missile);
x
-=VEL_NAVICELLA
;
navicella_table.
x_center=x
;
sem_post
(&navicella_table.
mx_missile);
draw_navicella
(ox
,0);
draw_navicella
(x
,COLOR_NAV
);
}
}
TASK navicella
()
{
navicella_table.
x_center=XMAX
/2;
draw_navicella
(XMAX
/2,4);
KEY_EVT a
;
keyb_set_map
(itaMap
);
a.
flag = 0;
a.
scan = KEY_ENT
;
a.
ascii = 13;
keyb_hook
(a
,shot
);
a.
scan = KEY_Z
;
a.
ascii = 'z';
keyb_hook
(a
,move_left
);
a.
scan = KEY_X
;
a.
ascii = 'x';
keyb_hook
(a
,move_right
);
while(1) {
sem_wait
(&navicella_table.
mx_missile);
if(navicella_table.
killed) { // controllo se sono stato colpito
if (navicella_table.
life==0) // e se ho terminato le vite
sys_end
();
else {
navicella_table.
life--; // decremento il contatore delle astronavi
navicella_table.
killed=0; // reimposto il flag killed a 0
draw_lifes
(navicella_table.
life);
}
}
sem_post
(&navicella_table.
mx_missile);
task_endcycle
();
}
return NULL
;
}
TASK enemy_missile
(void *arg
)
{
int index
;
int x
, y
;
int oy
;
int dy
;
int col
;
int outy
;
index
= (int)arg
;
sem_wait
(&navicella_table.
mx_enemies[index
]);
x
= enemy_table
[index
].
x; // posizione dell'invasore X
y
= oy
= enemy_table
[index
].
y; // posizione dell'invasore Y
sem_post
(&navicella_table.
mx_enemies[index
]);
dy
= LENGTH_MISSILE
;
col
= 4; // colore missile
while (1) {
y
+=dy
;
outy
= (y
>= YMAX
-HEIGHT_NAV
);
if (outy
) {
draw_missile
(x
,oy
,0);
break;
}
draw_missile
(x
, oy
, 0);
draw_missile
(x
, y
, col
);
/* Confronto la posizione della navicella */
/* con la posizione del missile */
/* per verificare se è stata colpita */
if (y
>=YMAX
-HEIGHT_NAV
-LENGTH_MISSILE
) {
sem_wait
(&navicella_table.
mx_missile);
//int colpita = (x >= navicella_table.x_center-LENGTH_NAV/2) && (x <= navicella_table.x_center+LENGTH_NAV/2);
if (x
>= navicella_table.
x_center-LENGTH_NAV
/2 && x
<= navicella_table.
x_center+LENGTH_NAV
/2) {
navicella_table.
killed=1; // segnalo alla navicella che è stata colpita
sem_post
(&navicella_table.
mx_missile);
}
else
sem_post
(&navicella_table.
mx_missile);
}
oy
= y
;
task_endcycle
();
}
return NULL
;
}
void hard_enemy_shot
(int index
)
{
HARD_TASK_MODEL m
;
hard_task_default_model
(m
);
hard_task_def_periodic
(m
);
hard_task_def_arg
(m
,(void*)index
);
hard_task_def_wcet
(m
, MISSILE_WCET
);
hard_task_def_mit
(m
, NAVICELLA_PERIOD
*1000);
hard_task_def_usemath
(m
);
pid
= task_create
("hard_enemy_missile", enemy_missile
, &m
, NULL
);
task_activate
(pid
);
}
void soft_enemy_shot
(int index
)
{
SOFT_TASK_MODEL m
;
soft_task_default_model
(m
);
soft_task_def_periodic
(m
);
soft_task_def_period
(m
, MISSILE_PERIOD
);
soft_task_def_arg
(m
,(void*)index
);
soft_task_def_wcet
(m
, MISSILE_WCET
);
soft_task_def_met
(m
, 800);
soft_task_def_usemath
(m
);
pid
= task_create
("soft_enemy_missile", enemy_missile
, &m
, NULL
);
task_activate
(pid
);
}
TASK enemy
(void *arg
)
{
int index
;
int x
, y
;
int ox
, oy
;
int dx
,dy
;
int col
;
int outx
, outy
;
int direzione
= 1;
index
= (int)arg
;
x
= ox
= XMIN
;
y
= oy
= YMIN
+D
*2;
dy
= D
*2; // passo di discesa verticale
col
= 1 + index
; // colore nemico
enemy_table
[index
].
color=col
;
/* il nemico controlla se è stato colpito da un missile */
while (1) {
sem_wait
(&navicella_table.
mx_enemies[index
]); // proteggo la risorsa del nemico[i]
if (enemy_table
[index
].
killed==1){ // se è settato il FLAG killed=>devo morire
enemy_table
[index
].
status=0; // libero la risorsa
sem_post
(&navicella_table.
mx_enemies[index
]); // libero il semaforo
draw_fly
(ox
, oy
, 0);
sem_wait
(&navicella_table.
mx_missile);
navicella_table.
count_enemies--; // decremento il contatore dei nemici
navicella_table.
count_missile--; // decremento il contatore dei missili
navicella_table.
score++; // conta il numero di nemici uccisi
draw_score
(navicella_table.
score); // scrivo il nuovo punteggio
sem_post
(&navicella_table.
mx_missile);
break;
}
else
sem_post
(&navicella_table.
mx_enemies[index
]);
dx
= (float)(VEL
* (direzione
)); // passo di spostamento orizzontale
x
+= dx
;
outx
= (x
>= XMAX
) || (x
<= XMIN
);
outy
= (y
>= YMAX
-HEIGHT_NAV
);
int sparo
= rand()%500;
/* SPARO?? */
if (sparo
==0) {
//count_missile++; // un solo missile per volta, si combatte in 2
soft_enemy_shot
(index
);
}
/* Controllo se sono arrivato al bordo dello schermo */
if (outx
) {
x
= x
- dx
; y
= y
+ 2 * D
;
direzione
=-direzione
; // in tal caso cambio direzione
dx
= (float)(VEL
* (direzione
));
x
+= dx
;
y
+= dy
;
}
if (outy
) {
sys_end
();
}
draw_fly
(ox
, oy
, 0);
draw_fly
(x
, y
, col
);
ox
= x
; oy
= y
;
// scrivo nella struttura condivisa
sem_wait
(&navicella_table.
mx_enemies[index
]);
enemy_table
[index
].
x = x
;
enemy_table
[index
].
y = y
;
sem_post
(&navicella_table.
mx_enemies[index
]);
task_endcycle
();
}
return NULL
;
}
TASK enemy_creator
(void *arg
)
{
int index
=0;
int i
;
SOFT_TASK_MODEL m
;
while(1) {
if (navicella_table.
count_enemies<MAX_ENEMIES
) {
sem_post
(&navicella_table.
mx_navicella); // semaforo di mutua esclusione per la risorsa generale
index
=navicella_table.
count_enemies; // l'indice parte da 0 fino a MAX_ENEMIES-1
navicella_table.
count_enemies++; // il contatore va da 1 a MAX_ENEMIES
sem_post
(&navicella_table.
mx_navicella);
/* cerco una posizione libera */
/* nell'array di nemici enemy_table */
for (i
=0;i
<MAX_ENEMIES
;i
++) {
sem_wait
(&navicella_table.
mx_enemies[i
]); // semaforo di mutua per la risorsa dei nemici[i]
if (!enemy_table
[i
].
status) {
index
=i
; // se la risorsa [i] è libera esco dal ciclo
break; // senza liberare il semaforo
}
sem_post
(&navicella_table.
mx_enemies[i
]); // se la risorsa è occupata libero il semaforo e passo a i+1
}
/* ALMENO UNA RISORSA DEVE ESSERE LIBERA */
/* quindi dopo il for questa la eseguo sempre */
enemy_table
[index
].
status=1; // occupo la risora e inizializzo tutte le variabili
enemy_table
[index
].
killed=0;
enemy_table
[index
].
x=XMIN
;
enemy_table
[index
].
y=YMIN
;
sem_post
(&navicella_table.
mx_enemies[index
]); // libero il semaforo di mutua per la risorsa[i]
soft_task_default_model
(m
);
soft_task_def_level
(m
,0);
soft_task_def_periodic
(m
);
soft_task_def_arg
(m
,(void*)index
);
soft_task_def_period
(m
,ENEMY_PERIOD
);
soft_task_def_wcet
(m
, ENEMY_WCET
);
soft_task_def_met
(m
, NAVICELLA_MET
);
soft_task_def_usemath
(m
);
pid
= task_create
("soft_enemy", enemy
, &m
, NULL
);
task_activate
(pid
);
}
task_endcycle
();
}
return NULL
;
}
PID crea_navicella
()
{
SOFT_TASK_MODEL m_s
;
PID pid
;
soft_task_default_model
(m_s
);
soft_task_def_level
(m_s
,0);
soft_task_def_period
(m_s
,NAVICELLA_PERIOD
);
soft_task_def_wcet
(m_s
, NAVICELLA_WCET
);
soft_task_def_met
(m_s
, NAVICELLA_MET
);
soft_task_def_usemath
(m_s
);
pid
= task_create
("navicella", navicella
, &m_s
, NULL
);
return pid
;
}
PID hard_crea_navicella
()
{
HARD_TASK_MODEL m_s
;
PID pid
;
hard_task_default_model
(m_s
);
hard_task_def_level
(m_s
,0);
hard_task_def_wcet
(m_s
, NAVICELLA_WCET
);
hard_task_def_mit
(m_s
, NAVICELLA_PERIOD
);
hard_task_def_usemath
(m_s
);
pid
= task_create
("navicella", navicella
, &m_s
, NULL
);
return pid
;
}
PID crea_enemy_creator
()
{
SOFT_TASK_MODEL m_s
;
PID pid
;
soft_task_default_model
(m_s
);
soft_task_def_level
(m_s
,0);
soft_task_def_periodic
(m_s
);
soft_task_def_period
(m_s
,ENEMY_CREATOR_PERIOD
);
soft_task_def_wcet
(m_s
, ENEMY_CREATOR_WCET
);
soft_task_def_met
(m_s
,ENEMY_CREATOR_MET
);
soft_task_def_usemath
(m_s
);
pid
= task_create
("enemy_creator", enemy_creator
, &m_s
, NULL
);
return pid
;
}
/*
PID crea_enemy_creator()
{
HARD_TASK_MODEL m_s;
PID pid;
hard_task_default_model(m_s);
hard_task_def_level(m_s,0);
hard_task_def_periodic(m_s);
hard_task_def_mit(m_s,ENEMY_CREATOR_PERIOD);
hard_task_def_wcet(m_s, ENEMY_CREATOR_WCET);
hard_task_def_usemath(m_s);
pid = task_create("hard_enemy_creator", enemy_creator, &m_s, NULL);
return pid;
}
*/
/****************************************************************/
/* This function is called when the system exits */
void byebye
(void *arg
)
{
grx_close
();
cprintf
("Numero di nemici totali: %d\n",navicella_table.
count_enemies);
cprintf
("LIVELLO: %d\n",navicella_table.
level);
cprintf
("Numero di nemici uccisi: %d\n",navicella_table.
score);
}
/****************************** MAIN ******************************/
void main
(int argc
, char **argv
)
{
TIME seme
; /* used to init the random seed */
init_navicella_table
(&navicella_table
);
/* Set the closing function */
sys_atrunlevel
(byebye
, NULL
, RUNLEVEL_BEFORE_EXIT
);
/* graphic card Initialization */
if (grx_init
() < 1) {
sys_abort
(1);
}
if (grx_open
(640, 480, 8) < 0) {
cprintf
("GRX Err\n");
sys_abort
(1);
}
/* The scenario */
char s
[10];
sprintf(s
,"Astronavi: %d",navicella_table.
life);
grx_rect
(XMIN
-D
-1, YMIN
-D
-1, XMAX
+D
+1, YMAX
+D
+1, 14);
grx_text
("SpaceInvaders...maddechè" , XMIN
, YMENU
+10, 13,0);
grx_text
("ENTER shot, 'z' Left, 'x' Right" , XMIN
, YMENU
+20, 12, 0);
grx_text
("ESC exit to DOS" , XMIN
, YMENU
+30, 12, 0);
grx_text
(s
, XMIN
+300, YMENU
+10, 12, 0);
grx_text
("Score: 0",XMIN
+300,YMENU
+20,12,0);
/* randomize!!!! */
seme
= sys_gettime
(NULL
);
srand(seme
);
KEY_EVT k
;
keyb_set_map
(itaMap
);
k.
flag=0;
k.
scan=KEY_ESC
;
k.
ascii=ESC
;
keyb_hook
(k
,end_fun
);
pid
=hard_crea_navicella
();
task_activate
(pid
);
pid
=crea_enemy_creator
();
task_activate
(pid
);
}
/*--------------------------------------------------------------*/