Archiv für die Kategorie ‘Flash’

Rufnummernansage mit Flash - erweitert

Dienstag, 19. September 2006
Ich habe eine erweiterte Version von FlashSayNumber (immer noch derselbe Arbeitstitel) hochgeladen, die es ermöglicht, eine von drei Stimmen auszuwählen. Es ist sogar möglich, während der Wiedergabe zwischen den Stimmen zu wechseln - ein Feature, auf das die Welt ja nur noch gewartet hat. :-)

Dank Anita, die mir höchstpersönlich Sprachsamples im Tonstudio aufgezeichnet und zur Verfügung gestellt hat, ist mir klar geworden, wie viel professionelle Ausrüstung ausmacht. Der Unterschied zwischen ihren Samples und meinen per Headset aufgezeichneten ist unglaublich.<br />

Lee Brimelow von gotoAndLearn.com schlägt in seinem Forum ja auch vor, ein vernünftiges Mikro zu verwenden. Ein Rat, dem ich sicher auch mal folgen werde, da Audioaufzeichnungen meines Erachtens im Netz eine große Rolle spielen und ich in dieser Richtung sicher auch noch mehr machen will.

Anyway, hier erneut der (gleichgebliebene) <a href=”http://www.christianscholz.com/demo/flashsaynumber/”>Link zu FSN</a>. Viel Spaß damit!

Ein großes Dankeschön an Anita für ihre zauberhaften Stimmsamples und Matthias für seine Bereitschaft und Mühe, mir mit der Software TextAloud Samples aufzuzeichnen.

Navi-Highlighting: Menüpunkt soll geklickt erscheinen

Freitag, 25. August 2006
Irgendwann wagt sich auch ein Flashneuling daran, ein Navigationsmenü für eine Flash-Website zu erschaffen. Unter Zuhilfenahme diverser Mausereignisse erreichen sie einigermaßen leicht, dass sich die einzelnen Menüeinträge verfärben, wenn BenutzerInnen sie mit dem Mauszeiger überrollen oder klicken.
Was aber oft nicht im ersten Versuch klappt, ist die Umsetzung des folgenden Plans, den bis hierhin gekommene FlashentwicklerInnen als nächstes in Angriff nehmen:
Bei Klick auf einen Menüeintrag soll dieser solange markiert bleiben, bis ein anderer geklickt worden ist. Wenn dieser Fall eingetreten ist, soll natürlich der vormals “geklickt” erschienene Menüeintrag wieder normal aussehen und sich der zuletzt geklickte nach “geklickt” hin färben oder wandeln (vgl. Beispieldatei 1).

Ziel
Dieser Artikel soll einen Weg aufzeigen, wie dieser Plan erfolgreich in die Tat umgesetzt werden kann. Nebenbei erhalten Flashneulinge vielleicht noch den einen oder anderen Tipp, wie sie ihre Navigation per Skript auf die Bühne zaubern können.

Los geht’s
Das folgende Schaubild soll illustrieren, dass zunächst lediglich ein einzelner Movieclip benötigt wird, der aus einem dynamischen Textfeld vor einem rechteckigen Hintergrund besteht:

<img width=”450″ height=”510″ alt=”" src=”http://www.christianscholz.com/img/tut_navi_highlighting.gif” />
Abb. 1: Movieclip menuItem; Abmessungen; Instanz- und Exportnamen

Es wird also in einer leeren Flashdatei ein leeres Movieclip-Symbol angelegt, welches aus den oben gezeigten Zutaten besteht. Wenn das Rechteck aufgezogen und das Textfeld geschaffen und mit dem Instanznamen tfMenuItem ausgestattet worden ist, sollte eben diesem Symbol ein Export- oder Linkagename verpasst werden, der genauso lautet wie der Symbolname: menuItem.

Im Rahmen dieses Artikels bleibt die Bühne leer; der Movieclip menuItem wird per Skript erst mehrfach auf die Bühne gebracht, während der Film läuft. Die dazu nötige Methode attachMovie() wird im folgenden Skript verwendet, wo dann auch deutlich wird, welchen Zweck der Exportname hat.

ActionScript (Frame 1 der Hauptzeitleiste)
// Anzahl der darzustellenden Menüpunkte
nAmountMenuItems = 5;

// Schleife, die bequem 5 Menüpunkte untereinander anzeigt
for (i=0; i<nAmountMenuItems; i++) {
mi = _root.attachMovie(”menuItem”, “menuItem_”+i, i);
mi._x = 50;
mi._y = i*(mi._height-1);
}

Zunächst wird in einer Variablen festgelegt, aus wie vielen Menüeinträgen die Navigation bestehen soll; hier sind es derer fünf.
Innerhalb einer FOR-Schleife wird bei jedem Schleifendurchlauf eine weitere Instanz des Movieclips, dessen Exportname menuItem lautet, an die Hauptzeitleiste gehängt, benannt und auf der Bühne positioniert.

