
/**************************************************************************
COLLISIONS DECOR:
Un sprite (vaisseau spatial) se déplace vers la souris (cliquer)
Le déplacement se fait sur un décor avec des murs présents
sur une carte de collision (bitmaps invisible au joueur)
Les murs ( blancs ) bloquent le déplacement...
Un objectif ( rouge ) permet de charger une jauge.
La détection des contacts est faite avec des getpixels
sur les bords de l'élément : on compte les getpixels
qui retournent une couleur particulière (mur ou autre)
**************************************************************************/
#include <allegro.h>
/****************************/
/* STRUCTURE ACTEUR */
/****************************/
// données personnelles de chaque acteur qui se déplace
typedef struct acteur
{
int x, y; // coordonnée (du coin sup. gauche)
int precx, precy; // coordonnées précédent le déplacement
int dx, dy; // vecteur deplacement
int tx,ty; // tailles : horizontal/vertical
BITMAP *img; // image de l'acteur
} t_acteur;
/****************************/
/* FONCTIONs UTILEs */
/****************************/
// Fonction détectant un contact avec couleur sur
// l'ensemble des pixels du rectangle encadrant l'acteur
// Retourne le nombre de pixels du bord en contact avec couleur
// ce qui peut s'interpréter comme un booléen au niveau de l'appelant
// ou être utilisé pour évaluer quantitativement la longueur du contact.
int contactBordActeur(t_acteur *acteur, BITMAP *bmp, int couleur){
int ncontact;
int xb,yb;
ncontact=0;
// Bords gauches et droits
for (yb=0;yb<acteur->ty;yb++){
if ( getpixel(bmp, acteur->x, acteur->y+yb) == couleur )
ncontact++;
if ( getpixel(bmp, acteur->x+acteur->tx, acteur->y+yb) == couleur )
ncontact++;
}
for (xb=0;xb<acteur->tx;xb++){
if ( getpixel(bmp, acteur->x+xb, acteur->y) == couleur )
ncontact++;
if ( getpixel(bmp, acteur->x+xb, acteur->y+acteur->ty) == couleur )
ncontact++;
}
return ncontact;
}
// Donner à l'acteur un déplacement pour qu'il se rapproche de la souris
void versSourisActeur(t_acteur *acteur){
// vecteur déplacement = vecteur centre_vaisseau->souris
acteur->dx = mouse_x - (acteur->x + acteur->tx/2);
acteur->dy = mouse_y - (acteur->y + acteur->ty/2);
// mais il faut limiter la vitesse : borner les valeurs obtenues
if (acteur->dx>5 ) acteur->dx= 5;
if (acteur->dx<-5) acteur->dx=-5;
if (acteur->dy>5 ) acteur->dy= 5;
if (acteur->dy<-5) acteur->dy=-5;
}
// Chargement "sécurisé" d'une image :
// interrompt le programme avec un message si problème...
BITMAP * load_bitmap_check(char *nomImage){
BITMAP *bmp;
bmp=load_bitmap(nomImage,NULL);
if (!bmp)
{
allegro_message("pas pu trouver %s",nomImage);
exit(EXIT_FAILURE);
}
return bmp;
}
/******************************************/
/* PROGRAMME PRINCIPAL */
/* initialisation puis boucle de jeu */
/******************************************/
int main()
{
t_acteur *acteur; // Un acteur (à créer)
BITMAP *page; // BITMAP buffer d'affichage
BITMAP *decor; // Image de fond, seulement pour visualiser
BITMAP *murs; // Image de fond, seulement pour les collisions
int jauge=1000; // Pour évaluer une jauge de carburant
int ncontact; // Pour évaluer le degré de contact avec couleur spéciale
// Lancer allegro et le mode graphique
allegro_init();
install_keyboard();
install_mouse();
set_color_depth(desktop_color_depth());
if (set_gfx_mode(GFX_AUTODETECT_WINDOWED,800,600,0,0)!=0)
{
allegro_message("prb gfx mode");
allegro_exit();
exit(EXIT_FAILURE);
}
// Montrer la souris à l'écran
show_mouse(screen);
// CREATION DU BUFFER D'AFFICHAGE à la taille de l'écran
page=create_bitmap(SCREEN_W,SCREEN_H);
clear_bitmap(page);
// charger image de fond
decor=load_bitmap_check("images/fond_decor.bmp");
// charger image de murs
murs=load_bitmap_check("images/fond_murs.bmp");
// Allocation et initialisation des paramètres de l'acteur :
acteur = (t_acteur *)malloc(1*sizeof(t_acteur));
acteur->tx = 99; acteur->ty = 38;
acteur->x = 300; acteur->y = 260;
acteur->dx = 0; acteur->dy = 0;
acteur->img = load_bitmap_check("images/spaceship_small.bmp");
// Boucle de jeu
while (!key[KEY_ESC])
{
// Effacer buffer en appliquant décor
blit(decor,page,0,0,0,0,SCREEN_W,SCREEN_H);
// GESTION INTERFACE si cliquer alors le vaisseau part vers la souris
if (mouse_b&1)
versSourisActeur(acteur);
// ENREGISTRER POSITION ACTUELLE
acteur->precx = acteur->x;
acteur->precy = acteur->y;
// DETERMINER NOUVELLE POSITION
acteur->x += acteur->dx; // équivalent à acteur->x = acteur->x + acteur->dx;
acteur->y += acteur->dy; // équivalent à acteur->y = acteur->y + acteur->dy;
// SI COLLISION AVEC LE DECOR ALORS ON REVIENT SUR LA POSITION PRECEDENT LE DEPLACEMENT
// ici on regard uniquement sur la carte de collision (murs) invisible pour l'utilisateur
if ( contactBordActeur(acteur, murs, makecol(255,255,255) ) )
{
acteur->x = acteur->precx;
acteur->y = acteur->precy;
// Souvent on accroche en dx ou dy mais on souhaite pouvoir "glisser" sur l'autre axe
// donc on va essayer de voir si sur un seul axe ça ne passe pas...
acteur->x += acteur->dx; // juste dx ?
if ( contactBordActeur(acteur, murs, makecol(255,255,255) ) )
acteur->x = acteur->precx; // ça ne passe toujours pas
acteur->y += acteur->dy; // juste dy ?
if ( contactBordActeur(acteur, murs, makecol(255,255,255) ) )
acteur->y = acteur->precy; // ça ne passe toujours pas
}
// SI CONTACT AVEC AUTRE COULEUR SPECIALE SUR CARTE DE COLLISION...
ncontact = contactBordActeur(acteur, murs, makecol(255,0,0) );
if ( ncontact!=0 )
{
jauge+=ncontact;
if (jauge>79199) jauge=79199;
}
// AFFICHAGE NOUVELLEs POSITIONs SUR LE BUFFER
draw_sprite(page, acteur->img, acteur->x, acteur->y);
rectfill(page,4,4,796,24,makecol(0,0,0));
rectfill(page,4,4,4+jauge/100,24,makecol(0,255,0));
rect(page,4,4,796,24,makecol(255,255,0));
// AFFICHAGE DU BUFFER MIS A JOUR A L'ECRAN
blit(page,screen,0,0,0,0,SCREEN_W,SCREEN_H);
// ON FAIT UNE PETITE PAUSE
rest(10);
}
return 0;
}
END_OF_MAIN();