今回は、Flash MX 2004でドックメニューを作ってみたいと思います。
今回のチュートリアルで、↓こんなメニューが出来ます。



【仕様】
・メニュー項目など外部ファイル(xml)で設定できるようにする
・画像には外部jpgファイルか、外部swfファイルを使用する
・上下左右に向き変更可能
・ステージサイズも変更可能

手順1


ライブラリに新規ムービークリップシンボルを追加し、名前・識別子・AS2.0を「dock_menu」とする。
ActionScriptだけで作成しますので、中身は空のムービークリップです。)
ステージサイズは、幅500、高さ200とする。
フレームレートは、32fpsくらいにする。
タイムライン1フレーム目に以下のActionScriptを記述する。
var xml_data = new XML();
//空白を有効にする。
XML.prototype.ignoreWhite = true;
//menu.xmlの場所
_root.xml_path = (_root.xml_path) ? _root.xml_path : "menu.xml";
xml_data.load(_root.xml_path);
xml_data.onLoad = function (loaded) {
  if (loaded) {
    //xml読み込み完了後の処理
    var fc = xml_data.firstChild;
    Stage.scaleMode = "noScale";
    _root._x += 500 / 2;                             //中心にもってくる
    _root._y += 200 / 2;                             //中心にもってくる
    Stage.width  = Number(fc.attributes["swidth"]);
    Stage.height = Number(fc.attributes["sheight"]);
    _root._x += Number(fc.attributes["xadjust"]);
    _root._y += Number(fc.attributes["yadjust"]);
    var para = {
      layout:fc.attributes["layout"],
      i_min:Number(fc.attributes["i_min"]),
      i_max:Number(fc.attributes["i_max"]),
      i_size:Number(fc.attributes["i_size"]),
      inf_wid:Number(fc.attributes["inf_wid"]),
      xml_data:xml_data.lastChild
    }
    dm = attachMovie('dock_menu''menu', 1, para);
  } else {
    _root.createTextField("ititle", 65535, 0, 0, 200, 20);
    _root["ititle"].text = "xmlが読み込めませんでした。"+_root.xml_path;
  }
}
this.stop();


手順2


テキストファイル「dock_menu.as」に以下のActionScriptを記述する。(UTF-8)
解説は、コード内に細かくコメントとして入れてあります。
コメントを含んで100行程度です。
//──────────────────────────────────
//dock_menu.asc
//──────────────────────────────────
class dock_menu extends MovieClip {
  var i_min    :Number;     //最小サイズ
  var i_max    :Number;     //最大サイズ
  var i_size   :Number;     //元画像のサイズ
  var i_sp     :Number = 5; //余白
  var inf_wid  :Number;     //マウスの影響範囲
  var inf_far  :Number = 0; //マウスの影響度合(0~1)
  var vary     :Number = 0; //inf_farの増減量
  var bxm      :Number;     //前ループのマウス座標
  var bym      :Number;     //前ループのマウス座標
  var layout   :String;     //レイアウト設定
  var xml_data :Object;     //メニュー項目xml
  var node_len :Number;     //メニュー項目数
  var img_load :Number = 0; //読込済み項目数
  var stw      :Number;     //ステージ横幅
  var sth      :Number;     //ステージ高さ
  //──────────────────────────────────
  //コンストラクタ
  //──────────────────────────────────
  function dock_menu(){
    //■レイアウト設定
    var layout_str:Object = { left:90, top:180, right:270, bottom:0 };
    this._rotation        = layout_str[this.layout];
    //■xml_dataからアイコンを作成
    this.node_len = this.xml_data.childNodes.length//メニュー項目数
    //ステージ原点から最初のminアイコンの中心までの長さ
    var start_p:Number = (this.node_len - 1) * (this.i_sp + this.i_min) / 2;
    for (var i in this.xml_data.childNodes){                           //アイコンは中心が原点
      this.createEmptyMovieClip(String(i), i + 10);
      this[i].createEmptyMovieClip('icon', 1);
      this[i].icon.createEmptyMovieClip('g', 1);                       //回転させるので画像を中心にするため
      //画像読込&読込完了したらonEnterFrame開始
      this[i].mcl               = new MovieClipLoader();
      this[i].mcl_listener      = new Object();
      this[i].mcl_listener.dock = this;                                //mcl_listenerからdock_menuにアクセスするため
      this[i].mcl.addListener(this[i].mcl_listener);
      this[i].mcl.loadClip(this.xml_data.childNodes[i].attributes["img_url"], this[i].icon.g);
      this[i].mcl_listener.onLoadComplete = function(){
        this.dock.img_load++;
        if (this.dock.img_load == this.dock.node_len){ this.dock.onEnterFrame = this.dock.ef; }
      }
      this[i].icon.g._x      = -this.i_size / 2;                       //x原点を中心に
      this[i].icon.g._y      = -this.i_size / 2;                       //y原点を下に
      this[i].icon._rotation = -this._rotation;                        //回転角度
      this[i].icon._y        = -this.i_size / 2;                       //y原点を下に
      this[i]._x             = i * (this.i_min + this.i_sp) - start_p; //初期位置
      this[i].bx             = this[i]._x;                             //初期位置を確保
      this[i]._y             = -this.i_sp;                             //余白分ずらす
      //クリックイベント
      this[i].onPress = function(){ getURL(_parent.xml_data.childNodes[i].attributes["get_url"]); }
    }
    //トレイ作成
    var h:Number = this.i_min  + this.i_sp * 2;
    var tray:MovieClip = this.createEmptyMovieClip('tray', 1);
    tray.lineStyle(0, 0xcccccc, 100);
    tray.beginFill(   0xeeeeee, 100);
    tray.lineTo(0, -h); tray.lineTo(100, -h); tray.lineTo(100, 0); tray.lineTo(0, 0);
    tray.endFill();
  }
  //──────────────────────────────────
  //EnterFrame
  //──────────────────────────────────
  function ef(){
    //マウスに動きなし&inf_farが0か1なら処理しない(CPU負荷軽減)
    if((this.bxm == this._xmouse) && (this.bym == this._ymouse) && ((this.inf_far == 0) || (this.inf_far == 1))) { return false; }
    this.bxm = (this.bxm == undefined) ? 0 : this._xmouse;                            //トレイ初期幅を正常にするため
    this.bym = this._ymouse;                                                          //画像読込完了待ちをしないと無理かも
    //----------inf_farの設定
    //varyが0なら、0.2か-0.2にする
    if (this.vary ==0){
      //マウスが影響範囲内かどうかの判定(一番高いところより下で、底辺より上で、トレイの左右端より内側)
      this.vary = (this.bym > (this.i_min - this.i_max) * this.inf_far - (2 * this.i_sp) - this.i_min)
      && (this.bym < 0) && (this.bxm > tray_l()) && (this.bxm < tray_r()) ? 0.2 : -0.2;
    }
    this.inf_far += this.vary;                                                        //inf_far増減
    if (this.inf_far < 0.01 || this.inf_far > 0.99) { this.vary = 0; }                //inf_farが変化不要なら、vary = 0
    this.inf_far = Math.min(1, Math.max(0, this.inf_far));                            //inf_farを0 ~ 1 にする
    //----------inf_farの設定ここまで
    //個々のアイコンの位置と大きさを計算
    //各アイコンの倍率は「中心からのマウスのズレ」で計算する
    //その結果に「アイコンへの影響度合inf_far」をかけている
    for (var i in this.xml_data.childNodes){
      //dx ・・・ 有効範囲での、初期位置とマウスの差(-this.inf_wid ~ this.inf_wid)
      var dx     :Number = Math.min(Math.max(this[i].bx - this.bxm, -this.inf_wid), this.inf_wid);
      var i_gap  :Number = this.i_max - this.i_min;                                   //maxとminの差
      var dx_cos :Number = Math.cos(1.57 * (dx / this.inf_wid));                      //1.57 = ラジアン四半周
      var dx_sin :Number = Math.sin(1.00 * (dx / this.inf_wid));                      //1.57 = ラジアン四半周
      var dim    :Number = i_gap         * (dx_cos * this.inf_far) + this.i_min;      //maxとminの差*倍率 + min
      this[i]._x         = (i_max + i_sp * 2) * (dx_sin * this.inf_far) + this[i].bx; //間隔        *倍率 + 初期位置
      this[i]._xscale    = 100 * dim / this.i_size;                                   //アイコン倍率
      this[i]._yscale    = 100 * dim / this.i_size;
    }
    //トレーをリサイズ
    this['tray']._x     = tray_l();
    this['tray']._width = tray_r() - this['tray']._x;
  }
  //──────────────────────────────────
  //トレイの両端計算
  //──────────────────────────────────
  function tray_l(){ return this[                0]._x - this[                0]._width / 2 - this.i_sp; }
  function tray_r(){ return this[this.node_len - 1]._x + this[this.node_len - 1]._width / 2 + this.i_sp; }
}


