Forums Développement Multimédia

Aller au contenu

detecter le clic d'un objet positioné sous un autre

CODE

18 réponses à ce sujet

#1 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 07 October 2015 - 21:14 PM

Bonjour la communauté,


Je cherche un moyen de détecter le clic de la pyramide verte malgré le carré bleu juste devant.


Image IPB
AS3 -- Flash CS5-5

Voici mon code basique, en fait je n'ai aucune idée de comment réussir ce tour de force.

var _clip:MovieClip = new clip1();
var _zone:MovieClip = new zone();

_clip.x = 150;
_clip.y = 150;
_zone.x = 150;
_zone.y = 150;

addChild(_zone);
addChild(_clip);

_zone.addEventListener(MouseEvent.MOUSE_DOWN, Click);

function Click(pEvt:MouseEvent):void {
trace("click");
}
 

Merci pour votre aide précieuse,

Matthieu

Fichier(s) joint(s)

  • Fichier joint  Clic.fla   6.1 Ko   0 téléchargement(s)


#2 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 07 October 2015 - 21:40 PM

Voici plus exactement le probleme auquel je suis confronté :

Image IPB

J'ai 8 Zones coniques et je dois faire une détections sur celles-ci. Seulement j'ai des objets (en bleu sur l'image) au dessus des zones qui eux même doivent être cliquable.
Autrement dit, au clic sur un objet bleu je doit aussi savoir sur quel zone mon clic a été fait.

Je n'arrive pas a programmer cette chose !


Matthieu

#3 draad

  • Members
  • PipPipPipPipPipPipPipPip
  • 653 messages

Posté 08 October 2015 - 01:53 AM

Salut,

Tu peux faire ça facilement en créant tes propres classes.


Par exemple, tu peux réer ta classe "CarreBleu" qui étend Sprite. Dans cette classe tu écoute l'evenement click comme ceci :


addEventListener(MouseEvent.MOUSE_DOWN, Click);
private function Click (e:MouseEvent):void
{
trace ("Le carré bleu a été cliqué");
dispatchEvent(e);
}
 


Ensuite avec une classe "ConeParent", qui étend Sprite aussi, tu écoute de même l'evenement comme ceci :


addEventListener(MouseEvent.MOUSE_DOWN, Click);
private function Click (e:MouseEvent):void
{
trace ("Le conne a été cliqué aussi");
}
 


Si ton CarreBleu est enfant du ConeParent, alors tu verra que l'evenement est bien passé au cone parent.

J'ai écrit le code a la volée, il y'a peut-etre des erreurs, mais tu as l'idée.

#4 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 02:32 AM

Oui !!

Ça fonctionne bien c'est cool cette astuce :)

Un énorme merci !

Matthieu

#5 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 03:00 AM

J'ai crié victoire un peu vite...

Avec ce code lorsque le carre dépasse de la zone conique et qu'on clic a cet endroit il me renvoie aussi l’événement clic conique puisqu'il étend sa classe. C'est pas bon.

Fichier(s) joint(s)

  • Fichier joint  Clic.fla   6.19 Ko   0 téléchargement(s)
  • Fichier joint  carre.as   865 octets   0 téléchargement(s)
  • Fichier joint  principal.as   958 octets   0 téléchargement(s)
  • Fichier joint  zone.as   849 octets   0 téléchargement(s)


#6 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 03:10 AM

Pour bien comprendre le chmilblik rien de mieux qu'une image, j'ai de multiples zones à gérer et le carre bleu chevauche ces zones. Seulement si je ne peux pas parenter un clip sur deux clip.
Et de toute manière déjà avec une seule zone, si je clic sur le carré en dehors de la zone j'ai un déclenchement d’événement clic Zone.
Image IPB

#7 draad

  • Members
  • PipPipPipPipPipPipPipPip
  • 653 messages

Posté 08 October 2015 - 04:28 AM

C'est difficile de t'aiguiller si je ne sais pas vraiment quel est le but à la fin. Pourquoi as-tu besoin de ces cones et de ces carrés bleu et pourquoi avoir besoin de detecter le clic sur les deux ?

Une premiere option c'est de déplacer ton carré de zone en zone, en fonction de celle qui est le plus recouverte par le carré, tu le parente à la zone la plus plausible. C'est pas très précis, mais selon les cas ça peut suffire.

Une seconde option est de te servir des coordonées de l'evenement click (e.localX et e.localY) pour déterminer quelle zone est touchée. Tu utilise ces coordonées pour savoir si un pixel actif de telle ou telle zone est touché, si oui, alors tu as trouvé ta zone ! Très précis, mais plus long a mettre en place.


PS : concernant la premiere idée, après vérifications, pas besoin de redispatcher l'evenement depuis le carré bleu, l'évenement se propagera tout seul aux parents.

#8 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 04:49 AM

Merci Draad,
Je t'explique un peu plus la finalité :
Il s'agit d'un jeu, il y a un personnage a habiller. Ses vêtements sont dispatchés autour de lui. On les sélectionne et on les glisse dans sa main. Le vêtement se place alors sur son corps au bon endroit.
L’idée du zoning sert a modifier le regard du personnage. C'est un personnage photo qui a 8 états de regard (dans toutes les directions).
Lors d'un clic dans la zone de jeu le regard correspondant a l'endroit du clic s'affiche,
Comme les zones de vision sont coniques je n'arrive pas a cadrer les conditions du genre : entre x=100 x=200 et y = 500 y = 600. Cela me donne des zones carre qui ne colle pas avec l’idée. Du coup je pensais utiliser une détection a partir de clips dessines,
Le problème sont que les vêtements sont dispatchés en semi aléatoire et passent par dessus tout le reste pour rester sélectionnable,

Je crois avoir compris ta première option mais comment détecter la zone la plus recouverte par le carre ?
Ta deuxième option soulève également une question ; comment savoir si un pixel est actif dans tel ou tel zone touche ?

Si tu as une meilleur idée pour le but recherche je suis tout ouï,

Matthieu

#9 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 08 October 2015 - 08:17 AM

Bonjour Matthieu.

Je pense que la solution pour toi serait autour de la fonction getObjectsUnderPoint.
Pour les vêtements, garde les événements MouseOver, MouseDown, MouseUp.
Pour le regard, passe par l'événement MouseMove.

Pour la théorie :

stage.addEventListener(MouseEvent.MOUSE_MOVE , onMouseMove);
function onMouseMove(e:MouseEvent):void {
    trace(stage.getObjectsUnderPoint(new Point(e.stageX , e.stageY)));
}

La fonction getObjectsUnderPoint te retourne donc un tableau, que tu peux parcourir à la recherche de tes clips directionnels.

Par contre, il me semble que c'est un peu lourd comme algo. Normalement, tes regards doivent avoir des paliers réguliers, genre angles de 45º. Pourquoi ne pas calculer l'angle entre la position de la souris et la position des yeux, diviser par huit, typer en int et aller tout simplement à l'image correspondante ? Toujours au MouseMove ?

#10 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7002 messages

Posté 08 October 2015 - 11:43 AM

Bonjour,

Citation

L’idée du zoning sert a modifier le regard du personnage. C'est un personnage photo qui a 8 états de regard (dans toutes les directions).
Lors d'un clic dans la zone de jeu le regard correspondant a l'endroit du clic s'affiche,
Comme les zones de vision sont coniques je n'arrive pas a cadrer les conditions du genre : entre x=100 x=200 et y = 500 y = 600. Cela me donne des zones carre qui ne colle pas avec l’idée.

Dans ce cas, j'opterai pour diriger le regard en fonction de la position de la souris sur un cercle dont le centre serait le regard.
En gros, il suffit de récupérer l'angle entre la souris et le regard pour savoir dans quelle direction pointer le regard.
Peu importe l'élément sur lequel tu cliques.
Je peux me tromper mais je pense que tu t'embêtes pour rien, un peu de trigo pour la direction du regard et tu peux oublier les zones coniques.

Au clic sur un objet tu regarde l'angle formé avec le centre du regard = tu sais dans quelle zone se trouve l'objet
zone 1 = 0 - > 45
zone 2 = 45 -> 90
zone 3 = 90 -> 135
zone 4 = 135 -> 180
zone 5 = 180 -> 225
zone 6 = 225 -> 270
zone 7 = 270 -> 315
zone 8 = 315 -> 360

Citation

Je crois avoir compris ta première option mais comment détecter la zone la plus recouverte par le carre ?

Deux solutions, soit via un calcul de surfaces pour détecter la surface recouverte la plus importante.
Soit via la position de la souris tout simplement, c'est moins précis mais plus fiable et surtout plus simple.

#11 draad

  • Members
  • PipPipPipPipPipPipPipPip
  • 653 messages

Posté 08 October 2015 - 15:05 PM

Je suis d'accord avec Mr Spy et dIdIer, oublie les cones et utilise la trigonométrie pour diriger le regard.

#12 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 15:36 PM

Merci les gars, l’idée me semble la plus simple et facile a mettre en place.

Reste un problème trigonométrique a résoudre non ? :D

Je ne trouve pas mon angle X malgré que je possède toutes les autres mesure, sur le net je ne trouve pas de formule pour calculer cet angle mais je continue à chercher.
Image IPB

#13 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7002 messages

Posté 08 October 2015 - 16:11 PM

Tu peux essayer un truc du genre :



// taille de la zone d'affichage
var W:int = stage.stageWidth;
var H:int = stage.stageHeight;

// cercle central
var cercle:Cercle = new Cercle();
cercle.x = W/2;
cercle.y = H/2;
addChild(cercle);

// écouteur principal
addEventListener(Event.ENTER_FRAME, movingMouse);

// rotation du cercle
function movingMouse(e:Event):void{
   cercle.rotation = getAngle(cercle.x, cercle.y, mouseX, mouseY)*180/Math.PI; // converti en degrés
}

// calcul de l'angle entre deux points
function getAngle (x1:Number, y1:Number, x2:Number, y2:Number):Number{
        var dx:Number = x2 - x1;
        var dy:Number = y2 - y1;
        return Math.atan2(dy,dx);
}
 

Fichier(s) joint(s)



#14 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7002 messages

Posté 08 October 2015 - 16:24 PM

Voilà un exemple avec des yeux :)

