Muisbewegingsbesturing toevoegen aan uw Flash-projecten gebaren met één lijn

Ik heb onlangs mijn eerste Bamboo gekocht, een Wacom-tablet die letters herkent van vormen die met de stylus zijn getekend. Het prikkelde herinneringen aan mijn eerste ervaring met een gebaargestuurde toepassing: met behulp van muisbewegingen, webbrowsers zoals Maxthon (en later Opera) konden gebruikers snel heen en weer bladeren door webpagina's in de geschiedenis, schakelen tussen verschillende tabbladen, enzovoort. Ik was gefascineerd door de nette gebruikersinterface, omdat het traditionele muisklikken weghaalt. Uiteraard zijn geavanceerde gestuurde apparaten zoals de Kinect, iPad en iPhone nu beschikbaar - maar het begon allemaal met de goede oude pc. In deze tutorial leer je hoe je een fotogalerij ontwikkelt die unieke muisbewegingen herkent.


Eindresultaat voorbeeld

Laten we eens kijken naar het uiteindelijke resultaat waar we naartoe zullen werken. Als u de fotokombuis in de vier hoofdrichtingen wilt verschuiven, klikt en sleept u de muis in de gewenste richting. Als u een foto wilt schalen, sleept u met de muis Zuidoost om te schalen en sleept u met de muis Noord-west om terug te schalen naar de standaardgrootte.

(Opmerking: dit maakt geen klik om de foto te centreren tijdens het pannen, het is gevoelig voor de lengte van de lijn die u tekent.)


Stap 1: Zelfstudiestroom

Dit is wat je zult leren in deze tutorial en de volgorde waarin je het zult leren:

  • Vectorinterpretatie van muisgebaren
  • Hard gecodeerde implementatie van muisbewegingen
  • Klasse om enkelvoudige muisbewegingen te detecteren
  • Voorbeeldapplicatie (fotogalerij) met behulp van de genoemde klas

Stap 2: Bewegingsdetectie: vectoranalyse

Het is belangrijk om de vector wiskunde te begrijpen die betrokken is bij het detecteren van muisbewegingen. Als de detectie van een enkele richting is begrepen, kan het begrip gemakkelijk worden uitgebreid tot alle acht richtingen.

In de onderstaande Flash-presentatie worden de stappen weergegeven van het detecteren van één muisbeweging naar rechts. Om door frames te scrollen in de onderstaande Flash-presentatie, (muis naar beneden - muisbeweging - muis omhoog) in een van de volgende richtingen:

  • Naar het oosten om het frame naar voren te schuiven
  • Westwaarts om frame achteruit te schuiven
  • Noordwaarts om naar het laatste frame te springen
  • Zuidwaarts om naar het eerste frame te springen

Stap 3: Bewegingsdetectie: hoekverschuivingen

Het implementeren van stap 2 zal eenvoudig zijn. De kans is echter 90% dat gebaren van gebruikers zullen mislukken. Diagram hieronder toont veel gebruikte commotie (midden); ze voldoen zelden aan een stijve Vector die naar rechts (links) wijst. Het is dus beter om onnauwkeurigheden in het gebaar op te heffen (rechts).

We kunnen bijvoorbeeld een verlichting van 30 ° aan beide kanten van de vector recht naar beneden verlichten, zodat de hoek van de vector van een gebaar die binnen dat bereik valt, wordt geaccepteerd en geïnterpreteerd als een gebaar naar rechtdoor.


Stap 4: Gebaardetectie: voorbeeldimplementatie

Hieronder is een implementatie van gebarenherkenning naar rechts. Druk op de muis, beweeg de muis naar rechts en laat de muis los in de Flash-presentatie hieronder. Probeer een beetje van het absolute recht af te kijken om de implementatie van verlichting te bekijken.


Stap 5: Variabelen

