Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Gestion des drag&drop

Compatible Director MX2004. Cliquer pour en savoir plus sur les compatibilités.Par glurp (Elliot Coene), le 16 mars 2010

Cliquez pour déplacer les carrés

Gestionnaire et POO

Pour réaliser des drag&drop efficaces, il ne suffit pas d'utiliser les mouseDown et mouseUp d'un sprite. En effet, ceux qui se sont essayés à cet exercice ont pu rapidement remarquer que lorsque la souris se déplace un peu vite, le mouseUp risque de se faire en dehors de l'acteur et donc de ne pas être appelé.
Un gestionnaire de drag&drop est donc indispensable pour la réalisation d'une application efficace. Et qui dit gestionnaire, dit aussi souvent POO. Je vous invite donc d'abord à vous familiariser avec le tutoriel sur la programmation orientée objet.

Programmation dynamique

Pour cet exercice, je vais pousser encore un peu plus loin la programmation.
Les seuls acteurs que nous aurons dans notre cast seront les 3 scripts indispensables ;
- script de movie “global”
- script de comportement “stop”
- script parent “carre_script”

Créations de carrés

Puisque nous n'allons pas utiliser de bitmap tous faits, il va falloir les créer.
Dans l'ordre, il faudra d'abord créer les images, puis les acteurs qui contiendront les image, puis les sprites qui contiendront les acteurs.

Ainsi, le new de notre “carre_script” contiendra le code suivant :

property pNum, pMember, pSprite, pClickOffset
 
on new me, tNum
 
  pNum = tNum
  pClickOffset = point(0,0)
 
  -- Création de l'image --
  tImage = image(30,30,32)
  tImage.fill(tImage.rect, rgb(random(255), random(255), random(255)))
 
  -- Création de l'acteur --
  tMember = _movie.newmember(#bitmap)
  tMember.image = tImage
  tMember.name = "image"&tNum
 
  pMember = tMember
 
  -- Création du sprite --
  pSprite = findEmptyChannel()
  channel(pSprite).makescriptedsprite(tMember, point(random(gWidth), random(gHeight)))
 
  -- Attache le script au sprite --
  sprite(pSprite).scriptInstanceList.add(me)
 
  return me
 
end

Vous remarquez sans doute l'appel à une fonction findEmptyChanne() globale et à deux autres valeurs gWidth et gHeight.
Créons notre script global pour les définir.

global gWidth, gHeight
 
on prepareMovie 
 
  -- Calcul des dimensions de la scene --
  tStage = (the stage).rect
  gWidth = tStage[3] - tStage[1]
  gHeight = tStage[4] - tStage[2]
 
end
 
on findEmptyChannel
 
  repeat with i = 1 to 50    
    if sprite(i).puppet = false and sprite(i).membernum = 0 then
      exit repeat
    end if    
  end repeat
 
  return i
 
end

Ceci fait, revenons à notre carre_script pour nous occuper de la fonction destroy().
La création d'acteurs et l'utilisation de sprites dynamiques nécessitent d'être très rigoureux quant à la suppression des éléments.

on destroy me
 
  -- Destruction de l'acteur --
  pMember.erase()
 
  -- Réinitialisation du sprite --
  resetChannel(pSprite)
 
end

A nouveau, nous utilisons une fonction resetChannel() qui nécessite d'être définie dans le script global.

on resetChannel tNum
 
  sprite(tNum).scriptInstanceList = []
  sprite(tNum).membernum = 0
 
  channel(tNum).removeScriptedSprite()
 
end

Je vous conseille vivement d'utiliser un resetChannel() dans vos projets, puisque le removeScriptedSprite() ne supprime pas forcément les propriétés des sprites utilisés.
Dès lors, lorsque l'on modifie les propriétés visible, blend, ink, etc., il est important de les réinitialiser.

Et bien sûr, n'oublions pas de faire appel à notre fonction destroy lors de la fermeture de l'application

on stopmovie
 
  -- destruction des objets --
  tCount = mesCarres.count  
  repeat with i = 1 to tCount
    mesCarres[i].destroy()
  end repeat  
  mesCarres = void
 
end

Pour terminer la création de nos carrés, il ne reste plus qu'à créer des instances de notre “carre_script”. Nous allons donc compléter notre prepareMovie :

global mesCarres
global gWidth, gHeight
 
on prepareMovie 
 
  -- Calcul des dimensions de la scene --
  tStage = (the stage).rect
  gWidth = tStage[3] - tStage[1]
  gHeight = tStage[4] - tStage[2]
 
  -- Créations des objets --
  mesCarres = []
  repeat with i = 1 to 15
    tScript = script("carre_script").new(i)
    mesCarres.add(tScript)
  end repeat
 
end

A ce stade de l'application, les carrés apparaissent mais ne sont pas encore manipulable.

Déplacement des carrés

Vous vous demandez peut-être pourquoi avoir attaché dans le new le script au sprite via l'ajout à la scriptInstanceList.
Parce que lorsque nous attachons un script parent à un sprite, il bénéficie automatiquement des événements propres aux sprites.
Nous pouvons donc compléter notre script d'un mouseDown bien pratique

on mousedown me
 
  -- Retenir le décalage du click par rapport au centre --
  pClickOffset = _mouse.mouseloc - sprite(pSprite).loc
 
  -- Activer le drag --
  setFollowMouse(pNum)
 
end

Et définir la fonction setFollowMouse dans le script global

on setFollowMouse tNum
 
  -- Démarre le drag --
  gFollow = tNum
  cursor 260
 
end

Attention, n'oubliez pas de définir la nouvelle variable globale gFollow qui servira à déterminer quel carré doit être déplacer.

Pour déplacer ce carré, nous allons simplement définir une boucle temporelle dans le script global

on prepareframe
 
  -- L'objet suit la souris --
  if gFollow > 0 then
 
    -- Eviter un saut lors du clic sur le sprite entre sa position et celle de la souris --
    tClickOffset = mesCarres[gFollow].getClickOffset()
    tPosition = _mouse.mouseloc - tClickOffset
 
    mesCarres[gFollow].setPosition(tPosition) 
 
  end if
 
end

Et retournons à notre “carre_script” pour définir la fonction setPosition() et getClickOffset()

on setPosition me, tPos
 
  -- Modifie la position --
  sprite(pSprite).loc = tPos
 
end
 
on getClickOffset me
 
  -- retourne le décalage originel du click --
  return pClickOffset
 
end

Désormais, lors du clic le carré suit bien la souris, mais le fait de relacher le clic n'a encore aucun effet.
Il est donc nécessaire de terminer par l'ajout d'un mouseUp global

on mouseup
 
  -- Drop de l'objet --
  gFollow = 0
  cursor 0
 
end

Et voilà, vous avez terminé votre gestionnaire de drag&drop !

En savoir plus