Forums Développement Multimédia

Aller au contenu

Gestion des événements et Canvas

CODE HTML5

11 réponses à ce sujet

#1 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 18 August 2013 - 14:35 PM

Salut,

Je commence à traduire ma série d'exercices du Wiki à propos de jeux Flash, pour cela j'utilise Javascript et Canvas.

La gestion des évènements clavier n'est pas un gros soucis, par contre celle de la souris est une horreur.
En gros, Canvas étant juste une zone de dessin il n'est pas possible (si je comprend bien) de poser simplement un écouteur sur un élément (si on ne veut pas utiliser de HTML mais rester purement dans le contexte JS+Canvas), puisque Canvas n'est qu'un gros bitmap qu'on redessine quand on en a besoin. La seule chose qu'il semble possible de faire c'est de poser un écouteur sur tout le Canvas.

Du coup, impossible de gérer les événements souris directement dans Canvas pour des objets précis sauf si on fait une map des éléments avec leur positions, et qu'on vérifie à chaque fois si les coordonnées de la souris correspondent aux coordonnées de l'élément (via la map), je ne me trompe pas ?

Je trouve ça super lourd, car la plupart de mes jeux utilisent des événements souris sur un objet (et parfois des dizaines voire des centaines), quelqu'un à une astuce simple à proposer à ce niveau ?

Le but étant de rester dans le contexte JS+Canvas, sans passer par l'intermédiaire du HTML et de balises.

Ici il y arrive : http://lib.ivank.net...demos&d=mevents
J'ai jeté un coup d'oeil rapide à la librairie, mais je n'ai pas trouvé (ou pas compris) l'astuce qu'il utilise.

Merci.

#2 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 August 2013 - 18:57 PM

Hello !


En fait, ce n'est pas aussi compliqué qu'il n'y parait Image IPB