Details zu FOR-Schleifen können <a href=”http://flash.christianscholz.com/articles/schleifen-sparen-zeit-und-muehe”>hier</a> nachgelesen werden.

Zwischenergebnis 1
Das Resultat sollten fünf sauber untereinander platzierte Menüeinträge sein, die allerdings alle den gleichen Text enthalten. Das wäre natürlich wenig vorteilhaft, wenn die Navigation irgendeinen Sinn haben soll. Daher werden ein paar Zeilen Code ergänzt, die dafür sorgen, dass jeder Eintrag einen eigenen Begriff anzeigt:

// Die Namen der Menüpunkte werden in einem Array abgelegt
arMenuHeadlines = new Array(”Home”, “Company”, “Products”, “Imprint”, “Contact”);

// Anzahl der darzustellenden Menüpunkte
nAmountMenuItems = 5;

// Schleife, die bequem 5 Menüpunkte untereinander anzeigt
for (i=0; i<nAmountMenuItems; i++) {
// Erzeugen der 5 Menüpunkte und Positionierung
mi = _root.attachMovie(”menuItem”, “menuItem_”+i, i);
mi._x = 50;
mi._y = i*(mi._height-1);

// Setze den Text im Textfeld
mi.tfMenuHead.text = arMenuHeadlines[i];
}

Ein Array speichert hier alle Texte, die auf den Menüeinträgen stehen sollen. Innerhalb der Schleife wird auf dieses Array zugegriffen und so jedem Eintrag ein anderes Arrayelement zugewiesen.

Details zu Arrays können <a href=”http://flash.christianscholz.com/articles/arrays”>hier</a> nachgelesen werden.

Er werde licht!
Als nächstes erhalten die Menüeinträge ein paar Benimm- und Verhaltensregeln. Dies geschieht ebenfalls in der Schleife, um Zeit und Platz zu sparen. Hier nur die neuen Zeilen Code; das vollständige Skript kann etwas weiter unten eingesehen werden.

mi.onRelease = function() {
this._alpha = 50;
};
mi.onRollOver = function() {
this._alpha = 50;
};
mi.onRollOut = function() {
this._alpha = 100;
};

Wird also ein Menüeintrag mit dem Mauszeiger überrollt oder geklickt, wird hier der ganze Movieclip auf halb-transparent gesetzt. Sicherlich nur für dieses Beispiel eine gute Idee. In der Regel würden sich andere Arten der Hervorhebung besser eignen.
Wird der Mauszeiger wieder weg bewegt, wird die Transparenz wieder aufgehoben.

Es ist erkennbar, dass auch der geklickte Eintrag wieder auf normale Darstellung zurückspringt, obwohl es ja wünschenswert und Ziel dieser Übung wäre, wenn er verwandelt bliebe. Um genau dies zu erreichen, wird jedem Menüeintrag eine Variable mit auf den Weg gegeben, die speichert, ob er sich in geklicktem/selektiertem Zustand befindet oder nicht: isSelected.

Ist nun ein Eintrag einmal angeklickt/selektiert worden, wird seine Variable isSelected auf den Wert true (wahr) gesetzt. Der für diesen Vorgang zuständige Skriptbereich ist der onRelease-Mouse-Handler. Hier wird (durch eine kleine Funktion namens restoreNavi()) auch geregelt, dass alle anderen Menüeinträge auf “normal” und nicht-selektiert geschaltet werden.

An anderer Stelle (beim onRollOut-Mouse-Handler) wird der Zustand des durch die Interaktion der BenutzerInnen betroffenen Menüeintrags wiederum abgefragt und entsprechend verfahren - war der Eintrag, von dem der Mauszeiger gerade wegbewegt worden ist, nicht vormals selektiert, passiert das Übliche und der Movieclip wird wieder auf “normal” geschaltet. War der Eintrag allerdings selektiert, bleibt er in seinem hervorgehobenen Zustand.

Finale und das vollständige ActionScript
Da die Menüeinträge alle ähnlich aussehen und sich ähnlich verhalten, bietet sich hier die Verwendung einer Schleife an. In anderen Szenarien mag dies nicht so naheliegend sein, aber die Technik - Speichern und Abfragen des Zustands - bleibt dieselbe.
// Die Namen der Menüpunkte werden in einem Array abgelegt
arMenuHeadlines = new Array(”Home”, “Company”, “Products”, “Imprint”, “Contact”);

// Anzahl der darzustellenden Menüpunkte
nAmountMenuItems = 5;

