first commit

This commit is contained in:
2026-06-22 22:07:13 +02:00
commit 7338a8db1c
8 changed files with 934 additions and 0 deletions

934
Projet.html Normal file
View File

@@ -0,0 +1,934 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Space Invaders sauce CMI</title>
<script>
// 2D context : objet dans lequel on va réaliser les dessins (en 2D)
// --> voir http://www.w3schools.com/jsref/dom_obj_canvas.asp
// pour connaître les fonctions offertes par cet objet
//canvas
let context = null;
//variables rectangle et munition
let colorR = "green";
let rectangle = { x: 0, y: 0, hauteur: 0, largeur: 0, couleur: colorR, vies : 3, score : 0 };
let munition = { x : 0, y: 0, hauteur: 10, largeur: 3, couleur: "white", exist : false};
// Variables/constantes qui repères l'état du jeu
let MENU=0;
let INGAME=1;
let GAME_OVER=2;
let PAUSE = 3;
let GAME_STATE=MENU;
// clic sur la zone de jeu (coordonnées relatives au canvas)
let clic = { x: 0, y: 0 };
// vecteur mouvement et vitesse
let vecMove=0;
let speed = 0.4;
// variable de type alien
let colorA = "White";
// variable de la vitesse des aliens
let speedAlien=1.5;
// variable compteur
let compteur=0;
// variables utiles pour calculer le delta T
let dt=0;
let lastD=0;
//variable qui insique si les aliens se déplacent de gauche à droite
let direction = "D";
// variable qui enregistre le x et le y de l'alien ou de la défense qui a été touché par le tir du vaisseau(joueur)
let coord;
// variable qui enregistre si une touche est appuyée et/ou relachée
let touches = {gauche : false, droite : false, espace : false};
// constante max comp
let MAX_COMPTEUR=140;
// variable qui aligne le texte du menu
let COORD_TEXT=120;
//variable pour le changement après le game_over
let comptOver =0;
//liste servant pour les tirs aliens
let munitionAlien=[];
let attaque;
let animationFrame=1;
// initialisation (appelée au chargement du corps du document <body onload="init">)
function init() {
// instanciation de la variable globale contenant le contexte
context = document.getElementById("cvs").getContext("2d");
context.width = document.getElementById("cvs").width;
context.height = document.getElementById("cvs").height;
// on associe au document des écouteurs d'événements
// --> voir http://www.w3schools.com/js/js_events.asp
// 2 écouteurs pour le clavier (appui/relâchement d'une touche)
document.addEventListener("keydown", captureAppuiToucheClavier)
document.addEventListener("keyup", captureRelacheToucheClavier)
// on associe au document un écouteur d'événements souris
document.addEventListener("click", captureClicSouris)
// --> ces événements vont appeler les fonctions captureXYZ définies après.
//intialisation du rectangle
rectangle.hauteur=25;
rectangle.largeur= 50;
rectangle.x=(context.width-rectangle.largeur)/2;
rectangle.y=context.height-rectangle.hauteur*2;
//initialisation des tableaux
Ennemi = [];
Defense = [];
// lancement de la boucle de jeu
boucleDeJeu();
}
function boucleDeJeu() {
if(GAME_STATE==INGAME){
// mise à jour de l'état du jeu
update(Date.now());
// affichage de l'état du jeu
render();
}else if(GAME_STATE==GAME_OVER){
OverDraw();
if(comptOver == 0){
setTimeout(passerAuMenu,3000);
comptOver = 1;
}
rectangle.score=0;
//passerAuMenu();
} else if(GAME_STATE==MENU){
effacerCanvas();
afficherMenu();
resetAlien();
resetDefense();
comptOver = 0;
rectangle.vies=3;
} else if(GAME_STATE==PAUSE){
render();
}
// rappel de la boucle de jeu
// requestAnimationFrame est une fonction JS servant à pré-calculer le prochain affichage
// http://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/
requestAnimationFrame(boucleDeJeu);
}
/**
* Mise à jour de l'état du jeu
* @param d date courante
*/
function update(d) {
// conditions pour le game over à faire ---------------------------------------------------------------------------------------------------------
if(maxY(Ennemi)>rectangle.y-rectangle.hauteur*6 || rectangle.vies<1){
GAME_STATE=GAME_OVER;
}
// mise à jour du delta T
dt=d-lastD;
lastD=d;
// permet d'éviter le lag de déplacement si on appuie sur les deux touches de direction en même temps
antiLagg();
// condition pour que le joueur ne sorte pas de l fenetre de jeu
antiNoClip();
// gestion de la munition
gestionMunition();
//collision munition & alien
collisionMunitionAlien();
//collision munition et defense
collisionMunitionDefense();
// boucle de déplacement des aliens
deplacementAliens();
// tir de la munition si elle n'existe pas déjà
tirJoueur();
//tout ce qui concerne le tir des aliens
gestionMunitionAliens();
randomTirIndiceAlien();
collisionTirAlienJoueur();
gestionAlienRouge();
}
/**
* Fonction réalisant le rendu de l'état du jeu
*/
function render() {
// effacement de l'écran
effacerCanvas();
//affichage joueur
affichageJoueur();
// affichage munition
affichageMunition();
// affichage aliens
affichageAliens();
//affichage défense
affichageDefense();
// affichage des tirs des aliens
affichageTirAlien();
//affichage du score
afficherScore();
//affichage de la vie
afficherVies();
if(alienRouge.exist){
afficherAlienRouge('randompts.jpg',alienRouge.x, alienRouge.y, alienRouge.width, alienRouge.height);
}
}
// ----------------------------------------------fonctions d'affichage------------------------------------------------------------------
// fonction qui permet de passer au menu
function passerAuMenu(){
GAME_STATE=MENU;
}
// fonction qui affiche game over
function OverDraw(){
context.font = '50px Paskowy';
context.fillStyle = 'BLUE';
context.textAlign="center";
context.fillText("Game Over", context.width/2, context.height/2);
}
//fonction qui affiche le menu
function afficherMenu(){
context.fillStyle='white';
context.font = '60px Arial';
context.textAlign="center";
context.fillText("SPACE INVADERS", context.width/2, COORD_TEXT );
context.font = '46px Arial';
context.fillText("= 10 pts", context.width/2, COORD_TEXT*2.1 );
context.fillText("= 20 pts", context.width/2, COORD_TEXT*2.7 );
context.fillText("= 30 pts", context.width/2, COORD_TEXT*3.3 );
context.fillText(" = ??? pts", context.width/2, COORD_TEXT*3.9 );
afficherAlienBlanc('10pts.png',330 ,COORD_TEXT*1.8 , 50, 50);
afficherAlienBlanc('20pts.jpg',330 ,COORD_TEXT*2.4 , 50, 50);
afficherAlienBlanc('30pts.jpg',330 ,COORD_TEXT*3 , 50, 50);
afficherAlienRouge('randompts.jpg',320,COORD_TEXT*3.6, 70,40 );
}
//fonction qui affiche le score
function afficherScore(){
context.fillStyle ='white';
context.font = '30px Arial';
context.fillText("score : " + rectangle.score, 90, 25)
}
//fonction qui affiche les points de vie
function afficherVies(){
context.fillStyle='white';
context.font='30px Arial';
context.fillText("LIVES : ", 600, 25);
let x = 660;
let y = rectangle.hauteur-15;
for (let i = 0; i<rectangle.vies;i++){
context.fillStyle =colorR;
context.fillRect(x+i*70, y, rectangle.largeur, rectangle.hauteur);
let tailleCanon = {largeur : 6, hauteur : 5};
context.fillRect(x+(rectangle.largeur-tailleCanon.largeur)/2+i*70 , y-tailleCanon.hauteur, tailleCanon.largeur, tailleCanon.hauteur);
//penser à faire reculer le x si le perso perd une vie
}
}
//fonctiin qui permet d'effacer le canvas
function effacerCanvas(){
context.clearRect(0, 0, context.width, context.height);
context.fillStyle='black';
context.fillRect(0,0,context.width,context.height);
}
//fonction qui empeche le lague déplacement si on appuie sur 2 touches en meme temps
function antiLagg(){
if(touches.droite && !touches.gauche){
vecMove=1;
} else if (touches.gauche && !touches.droite){
vecMove=-1;
} else if(!touches.gauche && !touches.droite){
vecMove=0;
}
rectangle.x+=speed*vecMove*dt;
}
// function qui affiche la munition
function affichageMunition(){
if(munition.exist==true){
context.fillStyle=munition.couleur;
context.fillRect(munition.x, munition.y, munition.largeur, munition.hauteur);
}
}
//fonction qui affiche les alien
function affichageAliens(){
if (Ennemi.length == 0 ){
resetAlien();
}
if(maxX(Ennemi)<context.width-65 && minX(Ennemi)>20){
for (i in Ennemi){
if(animationFrame==1){
if(Ennemi[i].score==10){
afficherAlienBlanc('10pts.png',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}else if(Ennemi[i].score==20){
afficherAlienBlanc('20pts.jpg',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}else if(Ennemi[i].score==30){
afficherAlienBlanc('30pts.jpg',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}
}else {
if(Ennemi[i].score==10){
afficherAlienBlanc('10ptsBis.jpg',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}else if(Ennemi[i].score==20){
afficherAlienBlanc('20ptsBis.jpg',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}else if(Ennemi[i].score==30){
afficherAlienBlanc('30ptsBis.jpg',Ennemi[i].x,Ennemi[i].y,Ennemi[i].width,Ennemi[i].height);
}
}
}
}
}
//fonction qui affiche un alien en fonction des parametres
function afficherAlienBlanc(source,x,y,width,height){
//création de l'élément image
let img = new Image();
img.addEventListener('load', function() {
}, false);
img.src = source; //
context.drawImage(img, x, y, width, height);
}
//fonction qui affiche les défenses
function affichageDefense(){
if ( Defense.length == 0){
Defense = tabDefense();
}
for (i in Defense){
context.fillStyle = Defense[i].color;
context.fillRect(Defense[i].x,Defense[i].y,Defense[i].width,Defense[i].height);
}
}
// fonction qui affiche l'avatar du joueur
function affichageJoueur(){
context.fillStyle =colorR;
context.fillRect(rectangle.x, rectangle.y, rectangle.largeur, rectangle.hauteur);
let tailleCanon = {largeur : 6, hauteur : 5};
context.fillRect(rectangle.x+(rectangle.largeur-tailleCanon.largeur)/2 , rectangle.y-tailleCanon.hauteur, tailleCanon.largeur, tailleCanon.hauteur);
}
//fonction qui affiche le tir des aliens
function affichageTirAlien(){
for ( i = 0; i<munitionAlien.length; i++){
if (munitionAlien[i].exist){
context.fillStyle = 'yellow';
context.fillRect(munitionAlien[i].x, munitionAlien[i].y, munitionAlien[i].largeur, munitionAlien[i].hauteur);
}
}
}
//fonction qui affiche un alien en fonction des parametres
function afficherAlienRouge(source,x,y,width,height){
//création de l'élément image
let redimg = new Image();
redimg.addEventListener('load', function() {
}, false);
redimg.src = source; //
context.drawImage(redimg, x, y, width, height);
}
// ---------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------Alien Rouge---------------------------------------------------------
let alienRouge={x:0, y:0, width:60, height:30, exist:false};
//fonction qui fait spawn l'alien rouge de façon aléatoire
function randomRandSpawnAlienRouge(){
if (1+Math.random()*(1000-1)+1>999){
return true;
}
return false;
}
//gestion de l'alien rouge, collision/deplacement/spawn
function gestionAlienRouge(){
if(alienRouge.exist){
collisionAlienRouge();
alienRouge.x-=1.5;
if(alienRouge.x<-alienRouge.width){
alienRouge.exist=false;
}
}else{
if(randomRandSpawnAlienRouge()){
alienRouge.y=90;
alienRouge.x=context.width;
alienRouge.exist=true;
}
}
}
//détection de la collision
function collisionAlienRouge(){
if(munition.exist&&alienRouge.exist){
if( alienRouge.x<munition.x && alienRouge.x+width>munition.x && alienRouge.y<munition.y && alienRouge.y+height>munition.y){
munition.exist=false;
alienRouge.exist=false;
let temp=1+Math.random()*(6-1)+1;
temp=Math.floor(temp);
rectangle.score+=50*temp;
}//endIf
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------création et reset des matrices d'alien et de defneses----------------------------
// fonction qui créé la matrice d'aliens aliens
function tabAlien(){
munitionAlien=[];
x=25;
y=145;
width=40;
height=40;
tab = [];
for(i = 0; i<5; i++){
for(j=0; j<11;j++){
if ( i == 0){
tab.push({x: x, y:y, width : width, height : height, score : 30, num : j});
munitionAlien.push( {exist: false, x : 0, y : 0, largeur : 3, hauteur : 9});
}else{
if ( i == 1 || i == 2){
tab.push({x: x, y:y, width : width, height : height, score : 20});
}else{
tab.push({x: x, y:y, width : width, height : height, score : 10});
}
}
x+=(width+12);
}
y+=(height+12);
x=25;
}
return tab;
}
//fonction qui crée les matrices des défenses
function tabDefense(){
x = 125;
y = 630;
width = 25;
height = 20;
tab = [];
for ( i = 0; i<4; i++){
for (j=0; j<4; j++){
if ( j == 0 || j == 3){
for (k=0;k<3;k++){
tab.push({ x : x, y :y, height : height, width : width, color : "Green", vies : 4})
y +=height;
}
}else{
for (k=0;k<2;k++){
tab.push({ x : x, y :y, height : height, width : width, color : "Green", vies : 4})
y +=height;
}
}
y=630;
x+=width;
}
x = x+4*width;
}
return tab;
}
// reset le déplacement des aliens
function resetAlien(){
speedAlien=1.5;
direction="D";
Ennemi = tabAlien();
rectangle.vies+=1;
alienRouge.exist = false;
}
//reset des défenses
function resetDefense(){
Defense = []
}
// --------------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------fonctions qui gère tout ce qui est en rapport avec le joueur-----------------------------------
// fonction qui empeche le joueur de sortir du canvas
function antiNoClip(){
if (rectangle.x<=0){
rectangle.x=0;
}
if (rectangle.x>=context.width-rectangle.largeur){
rectangle.x=context.width-rectangle.largeur;
}
}
// fonction qui gere l'apparition/disparition de la muntition
function gestionMunition(){
if(munition.y< -munition.hauteur && munition.exist==true){
munition.exist=false;
}
if(munition.exist== true){
munition.y-=6;
}
}
// fonction qui permet de tirer une munition
function tirJoueur(){
if(touches.espace && munition.exist==false){
munition.exist=true;
munition.x=rectangle.x+(rectangle.largeur/2);
munition.y=rectangle.y-munition.hauteur;
}
}
// fonction qui gere la collision entre la munition et l'alien
function collisionMunitionAlien(){
if(collisionA(munition) && munition.exist){
for(let i=0;i<Ennemi.length;i++){
if(Ennemi[i].x==coord.x && Ennemi[i].y==coord.y){
rectangle.score += Ennemi[i].score;
munition.exist=false;
Ennemi.splice(i, 1);
}
}
}
}
//fonction qui gère la collision entre la munition et la défense
function collisionMunitionDefense(){
if(( collisionD(munition) != null ) && munition.exist){
for (let i=0;i<Defense.length;i++){
if(Defense[i].x==collisionD(munition).x && Defense[i].y == collisionD(munition).y ){
Defense[i].vies-=1;
if(Defense[i].color=="Green"){
Defense[i].color="yellow";
}else if(Defense[i].color=="yellow"){
Defense[i].color="orange";
}else if(Defense[i].color=="orange"){
Defense[i].color="red";
}
if(Defense[i].vies==0){
Defense.splice(i,1);
}
munition.exist=false;
break;
}
}
}
if (collTirsAlienObstacle() != null){
for ( let i = 0; i<Defense.length; i++){
if(Defense[i].x == collTirsAlienObstacle().x && Defense[i].y == collTirsAlienObstacle().y){
Defense[i].vies-=1;
if(Defense[i].color=="Green"){
Defense[i].color="yellow";
}else if(Defense[i].color=="yellow"){
Defense[i].color="orange";
}else if(Defense[i].color=="orange"){
Defense[i].color="red";
}
if(Defense[i].vies==0){
Defense.splice(i,1);
}
attaque.y=0;
break;
}
}
}
}
// fonction qui détecte la collision
function collisionA(r1){
let col=false;
for (let r2 of Ennemi){
if( (r1.x+r1.largeur > r2.x && r1.x<r2.x+r2.width) && (r1.y+r1.hauteur > r2.y && r1.y<r2.y+r2.height) ){
col=true;
coord={x : r2.x, y: r2.y};
}
}
return col;
}
//fonction qui détecte si la munition touche une défense
function collisionD(r1){
for (let r2 of Defense){
if( (r1.x+r1.largeur > r2.x && r1.x<r2.x+r2.width) && (r1.y+r1.hauteur > r2.y && r1.y<r2.y+r2.height) ){
return r2;
}
}
return null;
}
// --------------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------déplacement des aliens--------------------------------------------------------------------
// fonction qui gere le déplacement des aliens
function deplacementAliens(){
//pr aller de gauche à droite
deplacementVersDroite();
// pr aller de droite à gauche
deplacementVersGauche();
}
//fonction pour gérer le déplacement vers la droite des aliens
function deplacementVersDroite(){
if(maxX(Ennemi)<context.width-65 && direction=="D"){
compteur+=speedAlien;
if(compteur>MAX_COMPTEUR){
for(let temp of Ennemi){
temp.x+=MAX_COMPTEUR/7;
}
compteur=0;
animationFrame=-animationFrame;
}
} else {
if(direction=="D"){
for(let temp of Ennemi){
temp.y+=45;
temp.x-= 20;
}
speedAlien+=1;
}
direction="G";
}
}
//fonction pour gérer le déplacement vers la gauche des aliens
function deplacementVersGauche(){
if(minX(Ennemi)>20 && direction=="G"){
compteur+=speedAlien;
if(compteur>MAX_COMPTEUR){
for(let temp of Ennemi){
temp.x-=MAX_COMPTEUR/7;
}
compteur=0;
animationFrame=-animationFrame;
}
} else {
if(direction=="G"){
for(let temp of Ennemi){
temp.y+=45;
temp.x+= 20;
}
speedAlien+=1;
}
direction="D";
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------fonctions qui cherches les X,Y min et max----------------------------------------------------
// fonction qui cherche la valeur de x maximale d'un tableau d'alien
function maxX(Ennemi){
let max = 0;
for(let temp of Ennemi){
if(temp.x>max){
max=temp.x;
}
}
return max;
}
//fonction qui cherche la valeur x minimale d'un tableau d'alien
function minX(Ennemi){
let min = context.width;
for(let temp of Ennemi){
if(temp.x<min){
min=temp.x
}
}
return min;
}
// fonction qui cherche la valeur y max d'un tableau d'aliens
function maxY(Ennemi){
let min = 0;
for(let temp of Ennemi){
if(temp.y>min){
min=temp.y;
}
}
return min;
}
// fonction qui cherche la valeur de y maximale d'un tableau d'alien
function minY(Ennemi){
let min = context.width;
for(let temp of Ennemi){
if(temp.y<min){
min=temp.y;
}
}
return min;
}
// --------------------------------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------Tirs des aliens------------------------------------------------------------
// fonction qui gere les munitions tirées par les aliens
function gestionMunitionAliens(){
for(let temp of munitionAlien){
if(temp.exist){
temp.y+=3;
}
if(temp.y>context.height){
temp.exist=false;
temp.y=0;
}
}
}
//fonction qui permet de vérifier si un des tirs alien a touché une défense ou non
function collTirsAlienObstacle(){
for(let r1 of munitionAlien){
for (let r2 of Defense){
if( (r1.x+r1.largeur > r2.x && r1.x<r2.x+r2.width) && (r1.y+r1.hauteur > r2.y && r1.y<r2.y+r2.height) ){
attaque = r1;
attaque.exist = false;
return r2;
}
}
}
return null;
}
// fonction qui détecte si un tir d'alien a touché le joueur
function collisionTirAlienJoueur(){
let col=false;
for(let r1 of munitionAlien){
if( (r1.x+r1.largeur > rectangle.x && r1.x<rectangle.x+rectangle.largeur) && (r1.y+r1.hauteur > rectangle.y && r1.y<rectangle.y+rectangle.hauteur) ){
col=true;
for(let r1 of munitionAlien){
r1.exist=false;
r1.y = 0;
}
rectangle.vies-=1;
GAME_STATE=PAUSE;
setTimeout(function(){ GAME_STATE=INGAME; rectangle.x=(context.width-rectangle.largeur)/2},2000)
r1.exist=false;
}
}
return col;
}
//fonction qui permet de remplir le tableau des aliens qui peuvent tirer
function remplirTabIndiceAlienTir(){
tab = [];
for (i = 0; i<Ennemi.length; i++){
if(Ennemi[i].y == minY(Ennemi)){
tab.push(Ennemi[i].num);
}
}
return tab;
}
//qui fait tirer les aliens
function randomTirIndiceAlien(){
let tab=remplirTabIndiceAlienTir();
let compteur=0;
for(let temp of tab){
if(randomTirAlien() && !munitionAlien[temp].exist){
munitionAlien[temp].exist=true;
munitionAlien[temp].y=minY(Ennemi)+Ennemi[0].height;
munitionAlien[temp].x=Ennemi[compteur].x+(Ennemi[compteur].width/2);
}
compteur+=1;
}
}
//fonction qui génère le random des tirs
function randomTirAlien(){
if (1+Math.random()*(1000-1)+1>999){
return true;
}
return false;
}
//------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Fonction appelée lorsqu'une touche du clavier est appuyée
* Associée à l'événement "keyDown"
*/
function captureAppuiToucheClavier(event) {
// pratique pour connaître les keyCode des touches du clavier :
// --> http://www.cambiaresearch.com/articles/15/javascript-key-codes
//Lancement du jeu si on appuie sur ENTER
if(event.code=="Enter" && GAME_STATE==MENU){
GAME_STATE=INGAME;
}
// gestion du tir
if(event.code=="Space" ){
touches.espace=true;
}
//gestion du déplacement
if(event.code=="ArrowRight" ){
touches.droite=true;
}
if(event.code=="ArrowLeft" ){
touches.gauche=true;
}
if(event.code=="KeyP"&& GAME_STATE==INGAME){
GAME_STATE=PAUSE;
} else if(event.code=="KeyP" && GAME_STATE==PAUSE){
GAME_STATE=INGAME;
}
}
/**
* Fonction appelée lorsqu'une touche du clavier est relâchée
* Associée à l'événement "keyUp"
*/
function captureRelacheToucheClavier(event) {
// gestion mouvement
if(event.code=="ArrowRight"){
touches.droite=false;
}
if(event.code=="ArrowLeft"){
touches.gauche=false;
}
if(speed<0.1 && (event.code=="ArrowUp"|| event.code=="ArrowDown")){
speed=0.1;
}
// gestion du tirJoueur
if(event.code =="Space"){
touches.espace=false;
}
}
/**
* Fonction appelée lorsqu'une touche du clavier est relâchée
* Associée à l'événement "click"
*/
function captureClicSouris(event) {
// calcul des coordonnées de la souris dans le canvas
if (event.target.id == "cvs") {
clic.x = event.pageX - event.target.offsetLeft;
clic.y = event.pageY - event.target.offsetTop;
}
}
</script>
</head>
<body onload="init()">
<canvas id="cvs" width="1000" height="800" style="margin: 10px auto; border: solid 1px #000;"></canvas>
</body>
</html>