11540 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,

Suite à mon précédent topic, j'aimerais ajouter d'autres étapes sur l'évolution de mes aliens.
Je recherche l'alien le plus proche du sol dans mon canvas en fonction de sa position.
Il s'agit du leader, une fois repéré, je vx qu'il change de couleur pour se différencier des autres.
Je vx qu'il soit rattraper par un autre alien et perde sa place de leader ou soit qu'il disparaît en bas de l’écran. J'utilise un tableau aliens[] qui contient la liste de mes aliens, une fonction pour afficher
mes aliens ds mon canvas: affiche_aliens() et une fonction alien_le_plus_bas() pour afficher l'alien le plus bas du sol et l'afficher d'une couleur dfférente.

var aliens = [ 
    { x:28,  y:28,  bras_en_bas:true, taille:[], position:[], couleur:[] },
    { x:127, y:127, bras_en_bas:true, taille:[], position:[], couleur:[] },
    ...
];

// affiche tous les aliens connus, le contenu du tableau aliens[]
function affiche_aliens () { 
    for ( var i = 0; i < aliens.length; ++i ) {
        affiche_alien(aliens[i]);
    }
    var alien = alien_le_plus_bas();
    if (alien.y === ymax) {
        alien.y = document.getElementById('canvas').style = 'blue';
    }
}
 
// affiche un seul alien, celui passé en argument de la fonction 'affiche_alien'
function affiche_alien ( alien ) {
    if (alien == null || typeof alien != "object") {
        alert("affiche_alien : alien n'est pas un objet");
        return;
    }
 
    if (alien.bras_en_bas) { 
        context.fillRect(alien.x, alien.y + 4*unit, unit, 3*unit); // Premier bras 
        ...
        alien.bras_en_bas = false;
    } else {
        ...
        alien.bras_en_bas = true;
    }
    ...
}

// retourne l'alien le plus bas
function alien_le_plus_bas () {
    var alien = aliens[0];
    var ymax = alien.y;
 
    for (var i = 1; i < aliens.length ; i++) {
        if (aliens[i].y > ymax) {
            ymax = aliens[i].y;
            alien = aliens[i];
        }
    }
    return alien;
}


Mais, je n'arrive pas à identifier mon alien le plus bas et lui donner une couleur différente des autres.

Merci par avance!
[/i][/i][/i][/i]
Modifié par dinolam (24 Dec 2014 - 13:19)
Modérateur
Bonjour,

Dans affiche_aliens (), le test if (alien.y === ymax) ne peut que échouer vu que ymax n'est pas défini.

Et d'ailleurs, pourquoi tu mets ce test, puisque tu as déjà mis l'alien le plus bas dans la variable alien avec var alien = alien_le_plus_bas(); ?

EDIT : la ligne alien.y = document.getElementById('canvas').style = 'blue'; ne va pas faire grand chose aussi. Je ne vois pas trop ce que tu espères colorier avec ce genre de ligne. En fait, c'est plutôt dans la fonction affiche_alien() qu'il faudrait tester si alien est alien_le_plus_bas(), et si oui alors colorier ce que tu veux colorier.

Amicalement,
Modifié par parsimonhi (26 Dec 2014 - 12:03)
Re,

J'ai réussit à résoudre ma question du 26 Déc.
Maintenant, j'envie quand je clic sur un alien qu'il disparaît et un autre réapparaît en haut à sa place. J'ai procédé de cette façon:

var disparait = null;

// Pour chaque alien connu
function animate_aliens () { 
   var leader = alien_le_plus_bas();
   var disparait = false;
    
   for ( var i = 0, e = aliens.length; i < e; ++i ) { 
       disparait = animate_alien(aliens[i], leader) || disparait; 
   } 

    if (disparait) {
     clearInterval(disparait);
     efface_alien(disparait);
    }
} 

// L'alien que l'on anime
function animate_alien (alien, leader) { 
     efface_alien(alien);

    if ( alien == null || typeof alien != "object" ) {
         alert("animate_alien : alien n'est pas un objet");
         return;
   }
    
    alien.y += alien.vitesse*unit; 

    if ((alien.y + 8*unit) >= hauteur) {  
     alien.y = 0;

        alien.vitesse = vitesse_aleatoire();
    } 
    
    affiche_alien(alien, leader); 
}
 
// Gère clic
function gere_clic (e) {
        var cx = e.pageX - canvas.offsetLeft;
        var cy = e.pageY - canvas.offsetTop; 
}
   