Il suffit d'avoir une classe associé à chaque "displayObject" et d'y créer un équivalent de la méthode 'hitTest' (en jouant sur canvas.style.cursor si tu veux modifier l'apparence du curseur)


<html>
<head></head>
<body>
<canvas id="canvas" width="500" height="500" />
<script type="text/javascript">
//Classe qui gére la position de la souris
var mouseObject = function(canvasMc){
this.x = 0;
this.y = 0;
this.isDown = false;
this.target = null;
var th = this;
canvasMc.onmousemove = function(){
         // je ne me rappelle plus du code pour choper la position de la souris en js
         th.x = POSITION_X;
  th.y = POSITION_Y;
}
canvasMc.onmousedown = function(){
        th.isDown = true;
}
canvasMc.onmouseup = function(){
        th.isDown = false;
        if(th.target != null){
           th.target.onClick();
       th.target = null;
        }
}
}
mouseObject.prototype.setTarget = function(target){
if(this.target == null && this.isDown){
         this.target = target;
}
}




//Classe décrivant un pseudo-displayObject;
var Square = function(name,posx,posy,width,height,mouseObject){
   this.name;
   this.x = posx;
   this.y = posy;
   this.w = width;
   this.h = height;
   this.color = "#cccccc";
 
 
   this.mouseObj = mouseObject;
   this.mouseIsOver = false;
   this.onMouseOver = function(){};
   this.onMouseOut = function(){};
   this.onClick = function(){};
}
Square.prototype.update = function(context2D){
 
var mx = this.mouseObj.x;
var my = this.mouseObj.y;
var minX = this.x;
var minY = this.y;
var maxX = this.x + this.w;
var maxY = this.y + this.h;

if(mx >= minX && mx <= maxX && my >= minY && my <= maxX){
  if(this.mouseIsOver == false){
   this.mouseIsOver = true;
   this.onMouseOver();
  }
}else{
  if(this.mouseIsOver == true){
   this.mouseIsOver = dalse;
   this.onMouseOut();
  }
}

context2D.fillRect(this.color,this.x,this.y,this.w,this.h);
}


//code principale-------------------------------------------------------------------



var mouseObj = new MouseObject();
var squares = [];
var i;
var nb = 100;
var mc;
var canvas = document.getElementById("canvasMc");
for(i=0;i<nb;i++){
   mc = new Square("mc"+i,Math.random()*500,Math.random()*500,30,30,mouseObj);
   mc.onMouseOver = function(){
          canvas.style.cursor = "pointer";
          this.color = "#990000";
   }
   mc.onMouseOut = function(){
          canvas.style.cursor = "default";
          this.color = "#cccccc";
   }
   mc.onClick = function(){
          alert(this.name);
   }
 
   squares[i] = mc;
}
//je renverse le tableau de tel maniere que les objets au premier plan soit listé en premier
//et que l'élement cliqué correspondent bien a celui voulu et pas un autre situé en dessous
squares = squares.reverse()

//[...]
//le code JS que je sais pas écrire par coeur avec lequel tu récupère le context2D du canvas
//[...]
setInterval(update,1000/60);
function update(){
   context.fillRect("#ffffff",0,0,500,500);
   for(i=0;i<nb;i++) squares[i].update(context);
}
</script>
</body>
</html>
 

Je n'ai évidemment pas testé le code car il en manque des bouts, mais l'idée est là.
Je suis certain que ça fonctionne car c'est comme ça que je faisais mes anims AS3 à la fin , en utilisant un seul objet Graphics pour tout faire et gagner en performance.

++

#3 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 18 August 2013 - 19:14 PM

Salut Tom,

Ok merci, je vais étudier ça de plus près (y a une tartine de code quand même pour un simple clic sur un objet lol Image IPB ).

Ce qui me fout un peu la haine c'est que si on peut le faire via une "simple" classe, pourquoi ils ne l'implémentent pas directement dans le langage, les interactions souris/objet c'est quand même une base, et on se retrouve comme en AS1 à devoir coder le moindre bout d'interactivité qu'on veut coller dans une anim, c'est pourtant bien la raison d'être de Canvas, alors pourquoi ne pas le faire directement au lieu de nous obliger à recoder ce qui devrait l'être nativement ? grrrrrr

Je viens de me refaire 8 de mes jeux et franchement c'est de la loose le JS..................



[EDIT] ok, vu, lu et compris (enfin je crois). En gros c'est pareil que de faire une "map" des objets et de tester la position de la souris par rapport à chaque objet de la map, sauf que là tu passe par une classe pour chaque objet, c'est plus propre et certainement plus fiable car au moins tu peux gérer la profondeur. Merci, je pense que je vais réutiliser ce principe, j'en suis a me demander si il n'est pas judicieux de se refaire une gamme complète de classes qui émule le comportement dont j'ai l'habitude avec AS, mais v'la la galère....

#4 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 August 2013 - 19:53 PM

Hello
je te répond en plus court car je suis sur mon téléphone ...

Je pense qu il ne l implémenter pas directement car en fonction de ce que tu veux faire on ne géré pas les collision de la même façon ( pixel perfect / collision à basé de triangle / etc... )

Le fait de ne pas l implémenter obligé le dev à concevoir les choses de manière optimisé (un seul displayobject dans lequel on dessiné tout), exactement la même structure que processing ( qui à fait ses preuve dans le monde artistique donc dans le monde créatif ).

Ce qu on reprochait à flash c était de pouvoir coder trop facilement n importe comment. la c est pas possible et dans le fond je trouvé ça mieux :)/>

#5 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 18 August 2013 - 20:13 PM

Re,

Tu n'as pas tort, j'en conviens, mais ça saoule quand même, il y a quand même un énorme besoin ne serait-ce que pour les interfaces, on pourrait disposer de quelques fonctionnalités simples tout en laissant le choix de les utiliser ou pas. Globalement c'est une perte de temps pour juste gérer des boutons par exemple, on en est pas au test de collision super poussé, c'est juste une hitBox, et puis si on parle d'optimisation un langage typé ce serait déjà une bonne avancée ;-)

M'enfin bon, on va faire avec et changer ses habitudes, pour les premiers jeux que j'ai refait j'utilise des grilles, donc pour le moment ça va je m'en sort avec la position de la souris dans la grille et un seul écouteur sur Canvas, mais j’appréhende le moment où je vais devoir faire une interface genre inventaire + drag & drop avec les objets qui peuvent être déplacés et ceux qui ne le doivent pas.... heureusement avec ta solution ça devrait aller, merci encore.

#6 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 18 August 2013 - 20:21 PM

Yo
en fait je crois que tu trompe quand tu dis que le rôle de canvas est de se substituer à flash ( en gros ).
Actuellement je fais un site en html / js aussi animé qu un site fullflash mais dans mon cas j utilisé canvas uniquement pour les rendus animé qu. tout les boutons sont code au niveau du html/css et c est beaucoup plus simple.