パブリッシュします。

手順3


設定ファイルを作ります。
xmlで、メニュー項目やステージサイズなどを設定します。
ファイル名menu.xmlで、下記のようなテキストファイルを作ります。
<?xml version="1.0" encoding="UTF-8"?>
<whole
 layout  = "bottom"
 i_min   = "32"
 i_max   = "128"
 i_size  = "128"
 inf_wid = "60"
 swidth  = "800"
 sheight = "250"
 xadjust = "0"
 yadjust = "50">
</whole>
<itemdata>
  <item img_url="http://wa.otesei.com/media/as/as_logo.swf"
   get_url="http://as.otesei.com/"></item>
  <item img_url="http://wa.otesei.com/media/as/fplayer.swf"
   get_url="http://wa.otesei.com/"></item>
  <item img_url="http://wa.otesei.com/media/as/firefox.jpg"
   get_url="http://wa.otesei.com/"></item>
  <item img_url="http://wa.otesei.com/media/as/icon.swf"
   get_url="http://wa.otesei.com/"></item>
  <item img_url="http://wa.otesei.com/media/as/adobe.jpg"
   get_url="http://wa.otesei.com/"></item>
</itemdata>

最初のwholeタグの属性で、各種設定を行い、itemdataタグのitem要素に各メニュー項目のデータを設定します。
layout = "bottom"top=上側、bottom=下側、left=左側、right=右側
i_min = "32"画像縮小時のサイズ
i_max = "128"画像拡大時のサイズ
i_size = "128"元画像のサイズ
inf_wid = "60"マウスに反応する範囲
swidth = "800"Flashのステージサイズ
sheight = "250"Flashのステージサイズ
xadjust = "0"ステージの調整(x座標を指定分ずらす)
yadjust = "50"ステージの調整(x座標を指定分ずらす)

以上です。

属性layoutを右側にすると、↓こんな感じになりますので、それに合わせてステージのサイズ、位置を調整して下さい。
<whole
 layout  = "left"
 i_min   = "32"
 i_max   = "128"
 i_size  = "128"
 inf_wid = "60"
 swidth  = "200"
 sheight = "500"
 xadjust = "-100"
 yadjust = "0">
</whole>
<itemdata>


縦長にするとサイドメニューとしても使えます。

項目名を表示するなど、まだまだ今後拡張していきたいと思います。

こちらからダウンロードできます。imgimgimgimgzipファイル[434clicks]
(ActionScriptファイル、xmlファイル、flaファイル、swfファイルを含むzip圧縮ファイルです。)