// Fonction d'initialisation
function initialisations () {
 canvas = document.getElementById('canvas');
 // Définition taille canvas
 canvas.setAttribute('width', largeur);
 canvas.setAttribute('height', hauteur);

 context = canvas.getContext('2d');
    
 setInterval('animate_aliens();', 200);

 disparait = canvas.addEventListener('click', gere_clic, false);
}


Merci![/i]
Modérateur
Bonjour,

Déjà, quand tu donnes un exemple de code évite le "i" comme indice des tableaux, car un i entre crochet signifie "mettre en italique". Rajoute des espaces autour du i. Ça facilitera la lecture de ceux qui te lisent.

Je ne vois pas ce que tu veux faire dans la fonction gere_clic(). En l'état, elle ne fait rien.

J'ai un peu de mal à comprendre ce que tu cherches à faire avec la variable disparait. Elle doit contenir quoi selon toi, cette variable : un objet représentant un alien ? un identifiant renvoyé par la fonction setInterval() ? un booléen ?

Amicalement,
Bonjour Parsimonhi,

Merci d'avoir pris le temps de me répondre.
En fait, dans ma fonction gere_clic, j'essaie de récupérer les coordonnées des clics par rapport à la position x ou y de mon Canvas. Comme il ne s'agit pas d'afficher ces coordonnées mais plutôt de d'identifier la position d'un alien par rapport au clic de la souris. C'est pourquoi j'ai crée la variable disparait pour qu'elle me renvoie l'identifiant de la fonction.

NB: Mon objectif est que qd je clique sur un alien en mvt qu'il disparait et un autre réapparait en haut à sa place.

Au début, j'ai pensé procédé de cette façon mais j'ai changé le nom de la variable disparait par clique et disparait devient une autre varaible disparait_alien:

var clique;
// Tableau d'aliens
var aliens = [ 
    { x:28,  y:28,  bras_en_bas:true, vitesse:vitesse_aleatoire(), coordx:gere_clic()},
    { x:127, y:107, bras_en_bas:true, vitesse:vitesse_aleatoire(), coordy:gere_clic()},
     ...............
];

// Pour chaque alien connu
function animate_aliens () { 
var disparait_alien;
   for ( var i = 0, e = aliens.length; i < e; ++i ) { 
       disparait_alien = animate_alien(aliens) || disparait_alien; 
   } 

    if (disparait_alien) {
     clearInterval(clique);
     efface_alien(clique);
    }
} 

// récupére les coord lors d'1 clic
fonction gere_clic(e, evt){
      coordx = - canvas.offsetLeft;
      coordy = - canvas.offsetTop; 
      while(e = e.offsetParent){
            coordx +=  e.pageX - canvas.offsetLeft;
            coordy += e.pageY - canvas.offsetTop; 
      }
      return;
}


Les autres fonctions ne changent pas à part les noms de variables.
Modifié par dinolam (02 Jan 2015 - 17:58)
Modérateur
Bonjour,

gere_clic() ne peut pas servir à initialiser coordx dans ton tableau d'aliens au début de ton code. gere_clic() est destinée à être exécutée quand tu cliques quelque part. Je pense que tu devrais modifier gere_clic() et dans cette fonction, faire une boucle pour savoir sur quel alien tu cliques, et ensuite, toujours dans cette fonction, faire les modifications sur cet alien (le cacher? le déplacer? lui changer sa couleur?...), ou appeler une fonction qui fera ces modifications.

Y a plein d'erreurs dans le reste du code. Mais il faut procéder par étape. Essaie déjà de faire fonctionner ta fonction gere_clic() en faisant en sorte que l'alien sur lequel tu cliques disparaisse.

Amicalement,
Re,
Voilà les modifications que j'ai apporté à ma fonction gere_clic():

// Cette fonction permet de réinitialiser notre canvas. Plus rien n'y est affiché.
function efface_alien (alien) {
	context.clearRect(alien.x, alien.y, 11*unit, 8*unit);
}

// Gère clic
function gere_clic (e) {
	var alien = aliens i ;
	var clic_alien = alien.y;

	for (var i = 1; i < aliens.length; i++) {
		if (clic_alien == (e.pageY - canvas.offsetTop)) {
		    	efface_alien(alien);
	        }
	}
	return alien;
}
Modérateur
Bonjour,

Ajouter des espaces autour des indices i, c'est bien, mais du coup tu peux laisser les crochets. Ça donne ça : aliens[ i ]. Smiley cligne

