9server.net

actionScriptなどの勉強

_parentするならSingletonのお話2

前回の続き。

あるクラスのインスタンスが複数の時。
シングルトンじゃない感じになりますけど。
以前はそのままインスタンスを返していましたが、
今度はインスタンスを配列に保存して返すだけ。

まず一つ目。ソースgetInctance2_1.zip(Flaファイル入り)

Btnクラスインスタンスは一つで、
Ballクラスのインスタンスは3つ作りました。
ロールオーバー/アウトでボールクラスインスタンス3つを操ります。

Ballクラス

class Ball extends MovieClip
{
	//poorにこのクラスのインスタンスを保存する
	static private var ballPoor:Array = new Array();
	private function Ball()
	{
		ballPoor.push(this);//自分のパスを配列に保存
		_visible = false;//最初みえません。
	}

	//クラス経由でアクセスするのでstaticな関数。
	static public function getInstacePoor():Array
	{
		return ballPoor;//インスタンスへのパスが入った配列を返す
	}

	public function setVisible(flg:Boolean)//見た目を変える
	{
		_visible = flg;
	}
}

Btnクラス

class Btn extends MovieClip
{
	private var ballPoor:Array;
	private function Btn()
	{
		//Ballクラスのインスタンスへのパスが入った配列を取得
		ballPoor = Ball.getInstacePoor();
	}

	private function onRollOver()//ロールオーバーでBallを全部出します
	{
		//Ballクラスのインスタンス全てに命令
		for( var i in ballPoor )
		{
			ballPoor[i].setVisible(true)
		}
	}

	private function onRollOut()//ロールオーバーでBallを全部消します
	{
		//Ballクラスのインスタンス全てに命令
		for( var i in ballPoor )
		{
			ballPoor[i].setVisible(false)
		}
	}
}

2つ目。ソースこちら。getInctance2_2.zip(Flaファイル入り)

Btnクラスインスタンスも3つにして、
対応するBallクラスインスタンスを操ります。

Ballクラス

class Ball extends MovieClip
{
	//poorにこのクラスのインスタンスを保存する
	static private var ballPoor:Array = new Array();
	private var id:String;
	private function Ball()
	{
		id = _name.substring(4);
		ballPoor[id] = this;//自分のidを目印にして保存
		_visible = false;//最初みえません。
	}

	//クラス経由でアクセスするのでstaticな関数。
	static public function getInstacePoor():Array
	{
		return ballPoor;//Ballクラスのインスタンスへの参照が入った配列を返す
	}

	public function setVisible(flg:Boolean)//見た目を変える
	{
		_visible = flg;
	}
}

Btnクラス

class Btn extends MovieClip
{
	private var ballPoor:Array;
	private var id:String;
	private function Btn()
	{
		id = _name.substring(3);//名前からid決める
		ballPoor = Ball.getInstacePoor();
	}

	private function onRollOver()//ロールオーバーでBallが出ます
	{
		ballPoor[id].setVisible(true)
	}

	private function onRollOut()//ロールオーバーでBallが消えます
	{
		ballPoor[id].setVisible(false)
	}
}
ballPoor[id] = this;//自分のidを目印にして保存

ってやりましたが、ここらへんは
どういう風にインデックスを付けるがいいんですかね。
そのまま名前でつけるとか。もっといい方法ありそう。

_parentするならSingletonのお話

nitoyonさんのエントリてっく煮ブログ – Flash 勉強会@大阪参加しました
を以前読んで、

Singleton
全部クラス化するなら、Singleton は有用
格言:parent するぐらいなら Singleton にしろ

の所なんですが、うんうん考えて、やっと理解できました。

で、具体的にやってみた。

サンプルファイルこちら。getInctance.zip

2つのクラスがあるとして、
ステージにも2つのクラスのインスタンスが配置されてます。
それぞれのクラスはライブラリのプロパティから
リンゲージ設定してあります。

ボタンにロールオーバーすると円が出て、ロールアウトで円が消えるという、簡単なサンプルを作ります。

Ballクラス

class Ball extends MovieClip
{
	//クラス経由で直接アクセスできるように、staticな変数にインスタンスを保持
	static private var singleton:Ball;
	private function Ball()
	{
		singleton = this;//代入して保存
		_visible = false;//最初みえません。
	}

