Flashの学習(11) オブジェクト指向で考えるActionScript

第4章 オブジェクトを使ったスクリプティング


[しゃべり担当] LoadVarsオブジェクトを使って外部ファイルを読み込むswfだ。



https://sites.google.com/site/itouhiro/2009/20090529oop_as04_1.swf


ここで外部ファイルはテキストファイル http://ai11.net/2009/flash/20090529data.txt だ。文字コード UTF-8 でBOMはあってもなくても同じだった。

スクリプトは _rootの1フレーム目に。

//filename = "20090529data.txt"
filename = "http://ai11.net/2009/flash/20090529data.txt"
extData = new LoadVars();
extData.onLoad = function(isSuccess){
	if(isSuccess){
		yaranaio_dialog_txt.text = "わたしの名前は "+ extData.name +" です。\n戦闘力は "+ extData.power +" ですよ。";
	}else{
		yaranaio_dialog_txt.text = "Error: '"+filename+"' cannot load!";
	}
}
extData.load(filename);

テキストフィールドは以下の設定だ。

powerというプロパティ名は定義してないから、undefinedになるかなと思ったけど空白になるんだな。


[つっこみ担当] filenameのところ、URLで指定するんだね。


[しゃべり担当] URLなしだと読み込みエラーになるんだよ。

という条件の場合


[つっこみ担当] しかしテキストファイルの形式がめんどうなことになってるな。変数名が必要だし、アンパサンド & 等を実体参照(&)で書かなきゃだし。


[しゃべり担当] この本には、LoadVarsオブジェクトじゃなくてXMLオブジェクトを使ったらファイルの中身をまるごと読めると書いてある。


XMLオブジェクトを使ってさっきのテキストファイル読み込むと、こう。


https://sites.google.com/site/itouhiro/2009/20090529oop_as04_2.swf



ちなみにほんもののXMLファイルを読み込んで解析すると……FlashPlayer6では動くんだがFlashPlayer9や10では動かないswfができあがった。


https://sites.google.com/site/itouhiro/2009/20090529oop_as04_3_4.swf


ソースはこれ。ActionScript(AS)1.0ではXPathが使えないので使ってない。

filename = "http://dailynews.yahoo.co.jp/fc/computer/rss.xml"

extData = new XML();  //external data
extData.ignoreWhite = true;
var str = "■Yahoo!ニュース[コンピュータ]";
extData.onLoad = function(src_str){
    // source string
    if(src_str != undefined){
        var child_node = extData.firstChild.firstChild.childNodes;
        str += child_node[i].firstChild.nodeValue + "\n";
        for(var i=0;i<child_node.length;i++){
            var title = child_node[i].firstChild.firstChild.nodeValue;
            if(title == null){
                str += "?";
            }else{
                title += "("+child_node[i].firstChild.nextSibling.nextSibling.firstChild.nodeValue+")";
                str += title+"\n";
            }
        }
        yaranaio_dialog_txt.text = str;
        trace(str);
    }else{
        yaranaio_dialog_txt.text = "Error: '"+filename+"' cannot load!";
    }
}
extData.load(filename);


[つっこみ担当] Flashは互換性高いと思ってたけど、動かなくなるswfもあるんだね。


[しゃべり担当]

FlashPlayer9や10では動かない理由を探したら、FlashPlayer7以降はセキュリティが厳しくなり、swfファイルのある場所と違うドメインからはXML.loadができなくなったからだった。
http://livedocs.adobe.com/flash/8_jp/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002871.html


以下のフラッシュは、 http://ai11.net/2009/flash/20090602oop_as04_4_4.swf に本体のswfファイルがある。そこで、同じドメインhttp://ai11.net/index.xml を読み込んでみると、FlashPlayer10でも確かに読み込める。


https://sites.google.com/site/itouhiro/2009/20090602oop_as04_4_4.swf