Pour la fonction gere_clic(), c'est bien l'idée. Mais tu n'as pas besoin de mettre un return alien; car ta fonction gere_clic() étant déclenchée par un clic, la valeur de retour ne peut être utilisée par aucune autre fonction.

Je n'ai pas vérifié si ta fonction gere_clic() calcule bien les coordonnées. Tu dois tester.

Ca se passe comme ça :
1) quelque part dans ton code, tu as mis un canvas.addEventListener('click', gere_clic, false); Ca signifie que si on clique sur le canvas, alors cette fonction gere_clic() sera exécutée,
2) tu affiches ta page dans le navigateur : la page attend que tu cliques quelque part ou bien elle exécute les éventuelles fonctions que tu mis dans un setInterval() (j'en ai vu dans ton code),
3) tu cliques sur le canvas, gere_clic() est donc exécutée,
4) gere_clic() trouve les coordonnées du clic, les compare aux coordonnées des aliens, et fait une action si le clic a bien été fait sur un alien,
4) une fois que gere_clic() a été exécutée, la page attend à nouveau un autre clic quelque part avant de faire quelque chose, ou bien elle exécute les éventuelles fonctions que tu mis dans un setInterval().

Amicalement,
Re,

Je n'arrive pas à récupérer les coordonnées.
J'ai cette erreur quand je clique dans mon canvas:
Uncaught TypeError: Cannot read property 'y' of undefined,
dans cette ligne de la fonction gere_clic(): var clic_alien = alien.y; or y est une propriété définit dans mon tableau aliens[].

Je n'arrive pas à la corriger.

J'ai utilisé la fonction animate_aliens() pour le 2e click dt tu parlais et initialisations() de cette façon:

// Pour chaque alien connu
function animate_aliens () { 
    var leader = alien_le_plus_bas();
    var dispa = false;
				
    for ( var i = 0, e = aliens.length; i < e; ++i ) { 
        dispa = animate_alien(aliens[i], leader) || dispa; 
    } 
    if (dispa) {
 	efface_alien(cache_alien);
    }
} 

// Fonction d'initialisation
function initialisations () {
	canvas = document.getElementById('canvas');
	// Définition taille canvas
	canvas.setAttribute('width', largeur);
	canvas.setAttribute('height', hauteur);
	context = canvas.getContext('2d');
	setInterval('animate_aliens();', 200);
       var cache_alien = canvas.addEventListener('click', gere_clic, false);
}


Merci! [/i]
Modifié par dinolam (02 Jan 2015 - 21:47)
Modérateur
dinolam a écrit :
Re,
Je n'arrive pas à récupérer les coordonnées.
J'ai cette erreur quand je clique dans mon canvas:
Uncaught TypeError: Cannot read property 'y' of undefined,
dans cette ligne de la fonction gere_clic(): var clic_alien = alien.y; or y est une propriété définit dans mon tableau aliens[].


Peut-être parce que alien ne contient pas ce que tu penses. alien est-il défini à cette ligne-là ?
Je vois, dans la dernière fonction get_clic() que tu as donnée en exemple, que tu initialises alien avec un var alien = aliens[ i ]; Que vaut i dans cette ligne-là à ton avis ?

Note : je vois aussi plus loin un for (var i = 1; ...) dans lequel il y a un var i. Bien que beaucoup de codeurs javascript, et même des bons, utilisent le mot clé var à l'intérieur d'un for, je déconseille cette pratique : on ne devrait utiliser var qu'en début de fonction. Faire autrement est source de bug.

Ensuite, il y a aussi le problème de calculer les bonnes coordonnées du clic. C'est un problème assez difficile si on veut que ça marche en toute circonstance, et qui a fait couler beaucoup d'encre. On va supposer ici que tu ne cherches à faire fonctionner ton code que sur des navigateurs assez récents, ce qui est forcément le cas vu que tu utilises des canvas. Je te conseille alors les lignes de code suivantes pour calculer les coordonnées d'un clic à l'intérieur de ton canvas (on met ces lignes de code dans la fonction gere_clic()) :

// "this" est l'élément html sur lequel on clique, ici le canvas
// e est l'event généré par le clic
var box = this.getBoundingClientRect();
var x_clic = e.clientX - box.left;
var y_clic = e.clientY - box.top;


