Mausposition und Mausverfolgung mit
Flash 4 und Flash 5

Dieses Tutorial stammt aus dem Buch "Flash 5 und Actionscript professionell - Tutorials und Workshops für fortgeschrittene Techniken".
vielen Dank für die Genehmigung an den Autoren und den Verlag.

Jetzt bestellen bei Amazon

Thema:
Mausposition und Mausverfolgung
Description:
Ermitteln der Mausposition in Flash und Verfolgen der Maus mit einem Objekt
Keywords:
Flash, Maus, Position, Feststellen, Ermitteln, Prüfen, Verfolgen, Mousefollow
Author:
Phaeton (Stephan Fischer )
Date:
14.11.1999
Doc-ID:
23-001
URL:
http://www.flashworker.de/tutorial/23/001.html
Version:
2.0
Änderungen:
10/2000: neues Kapitel f. Flash 5 angehängt
Anforderungen:
Flash 3 und höher / Flash 5
Vorkenntnisse:
Flash Grundkenntnisse

Download:
keine Downloads

Einleitung
  Was bringt dieses Tutorial?

Ermitteln der Mausposition
  Lösungsansätze
  Lösung 1 - unsichtbare 'Sensoren'
  Lösung 2 - angehängtes unsichtbares Symbol

Verfolgung der Maus mit Objekten
  Das Grundprinzip
  Beispiel 1 - Uhrzeiger
  Beispiel 2- Objekt folgt Maus

Maus-/Objektverfolgung
in Flash 5

  Objektorientiertes Skripten
  Beispiel 3

 


 


Was bringt dieses Tutorial?


Oft sieht man auf diversen Seiten, wie Objekte wie magnetisiert der Maus folgen, obwohl die direkte Abfrage der Mausposition in Flash 4 nicht möglich ist. Für diesen und verschiedene andere Effekte ist es aber unerläßlich die Position der Maus zu kennen. Mein Ziel ist es die Grundlagen zur Positionsermittlung und Mausverfolgung möglichst einfach zu erklären. Darauf aufbauend sollten sich einige andere Effekte verwirklichen lassen. Den Umgang mit Filmsequenzen sollte man bereits beherrschen.
Ich habe ein Kapitel zu Flash 5 angehängt, da ich aber denke, daß viele Flash 4 noch eine Weile benutzen werden, habe ich den alten Teil so belassen.
Sollten Sie noch Ideen oder Kritik haben, bin ich hier per E-mail erreichbar.





Ermitteln der Mausposition - Lösungsansätze


Um die Mausposition in Flash 4 feststellen zu können gibt es meines Wissens 2 Ansätze. Einen etwas einfacheren, der aber auch etwas ungenauer ist bzw. Fleißarbeit bedeutet, wenn er genau sein soll und auf der anderen Seite die genaue Ermittlung der Position durch einen kleinen Trick.

1. Lösung: unsichtbare 'Sensoren'
Diese Lösung beruht darauf, auf der betreffenden Fläche, in der die Mausposition abgefragt werden soll, viele kleine unsichtbare Buttons anzulegen. Versieht man diese Buttons mit einer Rollover-Aktion, weiss man auch, an welcher Stelle sich die Maus befindet. BEISPIEL zu Lösungsansatz 1 anzeigen.

Der Vorteil liegt darin, daß die Buttons einfach zu erstellen sind, man die Position nicht ständig abfragen muss (durch die Rollover-Aktion meldet sich der Button von allein) und daß man die Form der 'Sensorflächen' vollkommen frei bestimmen kann.
Der Nachteil liegt darin, daß man je genauer die Abfrage sein soll, auch die Anzahl der Buttons erhöhen muss. Diese kann einen so hohen Arbeitsaufwand erfordern, daß man über Lösung 2 vielleicht einfacher an sein Ziel kommt. Desweiteren verändert sich der Mauszeiger zur Hand, sobald er über einen Button bewegt wird, dieses ist in einigen Fällen auch störend.

2. Lösung: angehängtes unsichtbares Symbol
In diesem Fall wird beim Starten des Flashfilms (oder bei Bedarf auch an anderer Stelle) ein unsichtbares Symbol an den Mauszeiger gehängt, dessen Position man jederzeit abfragen kann, womit man auch gleichzeitig die Position der Maus bekommt (in Flash 5 geht das einfach mit _xmouse und _ymouse). BEISPIEL zu Lösungsansatz 2 anzeigen.

Hier die einzelnen Schritte.

1. Schritt:
Man erzeuge ein neues Symbol ohne Inhalt mit der Eigenschaft Filmsequenz und gebe dem ganzen einen Instanznamen (im Beispiel 'unsichtbarer_clip').