Laten we eens kijken naar de variabelen op onze hard-gecodeerde implementatie in stap 4. Ik heb de belangrijke Vector2D-variabelen benadrukt. Noteer de opmerkingen die ik aan het einde van elke variabele heb geplaatst.

 privé var t: TextField; private var eerder: Vector2D // bewaar muislocatie bij eerste klik op privé var-laatste: Vector2D // bewaar muislocatie bij vrijgave privé var RECHTS: Vector2D = nieuwe Vector2D (1, 0); // vector van absoluut RECHTS

Stap 6: implementatie van hardcoded

Ik neem aan dat je de basiskennis van het zetten van een al kent TextField in uw project zodat ik me zal concentreren op de ActionScript-implementatie van muisbeweging. De implementatie zoals hieronder aangegeven is zwaar becommentarieerd. Belangrijke vectorberekeningen worden ook gemarkeerd. Ik moedig de lezers aan om deze opmerkingen te bekijken, vooral de opmerkingen die zijn gemarkeerd, om de werking tijdens verschillende runtime-evenementen te begrijpen.

(De Vector2D-klasse is dezelfde als die ik heb gebruikt in eerdere zelfstudies, zoals deze.)

 openbare functie HardCoded () // Een tekstvak maken t = nieuw TextField (); t.selectable = false; t.width = 300; t.x = stage.stageWidth / 2; t.y = stage.stageHeight - 30; addChild (t); // Begin van bewegingsdetectiestadium.addEventListener (MouseEvent.MOUSE_DOWN, start);  // Registreer muislocatie bij neerwaartse muisbeweging persoonlijke functie start (e: MouseEvent): void // Registreer muis onderdruk locatie vroeger = nieuwe Vector2D (e.localX, e.localY); // Start om lijn graphics.lineStyle (3) te tekenen; graphics.moveTo (eerder.x, eerder.y); // voeg muisbewegings- en muisreleaselisten toe stage.addEventListener (MouseEvent.MOUSE_MOVE, verplaats); stage.addEventListener (MouseEvent.MOUSE_UP, hoger);  // Teken beweging bij verplaatsing van muisbeweging privéfunctie (e: MouseEvent): void graphics.lineTo (e.localX, e.localY);  // Evalueer gebaar bij muisvrijgave privéfunctie hoger (e: MouseEvent): void // Registreer muislocatie vrijgeven laatste = nieuwe Vector2D (e.localX, e.localY); // Vector van muizengebaar berekenen var-resultaat: Vector2D = laatst.minus (eerder); // Hoek berekenen van absoluut RECHTS tot gebarenvector. var deviation: Number = RIGHT.angleBuit between (result); afwijking = Math2.degreeOf (afwijking); // Interpretatie van gebaar met verlichting als (Math.abs (deviation) < 30) t.text = "RIGHT gesture detected"; else t.text = ""; //Clear screen of previous drawing. graphics.clear(); //remove mouse move and mouse up listeners stage.removeEventListener(MouseEvent.MOUSE_MOVE, move); stage.removeEventListener(MouseEvent.MOUSE_UP, up); 

Stap 7: Samenvatting

Ter verduidelijking, hier is een samenvatting van de hard-gecodeerde implementatie:

  1. Als de muis is ingedrukt, begint de bewegingsdetectie.
  2. Bij het verplaatsen van de muis, werkt u de laatste locatie van de muisaanwijzer bij.
  3. Bij de muis omhoog, evalueer het hele gebaar sinds (1).

Stap 8: Gebaarhoekverslechteringen

Een nauwkeurig gebaar maken met een muis is moeilijk. Het is moeilijk om rechte lijnen te maken (oost, zuid, west, noord), maar het is nog moeilijker om diagonale lijnen te maken (zuidoost, zuidwest, noordwest, noordoost) omdat we die extra 45 ° moeten schatten. Dus ik heb diagonale lijnen meer verlichtingen gegeven dan rechte lijnen. Let op de grotere grijze hoek voor diagonale Vector in vergelijking met die van de rechte Vector.