Faire des jeux avec canvas c est tout aussi faisable que de faire des jeux en flash5 mais c est pas fait pour ça mieux:)

#7 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 18 August 2013 - 20:36 PM

Citation

en fait je crois que tu trompe quand tu dis que le rôle de canvas est de se substituer à flash ( en gros ).

[mauvaise fois ON]
Je ne le dit pas, je le sous-entend fortement, c'est pas pareil .... lol ;-)
[mauvaise fois OFF]

C'est en revanche ce que tout le monde prône de partout, HTML5/JS/Canvas/CSS est prévu pour se substituer à Flash...

Citation

Actuellement je fais un site en html / js aussi animé qu un site fullflash mais dans mon cas j utilisé canvas uniquement pour les rendus animé qu. tout les boutons sont code au niveau du html/css et c est beaucoup plus simple.

Oui je fais pareil pour les sites que je fais, et à ce moment là je ne me pose même pas la question, voire je n'utilise même pas Canvas, CSS et JS suffisent la plupart du temps quand je peut me contenter de divs, mais là mon but c'est spécifiquement de faire du jeu.

Citation

Faire des jeux avec canvas c est tout aussi faisable que de faire des jeux en flash5 mais c est pas fait pour ça mieux:)
Bah on a pas tellement d'autre choix à part utiliser des players propriétaires du genre Unity3D, et c'est vrai qu'à la limite ce serait largement mieux, seulement ce que les clients demandent pour du casual c'est du Flash (de moins en moins) ou du HTML5/JS (de plus en plus). C'est sur que si je pouvais tout faire sur Unity je serait heureux... Et puis pour moi c'est aussi un entrainement, comme beaucoup j'ai surtout fait du Flash depuis des années, aujourd'hui on me demande d'utiliser Canvas il faut bien que je soit apte à répondre à la demande, donc le jeu est un bon entrainement, mais c'est clair que c'est pas la panacée comme techno pour le faire.

#8 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 19 August 2013 - 01:17 AM

je reprend le clavier mais j'ai un peu bu, je ne garanti pas que ce que je dis soit plus clair :)

En fait ce que je voulais dire, c'est que Canvas ne sert pas qu'à faire des jeux, loin de là - on peut très bien s'en servir pour faire des fond plus complexe qu'un aplat ou un dégradé, par exemple - et que de fait, on ne peut pas en attendre qu'il soit optimisé pour ça (gestion des evenements, etc...)

Après, je suis comme toi, je veux savoir faire avec canvas ce que je savais faire avec Flash, mais en fait justement, pour avoir opté pour ce type de structure alors que je faisais du Flash, j'ai pu apprécié le gain de perf et ça m'a donné envie de creuser dans cette voie (c'est pour ça que j'ai pu te pondre le code au dessus de tête en 15 minutes). Donc finalement, qu'aujourd'hui on m'oblige à faire ce que je m'obligeais déjà à faire de moi-même, d'une certaine manière c'est une confirmation que j'allais dans le bon sens - et donc je ne remet pas cette direction en question :) -

#9 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 19 August 2013 - 06:57 AM

Yop,

Si si, parfaitement clair et 100% d'accord avec toi ;-)
Je n'avais même pas envisagé de m'en servir pour faire un fond animé.... pour dire comme j'ai une vision de la chose assez limitée lol

C'est vrai que plus j'avançai avec Flash et plus j'avais tendance à vouloir tout faire en un seul dessin dès qu'il fallait gagner de la ressource, par contre j'ai gardé de "mauvaises" habitudes à me servir de displayObject multiples, trouvant ça bien pratique pour pas s'embêter quand la course au gain de perfs n'est pas obligatoire (par exemple un Démineur, ou un Jeweled). Je vais devoir m'imposer de ne plus choisir la facilité avec Canvas, du moins par "facilité" j'entends disposer d'outils tout prêts pour faire un truc en une ligne même si c'est pas super optimisé.

Merci de cette petite discussion, ça me rassure en un sens et me fait changer (un peu) la manière de voir Canvas.

#10 thot

    Ceinture Noire

  • Moderateur
  • PipPipPipPipPipPipPip
  • 328 messages

Posté 25 August 2013 - 01:34 AM

Plop c'est encore moiiiii ! Ce soir je hante le forum !
Monsieur Spi, je suis passé au html5 il y a un moment et comme toi, lors de mon passage à canvas, j'ai voulu
retrouver le confort de l'API flash.