// Schleife, die bequem 5 Menüpunkte untereinander anzeigt
for (i=0; i<nAmountMenuItems; i++) {
// Erzeugen der 5 Menüpunkte und Positionierung
mi = _root.attachMovie(”menuItem”, “menuItem_”+i, i);
mi._x = 50;
mi._y = i*(mi._height-1);
// Jeder Menüpunkt wird auf “nicht-selektiert” gesetzt
mi.isSelected = false;
// Setze den Text im Textfeld
mi.tfMenuHead.text = arMenuHeadlines[i];
// Ereignisse, auf die jeder Menüpunkt reagieren soll
mi.onRelease = function() {
restoreNavi();
this.isSelected = true;
this._alpha = 50;
};
mi.onRollOver = function() {
this._alpha = 50;
};
mi.onRollOut = function() {
if (this.isSelected == false) {
this._alpha = 100;
}
};
}

function restoreNavi() {
for (i=0; i<nAmountMenuItems; i++) {
_root["menuItem_"+i]._alpha = 100;
_root["menuItem_"+i].isSelected = false;
}
}

Flash nervt (Teil II): Verschachtelte Event Handler

Mittwoch, 16. August 2006
Je länger ich mit Flash arbeite, desto mehr füllt sich die Liste der nervigen Schwachstellen der immerhin mehrere hundert Euro teuren Software. Arbeiten mit Flash ist wie modernes Fernsehen - immer, wenn es interessant wird, hört der Spaß plötzlich auf. Im Fernsehen ist es Werbung, die alles ruiniert, bei Flash sind es Unzulänglichkeiten, die einen ambitionierten Programmierer vor den Kopf stoßen. Wer aber schon länger mit Flash arbeitet, wird sich auch bereits daran gewöhnt haben, sich ständig Umwege ausdenken zu müssen, wie diese Hürden, die uns FlashentwicklerInnen von Herrn und Frau Macromedia-Adobe aufgebürdet worden sind, doch noch zu überwinden sind; so genannte workarounds sind an der Tagesordnung.

Das Flashfeature, eigene Kontextmenüs zu erstellen, wird ja dadurch versaut, dass sie nun gerade nicht in Standalone-Anwendungen funktionieren, aber darüber habe ich mich ja schon an anderer Stelle aufgeregt.

Worum geht es?
Ein anderes Thema, das noch mehr Leute angeht, da es häufiger nachgefragt wird als die Manipulation irgendwelcher Kontextmenüs, ist das Verschachteln von event handlers. Zur Veranschaulichung folgender Screenshot:

<img src=”../img/freel_contact_beta_shot.gif” alt=”" width=”450″ height=”147″ />
Abb. 1: Einsatzgebiet für verschachtelte event handler aus der Praxis

Es handelt sich um eine Kontaktverwaltungsapplikation (unvollendet). Interessant ist hier hauptsächlich der Bereich, wo einzelne Kontakte angezeigt werden. Jeder Kontakteintrag besteht im Wesentlichen aus einem breiten, rechteckigen Block, in dem ein Foto und einige Textinformationen untergebracht sind. Ferner gibt es noch eine kleine Checkbox. Alles zusammen steckt in einem Movieclip, der über seinen Exportnamen aus der Library auf die Bühne gebracht wird. Das Foto und die Checkbox stellen jeweils eigene Movieclips innerhalb des vorgenannten Movieclips dar.

Das Ansprechen oder Referenzieren dieser ineinander verschachtelten Movieclips ist ja kein Problem. Spannend wird es erst, wenn ich folgenden Plan in die Tat umsetzen will:

  • Bei Überrollen des Blocks soll die Meldung “Block überrollt” ausgegeben werden.
  • Bei Klick auf das Foto soll die Meldung “Foto geklickt” ausgegeben werden.
Versuch 1:
block.onRollOver = function () {
trace(”Block überrollt”);
}
block.foto.onRelease = function () {
trace(”Foto geklickt”);
}

Ergebnis von ActionScript-Versuch 1:
Der event handler onRollOver wird wie gewünscht ausgeführt, die Meldung erscheint. Auf das Foto kann allerdings geklickt werden, bis die Maustaste ihren Geist aufgibt - nichts passiert, keine Meldung erscheint im Ausgabefenster. Das liegt daran, dass es in Flash (noch?) nicht ohne Weiteres möglich ist, event handler auf diese Weise zu verschachteln. Das Skript für den Eltern-Movieclip “block” überdeckt das Skript für den Kind-Movieclip “foto”.

ActionScript-Versuch 2:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
};

Ergebnis von ActionScript-Versuch 2:
Der event handler onRollOver wird ausgeführt, onRelease ebenfalls.

Wird also das überdeckende Skript nach dem ersten Inkrafttreten entfernt (per delete), erhält das zunächst überdeckte Skript eine Chance, seinen Dienst zu verrichten.