Stap 9: Gebaargevoeligheid

 Ik wil wijzen op een ander probleem - gevoelige gebaren. Gevoelige bewegingen identificeren bewegingsrichtingen wanneer de muisaanwijzer de minste verschuivingen in de locatie maakt, zelfs naar aangrenzende pixels. Diagram hieronder illustreert scenario's van gevoelige gebaren.

Als de gebruiker van gedachten verandert nadat de muispreset en de muis onmiddellijk zijn losgelaten, wordt er nog steeds een beweging gedetecteerd als zijn aanwijzer de minste beweging maakt naar de aangrenzende pixels. We moeten gebruikers toestaan ​​om bewegingsdetectie ongedaan te maken. In deze zelfstudie heb ik een minimale sterkte afgedwongen die de Vector van de huidige beweging moet overschrijden om geldig te zijn. Ik heb een diagram hieronder toegevoegd.


Stap 10: Class Variables

Om enkelvoudige muisbewegingen te detecteren die ik heb geïmplementeerd MGesture. Download en onderzoek dit ActionScript-bestand. Ik zal eerst zijn klassenvariabelen doornemen, daarna de klassemethoden.

veranderlijk Data type Doel
mainBox DisplayObjectContainer Container van waaruit gebaren worden gedetecteerd
routebeschrijving Vector. Vectoren van standaardrichtingen
_deviationFromMains Aantal Hoekverlichting toegestaan ​​van gebaar Vector uit 4 hoofdrichtingen (0 ~ 3 inch) routebeschrijving)
_deviationFromDiagonals Aantal Hoekverlichting toegestaan ​​van gebaar Vector vanuit 4 diagonale richtingen (4 ~ 7 in routebeschrijving)
_minDist Aantal Minimale grootte van huidige gebaar Vector is geldig
_earlier Vector2D Locatie van eerste klik
_latter Vector2D Continue aanwijzerlocatie na eerste klik

