前回の続き。
あるクラスのインスタンスが複数の時。
シングルトンじゃない感じになりますけど。
以前はそのままインスタンスを返していましたが、
今度はインスタンスを配列に保存して返すだけ。
まず一つ目。ソース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を目印にして保存
ってやりましたが、ここらへんは
どういう風にインデックスを付けるがいいんですかね。
そのまま名前でつけるとか。もっといい方法ありそう。
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;
って宣言してやっても出来たけどメンドクサイ。
デザインパターン勉強してて思いついた、イベント配信の方法。
まず、イベント配信してくれるクラスをシングルトンで。
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;
}
}
var init:Init = new 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");
}
}
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を取って来て、イベント登録できて、
階層関係なくイベント呼べる~。
なんで気付かなかったんだ。
なんんかイイのあったら教えてください!
<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。)やっぱりはずしたました(笑)。
05 6月
Posted by tamakichi as flash
自分用コピペ支援。
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)
タイトル通り、座標の小数点以下を四捨五入するjsfl作りました。
座標の小数点以下が0でないと画像がぼけてしまったりします。
なんで、画像などをステージに配置する際、
いちいち座標を調節してやる必要があって、それが面倒くさい。
これを使えば一発ですっきり。

▼

しかし1個問題が。シェイプには使えません。
なんでだろ。
<Jsflの使い方>
下記のフォルダにファイルを置くだけです。
C:\Documents and Settings\(ユーザー名)\Local Settings\Application Data\Macromedia\Flash 8\ja\Configuration\Commands
あとはFlashのコマンドメニューから実行です。
ショートカットを割り当てると便利です。
例えばCtrl+Alt+Zとか。
下記よりダウンロード出来ます。右クリック→保存。
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間で
通信するって感じ?