Wird jetzt allerdings erneut der Block überrollt, passiert nichts weiter, denn sein Skript ist ja entfernt worden. Das ist natürlich ungünstig, da BenutzerInnen natürlich ruhig so oft mit dem Mauszeiger über den Block rollen können sollen, wie sie wollen, ohne Funktionalitätseinbußen in Kauf nehmen zu müssen.

Irgendwie muss ich also das ursprüngliche Verhalten des Blocks wieder herstellen.

ActionScript-Versuch 3:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
};

Ergebnis von ActionScript-Versuch 3:
Teilerfolg! Der event handler onRollOver wird aktiv, onRelease ebenfalls. Leider befindet sich der Mauszeiger noch über dem Block (eigentlich über dem Foto, aber damit auch über dem Block), während sein Skript restauriert wird, so dass es sofort wieder ausgelöst - und gelöscht - wird.

Wenn ich die Wiederherstellung des Block-Skripts nicht mit onRollOver des Blocks koppele, sondern mit dessen onRollOut, …

ActionScript-Versuch 4:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
_root.block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
delete this.onRollOut;
};
};
};

Ergebnis von ActionScript-Versuch 4:
…komme ich der Lösung zwar ein Stückchen näher und das ursprüngliche Überroll-Verhalten des Blocks wird wieder hergestellt, aber nur(!), wenn vorher das Foto angeklickt worden ist. Wenn BenutzerInnen aber den Block überrollen, das Foto keines Blickes/Klicks würdigen und wieder aus dem Block herausrollen, habe ich immer noch dasselbe Problem: Der Block bleibt deaktiviert und regungslos zurück wie ein kurzgeschlossener Toaster. Füge ich statt dessen einen onRollOut event handler vor allem anderen ein, lande ich wieder in derselben Falle wie ganz am Anfang:

ActionScript-Versuch 5:
block.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
};
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
_root.block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
delete this.onRollOut;
};
};
};

Ergebnis von ActionScript-Versuch 5:
Das Foto-Skript wird wieder überdeckt, diesmal nicht vom onRollOver-, sondern vom onRollOut-Skript des Blocks.

Nicht nur, dass ich auf diese Weise offenbar nicht auf einen grünen Zweig komme; das Skript wird auch noch abartig unübersichtlich und unhandlich.

Anderer Ansatz - hitTest()
Kramt man etwas in Flashs Trickkiste, findet man eine Methode, die ich persönlich genauso halbherzig umgesetzt finde, wie so vieles andere in Flash: hitTest(). Sie soll FlashentwicklerInnen bei Kollisionsabfragen unterstützen, also Abfragen erlauben wie zum Beispiel “Überschneidet sich Movieclip A mit Movieclip B?” oder “Befindet sich der Mauszeiger über Movieclip X?”.

Der Gedanke bei dem folgenden Versuch ist einfach: Wenn man keine event handler verschachteln kann, die speziell mit Maus-Interaktion zusammen hängen, gelingt dann vielleicht die Verschachtelung aus so einem event handler und einer hitTest-Abfrage?

ActionScript-Versuch 6:
function over() {
trace(”Block überrollt!”);
};
block.onRollOver = over;block.foto.onEnterFrame = function() {
if (this.hitTest(_root._xmouse, _root._ymouse)) {
delete this._parent.onRollOver;
this.onRelease = function() {
trace(”Foto geklickt”);
};
} else {
this._parent.onRollOver = over;
}
};

Ergebnis von ActionScript-Versuch 6:
Das Skript ist nicht hübsch, aber es funktioniert. Dem Foto-Movieclip wird ein onEnterFrame event handler mit auf den Weg gegeben, der x mal pro Sekunde überprüft, ob sich der Mauszeiger über dem Foto befindet. Falls dies zutrifft, wird schnell ein geeigneter event handler für das Foto ins Leben gerufen und der event handler für den Block entfernt. Falls BenutzerInnen jedoch das Foto gar nicht im Visier haben, erhält der Block sein normales Verhalten (zurück, wenn das Foto berührt worden ist).

Eigentlich unlogisch
Im Grunde wundert mich, dass es auf diese Weise funktioniert, denn laut Flash-ActionScript Dictionary handelt es sich auch bei onEnterFrame um einen event handler, das heißt, wir haben es hier eigentlich wie bei den ganzen gescheiterten Versuchen oben auch mit sich überdeckenden event handlers zu tun. Nur dass es hier läuft… *seufz*

Mir Luft machen / Test: Textdarstellung bei PC und Mac