Hieronder vindt u de code-implementatie van klassevariabelen. Ik heb een afwijking van 10 ° van de hoofdrichtingen toegestaan. Bijvoorbeeld, -10 ° -10 ° wordt als oost gepast, -80 ° -100 ° wordt als gepast Zuid beschouwd, enz. Ik heb ook een afwijking van 30 ° vanuit diagonale richtingen toegestaan. Dus een Vector met oriëntatie tussen 15 ° -75 ° zal worden beschouwd als gevolg van Zuid-Oost, enzovoort. Ook is de minimale grootte die moet worden overschreden 10 px.

 private var mainBox: DisplayObjectContainer; privé var-routebeschrijving: Vector. = nieuw [nieuwe Vector2D (1, 0), // Oost nieuwe Vector2D (0, 1), // Zuid nieuwe Vector2D (-1, 0), // West nieuwe Vector2D (0, -1), // Noord nieuwe Vector2D ( 1, 1), // Zuid - oost nieuw Vector2D (-1, 1), // Zuidwest nieuw Vector2D (-1, -1), // Noordwest nieuw Vector2D (1, -1) // Noord - oost]; privé var diagonalen: Boolean = false; private var_deviationFromMains: Number = Math2.radianOf (10); private var_deviationFromDiagonals: Number = Math2.radianOf (30); private var _minDist: Number = 10; private var _earlier: Vector2D; private var _latter: Vector2D;

Stap 11: Nummeringsrichtingen

Je hebt het misschien al geraden van een verwijzing naar de code-implementatie van routebeschrijving. Ter verduidelijking, hier volgen de hoofdrichtingen 'integer-weergaven.


Stap 12: Class Methods & Property

Hieronder staan ​​klassemethoden voor MGesture.

methoden Invoer uitgang Omschrijving
MGesture Container waarin gebaren worden gedetecteerd leegte Klasse-initiatie, instellingencontainer waaruit gebaren worden gedetecteerd
begin leegte leegte Variabelen voor bewegingsdetectie (_earlier, _latter) initieert
bijwerken leegte Huidige gebaar's Vector (zonder te overwegen _minDist), Vector2D updates _latter en geeft het huidige gebaar terug Vector (_earlier naar _latter)
validMagnitude leegte De Vector van het huidige gebaar (voldoet aan de minimale grootte van _minDist), Vector2D Controleert of de grootte van het huidige gebaar groter is dan _minDist
evalDirections leegte Integer aanduidende richting, int Evalueert de huidige beweging door de Vector te vergelijken met die in routebeschrijving

Stap 13: Methoden

De essentiële methoden die in stap 12 zijn ingediend, zijn hier allemaal gedocumenteerd. Lees de opmerkingen door.

 / ** * Variabelen initiëren * @param-container waarbij muis wordt gedetecteerd uit * / openbare functie MGesture (container: DisplayObjectContainer) // -configuratiecontainer waaruit de muis beweegt mainBox = container;  / ** * Methode om initiële muislocatie te registreren * / public function start (): void var startMX: Number = mainBox.mouseX; var startMY: Number = mainBox.mouseY; _earlier = nieuwe Vector2D (startMX, startMY); // pointer location, initieel _latter = new Vector2D (startMX, startMY); // wijzerlocatie, later te worden bijgewerkt / ** * Methode om de muislocatie bij te werken * @ retourneer een Vector2D van de huidige muislocatie ten opzichte van die wanneer start () wordt aangeroepen; * / public function update (): Vector2D _latter = new Vector2D (mainBox.mouseX, mainBox.mouseY); var vecUpdate: Vector2D = _latter.minus (_earlier); return vecUpdate;  / ** * Methode om een ​​beweging te valideren. * @param newLoc Vector2D naar nieuwe muislocatie * @return null if invalid gesture, a Vector2D if valid * / private function validMagnitude (): Vector2D var gestureVector: Vector2D = update (); var newMag: Number = gestureVector.getMagnitude (); // als de voorwaarde magnitude niet is vervuld, stelt u gestureVector in op null if (newMag < _minDist) gestureVector = null; return gestureVector;  /** * Method to evaluate gesture direction * @return Integer indicative of direction. Invalid gesture, -1. */ public function evalDirections():int  //Pessimistic search (initialise with unsuccessful search) var detectedDirection:int = -1; //validate magnitude condition var newDirection:Vector2D = validMagnitude(); //if gesture exceed minimum magnitude if (newDirection != null)  //evaluation against all directions for (var i:int = 0; i < directions.length; i++)  var angle:Number = directions[i].angleBetween(newDirection); angle = Math.abs(angle); //check against main directions if ( i < 4 && angle < _deviationFromMains)  detectedDirection = i; break;  //check against diagonal directions else if (i > 3 && hoek < _deviationFromDiagonals)  detectedDirection = i; break;   //update mouse location for next evaluation _earlier = _latter;  //return detected direction return detectedDirection 

Stap 14: Fotogalerij

Nu dat het MGesture klas is ingesteld, zullen we verder gaan met een demotoepassing (fotogalerij) ervan. Ik heb hier een bronbestand opgenomen. Download en volg mee. Breng allereerst alle afbeeldingen naar de map "lib" in uw bestaande project. Afbeeldingen die ik hier heb gebruikt, zijn hoffelijkheid van mijn vrouw en dochter.


Stap 15: afbeeldingen insluiten

Maak een nieuwe Actionscript-klasse en geef deze een naam PhotoView. We zullen deze afbeeldingen gebruiken om onze galerij te bouwen.

  1. Genereer insluitcode van afbeeldingen. Ze worden als een generiek herkend Klasse voorwerp.
  2. Gegoten Klasse in Bitmap objecten zodat we het verder kunnen manipuleren.
  3. Zet dit allemaal Bitmap objecten in een Vector array voor eenvoudige selectie later.
 [Embed (source = '... /lib/Week3.jpg')] private var Week3: Class [Embed (source = '... /lib/Family.jpg')] private var Familie: Class [Embed (source = '... / lib / FatherDaughter.jpg ')] private var Dochter: Class [Embed (source =' ... /lib/Jovial.jpg ')] private var Jovial: Class [Embed (source =' ... /lib/NewBorn.jpg ')] privé var NewBorn: Klasse; [Embed (source = '... /lib/Posing.jpg')] private var Positie: Class [Embed (source = '... /lib/Smile.jpg')] private var Smile: Class [Embed (source = '... / lib / Surrender.jpg ')] private var Surrender: Class private var list: Vector. = nieuw  [nieuwe Week3 als bitmap, nieuwe familie als bitmap, nieuwe dochter als bitmap, nieuwe Jovial als bitmap, nieuwe NewBorn als bitmap, nieuwe poseren als bitmap, nieuwe glimlach als bitmap, nieuwe week3 als bitmap, nieuwe overgave als bitmap]

Stap 16: Lijstbeheer weergeven

Het is belangrijk om hier het beheer van te verduidelijken PhotoViewweergavelijst. Ik heb hier een Flash-presentatie opgenomen. Om het te gebruiken, maak een gebaar naar rechts of links. Raadpleeg stap 2 voor meer informatie.


Stap 17: afbeelding positioneren

In de PhotoView's constructor, we initiëren alle benodigde weergaveobjecten en plaatsen ze op hun plaats. En we initiëren MGesture en voeg gebeurtenissen luisteraars toe om bewegingsdetectie te starten. Ik heb de gebeurtenislisteners gemarkeerd. Hun details worden in de volgende twee stappen uitgelegd.

 openbare functie PhotoView () panel = nieuwe Sprite (); // Initate panel panel.x = stage.stageWidth / 2; // Centreerpaneel horizontaal paneel. Y = stage.stageHoogte / 2; // Centreerpaneel verticaal addChild (paneel); var currentBmp: int = 0; // Huidige afbeelding geselecteerd voor het positioneren van var bmpGaps: Number = 60; // Afstand tussen afbeeldingen var bmpOnX: int = 3; // Aantal afbeeldingen op horizontale as var bmpOnY: int = 3; // Aantal afbeeldingen op verticale as var bmp: Bitmap; // Bitmap-object om afbeelding var-container te bevatten: Sprite; // Sprite-container om bmp vast te houden // scrollen door Y voor (var j: int = -1 * Math.floor (bmpOnY / 2); j < Math.ceil(bmpOnY/2); j++)  //scrolling through X for (var i:int = -1*Math.floor(bmpOnX/2); i < Math.ceil(bmpOnX/2); i++)  bmp = list[currentBmp]; bmp.x = -1 * bmp.width / 2; //Bitmap centered horizontally in container bmp.y = -1 * bmp.height / 2; //Bitmap centered vertically in container container = new Sprite(); container.x = (bmp.width + bmpGaps )* i; //Positioning container on x accordingly container.y = (bmp.height + bmpGaps )* j; //Positioning container on y accordingly container.addChild(bmp); //Add bitmap into container container.addEventListener(MouseEvent.MOUSE_DOWN, select); panel.addChild(container); //Add container into panel currentBmp++ //Scroll to next bitmap   gesture = new MGesture(stage); //Initiate MGesture for gesture detection stage.addEventListener(MouseEvent.MOUSE_DOWN, start); 

Stap 18: Afbeelding selecteren om te schalen

De gemarkeerde regel 99 is niet gerelateerd aan de detectie van gebaren, maar alleen aan het selecteren van een afbeelding om te schalen en het bovenop alle andere afbeeldingen te plaatsen.

 persoonlijke functie selecteren (e: MouseEvent): void // Huidige afbeelding op schaal instellen & // Plaatsen bovenop alle andere afbeeldingen ImgSelected = e.currentTarget als Sprite; panel.swapChildrenAt (panel.numChildren - 1, panel.getChildIndex (ImgSelected)); 

Stap 19: Begin, eindig en evalueer muisgebaar

De eerste functie hieronder wordt uitgevoerd met de muis naar beneden. De tweede wordt uitgevoerd met de muis omhoog. Ik heb het gemarkeerd begin() en evalGesture () evenals aanstaande luisteraars.

 persoonlijke functie start (e: MouseEvent): void // Beginnen met bewegingsdetectie & // Luister naar muis omhoog gebeurtenis gesture.start (); stage.addEventListener (MouseEvent.MOUSE_UP, einde);  private function end (e: MouseEvent): void // De grootte van de huidige gesture voorbereiden voor het doel van de animatie // een maximale cap voor de grootte van de gesture implementeren gestureMag = gesture.update (). getMagnitude () / 2; gestureMag = Math.min (gestureMag, maxMag); // Evalueer de huidige bewegingsrichting = gesture.evalGesture (); // Nadat een geldig gebaar is gedetecteerd, voert u de animatie uit // Er worden geen verdere bewegingen gedetecteerd totdat de animatie eindigt als (richting> -1) stage.addEventListener (Event.ENTER_FRAME, move); stage.removeEventListener (MouseEvent.MOUSE_DOWN, start); 

Stap 20: Het paneel en afbeeldingen animeren

Zodra de richtingen zijn gedetecteerd, begint de animatie. Afhankelijk van het gemaakte gebaar, kan het hele paneel in vier richtingen bewegen of kan één enkele afbeelding groter of kleiner worden.

 privé-functie verplaatsen (e: Event): void var currentMag: Number // Motion of panel translation if (direction < 4)  //Function of easing motion currentMag = gestureMag * Math.cos(currentAngle += 0.1); if (direction == 0) panel.x += currentMag; else if (direction == 1) panel.y += currentMag; else if (direction == 2) panel.x -= currentMag; else if (direction == 3) panel.y -= currentMag;  //Motion of image scaling else  //Setting a maximum cap on motion gestureMag = Math.min(0.30, gestureMag); //Function of easing motion currentMag = gestureMag * Math.cos(currentAngle += 0.1); //Conditions to scale up: //Gesture is to South-East & //Image is not scaled up already if (direction == 4 && ImgSelected.scaleX < 1.30) ImgSelected.scaleX = ImgSelected.scaleY = -1 * currentMag + 1.30  //Conditions to scale down: //Gesture is to North-West & //Image is scaled up else if (direction == 6 && ImgSelected.scaleX > 1) ImgSelected.scaleX = ImgSelected.scaleY = currentMag + 1;  // Als hoek bij versnellingsfunctie groter is dan 90 graden / 0,5 Pi radiaal, // stop animatie en schakel bewegingsdetectie in als (currentAngle> Math.PI / 2) stage.removeEventListener (Event.ENTER_FRAME, move); stage.addEventListener (MouseEvent.MOUSE_DOWN, start); richting = -1; // Reset richting currentAngle = 0; // Hoek resetten

Stap 21: Publiceer PhotoView

Nu is alles ingesteld. U kunt eindelijk uw werk publiceren door op Ctrl + Enter op FlashDevelop te drukken. Nog een keer. hier is een stukje van het eindproduct.


Conclusie

Dit is niet het einde. In het volgende deel zullen we kijken naar de detectie van een gebarenreeks, die nog interessanter zal zijn dan dit deel (dat eigenlijk alleen de basis liet zien). Laat reacties achter en laat het me weten als MGesture was nuttig voor je geweest, evenals eventuele bugs, als je die tegenkwam. Eindelijk, terima kasih voor de tijd lezing. Ik hoop mijn medelezers te vermaken in deel 2.