クロスドメインポリシーファイル crossdomain.xml を読み出し先(たとえばhttp://dailynews.yahoo.co.jp/)が置いてくれれば、そのサイトのXMLも読めるんだが…。
他のサイトからファイルを直接読み込めないのは、残念だなあ……。


ところでAdobeのマニュアル見ると、AS2だとインスタンスの元になるものを「オブジェクト」じゃなくて「クラス」と呼ぶようになってるんだな。
これまで、StringオブジェクトとかObjectオブジェクトとか呼んできたけど、今後はObjectクラスと呼ぶことにしよう。

Flash MXまでの「ActionScriptリファレンスガイド」では、MovieClipの先頭の項目は「MovieClip(オブジェクト)」とされていました。ところが、Flash MX 2004では、「MovieClipクラス」という名称に変わっています。……
Flash MX以前の「ActionScript辞書」で、「MovieClip(オブジェクト)」というのは、明かに「クラス」を表しています。
(http://www.fumiononaka.com/TechNotes/Flash/FN0506003.html)

第5章 イベントを捉える―リスナー

キー入力を取得するには、ObjectクラスのインスタンスにaddListenerをさせるという手がある。
キーコードを16進数で表示するぞ。一度swfをクリックしないと反応しないかも。


https://sites.google.com/site/itouhiro/2009/20090529oop_as05_3.swf

ソースはこちら。


Objectクラスのインスタンスを使う理由は、MovieClipクラスと違ってonKeyDownなどのキー取得メソッドがないので、キー入力を二重に受け取る心配がないから。
このインスタンスはMovieClipじゃないから画面に表示されないけど、それでもListenerをaddできる。


[つっこみ担当] ふむふむ


[しゃべり担当]
次はキー入力の応用で、方向キーで動くswfだ。
シフトキーを押しながら方向キーも押すと、通常の10倍のスピードで動くぞ。


https://sites.google.com/site/itouhiro/2009/20090529oop_as05_4.swf

ソースは、シンボルqilinの1フレーム目にこれ。

ls = new Object(); //listener
ls.onKeyDown = function(){
    move4way(Key.getCode(), Key.isDown(Key.SHIFT));
}
function move4way(direction, accel){
    var movestep = accel ? 10 : 1;
    switch(direction){
        case Key.LEFT : this._x -= movestep; _root.arrow_mc.disp_arrow(180,accel); break;
        case Key.RIGHT: this._x += movestep; _root.arrow_mc.disp_arrow(0,accel);   break;
        case Key.UP   : this._y -= movestep; _root.arrow_mc.disp_arrow(270,accel); break;
        case Key.DOWN : this._y += movestep; _root.arrow_mc.disp_arrow(90,accel);  break;
    }
}
Key.addListener(ls);


シンボルarrowの1フレーム目にこれ。

var alphamask = 20;

this.onEnterFrame = function(){
    if(alphamask > 1){
        alphamask -= 10;
        this._alpha = alphamask;
    }
}

function disp_arrow(degree,accel){
    this._rotation = degree;
    alphamask = accel ? 100 : 50;
}


ここで発見だが、onKeyDownだけでキー入力を取得する(onKeyUpを使わない)と、OSのキーリピートが使えるんだな。これは知らなかった。



[つっこみ担当] 方向キー押してる途中でシフト押すと、動きが止まっちゃうね。アッドリスナーだとここらへん融通が利かないな。


[しゃべり担当]
次はキリンをマウスでドラッグすると矢印もあとをついて移動する。


https://sites.google.com/site/itouhiro/2009/20090529oop_as05_9.swf

動作はたいしたことないが、Listenerの仕組みで情報を伝達している。


qilinシンボルの1フレーム目にこのframe action。

this.lis = new Array(); //listeners

function addListener(myObj){
    this.lis.push(myObj);
    trace(this._name +".lis="+this.lis +"(addListener)");
}

function removeListener(myObj){
    for(var i=0; i<this.lis.length; i++){
        if(this.lis[i] == myObj){
            this.lis.splice(i,1);
            trace(this._name +".lis="+this.lis +"(removeListener)");
            return true;
        }
    }
    return false;
}

function broadcastMsg(distance){
    for(var i=0; i<this.lis.length; i++){
        this.lis[i].moveTgt(distance); //move target
        trace(this._name +":broadcastMsg: distance="+distance);
    }
}

this.myY = _y;
function myMove(){
    this.broadcastMsg(this._y - this.myY);
}
this.onPress = function (){
    this.startDrag();
    this.onEnterFrame = this.myMove;
}
this.onRelease = this.onReleaseOutside = function(){
    delete this.onEnterFrame;
    this.stopDrag();
}


arrowシンボルの1フレーム目に、このframe action。

this.onEnterFrame = function(){
    var tgt_mc = _parent.qilin_mc; //target movieclip: same dir-level
    if(typeof tgt_mc == "movieclip"){
        tgt_mc.addListener(this);
        delete this.onEnterFrame;
        rd = Math.random()/3.0+0.1; //random
        trace(this._name +": _y="+ _y +":rd="+ rd);
    }
};

this.myY = this._y;
function moveTgt(distance){ //move target
    this.tgt_y = this.myY + distance;
    trace(this._name +":moveTgt: tgt_y("+ this.tgt_y +")=this.myY("+ this.myY +") + distance("+ distance +")");
    if(this.onEnterFrame == undefined){
        this.onEnterFrame = this.easeOut;
    }
}
function easeOut(){
    var dist = this.tgt_y - this._y; //distance
    if(Math.abs(dist)<0.5){
        this._y = this.tgt_y;  //吸着
        delete this.onEnterFrame;
    }else{
        this._y += dist*rd; //距離が近くなるほど遅くなる移動
        trace(this._name  +":easeOut: _y("+  this._y  +")+=dist("+  dist  +") * rd("+  rd  +")");
    }
}


[つっこみ担当] このコードはどう動いてるの?


[しゃべり担当] このswfで操作できるのは「キリンをマウスでドラッグする」だけだ。
キリンのアクション(=スクリプト)を見ると、

  • onPress(マウスクリックの押下の瞬間)のときにstartDrag()とonEnterFrameへの登録を実施。
  • onRelease(マウスクリックしたあとマウスボタンから指を離す)のときに、onEnterFrameへの登録を解除して、stopDrag()する。
  • onEnterFrameに登録するのは、broadcastMsg関数を実行すること。broadcastMsg関数には、現在のキリンのY座標と、このフレームに入ったとき(実行開始時)のキリンのY座標の差を引数として渡す。
  • broadcastMsg関数は「リスナーに登録されたオブジェクト」すべてにmoveTgt関数を実行させる。moveTgt関数は「矢印」シンボルに定義してある。


矢印の持つアクション(script)を見ると、

  • moveTgt関数では、onEnterFrameへeaseOut()を登録する(毎フレームeaseOut()を実行する)。引数に、「現在の矢印のY座標と、このフレームに入ったとき(実行開始時)の矢印のY座標」の差を引数として渡す。


[つっこみ担当] うーむ……
なんか入り組んでるな。

Listener使うと、EventHandler使うより、コード量が多くなる気がする


[しゃべり担当] でもAS3ではListener使うのがむしろ標準的になってしまうんだ。EventHandlerも残ってるけど、クラスやオブジェクト指向でAS3スクリプト組むならListenerのほうが都合がいいらしい。慣れとこうかな。



macromedia FLASH ActionScriptバイブルfor Windows & Macintosh

macromedia FLASH ActionScriptバイブルfor Windows & Macintosh

  • 作者: 上野亨
  • 出版社/メーカー: オーム社
  • 発売日: 2000-12
  • メディア: 単行本

  • おすすめ度の平均:
    難しい文章が苦手な方に最適!