Mittwoch, 14. Juli 2004
Ich arbeite zur Zeit für einen Kunden, der noch nicht allzu viel Erfahrung mit Internet und Websites im Allgemeinen und Flashwebsites im Speziellen hat.
Das wäre an sich auch nicht weiter schlimm, wenn von vornherein eine Sache allseitig (sprich: auf Seiten des Kunden) bekannt gewesen wäre: Textdarstellung in Flash ist problematisch!

Dass bei einigen Dingen im Internet Unterschiede bemerkbar werden, sobald man sie sich auf zwei verschiedenen Rechnern mit verschiedenen Konfigurationen oder Betriebssystemen oder Browserarten oder Browserversionen anschaut, ist überall bekannt. Dachte ich. Man findet es nicht gut, dass es so ist, hat es aber schon lange als unumstößlich akzeptiert und sich damit abgefunden. Dachte ich.

Aber nein. Natürlich gibt es noch Menschen, die erst jüngst den Bleistift und das Radiergummi oder den Pinsel weggelegt haben, um mal über den Rand ihres Studiumstellers hinauszuschauen, und die dann ganz erstaunt auf das Medium Internet stoßen.
Wie groß die Freude ist! Und wie vielfältig die Pläne, wie man das neue Medium für sich nutzen könnte!
Eifrig werden unbekannte Werkzeuge zur Hand genommen und mittels Freehand und Photoshop die Träume in Pixel verwandelt. In Freehand und Photoshop sieht alles aus wie gewünscht, also ab damit zum Flasher.
Wie groß ist das Entsetzen! Wie gemein und unverschämt der Flasher, eine Umsetzung zu liefern, die derart nicht eins zu eins dem Layout entspricht!
Wie, ach, das liegt gar nicht am Flasher? Es gibt Dinge, die gehen gar nicht im Internet? Oder sehen scheisse aus? Oder lassen den Besucher der Website ob der zu ladenden Datenlast ächzen und stöhnen?

Gestern entgleisten mir sämtliche Gesichtszüge, platzten Kragen, stellten sich Nackenhaare auf und schwoll der Hals.
Ich fühlte mich wie Bruce Banner, der sich aufregt und zum Hulk mutiert. Innerlich.
Klingt übertrieben, weil ich hier nicht die ganze Geschichte erzählt habe. Werde ich auch nicht machen. Lediglich ein Mahnmal für mich. Ich zögere noch, in meinen WeBlogkalender eine Funktion für “Schwarze Tage” einzufügen.

*atmet tief durch und fühlt sich eigentlich schon wieder ganz gut*

Damit ich mir zukünftig nicht den Mund fusselig reden muss, sollte ich nochmals auf einen Web-Un-Profi treffen, habe ich  mir heute morgen die Mühe gemacht, auf einem PC und einem Mac eine Flashdatei anzeigen zu lassen, die ein Textfeld mit schwarzer Schrift auf weißem Hintergrund enthält. Die Schriftart bleibt bei allen Tests gleich, es verändern sich lediglich ein paar der in Flash MX zur Verfügung stehenden Textfeldoptionen, wie beispielsweise die Textfeldart.

Den veröffentlichten Film habe ich jeweils einmal auf dem PC im Mozilla 1.6 und einmal auf dem Mac im Safari 1.2.2 anzeigen lassen und geSCREENSHHOTtet.

Fazit:
Die Zeilenabstände werden vom Mac und PC nicht gleich interpretiert; beim Mac wird der Text mit geringerem Zeilenabstand angezeigt, obwohl der für das Textfeld in Flash eingestellte Wert nicht verändert wurde.

Dynamische Sitemap in Flash

Mittwoch, 30. Juni 2004
Gerade darüber nachgedacht, ob eine dynamische Sitemap für (m)ein WeBlog interessant wäre.

Mein Gedankengang bisher:

  • User klickt auf Textlink “Sitemap”.
  • Die Site wird als Stadt in isometrischer Ansicht abgebildet.
  • Gebäude stehen für die Hauptbereiche der Site (Kategorien).
  • Bäume stehen für Besucher am Tag/im Monat.
  • Diese Bäume werden in bestimmten Arealen untergebracht, so dass erkennbar ist, dass der und der kleine Wald bedeuten soll, dass so und so viele Leute innerhalb dieses oder jenen Zeitraums ins WeBlog geguckt haben.
  • Statt Bäumen könnten auch kleine Figuren sich vor den Gebäuden tummeln oder Autos in den Straßen, je mehr Besucher im Zeitraum, desto mehr.
  • Externe Links, also solche, die zu anderen Websites führen, werden beispielsweise als Helikopter/Flugzeuge/Raketen dargestellt; bei Klick wird wie üblich ein neues Browserfensterle mit der entsprechenden Site geöffnet oder alternativ erst ein Infotext von mir über diese Site.
  • Strukturelle Verbindungen innerhalb der Site werden durch Straßen symbolisiert. Straßen haben vielleicht auch Namen…?
  • Der Inhalt der Schreischachtel/Shoutbox oder anderer Bereiche, wo meine Leser zu Wort kommen, könnten auf einer Art Leinwand in einem stilisierten Open-Air-Kino angezeigt werden.
  • Die Sitemap könnte sich zoomen und rollen lassen.
  • Straßenlaternen könnten als Indikator benutzt werden für die Frequentiertheit einer Site-Kategorie (wird aber momentan noch gar nicht geloggt).
  • Auf rollOver geben die meisten Elemente noch Zusatz-/Detailinformationen an (Anzahl der Beiträge einer Kategorie, etc.).
  • Fenster in Häusern stehen für die letzten X Beiträge und können überrollt und geklickt werden.

