ActionScript3.0 苦行の軌跡・2
ActionScript3.0についての 愚痴 考察の続きです。忘れないうちに、矢継ぎ早にUPしてみました。
興味の無い方がほとんどと思いますので、今回の更新はあくまで自分の備忘ということでご了承を…。
相変わらず、生兵法で書いてますので、間違いなどあったらすみません。
(FlashCS4画面)
[ 複数の敵を配置 ]
同じクラスから複数のインスタンスを作って配置します。
まあ、普通にforループで作るんですが…
AS2.0で、6匹配置する場合
for (i=1;i<7;i++){
attachMovie("monster_mc", "mons"+i, 100+i);
}
てな感じでばっちりでした。
配置したモンスターキャラ(インスタンス)の名前は、mons1~mons6になります。
AS3.0ではattachMovie()→addChild()になってるんでしたね。ということで…
for (i = 1; i<7; i++){
var mons:monster_mc = new monster_mc();
this.addChild(mons);
}
と、こんな感じになって、これでちゃんと配置されます。
が…
これだと、各インスタンスに独自の名前が無いので、モンスターキャラを個別に参照したりできないんです!
かといって、
var mons+i:monster_mc = new monster_mc();
とか
var monname:string = "mons"+i;
var monname:monster_mc = new monster_mc();
とか
var this["mons"+i]:monster_mc = new monster_mc();
とか書いても、エラーになります!
ループを使わず書くなら、方法はあるんですけどね…
var mons1:monster_mc = new monster_mc();
this.addChild(mons1);
var mons2:monster_mc = new monster_mc();
this.addChild(mons2);
…以下略…
でも、こんなのやってられんでしょ。6匹ならまだしも、100匹出したいときとかね。
(ホント、なんか方法ないのかなあ…。)
インスタンスに「名前」を付ける方法はあるんです。
var mname:String = "mons"+i;
mons.name = mname;
これで、一応各々のインスタンスにmons1~mons6の「名前」がつきました。
めでたしめでたし…
…とはなりません!
この「名前」が曲者で…これ「真の名前」じゃないんです。「ゲド戦記」みたいな話ですが…。
このインスタンス内の関数を他のインスタンスから参照する場合
2.0では
_root.mons1.f_test();
こんな感じでした。
でも3.0では
MovieClip(root).mons1.f_test();
…これでは動かないんですよ!
"mons1"なんてインスタンスは知らん!と言われてしまいます。
正解は…
MovieClip(root).getChildByName("mons1").f_test();
なぜそうなのか…詳しいことは割愛しますが、肝はgetChildByName()。これを使って初めて、「付けた名前」からインスタンスを参照できるらしいんです。
これも本当に苦労しました…。
まあ、一度わかれば、次からはそう書けば良いだけなんですが…2.0に比べてすげー面倒!
どうにかならないんですかね…。
[ 弾を打つ(プレイヤーキャラ内スクリプトで、弾インスタンスを配置する) ]
弾はプレイヤーキャラが撃つので、スクリプトはプレイヤーキャラムービークリップに書きたいですね。
プレイヤーキャラのスクリプトで、メインタイムライン(root)に配置するスクリプトを書いてみます。
(↑メインタイムライン=root =シーン1)
MovieClip(root).addChild(tama1);
(tama1は弾のインスタンス名)
これで、弾はrootに置けたように思ったのですが…その後、弾のx座標を他のインスタンスから調べるため
MovieClip(root).tama1.x;
と書いたところ、「tama1なんて存在しない」といわれてしまったのです!
これも悩みに悩みましたね…。
参考書も2冊買ってたんですが、なかなかそのものズバリで書いてなくて…ネットまで調べてやっとわかりました。
正解は…
MovieClip(root).player1.tama1.x
でした!
rootに置いたつもりだったんですが、配置元のインスタンスの下層にいることになってるんですかね。
addchildというのはそういうものだから、ということなのか…すいません、イマイチよくわかってないです。
[ ムービークリップを削除する ]
撃った弾が、敵や壁に当たったりしたら、消しますよね。
2.0では、その弾のムービークリップ内に
removeMovieClip(this);
と書けば、きれいサッパリ消えてくれました。
しかし…3.0はそんな簡単なことで許してくれません(苦笑)。
addChildと対になるのはremoveChildです。
なので
MovieClip(root).removeChild(this);
と書けばいい…と思うじゃないですか、フツー。
でも、これだけでは警告が出てしまいます!
これに加えて、すでに設定されているイベントリスナーを取り除く必要があるようです。
this.removeEventListener(Event.ENTER_FRAME, f_move);
(f_moveは関数)
これも、長い間引っかかりましたよ…何が問題で警告が出ているのかさっぱりわからなくて…。
[ サウンドを鳴らす]
こんなところもだいぶ変わってますね。
2.0では
var fire:Sound = new Sound();
fire.attachSound("fire.wav");
function f_fire(){
fire.start();
}
(fire.wav=サウンドファイル。fire サウンドラベル名。f_fire()=実際に音を鳴らす関数)
こんな感じでした。
3.0ではattachSoundは無くなったり色々変わりましたが、まあ、新しい書き方に置き換えればよいだろうと…
var fire:Sound = new fire();
function f_fire(){
var cn_fire:SoundChannel = fire.play();
}
と書くとエラーになります!
正解は…
var snd_fire:Sound = new fire();
function f_fire(){
var cn_fire:SoundChannel = snd_fire.play();
}
今までのつもりで書いていたのですが、3.0ではクラス名と同じ変数名を使ってはいけない ということのようです。
そんな基本的なことを、ようやくここで知ることになりました…。
-----
とりあえず、今回はこんな感じでした。
これでひとしきり山を越えた…と思いたいなぁ。
それとも、次は次で、新たな苦難が待ち構えているのでしょうか…。
To be continued...
(2009.8.10)
追記)
[ 複数の敵を配置 ]の件について、助言を頂き、解決法のひとつが判明しましたので、追記します。
var monsters:Array = new Array();// 長さ0のArrayを作成
var i:int;
// Arrayにオブジェクトを代入
for (i = 0; i < 6; i++) {
var mons:monster_mc = new monster_mc();
mons.x = i *50; //テストのため、xを設定
mons.y = i *10; //テストのため、yを設定
monsters.push(mons); // Arrayの後ろに追加
this.addChild(monsters[i]); //monsters[i]を表示
}
その後はmonsters[i]のiに数値(0~5)を入れることで、そのインスタンスのプロパティなどにアクセスできるようになります。
これなら、わざわざgetChildByName()を使わなくてもOKになると思います。
いや~、懸案が解決しました。よかった~。
(2009.8.18)
追記)一部訂正(2009.8.19)
| 固定リンク
「Flash」カテゴリの記事
- Flash 今度こそ本当に終了…(2020.11.24)
- 群馬でGO! for Android(2016.09.21)
- ぐんまでGO!(2016.08.13)
- Flashがこの世から消えるだと…(2015.12.04)
- KUNG-FU DUEL(2015.10.09)
コメント
Visual Basicが.NET対応になった時と同じ苦しみを味わっている訳ですか。
本格的にオブジェクト指向になったのなら、rootに必要な変数をメンバ変数として持たせておけば、参照で苦労することはないんじゃないかと思います。
たとえば、敵をクラスmonster_mcのArrayとして持っていれば、インスタンスの作成も参照もforループでいけますよね。
と思ったけれど、Action Scriptの記事を読んでもメンバ変数の話が出てこない……。もしかして、メンバ変数が使えない?
投稿: 深井 | 2009年8月13日 (木) 01時11分
actionscript3.0にも、「メンバ変数」という言葉自体はあるみたいですが…そちらで言うものと同じものなのかどうかよくわかりませんね。
Netなどで色々調べた範囲では、どうもぱっと解決する方法はなさそうに見えたんですよね。
私の理解度が低いだけかもしれませんが…。
今、「カスタムクラス」勉強中でして、その中でわかってくるかもしれません。
投稿: 適当所長 | 2009年8月13日 (木) 21時53分
カスタムクラスというのはSpriteクラスなど、元から存在するクラスを継承した新しいクラスのことでしょう。
カスタムクラスに、そのクラスに必要なメンバ変数やメンバ関数を持たせる、というのが一般的(?)なオブジェクト指向言語の作法になります。
メンバ変数というのは、クラスが持っている関数からアクセスできる変数で、基本的にはクラス外からは見えないというのがオブジェクト指向的には美しい実装です。
>> var mons;monster_mc;
>> var mname:String = "mons"+i;
>> mons.name = mname;
この例で言うと、nameがmonster_mcクラスのメンバ変数になります。おそらくはmonster_mcクラスは何かのクラスを継承していて(なにかのクラスのカスタムクラスになっていて)、基本的には全てのクラスがpublic var name:Stringをメンバ変数として持っていると思われます(x, yといった座標もたぶんそう)。
そして外部から直接見えてしまうnameの実装は、オブジェクト指向的には美しくない(笑)。
でもいちいちnameを読み書きするために関数を呼んでいたら実行速度的にもプログラミング的にもよろしくないので、他のクラスから直接見えるようにしてあるんですな。
そんでこのメンバ変数nameは、ただのString型の変数であって、インスタンスの名前ではないので、直接コード上で呼び出すことは出来ません。コードから呼び出そうとするならば、newした時点で代入した変数をずっと持っていないといけません。
http://www.atmarkit.co.jp/fwcr/rensai2/as3_06/as3_06_3.html
ここに福笑いのActionScriptコードがありますが、最初の行の「public class Base extends Sprite」というのが、Spriteクラスを継承した「Base」という名前のカスタムクラスという意味になります。
二行目以降の「private const LEFT:String = "left";」というのがメンバ*定数*の宣言で、"const"を"var"に変えてやればメンバ*変数*になると思います。ここのprivateという宣言で、クラス外から見えるか見えないかを決めています(見せたい場合にはpublicと書く)。
最初に宣言されているクラス名と同じ名前の関数「public function Base()」は、コンストラクタというもので、このクラスが*newされた時に必ず実行*されます。返り値は誰も受け取れないので必ずvoidなのですが、いちいち書くのが面倒くさいのでなにも書かなくても良いことになってます。
情報が多すぎて消化不良になりそうなので、最初はこれくらいにしておきましょうか。
投稿: 深井 | 2009年8月14日 (金) 02時47分
コメントありがとうございました。
その後いただいたアドバイスで、問題のひとつが解決しました。
解決法を記事に追記しました。
投稿: 適当所長 | 2009年8月18日 (火) 21時10分
>> その後はmonsters[i]のiに数値(1~6)を入れることで、
ActionScript3.0の配列(Array)は0開始です。
for文も0から始まって7未満までループしてるでしょ?
つまり0~6で合計7つのインスタンスができています。
投稿: 深井 | 2009年8月18日 (火) 22時06分
おっと、そうですね。
6体ならループをi < 6にすべきですね。
訂正します。
投稿: 適当所長 | 2009年8月19日 (水) 21時07分