Fichier(s) joint(s)



#15 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 08 October 2015 - 16:31 PM

:ph34r: Et sinon, il y a toujours 'la pente d'une droite', niveau 5e. Mais bon, c'est trop facile, ça n'utilise pas la trigo, c'est de la gnognotte…

;)

#16 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7002 messages

Posté 08 October 2015 - 16:37 PM

Tu es un grand malade ! ..... :mrgreen:
Sans trigo point de salut ! :twisted:

[Edit] blague à part, si ça peut intéresser du monde, quelques formules utiles :

       
// ------------------------------------------------------
// USEFULS MATH & GEOM
// ------------------------------------------------------  

// distance entre deux objets  
function distance(a,b ) {
        var dx=a.x-b.x;
        var dy=a.y-b.y;
        return Math.sqrt(dx * dx + dy * dy);
}

// collision droite segment
function collisionDroiteSegment(a,b,c,d) {
        var AB={x:b.x-a.x,y:b.y-a.y};// vecteur AB
        var AD={x:d.x-a.x,y:d.y-a.y};// vecteur AD
        var AC={x:c.x-a.x,y:c.y-a.y};// vecteur AC
        if ((AB.x*AD.y - AB.y*AD.x)*(AB.x*AC.y - AB.y*AC.x)<0) {
                return true;
        }
        return false;
}