	//クラス経由でアクセスするのでstaticな関数。
	static public function getInstace():Ball
	{
		return singleton;//自分のインスタンスを返す
	}

	public function setVisible(flg:Boolean)//見た目を変える
	{
		_visible = flg;
	}
}

Btnクラス

class Btn extends MovieClip
{
	private function onRollOver()//ロールオーバーでBallが出ます
	{
		Ball.getInstace().setVisible(true);
	}

	private function onRollOut()//ロールオーバーでBallが消えます
	{
		Ball.getInstace().setVisible(false);
	}
}

これでスクリプトは全て。
_parentが出てこないです。
MovieClipの名前も出てきません。
今までだと_parent.ball_mc~とかやってたんですがコレは楽ちん。
さらに言えば、お互いがどの階層に居るかが問題では
無くなる
。これはショッキング。

前に書いた イベントの配信
のようにイベントでやっても_parent出てこなくて良いと思ったんですが、
こっちのがヨリ具体的というか。

シングルトンって

class Ball extends MovieClip
{
	//インライン初期化で自分のインスタンス生成
	static private var singleton:Ball = new Ball();
	static public function getInstace():Ball
	{
		return singleton;
	}
}

こんな感じで覚えましたが、
Flashだとステージ上に出現すると自動で
new Ball()されてしまう
ので、
上の例の用にインライン初期化でもnew Ball()してしまうと、
2回newされる(?)ようで、きちんとインスタンスが代入されてくれません。
なのでコンストラクタとかでインスタンスに代入してます。

んで、一つのクラスからできるインスタンスが
一つだけならこの方法でOK。
でも同じ機能を持ったインスタンス沢山作ったりしますもんね。
複数の時は、すこし違うやり方が必要(?)。
それは次回また。

クラスでFuse Kit使うとき。
thisを動かそうとした時って、
そのままだと

alphaToという名前のメソッドはありません。

みたいなエラー出るんですね。

MovieClip(this)って型変換してやると出来るのね。

import com.mosesSupposes.fuse.*;
class foo extends MovieClip
{
	function foo()
	{
		ZigoEngine.simpleSetup(Shortcuts);
		//this.alphaTo(0)ダメ
		MovieClip(this).alphaTo(0)
	}
}

同様に

MovieClip(this)._scale = 50;

とかならできる。

今まで

var target:MovieClip = this;
target.alphaTo(0);

とかメンドクサイ事やってた。
タイムラインに書いてもエラー出た時があったような。

最初に

private var alphaTo:Function;

って宣言してやっても出来たけどメンドクサイ。

イベントの配信

デザインパターン勉強してて思いついた、イベント配信の方法。

Singletonクラス

まず、イベント配信してくれるクラスをシングルトンで。

import mx.events.EventDispatcher;
class Singleton
{
	//インライン初期化でインスタンスを作る。最初で最後のnew。observerは一つだけ。
	private static var observer:Singleton = new Singleton();

	private static var first:Boolean = true;

	public var addEventListener:Function;
	public var removeEventListener:Function;
   	public var dispatchEvent:Function;

	//コンストラクタがprivateなので外からnewされない。
	private function Singleton(){};

	public static function getInstance():Singleton
	{
		if(first)//最初の一回のみ実行
		{
			EventDispatcher.initialize(observer);
			first = false;
		}
		return observer;
	}
}

コンストラクタで

private function Singleton()
{
	EventDispatcher.initialize(this);
};

ってやりたかったんだけども、EventDispatcherがundefindeで
出来なかた。なんかいい方法があるのかな。
なので、getInstanceの時に一回だけinitialize。

2007/06/25 追記 この方法↓があった。

class Singleton extends mx.events.EventDispatcher
{
	//インライン初期化でインスタンスを作る。最初で最後のnew。
	private static var observer:Singleton = new Singleton();

	//コンストラクタがprivateなので外からnewされない。
	private function Singleton()
	{
		initialize(this);
	};

	public static function getInstance()
	{
		return observer;
	}
}

_root第一フレーム

var init:Init = new Init();

Initクラス

class Init
{
	private var observer:Singleton;
	public function Init()
	{
		observer = Singleton.getInstance();//observerを取得
		observer.addEventListener("onClickEnd" , this);//onClickEndイベントを受け取れるようにする。

		var hoge:Hoge = new Hoge();
		setAction();
	}