loadSound()

Dienstag, 22. Juni 2004
Mein Freelancer-Kollege Sven hatte gerade das Problem, dass ein per loadSound(”meinmp3file.mp3″, true) gestreamter Sound mit nahezu doppelter Geschwindigkeit abgespielt wurde, was mitunter sicher witzig sein kann, bei seinem klassischen Soundtrack aber eher unpassend wirkte.
Wie üblich in solchen Fällen, wo ich selbst keinen Rat weiß und auf dieser Suchseite nichts Klärendes finden kann, gab ich die Frage an die deutschsprachige Newsgroup Macromedia.General.Germany (Anmerkung vom 7.Mai 2008: …die heute so gut wie tot ist) weiter.

Meine dortigen Mitstreiter Rolphee, Michael Kneib und Matthias Kannengießer (wurde zitiert) halfen mir und Sven aus der Klemme. Ursache für das akustische Phänomen war, dass Sven die MP3-Datei mit einer Bitrate von 32kHz gespeichert hatte (fragt mich nicht, warum *g*). Bei 44.1 kHz lief’s wie gewünscht.

Ferner hier das Zitat von M. Kannengießer auch zu diesem Thema:
“Die folgenden Datenraten (Bitraten) werden sauber von Flash verarbeitet:
8, 16, 20, 24, 32, 48, 56, 64, 80, 112, 128, 160.”

Codierung in Textdateien

Dienstag, 08. Juni 2004
Habe mich gerade wieder durch X Webseiten geGOOGLEt, bis ich auf der Suche nach einem Hinweis fündig wurde°, wie ein Ampersand/Kaufmanns-Und (&) codiert werden muss, das in einer per loadVariables / loadVars in Flash hineingeladenen Textdatei steht - %26 wäre es gewesen.
Denn jenes kleine Scheißerchen macht ja insofern Sorgen, da es eine Variable-Wert-Zuordnung unterbricht, wenn z.B.
var1=Scholz & Friends ist eine Agentur&var2=Da ist es auch schon passiert&
in der Textdatei steht. Das & nach Scholz muss also durch %26 ersetzt werden, dann gibt es keinen Ärger.

Auszug aus der ASCII-Tabelle:
%20: (Leerzeichen)
%22: “
%24: $
%25: %
%26: &
%2B: +
%2F: /

Die Codierung für einen Gedankenstrich bzw. eine Möglichkeit zur Darstellung in Flash suche ich immer noch, fürchte aber, dass dies nicht geht.

° Quelle und Surf-Tipp: http://de.wikipedia.org/wiki/ASCII

LOS oder auch Line of Sight

Donnerstag, 13. Mai 2004
LOS oder die Berechnung oder Herleitung derselben für meine seit Jahren gehegten “Kachelbasierten Spiele” (engl.: tile-based games) hat mich schon sehr lange gefesselt, frustriert und beschäftigt.

Vor ein paar Tagen habe ich es aufgegeben, eine wirkliche Berechnungsmethode zu schaffen. Statt dessen arbeite ich seit gestern erstmal mit einer LUT oder Look-up table, in der für eine auf 10 Felder begrenzte Sichtweite einer Spielfigur Werte abzulesen sind.