Enfin, quand tu cliques dans ton canvas sur un alien, celui-ci fait une certaine taille, et tu ne cliques pas forcément exactement aux coordonnées (x,y) que tu as mis dans ton tableau aliens. Il faut donc détecter non pas que le clic a pour coordonnées (x,y) mais qu'il est dans un rectangle qui entoure l'alien. Je ne sais pas comment sont dessinés tes aliens exactement, mais je vais supposer pour la suite que (x,y) sont les coordonnées du coin en haut à gauche de l'alien, que alien_largeur est la largeur du rectangle entourant l'alien, et que alien_hauteur est la hauteur du rectangle entourant l'alien. On obtient alors la fonction gere_clic() ci-dessous (à adapter si tes aliens ne sont pas dessinés dans un rectangle comme je l'ai supposé) :

var alien_largeur=40, alien_hauteur=20;
function gere_clic (e) {
	var i, alien;
	var box = this.getBoundingClientRect(); // "this" est le canvas
	var x_clic = e.clientX - box.left;
	var y_clic = e.clientY - box.top;
	for (i = 0; i < aliens.length; i++) {
		alien = aliens[ i ];
		if ((x_clic >= alien.x) && (x_clic <= (alien.x + alien_largeur))
			&& (y_clic >= alien.y) && (y_clic <= (alien.y + alien_hauteur))) {
			efface_alien(alien);
		}
	}
}


Amicalement,
Modifié par parsimonhi (03 Jan 2015 - 07:24)
Re,

Merci pour la modification et la nouveauté que tu as apporté dans la fonction gere_clic. Grâce à toi j'ai pris connaissance de la méthode getBoundingClientRect() qui n'est pas nouvelle j'imagine. Mais je ne la connaissais pas avant.
J'arrive maintenant à récupérer mes coords. Et j'ai aussi modifié mes deux fonctions d'animations animate_alien() et animate_aliens(). Seulement mon problème global demeure puisque je n'arrive pas à faire cacher mes aliens quand je leur clique dessus. Hors quand je clique sur un alien, il doit disparaître et remonter en haut.
Ci-dessous le code de mes deux fonctions:

.......................

var cache_alien = null;

// Pour chaque alien connu
function animate_aliens () { 
    var leader = alien_le_plus_bas();
    var dispa = false;			
    for ( var i = 0, e = aliens.length; i < e; ++i ) { 
        dispa = animate_alien(aliens[i], leader) || dispa; 
    }
    if (dispa) {
    	efface_alien(cache_alien);
    }
} 

// L'alien que l'on anime
function animate_alien (alien, leader) { 
    var cache_jeu = false;
    efface_alien(alien);
    ......................	 
    alien.y += alien.vitesse*unit; 
    if (cache_alien) { 
    	alien.y = 0;

   	cache_jeu = true;

        alien.vitesse = vitesse_aleatoire();
    }		 
    affiche_alien(alien, leader); 
    return cache_jeu;
}

// Fonction d'initialisation
function initialisations () {
     [ ....................... ]
     setInterval('animate_aliens();', 200);
    cache_alien = canvas.addEventListener('click', gere_clic, false);
}
[/i]
Modifié par dinolam (03 Jan 2015 - 22:48)
Re Parsimonhi,

J'ai un peu modifié ma fonction gere_clic() et ça marche très bien.

// Gère clic
function gere_clic (e) {
   var i, alien; 
   var x_clic = e.layerX;
   var y_clic = e.layerY;
    
   for (i = 0; i < aliens.length; i++) {
    alien = aliens[i];
    if ((x_clic >= alien.x) && (x_clic <= (alien.x + 11*unit)) && (y_clic >= alien.y)
        && (y_clic <= (alien.y + 8*unit))) {
        efface_alien(alien);
            alien.y = 0;
    }
   }
}


Merci beaucoup pour ton aide,
Je reviendrai pour d'autres questions.

A bientôt!
[/i]
dinolam a écrit :
Re Parsimonhi,

J'ai un peu modifié ma fonction gere_clic() et ça marche très bien.

// Gère clic
function gere_clic (e) {
   var i, alien; 
   var x_clic = e.layerX;
   var y_clic = e.layerY;
    
   for (i = 0; i &lt; aliens.length; i++) {
    alien = aliens[i];
    if ((x_clic &gt;= alien.x) &amp;&amp; (x_clic &lt;= (alien.x + 11*unit)) &amp;&amp; (y_clic &gt;= alien.y)
        &amp;&amp; (y_clic &lt;= (alien.y + 8*unit))) {
        efface_alien(alien);
            alien.y = 0;
    }
   }
}


Merci beaucoup pour ton aide,
Je reviendrai pour d'autres questions.

A bientôt!
[/i]