	private function setAction()
	{
		var scope = this;
		_root.onMouseDown = function()
		{
			//マウスダウンでobserverにonClickStartイベントを通知。Hogeクラスが受け取る。
			scope.observer.dispatchEvent({type:"onClickStart"})
		}
	}

	private function onClickEnd()
	{
		trace("end");
	}
}

Hogeクラス

class Hoge
{
	private var observer:Singleton;
	public function Hoge()
	{
		observer = Singleton.getInstance();//observerを取得。Initクラスのobserverと同じ。
		observer.addEventListener("onClickStart", this);//onClickStartイベントを受け取れるようにする。
		setAction();
	}

	private function setAction()
	{
		var scope = this;
		_root.onMouseUp = function()
		{
			//マウスアップでonClickEndイベントを通知。Initクラスが受け取る。
			scope.observer.dispatchEvent({type:"onClickEnd"})
		}
	}

	private function onClickStart()
	{
		trace("start");
	}
}

マウスダウンするとInitクラスがobserverに通知して、
Hogeクラスが受信、”start”と出力、
マウスアップするとHogeクラスがobserverに通知して、
Initクラスが受信、”end”って出力。
(言い方あってるのかな?)

observerは全インスタンス共通で同じの持ってたいから、
Singletonで一個だけインスタンス作って、みんなで
それを使う。

これまで何かのインスタンスをnewする時に引数でobserverを渡してた。
渡して、受け取ったのをまた渡して…みたいな感じでメンドクサイ。

これなら、どこからでも共通のobserverを取って来て、イベント登録できて、
階層関係なくイベント呼べる~。
なんで気付かなかったんだ。

なんんかイイのあったら教えてください!

Iteratorパターン for AS2.0

<2007/06/15 追記>
これからデザインパターンのコードをUPしていく予定でしたが、

まったく同じ事を既にされている方がいらっしゃって、内容がモロ被りなので
UPしていくのはやめます。わずか一回目で…早い!w
勉強は続けますけどね!

こちらのBlogです。やはり同じようなポイントで悩んでらっしゃったようで、参考になりました!
minfish.jp/blog: ActionScript2.0でデザインパターン(Iteratorの巻き)

</追記>

デザインパターン一回目。こちらの「増補改訂版Java言語で学ぶデザインパターン入門」のサンプルをActionScriptにしただけです。著作権マズいでしょうか…。本には、もっと詳しい説明が載っています。

抽象クラスなどAS2.0にはない概念は、FLASH OOPのサンプルを参考に、コンストラクタをprivateにするとかしてます。
完全にJavaのソースをASにしたわけじゃないので注意です。
というか、抽象クラス、インターフェイスは初めてなので、良く分かってません。

以下、メモ入りまくりのソース。
もっと良い書き方がある!っていうトコは教えて下さい。助かります。

Aggregateインターフェイス
Aggregate・・・「集約」の意
【集約】(名)スル
集めて一つのものにまとめること。
「各支部の意見を-する」

//集合体を表すクラスがこのインターフェイスを実装する
interface Aggregate
{
	//makeIteratorメソッドを実装しなければならない
    public function makeIterator():Iterator;
}

Iteratorインターフェイス
Iterator・・・「繰り返す」「反復子」の意
集合体を走査する
今回はnextだけだが、前に戻るpreviousとかもアリ。

interface Iterator {
	//hasNext、nextメソッドを実装しなければならない
    public function hasNext():Boolean;//次ぎがあるか調べる
    public function next():Object;//次ぎに進める
}

Bookクラス
本を表現するクラス

class Book{
	private var name:String;//本の名前
	//コンストラクタ
	public function Book(name:String)
	{
		this.name = name;
	}

	public function get _name():String
	{
		//自分の名前を返す
		return name;
	}
}

BookShelfクラス
本を入れる本棚を表現するクラス

class BookShelf implements Aggregate//集合体を表すAggregateを実装
{
	private var book_array:Array;//Bookインスタンス(本)を保存
	//コンストラクタ
	public function BookShelf()
	{
		//本棚を作成
		this.book_array = new Array();
	}

	public function appendBook(book:Book)
	{
		//本棚に本を入れる
		book_array.push(book);
	}

	public function getBookAt(index:Number):Book
	{
		//指定された番号の本を返す
		return book_array[index];
	}