Was sind “tile-based games”?
Für den uneingeweihten Mitleser (oder für mich selbst, sollte ich jemals einen Gedächtnisverlust erleiden) hier kurz noch die Hintergründe.
In tile-based games wird die Spielwelt aus kleinen “Kacheln” zusammengesetzt. Eine “Kachel” kann dabei - je nach Maßstab - ein Stück Grasland, ein Baum, ein Haus, ein Dorf oder ähnliches darstellen. Wenn man genügend verschiedene “Kacheln” gestaltet hat, kann man eine nette Landschaft zusammenbauen. Wie mit einem Baukasten.
In der Regel unterliegt so einem Spiel ein schlichtes Raster, das stark an Schiffeversenken oder eine Exceltabelle erinnert; es gibt Felder in horizontaler und in vertikaler Richtung und jedes davon lässt sich eindeutig benennen, z.B. mit “A1″ oder “(3,5)”, je nach Bezeichnung der zwei Achsen.
Nun faszinieren mich besonders KoSims oder Konfliktsimulationsspiele. Berühmte Vertreter dieses Genres sind Risiko, Axis and Allies oder Diplomacy. Bei diesen Spielen geht es also um die Inszenierung von Konflikten und der spielhaften Auseinandersetzung mit der jeweiligen Rolle des Spielers dabei. Langer Rede kurzer Sinn: es wird Krieg gespielt. Spieler A haut Spieler B, der haut zurück, usw.
Ein Aspekt unter vielen bei solchen Spielen kann die “Sichtlinie” (engl. “Line Of Sight” oder kurz “LOS”) sein, d.h. kann Spielfigur X die Spielfigur Y sehen oder stehen/liegen Hindernisse dazwischen, die den Sichtkontakt verhindern?

Träumereien
Da ich bereits seit Flash 4 kleine tile-based games entwickele, habe ich inzwischen genügend Erfahrungen gesammelt, die das Erschaffen einer ansehnlichen Spielwelt erlauben. Daher wurde es allmählich Zeit, ein, zwei Dinge zu finden, die in heute im Internet verfügbaren Flashspielen noch nicht oder nur schwach umgesetzt enthalten sind.
Ich stelle mir vor, dass zwei oder mehrere Spieler mit ihren Einheiten (welcher Art auch immer) durch meine Spielwelt laufen/fahren/schleichen/fliegen und einen Konflikt austragen, ohne die jeweils gegnerischen Einheiten ständig sehen zu können, wie es z.B. beim Schach möglich ist. Eher in Richtung Stratego, wo zwar die Einheiten sichtbar sind, aber nicht deren Rang. Um ehrlich zu sein, will ich eines Tages auf ein Niveau von Fallout Tactics hinaus. Ja, ich weiß - ich hab’ ‘nen Vogel, aber träumen werde ich wohl noch dürfen. Auf dem Weg zu diesem (zumindest mit Flash) unerreichbaren Ziel fällt sicher das eine oder andere markttaugliche Produkt ab. Da bin ich mir sicher.

Sichtlinie
Zurück zur LOS. Kurz die Problembeschreibung:
In einem 2D-Raster gibt es einerseits freie Flächen (Felder) und auf der anderen Seite für Spielfiguren undurchsichtige, undurchdringliche Hindernisse, wie z.B. Wände. Die Aufgabe, die gelöst werden soll, lautet, “besteht zwischen zwei gegebenen Feldern in diesem Raster eine Sichtlinie?”
Der Einfachheit halber wird festgelegt, dass die Sichtlinie blockiert ist, wenn sich auf dem Weg zwischen dem Start- und dem Zielfeld auch nur ein einziges Wand-Feld befindet.
Zur Ermittlung der LOS werden die Mittelpunkte der beiden Felder verbunden mit der vermeintlichen Sichtlinie.

Handarbeit statt Mathematik
Da mir keine mathematische Formel einfallen will, mittels derer ich herausfinden kann, welche Felder bei einer beliebigen Start-/Zielfeld-Paarung auf Vorhandensein einer Wand kontrolliert werden müssen, nehme ich diese Überprüfungen manuell vor und speichere diese Werte in Arrays. Die in Abb. 1 rot gekennzeichneten Felder müssten bei der Ermittlung der LOS auf Vorhandensein einer Wand geprüft werden.

Abb. 1: “Sehstrahl” (Anm. “LOT” ist falsch; “LOS” ist gemeint)

Mir geht es bei dieser manuellen Lösung darum, die Werte, die ich durch viel Handarbeit erhalten werde, möglichst unabhängig von der späteren Beschaffenheit des Rasters einsetzen zu können. Daher bilde ich im ersten Schritt so genannte Delta-Werte, die die aktuelle “Prüfsituation” beschreiben sollen.
Das Startfeld liegt bei (3,3), das Zielfeld bei (0,0), daher notiere ich als varDeltaX eine -3 (0 minus 3 gleich -3) und als varDeltaY ebenfalls eine -3.
Es mag bei allem, was ich hier beschreibe, sehr viel elegantere Wege geben. Da meine Kenntnisse auf dem Gebiet der OOP (Objekt Orientierte Programmierung) allerdings begrenzt sind, nehme ich das, was mir vertraut ist. In diesem Fall eine Kombination aus Variablen, Funktionen und Arrays. Am Ende soll eine Funktion entstehen, die aus Start- und Zielfeldkoordinaten einen Wert zurückgibt, der aussagt, ob LOS besteht oder nicht.

