Tips on haXe

[2008/2/28新規] [2008/3/1修正] [2008/3/7更新] [2008/3/17更新] [2008/5/10更新]

もくじ

haXe と Flash

Flash は主にウェブブラウザ上でインタラクティブなベクターグラフィックスや動画が効率よく扱え、その実行環境である Flash Player はクライアントサイドのウェブアプリケーション環境として極めて普及していると言える。その上、多くのプラットフォームで Flash Player がサポートされているので、環境に依存しないウェブ指向の可視化ツールとしても非常に有用である。

Flash のファイル形式 swf を作成するには、通常Adobeの統合開発環境(Flash CS3、Flex Builderなど)が必要だが、haXe という JavaScript に似たウェブ指向言語のコンパイラでも作成できる。かたや、Flash 9を生成するAdobeによるプラグラミング言語 ActionScript3 は ECMAScript(ECMA 262)に準拠しており、そもそもこれは JavaScript を元に策定された言語であるので、これらの言語は多少の差異はあれど、ほぼ同様にコーディングできる。

そして、プログラマだけでなくデザイナが Flash を指示する理由のひとつは、その後方互換性であろう。Flash 9 形式の swf は一般のウェブブラウザに搭載されている Flash Player 9 で扱う事ができ、Flash 6/7/8 形式の swf も Flash Player 9 で難なく扱う事ができる。ちなみに haXe は Flash 6/7/8/9 対応の swf を生成できる。その上、haXe からプレーンの ActionScript3 ソースコードも生成できる。

さて、ここでは haXe による Flash 9 プログラミングについて、簡単に備忘録としてまとめていくが、よって、Flash 8 以前や ActionScript2 以前についてはそれほど扱わない。モバイル環境やレガシーなシステムでは Flash Player 9 がサポートされていない故に、古い形式の Flash を作成することを軽視しない方が好ましいが、洗練された ActionScript3 を理解しつつ、必要に応じて ActionScript2 に触れる方が近道であろうと思う。

haXe のインストール

haXe公式サイトから、インストーラやコンパイル済みアーカイブを取得するか、それが 用意されてなければ cvs でソースコードを取得してコンパイルする。 Mac OS XとLinux用コンパイル済みアーカイブの場合は、/usr/local/lib/haxe 配下に展開されてないと動かないようなので、ここのMac OS X では以下のようにした。

