アプリ版:「スタンプのみでお礼する」機能のリリースについて

windows版FlashCS6で、ActionScript3を使用しております。
どうぞ、よろしくお願いいたします。

最初に、前提をご説明します。

埋め込みアセットクラスBoxをライブラリに準備します。
Boxの中には、50px × 50pxのビットマップが、基準点を中央で配置してあります。

埋め込みアセットクラスWallをライブラリに準備します。
Wallの中には、550px×400pxのビットマップが、基準点を中央で配置してあります。

ステージサイズは550px×400pxです。

タイムラインに、下記のActionScript3を書きます。

var myWall:Wall = new Wall();
myWall.x = 275;
myWall.y = 200;
addChild(myWall);

var myBox:Array = new Array(10);
for(var i:int=0 ; i<10 ; i++){
myBox[i] = new Box();
myBox[i].x = Math.random() * 550;
myBox[i].y = Math.random() * 400;
addChild(myBox[i]);
}

パブリッシュすると、ステージ上にはmyWallのインスタンスが1個と、myBoxのインスタンスが10個配置されます。

myBoxのインスタンスいずれかをクリックすると、クリックされたmyBoxが削除される(クリックされたmyBoxをremoveChild()し、それの参照を保存していた変数にnullを代入する)ようにするには、どのようにスクリプトを組めば良いでしょうか?

背景のmyWallは、クリックされても削除されないようにしたいです。

ご教示のほど、どうぞ、よろしくお願いいたします。

A 回答 (1件)

スクリプトとしてはとりあえず


次のような感じ↓で良いのではないでしょうか。


//====================================
var myWall:Wall = new Wall();
myWall.x = 275;
myWall.y = 200;
addChild(myWall);

var myBox:Array = new Array(10);
for (var i:int=0; i<10; i++) {
myBox[i] = new Box();
myBox[i].x = Math.random() * 550;
myBox[i].y = Math.random() * 400;
addChild(myBox[i]);
//------↓以降を追加変更↓------
//(各Boxマウスオーバーでハンドカーソルにする(要る?))
myBox[i].buttonMode = true;
//各Boxクリック時に関数 removeBox を実行
myBox[i].addEventListener(MouseEvent.CLICK,removeBox);
}

//関数 removeBox の定義
function removeBox(e:MouseEvent):void {
//クリックされたターゲットをこの階層の表示リストから削除
removeChild(DisplayObject(e.currentTarget));
}
//====================================





上記スクリプトの最後の部分↓ですが

//クリックされたターゲットをこの階層の表示リストから削除
removeChild(DisplayObject(e.currentTarget));

以下ではこの行についてのみの説明を書きます。


この最後の行は
次↓のように変更してもかまいません。

removeChild(Box(e.currentTarget));

または
Box クラスが MovieClip クラスを継承している場合は
次↓のように変更してもかまいません。

removeChild(MovieClip(e.currentTarget));


もし removeChild(e.currentTarget); のように
引数を「e.currentTarget」だけにした場合,
その「e.currentTarget」は
単なる「Object」クラスのインスタンスとして認識されてしまうため
removeChild(=表示リストから削除する) という命令を使うことができなくなります。
(「Object」クラスのインスタンスには,例えば「配列」や「関数」や「音」など "表示されないオブジェクト" も含まれるため「表示リストから削除する」という命令が通用しない。)

したがって少なくとも
クリックされたターゲットを "表示オブジェクト(DisplayObject)" として認識させる必要があります。

そのために
DisplayObject(e.currentTarget) のように書いて
イベントターゲットを「DisplayObject」に変換しているわけです。

MovieClipクラスも,Boxクラスも,
少なくとも DisplayObjectクラス は継承しているはずですから,
Box(e.currentTarget) や MovieClip(e.currentTarget) などにしてもかまわないということになります。


もし Box クラスが MovieClip クラスを継承していれば
クラスの継承関係は次のようになります。

Object > EventDispatcher > DisplayObject > InteractiveObject > DisplayObjectContainer > Sprite > MovieClip > Box

これらクラスのうち
DisplayObject 以下のクラスとして認識させれば removeChild できるという意味です。
認識させるクラスは作者の都合で適当に決めれば良いです。


ちなみに,
Array(配列) クラスであれば継承関係は次のようになります。
Object > Array

Function(関数/メソッド) クラスであれば継承関係は次のようになります。
Object > Function

Sound(音) クラスであれば継承関係は次のようになります。
Object > EventDispatcher > Sound

これら3つはどれも DisplayObject を継承していませんよね?

したがって
これらはどれも元から表示リストに加える(addChild する)ことができないので
表示リストから削除する(removeChild する)こともできないわけです。
(他にも DisplayObject でないオブジェクトはたくさん存在します。)



または,
別の書き方として次のように変更しても良いでしょう。

removeChild(e.currentTarget as DisplayObject);

removeChild(e.currentTarget as Box);

removeChild(e.currentTarget as MovieClip);

この「as」は ActionScript の略(=AS)ではなく,
英語の前置詞である「as (…として)」が語源でしょうね。

【英文例】I looked up to him as an engineer.
【和訳文】私は技術者として彼を尊敬している。

【Script】removeChild(e.currentTarget as DisplayObject);
【和訳文】表示オブジェクトとしてのイベントターゲットを表示リストから削除

この回答への補足

改めてネットで調べたところ、クロージャを利用することでも、必要な情報を受け渡せることが解かりました。
※恥ずかしながら、クロージャというモノを、初めて知りました。

お陰様で、今回の質問は解決しました。
ありがとうございました!!

補足日時:2013/12/24 18:00
    • good
    • 0
この回答へのお礼

ご教示ありがとうございます!
とても丁寧なご説明に、感激しました。

質問させていただいた後、少し考えて
removeChild(e.currentTarget);
と書いてみて、(当然ですが)コンパイルエラーが出て、理由が解からず困っていました。

>少なくとも
>クリックされたターゲットを "表示オブジェクト(DisplayObject)" として認識させる必要があります。

お教えいただき、ようやくコンパイルエラーの理由が解かりました。
ありがとうございます。

removeChildすることで、表示リストから「クリックされたBoxのインスタンス」を外すことが出来ました。
さらに「クリックされたBoxのインスタンス」への参照を保存している変数myBox[i]にnullを代入すれば、「クリックされたBoxのインスタンス」はガベージコレクションの対象になると思います(この考えは、間違えていないでしょうか。。。?)。

ガベージコレクションの対象とするために、setNullという関数を追加してみました。

//ここから上のスクリプトは省略しています。
//各Boxクリック時に関数 removeBox を実行
myBox[i].addEventListener(MouseEvent.CLICK,removeBox);
myBox[i].addEventListener(MouseEvent.CLICK,setNull);
}

function setNull(e:MouseEvent):void{
for(var k:int=0 ; k<10 ; k++){
if(myBox[k] != null){
if(myBox[k].root == null){
myBox[k] = null;
}
}
}
}

Boxのインスタンスをクリックした際に、myBoxの何番に「クリックされたBoxのインスタンスへの参照」が入っているか判らないため、setNullではmyBoxを全てチェックしています。

myBoxを全てチェックせずとも、「クリックされたBoxのインスタンスへの参照」を見つけることは可能でしょうか?
※上記のsetNullよりも、もっと効率の良い方法はないのでしょうか?

重ねての質問とはなりますが、お教えいただけませんでしょうか。。。?
何卒、よろしくお願い申し上げます。

お礼日時:2013/12/22 21:29

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!