Das Array arDeltas…
Für meinen nächsten Schritt gebe ich jedem Feld meines Rasters noch eine eindeutige Nummer (Abb. 2).


Abb. 2: Durchnummerierte Felder

In einem Array arDeltas speichere ich nun zunächst die folgenden Werte:
-3, -3, 1. Warum das? Das sind die drei Werte, die die “Prüfsituation” beschreiben, wie sie in der Abbildung zu sehen ist; varDeltaX, varDeltaY und die zugehörige Feldnummer. Die fertige Funktion soll später erst im Array arDeltas nachschauen, welche Feldnummer bei der gerade aktuellen “Prüfsituation” zum tragen kommt.

…und die Arrays arDelta1 bis arDeltan
Dann, in einem weiteren Array, dessen Name etwa arDelta1 lautet, wird gezielt nachgeschaut, welche Felder auf Hindernisse geprüft werden müssen. Bei arDeltas und der Durchnummerierung des Rasters handelt es sich also lediglich um einen nötigen Umweg, da ich in Flash nicht direkt schreiben kann delta_-3_-3 = …; Dies führte zu einem Syntaxfehler.
Wie auch immer. In arDelta1 notiere ich jetzt tatsächlich die Delta-Werte der zwei oben rot gekennzeichneten Felder, so dass ich erhalte…
// arDeltas = new Array (-3,-3,1);
arDelta1 = new Array (-1,-1,-2,-2);

Der große Zusammenhang
Die fertige Funktion bekommt ja später die X- und Y-Koordinaten des Start- und Zielfeldes übergeben, zwischen denen auf Vorhandensein einer LOS geprüft werden soll, also wie im Beispiel oben…
function LOS (3,3,0,0) {

}

Daraus ermittelt die Funktion LOS dann die zwei Abstände oder Delta-Werte varDeltaX = -3 und varDeltaY = -3.

Diese Werte werden in arDeltas gesucht und die damit verknüpfte Feldnummer 1 gefunden.

Daraufhin werden in genau einem weiteren Array, nämlich hier arDelta1, die Delta-Werte gefunden, die relativ zur aktuellen infrage kommenden Spielfigurposition geprüft werden müssen, hier also |-1, -1| und |-2,-2|.

Die Funktion prüft daraufhin effektiv die zwei Felder 2,2 (denn 3,3 als Startfeld mit Delta |-1,-1| bearbeitet führt zu Feld 2,2) und 1,1…

[codestart]if (feld2,2 == “wand” or feld1,1 == “wand”) {
// dann keine LOS gegeben!
}[codeend]

So etwas in der Art jedenfalls.

Nun ist der oben abgebildete Fall einer der einfachsten. Wenn alle “Prüfsituationen” so überschaubar wären, bräuchte ich nicht auf eine handgemachte LOT ausweichen. Sind sie aber nicht, wie Abb. 3 zeigen soll. Dort ist zu erkennen, dass der “Sehstrahl” vom Start zum Ziel mehrere Felder kreuzt, schneidet oder durchläuft, die alle auf Vorhandensein einer LOS behindernden Wand geprüft werden müssten.


Abb. 3: Kompliziertere “Prüfsituation”

Wie man sich denken kann, ist das Linienziehen und Array-Füllen einige Arbeit, um wenigstens eine halbwegs brauchbare LOT für Sichtweiten bis 5 Felder zu erhalten. Aus diesem Grund erstellte ich mir per Flash, PHP und lokalem Webserver eine kleine Hilfsapplikation, mit der das ganze Unterfangen schon einfacher und fast schon unterhaltsam wurde (einfache Gemüter sind leicht zu erfreuen).
Diese Applikation ergab dann ein arDeltas-Array mit 1323 Elementen und 441 arDeltaX-Arrays, die für Sichtweiten bis 10 Felder und entsprechende LOS-Ermittlungen ausreichen dürften. Klar, dieselbe Arbeit würde ich mir erneut machen müssen, wenn ich größere Sichtweiten zulassen wollte. Aber fürs erste reicht das.

Mein Plan für heute ist es, die fertige Funktion einzusetzen in einem “Spiel”, wo der Spieler lediglich durch einen Irrgarten rennen kann. Vor Spielbeginn hat der Computer eine Handvoll Felder des Irrgartens mit “Gegnern” besetzt, per Zufall verteilt. Die Positionen dieser “Gegner” sind dem Spieler verborgen.
Immer wenn die Spielfigur ein neues Feld betritt, wird die LOS-Funktion abgefeuert und geprüft, ob die Spielfigur in den Sichtbereich einer der “Gegner” geraten ist. In dem Fall wird der “Gegner” sichtbar.
Das soll’s auch schon sein - ich habe die Angewohnheit, beim Programmieren nur kleine Schritte zu unternehmen. Danach sehen wir weiter.