2. Schritt:
Dieses Symbol wird jetzt an den Mauszeiger gehängt in dem man in das erste Frame der Zeitleiste unter Eigenschaften/Aktionen folgende Aktion einträgt :

 Start Drag ("unsichtbarer_clip") 

Die Option 'Lock mouse to center' sollte aktiviert werden damit man die genauen Koordinaten erhält.

3. Schritt:
Nun legt man im ersten Frame des Hauptfilmes die Variablen position_x und position_y an.
Diese geht mit der Aktion:

Set Variable: "position_x" = "" 

und

Set Variable: "position_y" = "" 

Die Werte kann man vorerst leer lassen.

4. Schritt:
Erstellen eines Movieclip-Symbols für die Positionsabfrage. (Ich erzeuge für die Abfrage absichtlich ein eigenes Symbol, und setze dieses in einen eigenen Layer / Ebene. Somit ist die Abfrage unabhängig von dem Rest des Films aktiv. Sie kann aber nach Bedarf auch an anderer Stelle eingesetzt werden)

- neues Symbol erzeugen mit 2 Frames
- In das erste Frame kommt die Abfrage, im 2. Frame ein Goto Frame (genaueres zur Abfrage finden Sie in Beispiel 2)




Verfolgen der Maus mit Objekten


Das Grundprinzip:
Wenn man erst mal die Position ermittelt hat, kann man einem anderen Objekt über SetProperty sagen, auf welche Position es sich bewegen soll oder wie dieses Objekt reagieren soll (z.B. skalieren oder rotieren). Es gibt auch noch etliche andere Wege, auf die ich hier aber erstmal nicht eingehen will.

Im Beispiel 1 wird über den weiter oben beschriebenen 1. Lösungsansatz ein Uhrzeiger nach dem Mauszeiger ausgerichtet.
Im zweiten Beispiel wird die Position über den 2. Lösungsweg ermittelt (angehängtes Objekt) und ein anderes Objekt verfolgt über SetProperty den Mauszeiger.

Beispiel 1 - Uhrzeiger:
Wen man den Mauszeiger über das Ziffernblatt der Uhr bewegt, richtet sich der Minutenzeiger nach der Maus aus.
Der Mauszeiger ist hier ein einzelnes Symbol, als Filmsequenz definiert mit dem Instanznamen 'stunde' (nur Filmsequenzen lassen sich mit SetProperty ansprechen, mit Buttons bzw. Grafiken geht dieses nicht).
Als 'Mausdetektor' habe ich einen Button erzeugt, der den Bereich einer Stunde auf dem Ziffernblatt abdeckt. Diesen habe ich dann für jede weitere Stunde kopiert und entsprechend der benötigten Position um jeweils 30° rotiert und richtig ausgerichtet. BEISPIEL 1 anzeigen.

Damit der Stundenzeiger der Maus folgt habe ich die Buttons mit folgender Aktion belegt:

On (Roll Over) 

Set Property ("/stunde", Rotation) = "0" 

End On 

"/stunde" steht hierbei für den Instanznamen des Symbols, Rotation natürlich für das rotieren.
Die 0 steht für 0° Rotation (angefangen bei Stunde 12). Entsprechend habe ich für jede weiteren Button bzw. Stunde 30° addiert (360° / 12 = 30°).
Das war schon alles !

Entsprechend könnte man das gleiche für den Minutenzeiger machen, wobei hier dann schon 60 Buttons erstellt werden müßten, und die Rotation pro Minute 360° / 60 = 6° entsprechen würde. Das ganze währe schon etwas mehr Aufwand, was auch sehr gut zeigt, welchen Nachteil diese Methode evtl. hat.

(Eine andere Möglichkeit wäre auch noch, eine Filmsequenz mit entsprechend vielen Frames für jede Zeigerstellung zu erstellen und mit den Buttons die Filmsequenz in das passende Frame springen zu lassen. Dazu benötigt man den TellTarget-Befehl, der Thema eines anderen Tutorials ist.)


Beispiel 2 - Objekt folgt dem Mauszeiger:
In diesem Beispiel wird, wie in Lösungsansatz 2 beschrieben, die X- und Y-Position ermittelt und in den Variablen position_x und position_y gespeichert.

Das Symbol, welches dem Mauszeiger folgen soll wurde als Filmsequenz definiert (nur hier kann man die Position mit SetProperty verändern).
Der Instanzname heißt 'verfolger' (nicht besonders Einfallsreich, aber darum geht es hier ja auch nicht :-).
Die Aktionen für die Bewegung des Verfolgers habe ich mit in das gleiche Symbol geschrieben (theoretisch könnte Sie aber auch in der Hauptzeitleiste oder einem anderen Symbol liegen). Damit die Positionen ständig verglichen werden, habe ich 2 Frames angelegt, wobei im zweiten Frame die Anweisung 'Go to and Play (1)' steht, damit ein Loop entsteht.