	public function getLength():Number
	{
		//本棚の大きさ(配列の長さ)を返す
		return book_array.length;
	}

	public function makeIterator():Iterator
	{
		//BookShelfIteratorインスタンスを生成して返す
		return new BookShelfIterator(this);
	}
}

BookShelfIteratorクラス
本棚(BookShelfインスタンス)を自分のプロパティとして持ち、管理する

//本棚を自分のプロパティとして持ち、管理する
class BookShelfIterator implements Iterator
{
    private var bookShelf:BookShelf;//管理する本棚
    private var index:Number;//注目する本棚の番号
	//コンストラクタ
    public function BookShelfIterator(bookShelf:BookShelf)
	{
		//管理する本棚を格納する
        this.bookShelf = bookShelf;
        index = 0;
    }

	public function hasNext():Boolean
	{
		//bookShelf.getLength()は本棚に入っている本の数を返す
        if (index < bookShelf.getLength()) {
			//まだ本棚に本が入っていればture
            return true;
        } else {
			//もう本棚に本がなければfalse
            return false;
        }
    }

    public function next():Object
	{
		//注目している本を返し、注目番号を次に進める
        var book:Book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

Mainクラス
注目:whileループで使われているのは、iteratorのメソッドのみで、
bookShelfクラスの実装でつかわれているメソッドは使っていない。
よって、bookShelfクラスの実装に依存しない。
bookShelfクラスが管理の仕方を変更しても、
bookShelfがmakeIteratorメソッドを持っていて、
正しくiteratorを返してくれればいい。
つまり、Iteratorインターフェイスを正しく実装しているインスタンスを返してくれれば、
whileループはまったく変更しなくても動作する

class Main
{
	public function Main()
	{
		var bookShelf:BookShelf = new BookShelf();//本棚を作る
		//本を作って本棚に入れる
		bookShelf.appendBook(new Book("Around the World in 80 Days"));
		bookShelf.appendBook(new Book("Bible"));
		bookShelf.appendBook(new Book("Cinderella"));
		bookShelf.appendBook(new Book("Daddy-Long-Legs"));

		var iterator:Iterator = bookShelf.makeIterator();

		while (iterator.hasNext())//まだ本棚に本があれば繰り返す
		{
			//iterator.next()・・・今注目している番号の本を返し、番号を一つ進める
			var book:Book = Book(iterator.next());
			trace(book._name);
		}
	}
}

実行結果
flaファイル_root第一フレーム

var main:Main = new Main();var main:Main = new Main();
/*出力
Around the World in 80 Days
Bible
Cinderella
Daddy-Long-Legs
*/

まとめ?
集合体、いろいろあると思うんですが、xmlを解析する時とかに
使えるのかな?
取り敢えず今度使ってみよう。

今回のソースはこちら。コメントアウトが沢山はいったままですが、よければどうぞ。

書籍「増補改訂版Java言語で学ぶデザインパターン入門」を購入。すんばらしいっす。

23個の デザインパターンが、分かり易いサンプルと共に説明されています。
Javaで書かれているんですが、クラス使ってnew hoge()とか書いてる人なら結構すんなり読めると思います。
分からない所が出てきたらその都度調べれば多分へいき。

つまずいたのが

 john = (Dog)animal

っていう書き方。型の変換(キャスト)でした。
上の例だとanimal をDogクラスにキャストしているんですね。
ASだと

john = Dog(animal)

ですよね。

これから、この本のサンプルをAS2.0に変換しながら勉強していきたいと思います。
そのままJavaで理解していってもいいんだけどね…。
変換したものはUPしていきます。

<2007/06/15 追記>
既にやってらっしゃる方が居たのでUPは中止。
minfish.jp/blog: ActionScript2.0でデザインパターン(Iteratorの巻き)
参考にさせて貰いました!
</追記>
まだ4分の1ぐらいしか進んでないけど。

(どーでもいいんですけど、Amazonアフィリエイトのリンクが面白いですね。Ajax?なポップアップが。うざったいかもしれないけど。さすがAmazon。)やっぱりはずしたました(笑)。

自分用コピペ支援。

AsBroadcaster

class hoge
{
	public var addListener:Function;
	public var removeListener:Function;
	private var broadcastMessage:Function;
	private function hoge()
	{
		AsBroadcaster.initialize(this);
	}
}

broadcastMessage("onHoge", args1, args2 ,...);
とか書いて伝える。

EventDispatcher

import mx.events.EventDispatcher;
class fuga
{
	public var addEventListener:Function;
	public var removeEventListener:Function;
	private var dispatchEvent:Function;
	public function fuga()
	{
		EventDispatcher.initialize(this);
	}
}

dispatchEvent({type:"onFuga" , args_name:args});
とか書いて伝える。
伝える人. addListener addEventListener(”伝えたいイベント” , 伝えたい人);
(なつがえた! addListenerはAsBroadcasterだった、2007/06/22訂正)
みたいに、事前に、伝える人と何を伝えるか教えておかないと駄目。

OnEnterFrameBeacon

import mx.transitions.OnEnterFrameBeacon;
class foo
{
	private var onEnterFrame:Function;
	public function foo()
	{
		OnEnterFrameBeacon.init();
		MovieClip.addListener(this);
	}
}

FuseKit

import com.mosesSupposes.fuse.*;
class hoo
{
	public function hoo()
	{
		ZigoEngine.simpleSetup(Shortcuts, PennerEasing);
		ZigoEngine.SKIP_LEVEL = 1;
	}
}

ZigoEngine.simpleSetup(使いたいヤツ1 , 使いたいヤツ2. …);
ZigoEngine.SKIP_LEVEL = コールバックを実行するタイミング
0 (デフォルト値:変化があろうとなかろうと、トゥイーンを実行後、イベントを実行する)
1 (トゥイーンによる変化がない場合は、トゥイーンせず、即座にイベントを実行する)
2 (トゥイーンによる変化がない場合は、イベントを実行しない。)
FuseKitのSKIP_LEVELについては、
trick7さんのエントリtrick7.com blog: FuseKitのサンプルflaファイルを翻訳してみたよ
のサンプルFlaファイルより引用(というかコピペ)。いつもお世話になってます。

jsfl練習。
そして開発能率UP化。

下記のエントリを 参考にさせて頂きました。有難う御座います。

ants Lab. | Flash | Flash JavaScript APIでオーサリングを効率化(その2)


Adobeの 資料はこれかな?

はじめに

タイトル通り、座標の小数点以下を四捨五入するjsfl作りました。
座標の小数点以下が0でないと画像がぼけてしまったりします。
なんで、画像などをステージに配置する際、
いちいち座標を調節してやる必要があって、それが面倒くさい。

これを使えば一発ですっきり。



しかし1個問題が。シェイプには使えません。
なんでだろ。

<Jsflの使い方>
下記のフォルダにファイルを置くだけです。
C:\Documents and Settings\(ユーザー名)\Local Settings\Application Data\Macromedia\Flash 8\ja\Configuration\Commands

あとはFlashのコマンドメニューから実行です。
ショートカットを割り当てると便利です。

例えばCtrl+Alt+Zとか。

下記よりダウンロード出来ます。右クリック→保存。

roundPix.jsfl

EventDispatcherの使いどころ?

EventDispatcherの使いどころが分かんなくて、
ずっと考えていたんです。
最近FLASH OOPのCHAPTER13をやっていて、
EventDispatcherを使ったソースが書かれていたので、
それを読んでようやく分かったかも。

import mx.events.EventDispatcher;
var hoge = new Object();
EventDispatcher.initialize( hoge );
hoge.func = function()
{
	this.dispatchEvent({type: "onEvent"});
}

var box:Object = new Object();
box.setUp = function( model:Object )
{
	model.addEventListener("onEvent", this);
}

box.onEvent = function()
{
	trace("done");}

box.setUp( hoge );
hoge.func();

/*var fuga = hoge;
fuga.func();
*/

結果、doneが出力される 。

boxの中のmodel.funcを実行した訳ではないのに、
onEventが発生してる。

コメントアウトした部分、
hogeのコピーからfunc()を実行しても
同じ結果。

コピーした物を変えると、大元も変わるっていう、
参照型である事を利用してるのかな?

こういうのを使ってMovieClip間、Object間で
通信するって感じ?

  

Calendar

9月 2010
« 8月    
 12345
6789101112
13141516171819
20212223242526
27282930  

Recent Entries

    Recent Comments

      Most Commented