$ cd ~/import/lang/
$ tar xvzf haxe-1.19-osx.tar.gz
$ tar xvzf neko-1.7.0-osx.tar.gz
$ tar xvzf swfmill-0.2.12-macosx.tar.gz
$ cd haxe-1.19-osx/
$ ln -s ../neko-1.7.0-osx/* .
$ ln -s ../swfmill-0.2.12-macosx/* .
$ cd /usr/local/lib
$ sudo ln -s ~/import/lang/haxe-1.19-osx haxe

ちなみに上記の neko はサーバサイドのウェブアプリケーションの実行環境として有用な haXe 仮想マシンであるが、Flash しか扱わないなら特に必要ない。また、swfmill は Flash で埋め込みフォントなどを扱う際に必要になる。

ソースからビルド&インストールする場合、オブジェクト指向メタ言語 OCaml が必要となる。詳しい手順は haXe のサイトを参照のこと。

haXe と ActionScript3 のドキュメント

haXe を通して ActionScript3 を理解していく事になるので、ドキュメントとして以下の一次情報元を参考にしていく。

  1. Adobe, ActionScript3 Programming, http://livedocs.adobe.com/flash/9.0_jp/main/flash_as3_programming.pdf
  2. haXe project, haXe Tutorial, http://haxe.org/doc

さらに、以下のようにリストアップされるクラスファイル群は、何はなくとも非常に参考になる。

$ find /usr/local/lib/haxe/std/flash9
	:
/usr/local/lib/haxe/std/flash9/accessibility
	:
/usr/local/lib/haxe/std/flash9/display
	:
/usr/local/lib/haxe/std/flash9/events
	:
/usr/local/lib/haxe/std/flash9/external
	:
/usr/local/lib/haxe/std/flash9/filters
	:
/usr/local/lib/haxe/std/flash9/geom
	:
/usr/local/lib/haxe/std/flash9/media
	:
/usr/local/lib/haxe/std/flash9/net
	:
/usr/local/lib/haxe/std/flash9/printing
	:
/usr/local/lib/haxe/std/flash9/system
	:
/usr/local/lib/haxe/std/flash9/text
	:
/usr/local/lib/haxe/std/flash9/ui
	:
/usr/local/lib/haxe/std/flash9/utils
	:
/usr/local/lib/haxe/std/flash9/xml
	:

C/C++ プログラマは例えば `man atanh` によるマニュアルページ閲覧だけでなく `grep atanh /usr/include/*` のようなインクルードファイルへの検索をプログラミングの過程で行なうと問題解決の糸口が掴めることが多いが、haXe と Flash のコーディングにおいても同様に `grep Camera /usr/local/lib/haxe/std/flash9/*/*` が有用となるはずである。

haXe と ActionScript3 の違い

haXe を通して ActionScript3 を理解していく際に、言語仕様の差異を大まかにでも把握しておくとよい。ここでは、気付いたところからそれらを纏めておく。

haXe ActionScript3
コンストラクタ 「new」 クラス名
上位クラスのコンストラクタ super() を new() の中で呼ぶ必要がある 明示的に super() を呼ばないときは自動的に呼ばれる
Arrayクラス var foo:Array<Dynamic> = [1, 2, 3]; var foo:Array = [1, 2, 3];
void型 「Void」 「void」
クラス名 必ず大文字から 小文字からでも可
型なしクラス 「Dynamic」var foo:Dynamic; 「Obj」var foo:Obj; var foo:*; var a;
論理型 「Bool」 「Boolean」
数値型 「Int, UInt, Float」 「int, uint」「Number」
import文 アスタリスク「*」不可 アスタリスク「*」可
package文 package pkg; class ClassName {} package pkg { class ClassName {} }
引数の省略 function (a, ?b, ?c):Void {} function (a, b=0, c=0):void {}
可変引数 なし 「... args」
型検証 Std:is is
型のキャスト b = cast(a, Int); a as Int;
forループ for (i in 0...n) for (var i=0; i<n; i++)
switch文 v=switch(c){case 0:0;default:1;} switch(c){case 0:v=0;break;default:v=1;break;}
プロパティ getter-settter var x(getter, setter):UInt function get getter(){} function set setter(x:UInt){}
正規表現 EReg クラス RegExp クラス
XML Xml クラス XML クラス
トップレベルの MovieClip main から flash.Lib.current に addChild する MovieClip を継承したクラスを使用する

ActionScript3 と ActionScript2

ActionScript2よりもActionScript3の方がプログラミング言語として洗練され、実現できることも多く、優れている。

これらは haXe においても扱うことができる。

haXe サンプルコード for Flash9

ここでは簡単な Flash9 を生成する haXe サンプルコードを紹介する。

まずは、「Adobe, ActionScript3 Programming」の TextField クラスあたりのいくつかのサンプルコードを haXe に置き換えていく。

ちなみに、ページ番号が書いてる例は、上述のドキュメントで紹介されているコードをなるべくそのまま haXe 用に置き換えることを努めた(そうでない例もある)。しかし、Adobe のソフトウェア開発環境では IDE(統合開発環境)でリソースを生成するものも多く、上述のドキュメントを読めばわかるが、そもそもドキュメントに掲載されているコードは全体像を表していない。こうした IDE を使う限りプログラミング言語としての全体像が把握しにくく、むしろ、haXe でコーディングした方が Flash の仕組みが理解しやすいのではないだろうか。しかも、haXe を使うと swf だけでなく、ActionScript3 用のソースコードを生成することが簡単にでき、IDE では見えにくくなっているリソースの様子を理解する手助けとなるだろう。

先立って、複数のサンプルコードをコンパイルするための makefile を用意してあるので、ビルド方法はそれで明らかだろう。並びに、それぞれ、haXe によって生成された swf もリンク[SWF]の形で添えてあるので参考にされたい。

as3/makefile
HAXEFLAGS=--flash-use-stage
#HAXEFLAGS=--no-traces

HAXE_EXTRA_LIBS=-swf-lib lib/myFont.swf
#HAXE_EXTRA_LIBS=-swf-lib lib/symbolFonts.swf

HAXE=/usr/local/lib/haxe/haxe $(HAXEFLAGS) $(HAXE_EXTRA_LIBS)

SWFS=\
ExampleText.swf	\
ExampleHTMLText.swf	\
ExampleScrollText.swf	\
ExampleUserInputText.swf	\
ExampleCSSHTMLText.swf	\
ExampleAdvancedText.swf	\
ExampleRegExp.swf	\
ExampleXML.swf	\
\
ExampleMovieClip0.swf	\
ExampleMovieClip.swf	\
ExampleDraggableMovieClip.swf	\
ExampleDisplayList.swf	\
ExampleAnimation.swf	\
ExampleExternalMovieClip.swf	\
ExampleGeom.swf	\
\
ExampleSystem.swf	\
ExampleCapabilities.swf	\
\
ExampleMicrophone.swf	\
ExampleCamera.swf	\
ExampleURLSound.swf	\
ExampleURLVideo.swf	\

#all: $(SWFS) $(SWFS:.swf=.html) $(SWFS:.swf=)
all: $(SWFS) $(SWFS:.swf=.html)

%.swf: %.hx
	$(HAXE) -swf $@ -main $* -swf-version 9 -swf-header 640:480:10:ffffff

%.html: %.swf
	echo "<html><head><title>$<</title></head><body><embed src=\"$<\" width=\"640\" height=\"480\" allowfullscreen=\"true\" type=\"application/x-shockwave-flash\"/></body></html>" > $@

%: %.hx
	$(HAXE) -as3 $* -main $* -swf-version 9 -swf-header 640:480:10:ffffff

clean: clean.htmls clean.as3s
	rm -f $(SWFS)

clean.htmls:
	rm -f $(SWFS:.swf=.html)

clean.as3s:
	rm -rf $(SWFS:.swf=)

distclean:
	rm -f $(SWFS:.swf=.hx~)

テキスト関係

as3/ExampleText.hx P.514 テキスト
import flash.display.Sprite;
import flash.text.TextField;
//import flash.text.TextFieldAutoSize;

class ExampleText extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "Hello World!";

  public function new() {
    super();
    //myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);
    myTextBox.text = myText;
  }
  static function main() {
    var me = new ExampleText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

日本語などのソースファイルは utf-8 形式で保存する必要がある。emacs の場合は M-x set-buffer-file-coding-systemutf-8 を選べば良い。

as3/ExampleHTMLText.hx P.515 HTMLテキスト
import flash.display.Sprite;
import flash.text.TextField;

class ExampleHTMLText extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "<p>これは<u>HTML</u>テキストとして<i>描画</i>すべき<b>内容</b>です。</p>";

  public function new() {
    super();
    myTextBox.width = 160;
    myTextBox.height = 120;
    myTextBox.multiline = true;
    myTextBox.wordWrap = true;
    myTextBox.border = true;
    addChild(myTextBox);
    myTextBox.htmlText = myText;
  }
  static function main() {
    var me = new ExampleHTMLText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleScrollText.hx P.516 テキストのスクロール
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.events.MouseEvent;

class ExampleScrollText extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "マウスをクリックするとテキストが上にスクロールするようになっています。テキストが下にスクロールするようにはなっておりません。";

  public function new() {
    super();
    myTextBox.text = myText;
    myTextBox.width = 160;
    myTextBox.height = 30;
    myTextBox.multiline = true;
    myTextBox.wordWrap = true;
    myTextBox.background = true;
    myTextBox.border = true;
    var format:TextFormat = new TextFormat();
    format.font = "Verdana";
    format.color = 0xFF0000;
    format.size = 10;
    myTextBox.defaultTextFormat = format;
    myTextBox.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownScroll);
    addChild(myTextBox);
    myTextBox.htmlText = myText;
  }
  public function mouseDownScroll(event:MouseEvent):Void {
    myTextBox.scrollV++;
  }
  static function main() {
    var me = new ExampleScrollText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleUserInputText.hx P.518 テキスト入力のキャプチャ
import flash.display.Sprite;
import flash.display.Stage;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.events.TextEvent;

class ExampleUserInputText extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myOutputBox:TextField = new TextField();
  static var myText:String = "テキストが追加されると捕捉されます。";
  public function new() {
    super();
    captureText();
  }
  public function captureText():Void {
    myTextBox.type = TextFieldType.INPUT;
    myTextBox.background = true;
    myTextBox.width = 160;
    myTextBox.multiline = true;
    myTextBox.wordWrap = true;
    myTextBox.border = true;
    addChild(myTextBox);
    myTextBox.text = myText;
    myTextBox.addEventListener(TextEvent.TEXT_INPUT, textInputCapture);
  }
  public function textInputCapture(event:TextEvent):Void {
    var str:String = myTextBox.text;
    createOutputBox(str);
  }
  public function createOutputBox(str:String):Void {
    myOutputBox.background = true;
    myOutputBox.width = 160;
    myOutputBox.multiline = true;
    myOutputBox.wordWrap = true;
    myOutputBox.border = true;
    myOutputBox.x = 160;
    addChild(myOutputBox);
    myOutputBox.text = str;
  }
  static function main() {
    var me = new ExampleUserInputText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

次は外部の CSS(カスケードスタイルシート)ファイルを利用するサンプルコードある。それに先立って、あらかじめ以下のような CSS ファイルを作成しておく。

as3/ExampleCSSHTMLText.css
h1 {
  font-size: 20;
  font-family: Arial, Helvetica, _sans;
  font-weight: bold;
}
p {
  font-size: 14;
  font-family: Times New Roman, Times, _serif;
}
.bluetext {
  color: #0000CC;
}
as3/ExampleCSSHTMLText.hx P.521 CSS HTMLテキスト
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;

class ExampleCSSHTMLText extends Sprite {
  var loader:URLLoader;
  var field:TextField;
  var exampleText:String;

  public function new() {
    super();
    /*ExampleCSSHTMLText*/iam();
  }
  public function /*ExampleCSSHTMLText*/iam():Void {
    field = new TextField();
    field.width = 300;
    field.autoSize = TextFieldAutoSize.LEFT;
    field.wordWrap = true;
    addChild(field);
    var req:URLRequest = new URLRequest("ExampleCSSHTMLText.css");
    loader = new URLLoader();
    loader.addEventListener(Event.COMPLETE, onCSSFileLoaded);
    loader.load(req);
    exampleText = "<h1>これがヘッドライン</h1>" +
"<p>これはパラグラフ。これは、" + 
"<span class='bluetext'>青色の属性の範囲</span>。</p>";
  }
  public function onCSSFileLoaded(event:Event):Void {
    var sheet:StyleSheet = new StyleSheet();
    sheet.parseCSS(loader.data);
    field.styleSheet = sheet;
    field.htmlText = exampleText;
  }
  static function main() {
    var me = new ExampleCSSHTMLText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

次は埋め込みフォントのサンプルコードである。それに先立って、あらかじめ swfmill を使って ttf フォントから swf ファイルを作成しておく。

as3/lib/makefile
XML2SWF=/usr/local/lib/haxe/swfmill simple

SWFS=\
myFont.swf	\

all: $(SWFS)

%.swf: %.xml
	$(XML2SWF) $< $@

clean: distclean
	rm -f $(SWFS)

distclean:
	rm -f $(SWFS:.swf=.xml~)
as3/lib/myFont.xml
<?xml version="1.0" encoding="iso-8859-1" ?>
<movie version="9">
  <background color="#000000"/>
  <frame>
    <library>
      <!-- wget -N http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.tar.bz2 -->
      <font name="myFont" import="Vera.ttf"
        glyphs="Hello World!"
      />
    </library>
  </frame>
</movie>

埋め込みフォントのサンプルコード、さらに、クリックするとフォントのレンダリングにおけるアンチエイリアスを変更する例である。

as3/ExampleAdvancedText.hx P.525 埋め込みフォント
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.AntiAliasType;
import flash.text.CSMSettings;
import flash.text.TextRenderer;
import flash.text.TextColorType;
import flash.text.FontStyle;
import flash.text.FontType;

class ExampleAdvancedText extends Sprite {
  public function new() {
    super();
    var format:TextFormat = new TextFormat();
    format.color = 0x336699;
    format.size = 48;		// フォントサイズ
    format.font = "myFont";	// フォント名
    var myText:TextField = new TextField();
    myText.embedFonts = true;	// 埋め込みフォント
    myText.autoSize = TextFieldAutoSize.LEFT;
    myText.antiAliasType = AntiAliasType.ADVANCED; // TextRendererを使用する場合
    myText.defaultTextFormat = format;
    myText.selectable = false;
    myText.mouseEnabled = true;
    myText.text = "Hello World?";
    addChild(myText);
    myText.addEventListener(MouseEvent.CLICK, clickHandler);
  }
  function clickHandler(event:Event):Void {
    var myAntiAliasSettings:CSMSettings = new CSMSettings(
      48,	// fontSize:		ターゲットとなるフォントサイズ
      2,	// insideCutoff:	これを大きくすると細く滑らかになる
      -0	// outsideCutoff:	これを大きくすると太く滑らかになる
    );
    var myAliasTable:Array<CSMSettings> = [myAntiAliasSettings];
    TextRenderer.setAdvancedAntiAliasingTable(
      "myFont", FontStyle.REGULAR,	// ターゲットとなるフォント名とスタイル
      TextColorType.DARK_COLOR,		// 線が濃い(DARK_COLOR)か、薄い(LIGHT_COLOR)か
      myAliasTable			// 所望の CSMSettings
    );
  }
  static function main() {
    var me = new ExampleAdvancedText();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

正規表現

現状[2008/3/7]の haxe では ActionScript3 標準の正規表現クラス RegExp を直接利用するのではなく、haxe 標準の EReg を通して使用するようになっている。以下はそのサンプルコードである。

as3/ExampleRegExp.hx P.285 正規表現
class ExampleRegExp {
  public function new() {
    var regexp:String;
    var pattern:EReg;
    var target:String;
    var result:Bool;
    var dest:String;

    regexp = "ABC";
    pattern = new EReg(regexp, "i");
    target = "abc";
    dest = "efg";
    trace("[regexp]" + regexp + " " +
      "[target]" + target + " " +
      "[match]" + (result=pattern.match(target)) + " " +
      "[replace]" + pattern.replace(target, dest));

    regexp = "<P>.*?</P>";
    pattern = new EReg(regexp, "is");
    target = "<p>paragraph1\n</p><p>paragraph2</p>";
    dest = "";
    trace("[regexp]" + regexp + " " +
      "[target]" + target + " " +
      "[match]" + (result=pattern.match(target)) + " " +
      "[replace]" + pattern.replace(target, dest));

    regexp = "(sh\\w*)";
    pattern = new EReg(regexp, "g");
    target = "she sells seashells by the seashore.\n";
    dest = "($1)";
    trace("[regexp]" + regexp + " " +
      "[target]" + target + " " +
      "[match]" + (result=pattern.match(target)) + " " +
      "[replace]" + pattern.replace(target, dest));
  }
  static function main() {
    var me = new ExampleRegExp();
  }
}
[SWF]

XML

現状[2008/3/18]の haxe では ActionScript3 標準のXMLクラス XML を直接利用するのは難しく、haxe 標準の Xml を使用するようになっている。以下はそのサンプルコードである。

as3/ExampleXML.hx P.348 XML
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;

class ExampleXML extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "";

  public function new():Void {
    super();
    myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);

    var myText:String = "
<order>
  <item id='1'>
    <menuName>burger</menuName>
    <price>3.95</price>
  </item>
  <item id='2'>
    <menuName>fries</menuName>
    <price>1.45</price>
  </item>
</order>
";
    var myXml:Xml = Xml.parse(myText);

    for (e0 in myXml.elements()) {
      //this.trace("e0: " + e0);
      for (e1 in e0.elements()) {
        //this.trace("e1: " + e1);
        /*for (e2 in e1.elements()) {
          this.trace("e2: " + e2);
        }*/
        var item = new haxe.xml.Fast(e1);
        this.trace("item.att.id: " + item.att.id);
        this.trace("item.node.menuName.innerData: " + item.node.menuName.innerData);
        this.trace("item.node.price.innerData: " + item.node.price.innerData);
      }
    }
    this.trace("");

    myXml.firstElement().addChild(Xml.parse("
  <item id=\"3\">
    <menuName>medium cola</menuName>
    <price>1.25</price>
  </item>
"));
    myXml = Xml.parse(myXml.toString()); // !
    for (e0 in myXml.firstElement().elements()) {
      var item = new haxe.xml.Fast(e0);
      this.trace("item.att.id: " + item.att.id);
      this.trace("item.node.menuName.innerData: " + item.node.menuName.innerData);
      this.trace("item.node.price.innerData: " + item.node.price.innerData);
    }
    /*this.trace("");

    myXML.item[0].menuName="regular burger";
    myXML.item[1].menuName="small fries";
    myXML.item[2].menuName="medium cola";
    myXML.item.(menuName=="regular burger").@quantity = "2";
    myXML.item.(menuName=="small fries").@quantity = "2";
    myXML.item.(menuName=="medium cola").@quantity = "2";

    var total:Number = 0;
    for each (var property:XML in myXML.item) {
      var q:int = Number(property.@quantity);
      var p:Number = Number(property.price);
      var itemTotal:Number = q * p;
      total += itemTotal;
      this.trace("menuName: " + property.menuName + " " +
        "price: " + property.price + " * " +
         "@quantity: " + q + " = " + itemTotal.toFixed(2));
    }
    this.trace("Total: $" + total.toFixed(2));*/
  }
  function trace(text:String):Void {
    myText += text + "\n";
    myTextBox.text = myText;
  }
  static function main() {
    var me = new ExampleXML();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

ディスプレイ関係

次に、MovieClip や Sprite など描画関係のサンプルコードをいくつか紹介する。

as3/ExampleMovieClip0.hx
import flash.display.MovieClip;

class ExampleMovieClip0 {
  static function main() {
    var mc:MovieClip = flash.Lib.current;
    mc.graphics.lineStyle(1, 0xFF0000, 100);
    mc.graphics.beginFill(0x0000FF, 100);
    mc.graphics.moveTo(100, 100);
    mc.graphics.lineTo(200, 100);
    mc.graphics.lineTo(200, 200);
    mc.graphics.lineTo(100, 200);
    mc.graphics.lineTo(100, 100);
    mc.graphics.endFill();
  }
}
[SWF]
as3/ExampleMovieClip.hx
import flash.display.MovieClip;
import flash.events.MouseEvent;

class ExampleMovieClip {
  static function main() {
    var mc:MovieClip = new MovieClip();
    flash.Lib.current.addChild(mc);
    mc.graphics.lineStyle(1, 0x000000, 100);
    mc.graphics.beginFill(0xFF0000, 100);
    mc.graphics.moveTo(100, 100);
    mc.graphics.lineTo(200, 100);
    mc.graphics.lineTo(200, 200);
    mc.graphics.lineTo(100, 200);
    mc.graphics.lineTo(100, 100);
    mc.graphics.endFill();

    mc.addEventListener(MouseEvent.MOUSE_DOWN, function(ev:MouseEvent) { mc.startDrag(false); });
    mc.addEventListener(MouseEvent.MOUSE_UP, function(ev:MouseEvent) { mc.stopDrag(); });
  }
}
[SWF]
as3/ExampleDraggableMovieClip.hx
import flash.display.MovieClip;
import flash.events.MouseEvent;

class ExampleDraggableMovieClip extends MovieClip {
  public function new() {
    super();
    graphics.lineStyle(1, 0x000000, 100);
    graphics.beginFill(0xFF0000, 100);
    graphics.moveTo(100, 100);
    graphics.lineTo(200, 100);
    graphics.lineTo(200, 200);
    graphics.lineTo(100, 200);
    graphics.lineTo(100, 100);
    graphics.endFill();
    addEventListener(MouseEvent.MOUSE_DOWN, onPress);
    addEventListener(MouseEvent.MOUSE_UP, onRelease);
  }
  public function onPress(ev:MouseEvent):Void { startDrag(false); }
  public function onRelease(ev:MouseEvent):Void { stopDrag(); }
  static function main() {
    var me = new ExampleDraggableMovieClip();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleDisplayList.hx P.385 ディスプレイオブジェクト
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;

private class Ball extends MovieClip {
  public function new(color:Int, label:String) {
    super();
    graphics.lineStyle(1, 0x000000, 100);
    graphics.beginFill(color, 100);
    graphics.drawCircle(x, y, 30);
    graphics.endFill();
    var myTextField:TextField = new TextField();
    myTextField.text = label;
    addChild(myTextField);
  }
}

class ExampleDisplayList extends Sprite {
  var ball_A:Ball;
  var ball_B:Ball;
  var ball_C:Ball;

  public function new() {
    super();
    ball_A = new Ball(0xFFCC00, "a");
    ball_A.name = "ball_A";
    ball_A.x = 20;
    ball_A.y = 20;
    addChild(ball_A);
    ball_B = new Ball(0xFFCC00, "b");
    ball_B.name = "ball_B";
    ball_B.x = 70;
    ball_B.y = 20;
    addChild(ball_B);
    ball_C = new Ball(0xFFCC00, "c");
    ball_C.name = "ball_C";
    ball_C.x = 40;
    ball_C.y = 60;
    addChildAt(ball_C, 1);
    addEventListener(MouseEvent.MOUSE_DOWN, onPress);
    addEventListener(MouseEvent.MOUSE_UP, onRelease);
    x = y = 20;
  }
  public function onPress(ev:MouseEvent):Void { removeChild(ball_C); startDrag(false); }
  public function onRelease(ev:MouseEvent):Void { stopDrag(); addChild(ball_C); }
  static function main() {
    var me = new ExampleDisplayList();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleAnimation.hx P.416 アニメーション
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.events.Event;

private class Ball extends MovieClip {
  var d:Float;
  public function new(color:Int, label:String) {
    super();
    graphics.lineStyle(1, 0x000000, 100);
    graphics.beginFill(color, 100);
    graphics.drawCircle(x, y, 30);
    graphics.endFill();
    var myTextField:TextField = new TextField();
    myTextField.text = label;
    addChild(myTextField);
    d = -0.05;
    addEventListener(Event.ENTER_FRAME, animate);
  }
  public function animate(ev:Event):Void {
    alpha += d;
    if (alpha < 0) { d = 0.05; }
    else if (alpha > 1) { d = -0.05; }
  }
}

class ExampleAnimation extends Sprite {
  var ball_A:Ball;
  var ball_B:Ball;
  var ball_C:Ball;

  public function new() {
    super();
    ball_A = new Ball(0xFFCC00, "a");
    ball_A.name = "ball_A";
    ball_A.x = 20;
    ball_A.y = 20;
    addChild(ball_A);
    ball_B = new Ball(0x00FFCC, "b");
    ball_B.name = "ball_B";
    ball_B.x = 70;
    ball_B.y = 20;
    addChild(ball_B);
    ball_C = new Ball(0xCC00FF, "c");
    ball_C.name = "ball_C";
    ball_C.x = 40;
    ball_C.y = 60;
    addChildAt(ball_C, 1);
    addEventListener(MouseEvent.MOUSE_DOWN, onPress);
    addEventListener(MouseEvent.MOUSE_UP, onRelease);
    x = y = 20;
  }
  public function onPress(ev:MouseEvent):Void { removeChild(ball_C); startDrag(false); }
  public function onRelease(ev:MouseEvent):Void { stopDrag(); addChild(ball_C); }
  static function main() {
    var me = new ExampleAnimation();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleExternalMovieClip.hx P.416 外部 swf オブジェクトのロード
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Loader;
import flash.net.URLRequest;

private class Ball extends MovieClip {
  var d:Float;
  public function new(color:Int, label:String) {
    super();
    graphics.lineStyle(1, 0x000000, 100);
    graphics.beginFill(color, 100);
    graphics.drawCircle(x, y, 30);
    graphics.endFill();
    var myTextField:TextField = new TextField();
    myTextField.text = label;
    addChild(myTextField);
    d = -0.05;
    addEventListener(Event.ENTER_FRAME, animate);
  }
  public function animate(ev:Event):Void {
    alpha += d;
    if (alpha < 0) { d = 0.05; }
    else if (alpha > 1) { d = -0.05; }
  }
}

class ExampleExternalMovieClip extends Sprite {
  var ball_A:Ball;
  var ball_B:Ball;
  var ball_C:Ball;

  public function new() {
    super();
    ball_A = new Ball(0xFFCC00, "a");
    ball_A.name = "ball_A";
    ball_A.x = 20;
    ball_A.y = 20;
    addChild(ball_A);
    ball_B = new Ball(0x00FFCC, "b");
    ball_B.name = "ball_B";
    ball_B.x = 70;
    ball_B.y = 20;
    addChild(ball_B);
    ball_C = new Ball(0xCC00FF, "c");
    ball_C.name = "ball_C";
    ball_C.x = 40;
    ball_C.y = 60;
    addChildAt(ball_C, 1);
    addEventListener(MouseEvent.MOUSE_DOWN, onPress);
    addEventListener(MouseEvent.MOUSE_UP, onRelease);
    x = y = 20;

    var ldr:Loader = new Loader();
    var urlReq:URLRequest = new URLRequest("ExampleDraggableMovieClip.swf");
    ldr.load(urlReq);
    ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
    flash.Lib.current.addChild(ldr);
  }
  public function onPress(ev:MouseEvent):Void { removeChild(ball_C); startDrag(false); }
  public function onRelease(ev:MouseEvent):Void { stopDrag(); addChild(ball_C); }
  public function loaded(event:Event):Void { flash.Lib.current.addChild(event.target.content); }
  static function main() {
    var me = new ExampleExternalMovieClip();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

ジオメトリ関係

as3/ExampleGeom.hx P.440 Matrix オブジェクト P.455 グラデーションフィルとMatrix オブジェクト
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.display.InterpolationMethod;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Transform;

private class Ball extends MovieClip {
  var d:Float;
  public function new(color:Int, label:String) {
    super();
    graphics.lineStyle(1, 0x000000, 100);
    var colors:Array<UInt> = [color, 0xFFFFFF];
    var alphas:Array<Dynamic> = [1, 1];
    var ratios:Array<Dynamic> = [0, 255];
    var matrix:Matrix = new Matrix();
    matrix.createGradientBox(
      /*Width:			*/60,
      /*Height:			*/60,
      /*Rotation:		*/0,
      /*X:			*/-30,
      /*Y:			*/-30
    );
    graphics.beginGradientFill(
      /*GradientType:		*/GradientType.RADIAL,
      /*colors:			*/colors,
      /*alphas:			*/alphas,
      /*ratios:			*/ratios,
      /*Matrix:			*/matrix,
      /*SpreadMethod:		*/SpreadMethod.PAD,
      /*InterpolationMethod:	*/InterpolationMethod.LINEAR_RGB,
      /*focalPointRatio:	*/0
    );
    graphics.drawCircle(x, y, 30);
    graphics.endFill();
    var myTextField:TextField = new TextField();
    myTextField.text = label;
    addChild(myTextField);
    d = -0.05;
    addEventListener(Event.ENTER_FRAME, animate);
  }
  public function animate(ev:Event):Void {
    alpha += d;
    if (alpha < 0) { d = 0.05; }
    else if (alpha > 1) { d = -0.05; }
    var mat:Matrix = new Matrix();
    mat.scale(1-alpha, 1);
    mat.translate(x, y);
    transform.matrix = mat;
  }
}

class ExampleGeom extends Sprite {
  var ball_A:Ball;
  var ball_B:Ball;
  var ball_C:Ball;

  public function new() {
    super();
    ball_A = new Ball(0xFFCC00, "a");
    ball_A.name = "ball_A";
    ball_A.x = 20;
    ball_A.y = 20;
    addChild(ball_A);
    ball_B = new Ball(0x00FFCC, "b");
    ball_B.name = "ball_B";
    ball_B.x = 70;
    ball_B.y = 20;
    addChild(ball_B);
    ball_C = new Ball(0xCC00FF, "c");
    ball_C.name = "ball_C";
    ball_C.x = 40;
    ball_C.y = 60;
    addChildAt(ball_C, 1);
    addEventListener(MouseEvent.MOUSE_DOWN, onPress);
    addEventListener(MouseEvent.MOUSE_UP, onRelease);
    x = y = 20;
  }
  public function onPress(ev:MouseEvent):Void { removeChild(ball_C); startDrag(false); }
  public function onRelease(ev:MouseEvent):Void { stopDrag(); addChild(ball_C); }
  static function main() {
    var me = new ExampleGeom();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

システム関係

次にシステム情報やクリップボードのサンプルコードを紹介する。

以下は、システム情報を取得して、その結果をクリップボードに保持する例である。ちなみに、クリップボードの内容を ActionScript から取得することは、セキュリティの観点から、用意されていない。

as3/ExampleSystem.hx P.698 システムクラスとクリップボード
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.system.System;

class ExampleSystem extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "System properties and Clipboard:\n";

  public function new() {
    super();
    myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);
    myText += "  totalMemody:\t" + System.totalMemory + "\n";
    myText += "  useCodePage:\t" + System.useCodePage + "\n";
    myText += "  vmVersion:\t" + System.vmVersion + "\n";
    System.setClipboard(myText);
    myTextBox.text = myText;
  }
  static function main() {
    var me = new ExampleSystem();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

以下は、Flash Player のさまざまな性能情報を取得して、その結果を表示する例である。

as3/ExampleCapabilities.hx P.699 キャパビリティクラスによる性能調査
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.system.Capabilities;

class ExampleCapabilities extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "Capabilities properties:\n";

  public function new() {
    super();
    myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);
    myText += "  avHardwareDisable:\t" + Capabilities.avHardwareDisable + "\n";
    myText += "  hasAccessibility:\t" + Capabilities.hasAccessibility + "\n";
    myText += "  hasAudio:\t" + Capabilities.hasAudio + "\n";
    myText += "  hasAudioEncoder:\t" + Capabilities.hasAudioEncoder + "\n";
    myText += "  hasEmbeddedVideo:\t" + Capabilities.hasEmbeddedVideo + "\n";
    myText += "  hasIME:\t" + Capabilities.hasIME + "\n";
    myText += "  hasMP3:\t" + Capabilities.hasMP3 + "\n";
    myText += "  hasPrinting:\t" + Capabilities.hasPrinting + "\n";
    myText += "  hasScreenBroadcast:\t" + Capabilities.hasScreenBroadcast + "\n";
    myText += "  hasScreenPlayback:\t" + Capabilities.hasScreenPlayback + "\n";
    myText += "  hasStreamingAudio:\t" + Capabilities.hasStreamingAudio + "\n";
    myText += "  hasStreamingVideo:\t" + Capabilities.hasStreamingVideo + "\n";
    myText += "  hasTLS:\t" + Capabilities.hasTLS + "\n";
    myText += "  hasVideoEncoder:\t" + Capabilities.hasVideoEncoder + "\n";
    myText += "  isDebugger:\t" + Capabilities.isDebugger + "\n";
    myText += "  language:\t" + Capabilities.language + "\n";
    myText += "  localFileReadDisable:\t" + Capabilities.localFileReadDisable + "\n";
    myText += "  manufacturer:\t" + Capabilities.manufacturer + "\n";
    myText += "  os:\t" + Capabilities.os + "\n";
    myText += "  pixelAspectRatio:\t" + Capabilities.pixelAspectRatio + "\n";
    myText += "  playerType:\t" + Capabilities.playerType + "\n";
    myText += "  screenColor:\t" + Capabilities.screenColor + "\n";
    myText += "  screenDPI:\t" + Capabilities.screenDPI + "\n";
    myText += "  screenResolutionX:\t" + Capabilities.screenResolutionX + "\n";
    myText += "  screenResolutionY:\t" + Capabilities.screenResolutionY + "\n";
    myText += "  serverString:\t" + Capabilities.serverString + "\n";
    myText += "  version:\t" + Capabilities.version + "\n";
    myTextBox.text = myText;
  }
  static function main() {
    var me = new ExampleCapabilities();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

マルチメディア関係

ここでは、マイクロフォンやカメラなどの AV 関連の例をいくつか示す。

as3/ExampleMicrophone.hx P.617 マイクロフォン
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.media.Microphone;

class ExampleMicrophone extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "マイクをスピーカーに繋げます。\n";

  public function new() {
    super();
    myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);
    myTextBox.text = myText;

    var mic:Microphone = Microphone.getMicrophone();
    mic.setUseEchoSuppression(true);
    mic.setLoopBack(true);
  }
  static function main() {
    var me = new ExampleMicrophone();
    flash.Lib.current.addChild(me);
  }
}
[SWF]
as3/ExampleCamera.hx P.577 カメラ
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.media.Camera;
import flash.media.Video;

class ExampleCamera extends Sprite {
  static var myTextBox:TextField = new TextField();
  static var myText:String = "カメラをモニターに繋げます。\n";

  public function new() {
    super();
    myTextBox.autoSize = TextFieldAutoSize.LEFT;
    addChild(myTextBox);
    myTextBox.text = myText;

    var cam:Camera = Camera.getCamera();
    var vid:Video = new Video();
    vid.attachCamera(cam);
    addChild(vid); 
  }
  static function main() {
    var me = new ExampleCamera();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

以下は MP3 ファイルを URL で指定して、ボタンを押すと再生するサンプルコードである。フリーの音源、例えば「http://stop-rokkasho.org/media/1/02_rokkasho-piano_version_1.mp3」などで試すとよいだろう。

as3/ExampleURLSound.hx P.600 サウンド
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import flash.display.SimpleButton;

class Label extends Sprite {
  public var tf:TextField;
  public var bg:Sprite;
  var type:Int;
  var state:Int;
  var size:Array<Float>;

  public function new(label:String, ?tfm:TextFormat, ?type:Int, ?state:Int, ?size:Array<Float>) {
    super();
    tf = new TextField();
    if (tfm != null)
      tf.defaultTextFormat = tfm;
    this.type = type;
    this.state = state;
    if (size != null) {
      this.size = size;
      tf.width = size[0] + 2*2;
      tf.height = size[1] + 2*2;
    }
    else
      tf.autoSize = TextFieldAutoSize.LEFT;
    tf.htmlText = label;
    switch (type) {
      case 1: {
        tf.type = TextFieldType.INPUT;
      }
    }
    tf.embedFonts = switch (tfm.font) {
    case "Webdings", "Wingdings", "Wingdings 2", "Wingdings 3": true;
    default: false;
    }
    bg = new Sprite();
    bgDraw();
    addChild(bg);
    addChild(tf);
  }
  public function bgDraw() {
    var m:Float = tf.defaultTextFormat.leftMargin + tf.defaultTextFormat.rightMargin;
    var d:Float = switch (state) { case 2,3: 2.0; default: 4.0; };
    var size:Array<Float> = (this.size != null) ? this.size : [tf.textWidth, tf.textHeight];

    x = y = 4 - d;
    bg.graphics.clear();
    switch (type) {
      case 0: {
        var w:Float = switch (state) { case 1: 2.0; default: 1.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRoundRect(d, d, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.lineStyle(w, 0xFFFFFF);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRoundRect(0, 0, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.endFill();
      }
      case 1: {
        var w:Float = switch (state) { case 1: 2.0; default: 1.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRect(d, d, size[0] + m + 2*2, size[1] + 2*2);
        bg.graphics.lineStyle(w, 0x000000);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRect(0, 0, size[0] + m + 2*2, size[1] + 2*2);
        bg.graphics.endFill();
      }
      default: {
        var w:Float = switch (state) { case 1: 4.0; default: 2.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRoundRect(d, d, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.lineStyle(w, 0x000000);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRoundRect(0, 0, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.endFill();
      }
    }
  }
  public function setLabel(label:String) {
    tf.htmlText = label;
    bgDraw();
  }
}

class ExampleURLSound extends Sprite {
  var snd:Sound;
  var sndc:SoundChannel;
  var items:Array<Dynamic>;
  var fs:Array<TextFormat>;

  public function new() {
    super();
    var s:Float = 16.0;
    fs = [
      new TextFormat("Courier", s, 0x000000),
      new TextFormat("Webdings", s, 0x000000),
    ];
    items = [
      new Label("URL",	fs[0], 0, 0, [s*2, s]),
      new Label("",	fs[0], 1, 0, [s*32, s]),
      new SimpleButton(),
    ];
    transition();
    items[2].addEventListener(MouseEvent.CLICK, pbPlay);
    items[0].x = items[0].y = 4;
    layouts(0, [items[0], items[1], items[2]]);
    for (i in 0...items.length)
      addChild(items[i]);
  }
  function layouts(type:Int, items:Array<Dynamic>) {
    var i:Int;

    switch (type) {
    case 0:
      for (i in 1...items.length) {
	items[i].x = items[i-1].x + items[i-1].getRect(this).width + 4;
	items[i].y = items[i-1].y;
      }
    case 1:
      for (i in 1...items.length) {
	items[i].x = items[i-1].x;
	items[i].y = items[i-1].y + items[i-1].getRect(this).height + 4;
      }
    }
  }
  function transition() {
    items[2].upState      = new Label((snd!=null)?"\x55":"\x56", fs[1], 2, 0);
    items[2].overState    = new Label((snd!=null)?"\x55":"\x56", fs[1], 2, 1);
    items[2].downState    = new Label((snd!=null)?"\x55":"\x56", fs[1], 2, 2);
    items[2].hitTestState = new Label((snd!=null)?"\x55":"\x56", fs[1], 2);
  }
  public function pbPlay(event:MouseEvent) {
    if (snd == null) {
      if (items[1].tf.text != null) {
        snd = new Sound(new URLRequest(items[1].tf.text));
        sndc = snd.play();
      }
    }
    else {
      sndc.stop();
      snd = null;
    }
    transition();
  }
  static function main() {
    var me = new ExampleURLSound();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

ちなみにこれは、簡単なユーザインターフェースである SimpleButton の使用例ともなっている。

以下は FLV ファイルを URL で指定して、ボタンを押すと再生するサンプルコードである。サンプル動画、例えば「http://www.videospark.com/prog_flv8/BadDayInAfica.flv」などで試すとよいだろう。

as3/ExampleURLVideo.hx P.561 動画, P.391 フルスクリーン
import flash.display.DisplayObject;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.FullScreenEvent;
import flash.display.Sprite;
//import flash.events.AsyncErrorEvent;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.events.TimerEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.Timer;
import flash.display.SimpleButton;

class Label extends Sprite {
  public var tf:TextField;
  public var bg:Sprite;
  var type:Int;
  var state:Int;
  var size:Array<Float>;

  public function new(label:String, ?tfm:TextFormat, ?type:Int, ?state:Int, ?size:Array<Float>) {
    super();
    tf = new TextField();
    if (tfm != null)
      tf.defaultTextFormat = tfm;
    this.type = type;
    this.state = state;
    if (size != null) {
      this.size = size;
      tf.width = size[0] + 2*2;
      tf.height = size[1] + 2*2;
    }
    else
      tf.autoSize = TextFieldAutoSize.LEFT;
    tf.htmlText = label;
    switch (type) {
      case 1: {
        tf.type = TextFieldType.INPUT;
      }
    }
    tf.embedFonts = switch (tfm.font) {
    case "Webdings", "Wingdings", "Wingdings 2", "Wingdings 3": true;
    default: false;
    }
    bg = new Sprite();
    bgDraw();
    addChild(bg);
    addChild(tf);
  }
  public function bgDraw() {
    var m:Float = tf.defaultTextFormat.leftMargin + tf.defaultTextFormat.rightMargin;
    var d:Float = switch (state) { case 2,3: 2.0; default: 4.0; };
    var size:Array<Float> = (this.size != null) ? this.size : [tf.textWidth, tf.textHeight];

    x = y = 4 - d;
    bg.graphics.clear();
    switch (type) {
      case 0: {
        var w:Float = switch (state) { case 1: 2.0; default: 1.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRoundRect(d, d, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.lineStyle(w, 0xFFFFFF);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRoundRect(0, 0, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.endFill();
      }
      case 1: {
        var w:Float = switch (state) { case 1: 2.0; default: 1.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRect(d, d, size[0] + m + 2*2, size[1] + 2*2);
        bg.graphics.lineStyle(w, 0x000000);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRect(0, 0, size[0] + m + 2*2, size[1] + 2*2);
        bg.graphics.endFill();
      }
      default: {
        var w:Float = switch (state) { case 1: 4.0; default: 2.0; };
        bg.graphics.lineStyle(0, 0xCCCCCC);
        bg.graphics.beginFill(0xCCCCCC);
        bg.graphics.drawRoundRect(d, d, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.lineStyle(w, 0x000000);
        bg.graphics.beginFill(0xFFFFFF);
        bg.graphics.drawRoundRect(0, 0, size[0] + m + 2*2, size[1] + 2*2, 2*4);
        bg.graphics.endFill();
      }
    }
  }
  public function setLabel(label:String) {
    tf.htmlText = label;
    bgDraw();
  }
}

class NetStreamClient {
  public var duration:Float;

  public function new() {}
  public function onMetaData(info:Dynamic) {
    duration = info.duration;
  }
}

class ExampleURLVideo extends Sprite {
  var start:Bool;
  var pause:Bool;
  var scale:Float;
  var nc:NetConnection;
  var ns:NetStream;
  var tm:Timer;
  var items:Array<Dynamic>;
  var fs:Array<TextFormat>;

  public function new() {
    super();
    var s:Float = 16.0;
    fs = [
      new TextFormat("Courier", s, 0x000000),
      new TextFormat("Webdings", s, 0x000000),
    ];
    items = [
      new SimpleButton(),
      new SimpleButton(new Label("\x37", fs[1], 2, 0),
                       new Label("\x37", fs[1], 2, 1),
                       new Label("\x37", fs[1], 2, 2),
                       new Label("\x37", fs[1], 2)),
      new SimpleButton(new Label("\x38", fs[1], 2, 0),
                       new Label("\x38", fs[1], 2, 1),
                       new Label("\x38", fs[1], 2, 2),
                       new Label("\x38", fs[1], 2)),
      new Label("URL",	fs[0], 0, 0, [s*2, s]),
      new Label("",	fs[0], 1, 0, [s*24, s]),
      new SimpleButton(),
      new SimpleButton(new Label("\x4c", fs[1], 2, 0),
                       new Label("\x4c", fs[1], 2, 1),
                       new Label("\x4c", fs[1], 2, 2),
                       new Label("\x4c", fs[1], 2)),
      new SimpleButton(new Label("\x31", fs[1], 2, 0),
                       new Label("\x31", fs[1], 2, 1),
                       new Label("\x31", fs[1], 2, 2),
                       new Label("\x31", fs[1], 2)),
      new Video(),
      new TextField(),
    ];
    start = pause = false;
    scale = 1;
    transition_pause();
    transition_start();
    transition();
    items[0].addEventListener(MouseEvent.CLICK, pbPause);
    items[1].addEventListener(MouseEvent.CLICK, pbRew);
    items[2].addEventListener(MouseEvent.CLICK, pbFF);
    items[5].addEventListener(MouseEvent.CLICK, pbStart);
    items[6].addEventListener(MouseEvent.CLICK, pbScaleVideo);
    items[7].addEventListener(MouseEvent.CLICK, pbFullScreen);
    items[9].autoSize = TextFieldAutoSize.LEFT;
    items[0].x = items[0].y = 4;
    layouts(0, [items[0], items[1], items[2], items[3], items[4], items[5], items[6], items[7]]);
    layouts(1, [items[0], items[8], items[9]]);
    for (i in 0...items.length)
      addChild(items[i]);
    nc = new NetConnection();
    nc.connect(null);
    ns = new NetStream(nc);
    //ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
    ns.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
    ns.client = new NetStreamClient();
    items[8].attachNetStream(ns);
    items[8].smoothing = true;
    tm = new Timer(1000, 0);
    tm.addEventListener(TimerEvent.TIMER, timerHandler);
    flash.Lib.current.stage.align = StageAlign.TOP_LEFT;
    flash.Lib.current.stage.scaleMode = StageScaleMode.NO_SCALE;
  }
  function layouts(type:Int, items:Array<Dynamic>) {
    var i:Int;

    switch (type) {
    case 0:
      for (i in 1...items.length) {
        items[i].x = items[i-1].x + items[i-1].getRect(this).width + 4;
        items[i].y = items[i-1].y;
      }
    case 1:
      for (i in 1...items.length) {
        items[i].x = items[i-1].x;
        items[i].y = items[i-1].y + items[i-1].getRect(this).height + 4;
      }
    }
  }
  function transition_pause() {
    items[0].upState      = new Label(pause?"\x34":"\x3b", fs[1], 2, 0);
    items[0].overState    = new Label(pause?"\x34":"\x3b", fs[1], 2, 1);
    items[0].downState    = new Label(pause?"\x34":"\x3b", fs[1], 2, 2);
    items[0].hitTestState = new Label(pause?"\x34":"\x3b", fs[1], 2);
  }
  function transition_start() {
    items[5].upState      = new Label(start?"\xb7":"\xb8", fs[1], 2, 0);
    items[5].overState    = new Label(start?"\xb7":"\xb8", fs[1], 2, 1);
    items[5].downState    = new Label(start?"\xb7":"\xb8", fs[1], 2, 2);
    items[5].hitTestState = new Label(start?"\xb7":"\xb8", fs[1], 2);
  }
  function transition() {
    items[9].text = "";
    if (ns != null) {
      items[9].text += "bytes: " + ns.bytesLoaded + "/" + ns.bytesTotal + "\n";
      items[9].text += "time: " + ns.time + "/" + ns.client.duration + "\n";
      if (items[8].videoWidth!=0 && items[8].videoHeight!=0 &&
          (items[8].width != items[8].videoWidth*scale ||
           items[8].height != items[8].videoHeight*scale)) {
        items[8].width = items[8].videoWidth*scale;
        items[8].height = items[8].videoHeight*scale;
        layouts(1, [items[0], items[8], items[9]]);
      }
    }
  }
  public function statusHandler(event:NetStatusEvent) {
    switch (event.info.code) {
    case "NetStream.Buffer.Full":
    case "NetStream.Buffer.Empty":
      {}
    default:
      items[9].text += event.info.code + "\n";
    }
  }
  public function timerHandler(event:TimerEvent) {
    transition();
  }
  public function pbStart(event:MouseEvent) {
    if (!start) {
      if (items[4].tf.text != null) {
        ns.play(items[4].tf.text);
        start = true;
        tm.start();
        transition_start();
      }
    }
    else {
      ns.close();
      start = pause = false;
      tm.stop();
      transition_start();
      transition_pause();
    }
    transition();
  }
  public function pbPause(event:MouseEvent) {
    if (start) {
      ns.togglePause();
      pause = !pause;
      transition_pause();
    }
  }
  public function pbRew(event:MouseEvent) {
    if (start)
      ns.seek((ns.time>=10)?ns.time-10:0);
  }
  public function pbFF(event:MouseEvent) {
    if (start)
      ns.seek(ns.time+10);
  }
  public function pbScaleVideo(event:MouseEvent) {
    scale = if (scale == .5) 1;
    else if (scale == 1) 1.5;
    else if (scale == 1.5) 2;
    else if (scale == 2)
      Math.min((stage.stageWidth-(items[8].x+4))/items[8].videoWidth,
	       (stage.stageHeight-(items[8].y+4))/items[8].videoHeight);
    else .5;
    transition();
  }
  public function pbFullScreen(event:MouseEvent) {
    stage.displayState = (stage.displayState==StageDisplayState.FULL_SCREEN)?
      StageDisplayState.NORMAL:StageDisplayState.FULL_SCREEN;
    scale = (stage.displayState==StageDisplayState.FULL_SCREEN)?2:.5;
    pbScaleVideo(event);
  }
  static function main() {
    var me = new ExampleURLVideo();
    flash.Lib.current.addChild(me);
  }
}
[SWF]

ちなみにこれは、フルスクリーンを扱うための Stage クラスの使用例ともなっている。

haXe サンプルコード for Flash8

次に、ActionScript2 以前の資料も多いこと、Flash 8 以前の資源も多いことから、補足的ながら以下の一次情報元を参考に例題を紹介する。

  1. Adobe, ActionScript2.0 Language Reference, http://livedocs.adobe.com/flash/9.0/main/flash_as2_language_reference.pdf
  2. haXe project, haXe Tutorial, http://haxe.org/doc

さらに、以下のようにリストアップされるクラスファイル群は、何はなくとも非常に参考になる。

$ find /usr/local/lib/haxe/std/flash
	:
/usr/local/lib/haxe/std/flash/display
	:
/usr/local/lib/haxe/std/flash/external
	:
/usr/local/lib/haxe/std/flash/filters
	:
/usr/local/lib/haxe/std/flash/geom
	:
/usr/local/lib/haxe/std/flash/net
	:
/usr/local/lib/haxe/std/flash/system
	:
/usr/local/lib/haxe/std/flash/text
	:

ここでは、Flash 8 以前向け swf 生成のためのサンプルコードを紹介する。

やはり先立って、複数のサンプルコードをコンパイルするための makefile を用意してあるので、ビルド方法はそれで明らかだろう。

as2/makefile
HAXE=/usr/local/lib/haxe/haxe

SWFS=\
ExampleMovieClip.swf	\
ExampleEmptyMovieClip.swf	\

all: $(SWFS) $(SWFS:.swf=.html)

%.swf: %.hx
	$(HAXE) -swf $@ -main $* -swf-header 640:480:10:ffffff

%.html: %.swf
	echo "<html><head><title>$<</title></head><body><embed src=\"$<\" width="640" height="480" type="application/x-shockwave-flash"/></body></html>" > $@

clean: clean.htmls
	rm -f $(SWFS)

clean.htmls:
	rm -f $(SWFS:.swf=.html)

distclean:
	rm -f $(SWFS:.swf=.hx~)
as2/ExampleMovieClip.hx
import flash.MovieClip;

class ExampleMovieClip {
  static function main() {
    var mc:MovieClip = flash.Lib.current;
    mc.lineStyle(1, 0xFF0000, 100);
    mc.beginFill(0x0000FF, 100);
    mc.moveTo(100, 100);
    mc.lineTo(200, 100);
    mc.lineTo(200, 200);
    mc.lineTo(100, 200);
    mc.lineTo(100, 100);
    mc.endFill();
  }
}
[SWF]
as2/ExampleEmptyMovieClip.hx
import flash.MovieClip;

class ExampleEmptyMovieClip {
  static function main() {
    var mc:MovieClip = flash.Lib.current.createEmptyMovieClip("mc", 1);
    mc.lineStyle(1, 0x000000, 100);
    mc.beginFill(0xFF0000, 100);
    mc.moveTo(100, 100);
    mc.lineTo(200, 100);
    mc.lineTo(200, 200);
    mc.lineTo(100, 200);
    mc.lineTo(100, 100);
    mc.endFill();

    mc.onPress = function() { mc.startDrag(false); };
    mc.onRelease = function() { mc.stopDrag(); };
  }
}
[SWF]

ダウンロード

サンプルコードの tarball … haxe-20080510.tar.gz

Copyright (C) 2008 Taiji Yamada, All rights reserved.