In Frame 1 steht das wichtige Action-Script, als erstes:

Set Variable: "verfolger_x" = GetProperty ("/verfolger",_x) 

Set Variable: "verfolger_y" = GetProperty ("/verfolger",_y) 

Hiermit bekommen die Variablen verfolger_x und verfolger_y immer die aktuellen X- und Y-Koordinaten des Verfolger-Symbols zugewiesen. Normalerweise kann man auch im weiteren Skript direkt mit GetProperty ("/verfolger",_x) arbeiten, wenn man aber bedenkt das evtl. noch sehr viele Vergleiche gemacht werden müssen, ist das arbeiten mit Variablen (die dann kurz vielleicht nur noch vx und vy heißen) wesentlich einfacher.

Damit sich der Verfolger auch noch bewegt, kann man folgende Aktion benutzen:

If (_level0/:position_x<verfolger_x)

Set Property ("/verfolger", X Position) = verfolger_x-1 

End If 

Hier prüfe ich, ob position_x der maus (_level0/:position_x weil die variable in der hauptebene liegt) kleiner ist als die x-position des verfolgers (verfolger_x). Wenn ja, setzte ich mit SetProperty die X-Position des Verfolgers um 1 niedriger, er bewegt sich also nach links.
Ähnlich ist die Abfrage ob die Maus rechts vom Verfolger steht, x also größer ist, nur das verfolger_x um 1 erhöht wird:

If (_level0/:position_x>verfolger_x)

Set Property ("/verfolger", X Position) = verfolger_x+1 

End If 

Das gleiche macht man dann nochmal mit position_y und verfolger_y und man ist fertig.




Maus-/Objektverfolgung in Flash 5


Die neue Version von Flash bringt wesentliche Erleichterungen was das Skripten angeht. Ursprünglich wollte ich nur das vorhandene Flash 4 Skript an Flash 5 anpassen. Beim rumprobieren merkte ich aber, daß man mit der objektorientierten Programmierung ziemlich einfach ein Objekt bauen kann, welches individuell der Maus oder auch einem anderen Objekt folgen kann. Das will ich euch natürlich nicht vorenthalten, Ihr könnt es in Beispiel 3 sehen.
Im letzten Jahr habe ich natürlich auch dazugelernt und deshalb einen Verzögerungseffekt mit eingebaut (ich hoffe, daß er bei schnellen Rechnern genauso wirkt wie auf meinem alten PII :-)).

Objektorientiertes Skripten
Vereinfacht bedeutet es, daß man z.B. Funktionen, die öfter (von verschiedenen Programmteilen) aufgerufen werden auch als einzelne Funktion programmiert und nicht widerholt an verschiedenen Stellen eingibt. Diese Funktion kann man dann von allen anderen Stellen aufrufen und man spart somit Speicherplatz im Quellcode.
In diesem Beispiel bedeutet es, daß ich eine Filmsequenz habe, welches ein eigenes Skript ausführt und somit seine Position selbst bestimmt. Dadurch, daß ich bestimmte Befehle / Variablen auf das Objekt (die Filmsequenz) selber beziehe, kann jede Instanz dieses Objektes eigenständig arbeiten.
Objektorientiertes Programmieren geht noch wesentlich weiter und ist eigentlich ein Studium für sich, ich denke aber daß es in diesem Zusammenhang übertrieben wäre, weiter darauf einzugehen.

Beispiel 3 - Mousfollow mit Flash 5:
Wie aus dem folgenden Screenshot zu sehen besteht das Beispiel nur noch aus einem Symbol, das ich 'verfolger' genannt habe. Die Filmsequenz 'radar' ist nur Bestandteil von 'verfolger' und enthält die Animation des 'Radars', ist aber für die Funktion selber unwichtig. Von dem Symbol 'verfolger' habe ich 2 Instanzen auf der Bühne plaziert und die Instanznamen 'verfolger1' und 'verfolger2' vergeben. Die Instanz 'verfolger1' soll der Maus folgen und Instanz 'verfolger2' soll 'verfolger1' folgen.



Bild 1: Bühne und Bibliothek mit den Symbolen

Damit das Objekt weiss, was es machen soll, setze ich ein paar Variablen in den Objektaktionen der entsprechenden Instanz. Dorthin kommt man, indem man die Instanz mit der rechten Maustaste anklickt (für Apple-User: 'Ctrl'-Taste und dann Mausklick) und dann auf 'Aktionen' klickt.
Das Skript sieht folgendermaßen aus:

onClipEvent (load) { 

   xpos1 = this._x; 

   ypos1 = this._y; 

   folge = "maus";

   abstandx = 0; 

   abstandy = 0; 
}

Beim Laden der Filmsequenz (onClipEvent (load)) werden Variablen definiert, die sich auf das Objekt beziehen.
'xpos1' und 'ypos1' entsprechen der aktuellen X- und Y-Position der Filminstanz beim Start. Das Schlüsselwort this. bezieht sich immer auf das Objekt, in dem der Code steht.

Die Variable 'folge' muss auf "maus" gesetzt werden, wenn die Filminstanz der Maus folgen soll. Soll die Filminstanz einem Objekt folgen, muss der absolute Pfad der zur verfolgenden Filminstanz angegeben werden. In den Objektaktionen der Instanz 'verfolger2' habe ich entsprechend folge = "/verfolger1" gesetzt.

Als letztes setze ich die Variablen 'abstandx' und 'abstandy', die den Abstand zu dem verfolgtem Objekt oder der Maus in Pixeln angeben. Statt einer Zahl kann man hier natürlich auch einen Ausdruck benutzen, zum Beispiel die Höhe des Objekts (abstandx=this._width;), wie ich es in der Instanz 'verfolger2' getan habe.

Das sind die einzigen Angaben, die für jede Filminstanz getrennt gemacht werden müssen. Man bedenke, daß man hier nicht das Ursprungssymbol verändert, sondern nur die jeweiligen Instanzen!

Als nächstes kommt das Skript, welches für die Bewegung zuständig ist. Es steht in der Zeitleiste der Filminstanz und ist verständlicherweise in jeder Instanz gleich. Es muss bzw. darf nicht abgeändert werden (ausser für Testzwecke natürlich)! Die Zeitleiste besteht aus zwei Frames, damit ich eine ständig laufende Schleife erzeugen kann.


Bild 2: Zeitleiste der Filmsequenz 'verfolger'

Skript in Frame 1:

if (this.folge == "maus") {

   Xpos = _level0._xmouse;

   Ypos = _level0._ymouse;

   } else {

   Xpos = eval(this.folge add "._x");

   Ypos = eval(this.folge add "._y");

}

Hier prüfe ich, ob die Filminstanz der Maus folgen soll oder einer anderen Filminstanz und bestimme die aktuelle Soll-Position (wo die Instanz hin folgen soll).
Ist die Variable 'folge' dieser Intsanz auf "maus" gesetzt, belege ich die Variablen Xpos und Ypos mit der aktuellen Position der Maus (_xmouse und _ymouse).
Ich setze _level0. davor, damit ich den absoluten Wert von der oberen linken Bühnenecke aus bekomme. Ohne bekommt man den Wert relativ zur Filminstanz, der in diesem Fall nicht weiterhilft.

Steht etwas anderes in der Variable 'folge', gehe ich davon aus, daß eine Filminstanz angegeben ist und hole mir die X- und Y-Position von dieser Filminstanz. Wenn ich also "/verfolger1" angebe, würde daraus eval("/verfolger1" add "._x"), dieses wiederum entspricht eval("/verfolger1._x"), womit ich die X-Position hätte. Lasse ich das eval() weg, würde Xpos nur eine Zeichenkette mit dem Wert "/verfolger1._x" übergeben und das ganze würde nicht mehr funktionieren. Gleiches gilt natürlich entsprechend für Ypos.

 xpos1 = (Xpos+3*xpos1)/4;

 ypos1 = (Ypos+3*ypos1)/4;

 this._x = int(xpos1+abstandx);

 this._y = int(ypos1+abstandy);

Als nächstes berechne ich die neue Position der Filminstanz und weise sie den Variablen xpos1 und ypos1 zu. Die Formel (Xpos+3*xpos1)/4 ergibt eine Teilstrecke zwischen den beiden Objekten (Instanz/Maus oder Instanz/Instanz) um die die verfolgende Filminstanz verschoben wird. Diese Teilstrecke wird prozentual immer kleiner, wodurch der Verzögerungseffekt entsteht.

Mit this.x und this.y setze ich dann die Position der aktuellen Filminstanz neu, welche aus der ganzzahligen (int) Summe aus 'xpos' + 'abstandx' bzw. 'ypos' + 'abstandy' besteht.

Skript in Frame 2:

gotoAndPlay (1); 

Hiermit erzeuge ich eine ständig laufende Schleife, damit die Position auch immer wieder neu berechnet wird.

Das war schon alles!
Wie man sieht kann man mit einem kleinen Skript große Wirkung erzielen, der komplette Film hat gerade mal 6kb (mit eingebundener Schriftart 23kb).