Qu'à cela ne tienne, j'ai recodé une bonne grosse partie de ce comportement !
Je tiens à préciser que j'ai d'abord tatonné mais que finalement toutes mes années passées
à optimiser des jeux en flash m'ont bien servi.

Alors pour répondre à ta question, voilà dans quelle direction tu peux t'orienter:

Tout d'abord prévoir une classe de type "displayobject"
comme dit plus haut, cette classe devra comporter une méthode hittest qui renverra true ou false.
ensuite, coder une classe "displayobjectcontainer" qui contiendra ces "displayobject" et qui en sera un
lui-même.

Bref... jusqu'ici rien de bien fou, rien qu'avec ça tu as une bonne base, là ou ca se complique,
c'est lorsque tu veux gérer pleiins de choses, notamment:

la rotation, le scale, la position en x et y de chaque élement ET les implications que ça a
sur les élements enfants, pour ça y a pas 10 000 solutions, les matrices sont tes amies.
Seulement voilà je n'apprend rien à personne, les calculs matriciels c'est douloureux pour le CPU
( c'est d'ailleurs pas pour rien que les GPU ont été crées ).

Fort heureusement il existe pas mal de techniques pour réduire le recalcul des matrices notamment:

- Ne calculer que les matrices qui ont expressément demandées à l'être ( ça on peut le faire à chaque fois
que l'on change les données graphiques du style x,y,z,scale,rotation d'un objet ) et ça une seule fois par frame.

Lorsqu'on souhaite réaliser un hittest sur un displayobject il suffit alors:

Dans le cas d'un displayobject simple, de multiplier ses valeurs par la matrice resultante de la
multiplication, de toutes les matrices de ses parents + la sienne et de réaliser un hittest simple.

Dans le cas d'un displayobjectcontainer, boucler sur ses enfants pour un hittest et dès qu'un des enfants répond
"true" on stoppe la boucle et on renvoit true.

A ça tu peux rajouter un système de tri binaire sur ton displayobjectcontainer çad:
tu vas choisir un axe dans le repere de ton displayobjectcontainer et tu vas classer ses enfants en
fonction de quel côté il se trouve de l'axe. Une fois que tu demanderas un hittest sur ce
displayobjectcontainer tu pourras savoir, en fonction des coordonnées du hittest de quel côté de l'axe
tu dois réaliser ton test et donc exclure automatiquement une bonne partie des enfants du displayobjectcontainer.

En esperant avoir été clair, au pire pose moi des questions.

PS: en écrivant ma réponse, je me suis demandé si une lib toute simple qui permettrait de réaliser ceci serait quelque chose
d’intéressant pour vous ou si vous souhaitez juste conserver l'interêt pédagogique de la chose ???

#11 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7010 messages

Posté 25 August 2013 - 12:09 PM

Hello,

Merci de ces infos, ça va être utile effectivement.

Citation

en écrivant ma réponse, je me suis demandé si une lib toute simple qui permettrait de réaliser ceci serait quelque chose
d’intéressant pour vous ou si vous souhaitez juste conserver l'interêt pédagogique de la chose ??

Plus ça va et plus il y a de gens qui sont amenés à se poser ce genre de questions, je pense qu'il y aurait un intérêt certain à faire un petit tuto là dessus sur le Wiki, ça contribuerai du passage d'une techno à l'autre pour tous ceux qui viennent de Flash et se recyclent. Ca plus quelques classes pratiques et ce serait le top en fait.

Je vais avancer de mon côté, j'aurais surement des questions, mais n'hésitez pas si vous vous sentez le tuto ;-)

#12 Amaan-Ullah

    Ceinture Blanche

  • Members
  • Pip
  • 1 messages

Posté 10 November 2014 - 05:35 AM

Hello! In Fact, it is not as complicated as it Seems you need is Associated with each "displayObject" class and year to create equivalent method 'hitTest' (playing on canvas .style.cursor if you want to change the appearance of the cursor)
Johni Imtiaz..!!



1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)

authorised training centre

Centre de Formation Mediabox - Adobe et Apple Authorised Training Center.

Déclaré auprès de la Direction du Travail et de la Formation Professionnelle

Mediabox : SARL au capital de 62.000€ - Numéro d'activité : 11 75 44555 75 - SIRET : 49371646800035

MEDIABOX, 23, rue de Bruxelles, 75009 PARIS

FFP