// collision segment segment
function collisionSegmentSegment(a,b,c,d) {
        if (! collisionDroiteSegment(a,b,c,d)) {
                return false;
        }
        if (! collisionDroiteSegment(c,d,a,b )) {
                return false;
        }
        return true;
}

// calcule le milieu d'un segment
function segmentCenter(a,b ) {
        return {x:(a.x+b.x)/2,y:(a.y+b.y)/2};
}

// détecter si un point est sur un segment
function pointInSegment(a,b,p) {
        var AB = Math.sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
        var AP = Math.sqrt((p.x-a.x)*(p.x-a.x)+(p.y-a.y)*(p.y-a.y));
        var PB = Math.sqrt((b.x-p.x)*(b.x-p.x)+(b.y-p.y)*(b.y-p.y));

        // exclure les sommets du segment
        var onA=a.x==p.x&&a.y==p.y;
        var onB=b.x==p.x&&b.y==p.y;

        if (int(AB) == int(AP + PB) && !onA && !onB) {
                return true;
        }
        return false;
}

// point d'intersection entre deux segments
function pointIntersection(a,b,c,d) {
        var AB={x:b.x-a.x,y:b.y-a.y};// vecteur AB
        var AD={x:d.x-c.x,y:d.y-c.y};// vecteur AD
        var AC={x:c.x-a.x,y:c.y-a.y};// vecteur AC
        var t = (AC.x*AD.y-AC.y*AD.x)/(AB.x*AD.y-AB.y*AD.x);
        return {x:a.x+AB.x*t,y:a.y+AB.y*t};
}

Et vous pouvez compléter avec quelques formules pour les collisions ici : http://forums.mediab...iche_collisions

Si vous en avez d'autres...

#17 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 08 October 2015 - 17:44 PM

Alors, découpons le camembert en huit, sans la trigo :
function sectoriser(x:int, y:int):int {
   const PENTE:int  = 1,
         SUD:int  = 2,
         OUEST:int = 4;
   var   pente:Number  = x/y,
         secteur:int = 1;

   if (x<0)  secteur += SUD;
   if (y<0)  secteur += OUEST;
   if (pente*pente>1)  secteur += PENTE;

   return secteur;
}


#18 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 08 October 2015 - 18:17 PM

Ça m'a l'air nickel, la formule est simple c'est cool :)
Je m'empresse de tester ça en condition réel.

Merci !!
Matthieu

#19 screenart

    Ceinture Bleue

  • Members
  • PipPipPipPipPip
  • 86 messages

Posté 09 October 2015 - 19:12 PM

Salut,

Au final par rapport a ma figure géométrique, j'ai découvert que l'angle x mesure le double de ACB, c’était donc pas forcément très compliqué non plus par la voie trigonométrique n'en déplaise à didler ;)

Merci encore,
Matthieu



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