■AS1と比べて大きく異なった部分・・・
■AS3独自のもの・・・
■Papervision3D・・・
■勉強のため題材として拵えたモノ・・・
AS3との融合って、ちとオーバーでしたね。使用したAS3は超簡単なモノですので、こんなオーバーなタイトルを付けるんじゃなかった。
と、いきなりの反省から始まるパターン描画ツールは「つる模様」っす。まずをサンプルのスタートボタンを押してください。
描画ツールの「ツル模様」には花と葉っぱの部分がオリジナルのムービークリップと差し替えできるようになっている。そこで、花が咲くムービークリップ[ hana ]を作り、それをさらに[ hana_mc ]という名前にしたムービークリップにして、そのフレームにマウスコントロールをするスクリプトを書き込んで、下記の設定ウィンドウで登録します。
ついでに葉っぱも[葉っぱ]というムービークリップにして、それも登録します。

パターン描画ツールの「つる模様」のウインドウ・・・
上の写真で「花:」と「葉:」の[編集]ボタンを押してムービークリップを選択する。そして下の「詳細オプション」で細かく調整するだけです。
「詳細オプション」の「枝の角度」は枝が伸びていく方向を指示するもので、0°で右方向、+90°で下方向に枝が伸びていく、負の角度にすると半時計回りになる。なので、今回は左下から右上に生えていって欲しいので、「-45°」に設定した。「枝の角度」の右にあるカラーボックスをクリックすると枝の色を変更できます。
「パターンの伸縮」「セグメントの長さ」は少ない数値にすると細かい絵になっていくようだが、なかなか思ったとおりにならないので、あまり大きな変更をしないほうがいいみたい。
最後に「パターンをアニメーション化」にチェックを入れると、今回のように枝が生えていくムービーを作ってくれる。ムービーといっても枝の生える過程をワンステップずつフレームに書き出してくれるだけ。速くしたければフレーム数を増やせばいい。
で、描画を開始するには、書き出すレイヤーに範囲を示す枠を書いておかないと、ステージ全体に書き出されるので、とんでもない大きなモノになるので注意。
今回のこの大きさで「1ステップごとのフレーム数」を1にすると、描画にぬあんと52秒も掛かっている。マシンはペンティアム core i5で、クロックは3.2GHzのWindows7 でっす。
ま、一度アニメーションが展開されたら以降は瞬時に動くからご安心あれ。

「つる模様」がアニメーション化されたフレーム(レイヤー「アニメーション」)・・・
やってみるとわかるが、範囲指定の枠もアニメーション化のときに各フレームごとに書き出されるので、枠を削除したり修正しようとすると、全フレームに渡ってその作業をやらなければいけないという、気の遠くなることを強いられるので、この範囲指定の枠はムービークリップにしてしまったほうが賢い。
ムービークリップでも範囲指定としての機能もあるようだし、書き出されるのはインスタンスのほうなので、修正したいときはライブラリに入っているシンボル本体を修正すれば、全フレームに書き出された枠が修正されるよ。
また削除するとき、素直に削除しようとすると、全フレームに書き出された枠を消すはめになるので、ここは奥の手で・・・。
どうするかというと、ライブラリに入っているシンボル内で枠を描いているいるレイヤーをガイドレイヤーに変更してしまう。そうすると、ガイドレイヤーはswfに書き出されないので、削除したのと同じ効果がある。再び枠が必要になったときはガイドレイヤーから標準レイヤーにもどせば復帰できるっす。
Startボタンがあるのでその部分のスクリプトを無視して花だけのスクリプトを書き出してみると・・・。
まず、アニメーション化されたフレームがずらっと並ぶメインタイムラインの最終フレームに以下のスクリプトを書いて、全体を停止するようにしてます。
stop();
これは枝の生えるアニメーションが終わったところで停止させないとまた初めに戻ってしまうのでね。
では、ステージ上に描画ツールでアニメーション化された花に指定したムービークリップ、[ hana_mc ]のひとつをWクリックして構造を覗くと・・・。

「花:」に指定したムービークリップの構造・・・
ムービークリップ[ hana_mc ]の中にムービークリップ[ hana ]があり、そこに花が咲いてしぼむまでのアニメーションが書かれている。そして花が咲き終わったフレームに[ stop(); ]と書いて停止するようにしてます。
[ stop(); ]と書いた次のフレームから萎むアニメーションが始まっていて、最終フレームで[ gotoAndPlay(1); ]と書いて最初に戻しているだけっすよ。
次にマウスアクションのスクリプトも簡単。ムービークリップ[ hana_mc ]のフレームに以下のスクリプトを書かいている。
【Script-1】
stop(); var hana:MovieClip; hana.play(); hana.addEventListener(MouseEvent.ROLL_OVER,F_onRollOver); ////////////////////////////////////// // onRollOver function F_onRollOver(evt:MouseEvent):void { hana.play(); }
簡単でしょ。
[ hana_mc ]が読み込まれたら、その内容である[ hana ]ムービークリップをスタートさせて、その[ hana ]ムービークリップに[ ROLL_OVER ]マウスイベントを設定しているだけ。イベントが起きたら[ hana ]ムービークリップがどんな状態であってもフレームを進めるようにしてます[ hana.play(); ]。
どんな状態っていっても、[ hana ]ムービークリップはフレームが進んでいるか、咲き終わって停止しているしかないので、咲き終わっている花にマウスが乗るとフレームが動き出す、というわけ。
今回は超簡単なスクリプトで実験したので、葉の後ろに花が書き込まれてしまう不具合をスクリプトで修正していない。枝が生えるアニメーションの最終フレームでパターン描画処理で書きだされた画像のグループ化を外して、[ hana_mc ]ムービークリップだけを選択してから、重ね順を最前面に設定するという手抜きでごまかしているので、どもすみません。枝が生えるアニメーション中で、咲き出した花が葉っぱの後ろにチラチラ見えているけどそこはひとつお許しを・・・。
おまけとして・・・・・。
パターン描画ツールの中には同じ配置を自動的に繰り返してくれるモノがあります。だから〝パターン〟描画ツールなんだけどね。その中の「格子模様」を利用してスクリプトの入ったムービークリップを配置させた例です。
今回は、なんでもかんでもクラス定義だの、インポートだの、むずかしく考えることは無いということが勉強になった。AS1のようにフレームスクリプトで書き込んでいけば、そんなに変わらないのでは・・・と舐めてかかっていますが・・・どうでしょ。
・・・しっぺ返しを喰らうかもね・・・。おお、怖わぁ~。
3Dオブジェクトをマウスでクリックさせて、いろいろなボタンなどに利用する場面って多いと思うけど、Cubeの各面を個別に識別できる方法はないかと調べたら、ここにありました。
→http://papervision2.com/10-advanced-interactivity/
上記は英語版なので、簡単に記録しておくと。
まず、material を作る。(mc_1という名前でリンケージしたムービークリップをfrontMaterialにしている)
var frontMaterial:MovieAssetMaterial=new MovieAssetMaterial("mc_1",true);
次にinteractiveをtrueにして、マウスイベントを受けるようにする
frontMaterial.interactive=true;
materialにはnameというプロパティがあるらしいので、これにユニークな名前をつける。ユニークといっても面白いという意味ぢゃないよ。"独特"な名前という意味だからね。
↓これで、そのmaterial.nameが"Front"と定義される。
frontMaterial.name="Front";
あとは、マウスイベントで受け取る引数 evt (イベントで受ける変数をこのページでは常に"evt "としてます)から face3D.material.name と遡って求めることができる。
例えばマウスクリックハンドラで…。(evtが受け取るClass 名もそのままなので間違えないように)
function clickFunc(evt:InteractiveScene3DEvent):void {
// ↓これでクリックした面の名前をclickMaterial に入れている。
clickMaterial=evt.face3d.material.name;
// ↓これでクリックしたCubeの参照を clickCube に入れている(参考までに・・・)
clickCube=evt.target;//
/////////////// Cubeの面の判別 //////////////////
switch (clickMaterial) {
case "Front" :
//Front 専用の何らかの処理
break;
case "Right" :
//Right 専用の何らかの処理
break;
:
:
:
:
:
・・・となる。
【補足として】
evtで受け取る InteractiveScene3DEvent は、mouseOverとmouseClick イベントのときは正しく evt.face3d.material.name を受け取れるが、mouseOut イベントのときは evt.face3d.material.name=nullになるので注意。
materialのinteractiveプロパティをtrueにすると、マウスイベントが受け取れるようになるが、マウスが指のカタチになってくれない。
で、こう書く・・・。
viewport.containerSprite.buttonMode=true;
viewportにはcontainerSprite.buttonModeというプロパティがあるみたい。だけど、interactive=falseのオブジェクトにマウスが載っても指になってしまう。(な~んじゃそれ)
仕方がないので、普段は…。
viewport.containerSprite.buttonMode=false;
としておいて、interactive=true にしたオブジェクトがmouseOver 時に…。
viewport.containerSprite.buttonMode=true;
と、載った瞬間に切り替える。
そして、mouseOut 時に…。
viewport.containerSprite.buttonMode=false;
として切り替えるとうまくいく。神業ぢゃ。
【補足として】
イベントは透過してしまうので、Cubeの特定の面にこれをやると指のマウスにしたくない面の向こう側に、指のマークにする面があると、イベントが向こうで受け取られて指マークになってしまう。
Flashのコンテンツでは、これまでもオブジェクトの立体的な回転を手掛けたことは何度かある。例えば、看板が〝クルン〟と回転して裏側が見えるようになるとか、立方体がゴトゴト回転して登場するとか、のはいくつも作ってきた。でも、すべて擬似的にやっていたっす。
(立方体の回転はここで使われています→サイト・KEYOSSの「ド・レ・ミでSEを作る」のタイトルオープニング)
擬似的にとは、どういうことかというと、回転する連続画像をいくつも作って、順番に切り替えて見せる、早い話が〝アニメ〟と同じ。強引に回っているように見せる・・・。という力技でした。というより能力不足を誤魔化す最後の手段かな?
この強引な方法で、時計回りにも反時計回りにも自由に360°回転させるとなると、ものすごい数の絵を拵えなくてはいけないので、それはそれは大騒ぎになった。
たとえば、一度に1°ずつ回転させようとすると、360枚の絵が必要になるでしょ。それをシステム全部含めて納期2日で作れ、って云われれば「鬼ぃ~」って叫んでしまう。
Flashの動画も映画と同じで、すこしずつ変化する画像をひとコマずつフイルムに焼ているようなモノ。それを1秒間に何コマ進めるかで滑らかさが決定する。現代の映画のコトはよく知らないが、昔の映画のフィルムは1秒間に24~30枚進めていたと聞いているけど・・・。
Flashの場合もここらは同じで、1秒間に何コマ進めるかは制作者が決められる。これをフレームレートと呼ぶ。とうぜんフレームレートは高いほど映像は滑らかに動く、先ほどの360°回転するモノを360枚の絵にして、1秒間でひと回転させたら、フレームレートは360になるっす。
しかし、360枚の絵を搭載するとデータ量は膨大な数値に膨れ上がり、とてもネットで流せるものではなくなる。これはではたまらんので、少し荒く見えるが、5~6°単位で回転させると約72~60枚の絵でなんとかなるね。

湯水のごとく絵を使う回転アニメーション・・・。
イラストレーターのCS1あたりから搭載された、3D効果というツールを利用して少しずつ回転させた静止画を作るので、60枚ほどの絵ならそれほどツライ工程ではないが、修正が入るとすべてやり直しになるので非常に効率が悪かった。
先も書いたがこの方法の最大の欠点は、回転する絵を大量に搭載するのでファイルが大きくなること。絵でなく写真を使用しても作れるが、ファイル量はもっと膨れ上がる。それともうひとつ、この方法だと絵の回転軸が微妙にブレるので、ちょっとフワフワ揺れながら回転しているように見えてしまうということです。
いまのところPV3Dを利用すると、このあたりの問題が一挙に解決しそう。〝いまのところ・・・〟というのは、自由な形状のモノを回転させようとすると、その形状のモデリングデータを作成しなければいけなくなり、これはこれで別の仕事になってくるね。
ま、それまでは、PV3Dの恩恵にあやかることにしましょう・・・。
次の画像は単純にy軸に対して回転させているが、swfファイルの大きさはたったの138Kバイト。
この程度の(←むふふ、やっとできるようになったくせに・・・)回転はつぎのスクリプトをonEnterFrameイベントで動くように記序しているだけ。
private function motion():void { cube.rotationY+=1; cube.rotationY%=360; }
たったの2行・・・。それも2行目は360°回転したらもとの0°にもどしているだけのコト。これで1フレームに角度1°の回転ができている。
1行目の 〝+=1〟 という記序は、+1して変数に格納するという意味。
60枚の絵を書いていたころの自分に・・・。
ご冥福をお祈り申し上げます・・・。あははは。
ファイルサイズが138Kバイトで少ない・・・って書いたけど、ただ横に回転させるだけにしては大きくない?って思われたかもしれない、確かにこの138Kバイトを消費しているのは、本の画像が原因ではない。本の画像なんて30Kバイトに満たないっす。
実は半分ぐらいが立体映像を作成するために気の遠くなるようなプログラム(ライブラリ)がインストールされている。PV3Dの開発チームが作り上げたプログラムが自分の作った、しょうもない(あはは。云いよった)画像にインポートされているんだよ。
138Kバイトを大きいとするか、小さいとするかは次のサンプルを見て頂戴。これから登場するサンプルはすべて138Kバイトで、容量はまったく同じ。異なるのは、回転軸をX、Y、Zに対してそれぞれ自由に可能なようにスクリプトを書き換えたもの。
どれだけ複雑に回転させても、ファイルサイズは何も変わらない。これがすごいぞPV3D。
回転部分の記序は次のとおり
private function motion():void { if (xFLG){ cube.rotationX+=runVal*speed; cube.rotationX%=360; } if (yFLG){ cube.rotationY+=runVal*speed; cube.rotationY%=360; } if (zFLG){ cube.rotationZ+=runVal*speed; cube.rotationZ%=360; } }
xFLG、yFLG、zFLGがtrueのとき、それぞれの回転が起きるようになっているでしょ。trueかfalseを決めているのは、左上に並んでいる各回転ボタン。
runValは回転方向で、1になったり-1にしたりを左上の「時計回り・反時計回り」ボタンで切り替えている。そしてspeedは回転速度の数値。なので・・・。
cube.rotationX+=runVal*speed となっているので、speed=3とすると、3を加え続けたり、-3を加え続けたりしているだけ・・・。
例によって、情報パネルの数値はオブジェクトが停止させているときだけ変更が可能なので、自由な角度にセッティングできるのでイロイロ遊んでみて・・・。
ここでおかしな現象に気がついた方はおられるでしょうか?
自動的に回転させるのではなく、オブジェクトは止めておいて、情報パネルで角度を入力していくとおかしな現象に気がつく。
例えば、x軸を90度に回転させると本はx軸を中心にして90度回転するので、表紙を上に向けて北側を頭にして倒れる。分かりにくい方は、最初45°にしてから90°に倒すとどっちへ倒れこんでいるか分かるよ。
で、倒れたので、y軸も90°倒れてこちらから向こうに向かって、ちょうど倒れる前のz軸と同じになった思うでしょ。そこで、y軸に90°回転させると・・・。
本は右下の角を左にして、紙がペラペラする部分を正面にした位置に回転する。
あり? y軸が倒れていないゾ?
軸そのものも一緒に回転するのではなく、オブジェクトを含む外の世界の軸に沿って回転するの?
・・・と、思えば間違いではないので、
気を取り直して、もう一度実験だぁ~。
「元に戻す」ボタンを押して初期に戻す。こんどはz軸に45°回転させてから、y軸に沿って45°回転させると・・・。
あり? ちゃんとy軸も一緒に45°回転してるじゃん・・・どゆこと?
これは謎っす・・・。脳ミソ沸騰寸前でござる・・・。
rotationで回転させる場合、まだ意味はわかっていないが、何かしらの法則があるように感じられる。さらにドキュメント情報を読み進んでいくと・・・。
何せ、英文ですので読解速度が著しくおそいんです・・・ハイ。
yaw、pitch、roll というメソッド(=関数・サブルーチン・モジュール・・・どれでもお好きなをどうぞ) があることが分かった。
pitchはオブジェクトをx軸に沿って、yawはオブジェクトをy軸に沿って、rollはオブジェクトをz軸に沿って回転させる処理のようですね。
それを利用して先ほどの回転サンプルを改造したのがこれ・・・・。
回転部分の記序は次のとおり
private function motion():void { // pitch if (xFLG){ cube.pitch(runVal*speed); } // yaw if (yFLG){ cube.yaw(runVal*speed); } // roll if (zFLG){ cube.roll(runVal*speed); } }
何も難しいことはやってないよ。本当に替えただけっす。でも思ったとおりに軸も一緒に回転する非常に複雑な動きが実現しました。
昔のやり方では、とてもとても・・・不可能ですラ。
今回はもう少し本格的に動きを追ってみました。
例のごとく、2冊の本を2つのCubeで拵えて実験をしようということに。
今回はカメラを動かすのではなく、Cube(本)の位置を示すパラメータ、東西・上下・南北を時間に沿って変化させると、どのように映し出されるかの実験。
右上の白い「情報パネル」の数値は、表示と変更を兼ねるようにしたので、「元に戻す」ボタンで初期状態に戻してから、いろいろと数値を変更して、「enter」ボタンを押して頂戴。その数値でカメラやCube(本)の位置を初期化できるからね。
カメラの位置は左上のカメラの絵にある矢印をクリックしてもできる。それとおまけとして「shift」キーを押しながらクリックすると、±100の数値で変更できるよ。
時間に沿って変化するのは、初期状態ではCube(本)の東西(x座標)と南北(z座標)だけど、「スタート/停止」ボタンの上にある「上下移動無し」ボタンを「上移動あり」にすると、時間に沿ってCube(本)の上下(y座標)も変化するようになるから、あとでやってみて。
数値の入れ方によってはCube(本)が地面にぶつかってしまうことがある。数値で云うとCubeの上下位置が150以下になったとき。これはCube(本)の高さが300なので、その中心、150の位置がCube(本)のy軸になるみたい。なのでこのときCube(本)の底がちょうど地面に着くようだ。だから「下移動あり」にしても150以下にはならないようにしている。地面にもぐりこむCube(本)っておかしいでしょ。
あと注意として、動いている最中は「情報パネル」で数値の変更はできないのと、途中で「情報パネル」の数値を変更すると、その位置が最初の位置として記録されてしまうのでので、本当の最初に戻せなくなったときは、ブラウザの更新ボタンを押して・・・。(手抜きっす)
どお?いろいろな数値で動かすと、まるでスターウォーズのシーンを思い出すような動きをするでしょ。おもしろいね。
これを本当のCube型でやれば、スタートレックヴォイジャーのボーグキューブが迫ってくるときのシーンが簡単に作れそう。すごいぞPV3D。
で、やってみた。
ひとつのCubeをボーグキューブと見立てて、それをカメラ位置よりも少し上に配置。さらにy軸に対してわずかに回転させながら通過するように下記の記序をしてだけ。
private function cubeMotion():void { cube.x+=5; cube.z+=-5; cube.rotationY+=0.3 if (cube.y>150){ cube.y+=udVal } }
if文の記序は下方向に150以上下がると地面にめり込むので、それ以上は下がらないようにしているだけで、あとはフレームごとにCubeのx座標(東西)とz座標(南北)を+5して、y軸(上下)に0.3だけ回転を加えています。
こんな簡単なスクリプトで動いているのが次のボーグキューブの映像・・・。
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
音が聞こえてきそうな迫力になった。すごいね。
こうなると、シェーディングや
ライティングにも手を出したくなるね。
AS3にそこそこ慣れてくると、やはり3Dの処理をしたくなるね。ただ、AS3を駆使して立体画像をグルングルン回したりするには、ものすごく脳みそを使ということが分かってきた。かといって難しいことはやりたくない、でも3Dはやってみたいね。
で、どうするか・・・。
私のような横着者にうってつけなのが、Papervision3D(以降、PV3Dと書きます)というライブラリ(フレームワーク)。そして・・・。
ぬぁ~んと、このライブラリは無料で手に入る。大阪人にとって〝只〟という言葉ほどすてきな言葉はないっす。
ほんとうにありがとう。開発チーム様へはココロより感謝させていただきます。ほんと、こんなに簡単に3Dモーションが作れるようになるなんて夢のようです。
で、さっそくどんな構造になっているのか、とりあえず実験的な世界を拵えてみた。コレを基礎につぎなる3Dモーションへジャンプアップできるだろう・・・ね。たぶん・・・。
いま見ているこの映像は、人間が覗いているというよりも、コンピュータの中に作られた世界をその中に置いてあるカメラで映し出していると思ったら理解しやすい。
カメラの現在位置は右上に「東西・上下・南北」の数値で一覧表示してあります。
カメラの前に青い本と緑のほんが置いてあり、カメラは緑の本の表紙表面から南へだいぶ下がった位置(カメラの南北位置が600)に置いてある。あとは画面の中心なので、東西と上下はともに位置が=0になっています。
青い本は緑の本より、西へすこし、北へすこし行った位置に置いてあって、さらに2冊の本は水色の床からすこし上の位置に浮かんでいる。
これがカメラの最初の位置。
今回のサンプルではカメラを一番手前の緑の本に常に向くようにプログラムしてあるので、これを「東西・南北・上下」にすこしずつ移動させて、機械の中の2冊の本がどう見えるか、その立体感を味わおうという・・・計画です。
ところで、カメラは常に青い本を向くようになっていることを忘れないでね。これがミソっす。中央の円に×のマークがカメラの見ている中心点になります。
まず、一番わかりやすいのが上下移動。左上の青いボックスをクリックして「カメラを上下に移動」に切り換える。そして画面中央の赤い分割線の右側の画面上をクリックすれば、カメラが上空に上がっていく。カメラは緑の本から目を離さないので、そのように画面が変化していくでしょ。
分割線の左側をクリックするとカメラは下方向へ移動していく。何度も書くけど、カメラは緑の本を見つめながら下がって行く、そして水色の床が迫ってきて、ついにはそれを突き抜けて裏側から眺めることになるっす。
上下位置を-190~-196にすると2冊の本が床からどれぐらい浮いているかがよく分かるでしょ。
-198を超えて-200になると、床がカメラに対して真横になるので見えなくなる。何故見えないかというと、床は厚みの無い面として作られているので、真横になるとペラペラの紙みたいになって見えなくなる。
一度「元に戻す」ボタンを押して、初期状態に戻してから、左上のボックスをクリックして、「カメラを東西に移動」にして赤い分割線の左の画面をクリックして負の数値、東へ移動してみまよう。
2冊の本がすこしずつ回転しながらカメラから離れていき、やがて背表紙が見えてくる。クリックを続けているとどんどん遠ざかって行って、本の回転はある程度までで、それ以上は回転しなくなり、あとは遠ざかるだけです。
何故回転するのかな?とすこし考えた。
実際に左手に本を持って、目の前で動かしてみて納得。
本を見つめながらそれを左方向に移動させると、画面と同じように背表紙がある程度まで見えて、あとは遠ざかっていく。なるほど、よくできているね~。
では、この本はどうやって画面に出しているかというと、ここが PV3Dのありがたいところ。Cubeという立体物を作るライブラリがあります。Cubeは立方体なので6個の面を持っている。正面、裏面、上面、下面、右面、左面の6面。この面にFlashで拵えた絵をプリントしているだけ。スクリプトで書くとこんな感じ。
// 緑の本 var materialList:MaterialsList = new MaterialsList({ front: new MovieAssetMaterial("Front", true ), back: new MovieAssetMaterial("Back", true ), right: new MovieAssetMaterial("Right", true ), left: new MovieAssetMaterial("Left", true ), top: new MovieAssetMaterial("Top", true ), bottom: new MovieAssetMaterial("Bottom", true ) }); cube = new Cube(materialList, 250, 25, 300, 16, 8, 16);// 幅、奥行き、高さ、セグメント scene.addChild(cube);
MaterialsList という構造体に、各面のFlashのインスタンスのリンケージ名("Front"とか"Back"とかの部分)を登録しているだけで、最後に・・・
cube = new Cube(materialList, 250, 25, 300, 16, 8, 16) と、Cube(立方体)のインスタンスを作成しています。
幅、奥行き、高さの数値がそれぞれ異なるのは、本という直方体を作っているからで、全部同じ数値にすればサイコロのような立方体になるでしょ。
ねぇ~。便利でしょ。
3Dの画面を作成するには、他にも・・・。
renderer の作成や、scene 、viewportなどを作成して、
addChild(viewport); を行ってステージに登録しないといけないが、これは常に決まりきった手順なので、いちど記序してしまえば、何も難しいところはないので安心っすよ。
ところで、2冊目の青い本はどうやっているかというと、まったく同じ、次のように Cube2を作って表示させているだけ。
// 青い本 var materialList2:MaterialsList = new MaterialsList({ front: new MovieAssetMaterial("Front2", true ), back: new MovieAssetMaterial("Back2", true ), right: new MovieAssetMaterial("Right", true ), left: new MovieAssetMaterial("Left2", true ), top: new MovieAssetMaterial("Top", true ), bottom: new MovieAssetMaterial("Bottom", true ) }); cube2 = new Cube(materialList2, 250, 25, 300, 16, 8, 16);// 幅、奥行き、高さ、セグメント cube2.x = 100; cube2.y = 0; cube2.z = -100; scene.addChild(cube2);
異なるところは、本の初期位置。
cube2.x = 100;
cube2.y = 0;
cube2.z = -100;
と、しているでしょ。
これをしないと、緑の本とまったく同じ位置に表示されてしまうので、x座標(東西)を100 → 西へ100移動。z座標(南北)を-100 → 北へ100移動させている。
あとはカメラの位置を決めて・・・。
private function setCamera():void { camera = new Camera3D(); cameraIni(); } // カメラを初期位置にセットする private function cameraIni():void{ camera.x = 0; camera.y = 0; camera.z =600; camera.zoom = 30; camera.focus = 30; }
と、やってカメラの位置を決めている。camera.z=600; とやっているのは600ほどカメラを南方向に動かしてやらないと、緑の本の表面にレンズが当り、何も見えないから。このあたりもよくできているね・・・。
そして、全部の設定が終わってから最後に・・・。
camera.target = cube;
として、カメラが見つめる相手(target)を緑の本(cube)にして終わり。
すごいぞPV3D・・・。
3Dの難しい概念や仕組みをまったく知らない素人の私にでもできるなんて・・・。
さすがは、PV3Dだ。
少しほめすぎたけど、ただ、素人が手を出せるのは、PV3Dがあらかじめ作ってくれている形を利用する範囲内だけになる。それ以外の例えば、〝椅子〟だとか〝机〟だとかは、でき合いの立方体や直方体を組み合わせて作る以外は、モデリングデータを作成しなければいけないという、ちと面倒なことになるらしい。
でも、しばらくはこの状態でもかなりのことはできると思う。
ところで、PV3Dで、あらかじめ作ってくれている形のことを 〝プリミティブオブジェクト〟というらしいが、種類が豊富で以下のクラスが用意されています。
●Plane クラス(単一面)
●Cube クラス(立方体・直方体)
●Sphere クラス(球体)
●Cone クラス(円錐)
●Cylinder クラス(円柱)
●PaperPlane(紙飛行機)
●Line(直線)
などがあるが、PaperPlane(紙飛行機)って、どんなのだろうね。
まだまだ、おもしろそうだ。
やっと、あ~AS3にしてよかったなぁ~と、思えるモノに出会ったよ。
それが、Tweenクラス。この先まだまだお涙チョチョ切れるモノに出会うかもしれないが、コレが始めてのチョチョ切れです。
FlashでTween(トゥイーン)といえば、タイムラインで拵える、モーショントゥイーンや、シェイプトゥイーンなどがあるが、それをスクリプトで実現しようと思うとなかなか大変。たとえばスクリプトを使って画面の左端にあるムービークリップを右へ等速度で300ピクセル移動させたとしても、それはトゥイーンとはいえない。動きが単純すぎて見ている人を感動させることができないからね。どうするかというと、左から右への移動にアクションをつけてやると、それっぽくなるよ。
これをイーズと呼ぶみたい。例えば左から右へ動き出すときに徐々に加速をつけるように動き出し、停止するときはブレーキが掛かったように急速に速度を落とし、ゆっくり止まるとか、止まった瞬間にバネのように〝ボヨヨン〟と振動して止まるとか、考えれば切りがない。
このような凝った動きをスクリプトで実現するのは不可能じゃないが、非常に込み入っていて超めんどくさい作業になる。ま、よくやっていたのは、急速に速度を落としてゆっくり止まるイーズアウトかな。一回の移動先を現在位置から停止位置までの20%とかに決めて移動させる、残りの距離が小さくなればなるほど移動距離が小さくなりブレーキが掛かったように見える。これがスクリプトで作れる一番簡単なイーズィング。
バネのようにとか、加速と減速を組み合わせるとになると途端にやる気がなくなる…お恥ずかしいかぎりですが、そのような時はできる限りタイムラインを使ったイーズィングでゴマかす。うははは。
でも、AS3ではこれらのめんどくさい作業をTweenクラスが一手に引き受けてくれる。importする必要はあるが、イーズする目的のインスタンス名とイーズィングの種類、どのプロパティにイーズィングを掛けるかの指定と、開始値と終了値、イーズィングの速さなどを引数に書き込んで、Tweenインスタンスを生成すればあとは勝手にやってくれというすぐれもの。
たとえば次の例は、トランプのカードが現在位置から右方向、X座標にして810pxの位置まで、バネのように跳ねて加速して、バネのように振動しながら停止するTweenの例。(カードをクリックすると動きだし、ブラウザの更新ボタンで再起動するよ)
Tween sample-1
AS1のスクリプトでコレを実現するとなるとちょっと引いてしまうが、AS3では以下のスクリプトをメインタイムラインに書いているだけ。ねぇ~。楽チンでしょ。コメントを取っ払ったら10行以内ですからね。
(カードのインスタンス名は card_mc としています)
import fl.transitions.Tween; import fl.motion.easing.Elastic; card_mc.buttonMode = true; //カードがクリックされたらTweenをセットするメソッドをセット; card_mc.addEventListener(MouseEvent.CLICK,twStart); var endPoint:int = 810;//右端終了位置 var bom:Tween; ////////////////////////////////////////////////// // 右端へ飛んでいくtweenを設定 function twStart(evt:MouseEvent):void { // 第1引数:Tween を掛けるオブジェクト → card_mc // 第2引数:Tween を掛けるプロパティ名 → "x" // 第3引数:Tween の種類 → Elastic.easeInOut(開始と終了時にバネのように跳ねる) // 第4引数:Tween を掛ける初期値 → card_mcの x 位置 // 第5引数:Tween を掛ける最終値 → endPoint=810 // 第6引数:Tween を速度(秒かフレーム) → 1.2秒 // 第7引数:Tween を速度を秒にする=true) → 秒にする bom = new Tween(card_mc,"x",Elastic.easeInOut,card_mc.x,endPoint,1.2,true); }
Tween 関係のクラスを import することを忘れずに・・・。忘れると次のようなエラーが2つ出ます。
1046: 型が見つからないか、コンパイル時定数ではありません : Tween。 1180: 未定義である可能性が高いメソッド Tween の呼び出しです。
ちなみに、タイムラインに直接書き込むスクリプトの場合、MouseEventなど頻繁に使用するクラスのimport は自動的にやってくれる。でも Tween はやってくれないので自前で書き込まなければいけない。ところが慣れるまでは結構忘れてしまう。なので上記のようなエラーが出た場合、import を忘れているな・・・っと思ったほうがいいかも、
あ~、しゃて。
先のサンプルは、第二引数の Tween を掛けるプロパティ名を〝x〟にしたので、ムービークリップの〝x〟座標が変化する Tween になった。では回転のプロパティ=rotation にしてみるとどうなるか。
bom = new Tween(card_mc,"rotation",Elastic.easeOut,0,90,1.2,true);
トランプのカードが時計方向に回転して〝ボヨヨ~ン〟とバネのように弾けて停止する(イラスティック・イーズアウト)。う~んたいしたもんだ。少しは楽できそうっすな。
Tween sample-2
では、ふたつのプロパティを変化させる Tween はどうするか。それに関してはどこにも資料が無かったので正しいかどうかわからないが、私は次のように、ふたつの Tween を同時に操作してみたよ。
bom = new Tween(card_mc,"scaleX",Elastic.easeOut,1,2,0.5,true); bom2 = new Tween(card_mc,"scaleY",Elastic.easeOut,1,2,0.5,true);
scaleX と scaleY の両方にbomとbom2のふたつのTween を掛けるとちゃんと、scaleX,scaleYの変化=拡大縮小に対して Tween が掛けられる。ようするにトランプのカードがスケール1倍とスケール2倍の範囲で〝ボヨヨ~ン〟とバネのように跳ねて大きく拡大される。やるぢゃん、AS3。
ここでハタっと手が止まった。
今回AS3を勉強するために題材にした神経衰弱ゲームでは、開いたカードが同じだった場合、カードが〝ボヨヨ~ン〟と大きくなって、すぐに画面右端に飛んで行ってから、スコアーアップするつもりなので、ひとつひとつの Tween が終わったことが分からなくてはいけない・・・。
そこまで考えられているのか、このTweenクラスは・・・。
持っている参考書にはそれらしいことは一切触れてないし・・・ネットでどう調べるか検索単語すら解らなかった。〝Tweenが終了したら〟とか適当な言葉で検索してみたがそれらしいことは出てこなかった。
とりあえずスコアーアップのタイミングは、メインタイムラインのenterFrameイベントを利用して、カードが右端、ようするにX座標にして810になったかを検知し続けて、なればTweenが終了した、と判断できる・・・と考えたが、カードが〝ボヨヨ~ン〟と大きくなる Tween が終了したことをどうやって知るの?
scaleX が2になったら終了? いや、〝ボヨヨ~ン〟と大きくなるときに瞬間でも〝2〟になるはず、そのときを検知してしまうし・・・。
そこで最悪の場合に備えて考えた検知方法が、〝ボヨヨ~ン〟と大きくなるのに要する時間が経過したら次の Tween に切り替えるという方法。
う~ん。ほんと最悪な方法だな。使いたくない。知性のかけらも無いな・・・。(恥)
もう一度ネットをさまよう。
するとAS2での〝Tween.Finish〟という単語が引っかかった。〝Finish〟という単語がクサイな。と思って、〝AS3 Finish〟で検索すると出てきましたがな。〝motionFinish〟というイベントが存在することが・・・。
くそぉ~。独学は辛いな~。
こんな簡単なことを見つけるのに、半日掛かってるもんな~。詳しい人が横にいたら数秒でわかるのにね~。
「あ、それなら〝motionFinish〟っていうイベントがあるよ」のひとことで解決するのにな~。
と、ボヤいてもしょうがない。独学の辛さは今始まったわけではないもんね。
さっそく、最初のTween 〝ボヨヨ~ン〟と大きくなったら、
〝motionFinish〟イベントを受け取って、次の、画面の右端へ〝ボヨヨ~ン〟と飛んで行くスクリプトに切り替わるようにしたのが次の
Tween sample-3
このスクリプトを神経衰弱ゲームに応用すると、AS1ではめんどくさくてやりたくなかったような、Tween を簡単に実装できた。こりはすごいぞAS3!
と、思っていたのはほんの数分間だけでしたね。
何度かゲームをやっていると、カードが画面の右端にすっ飛んでいく途中で固まる現象が起きた。最後の Tween が完了してからスコアーアップ処理を行っているので、そちらのバグか?と思って調べるが異常なし。どう考えても Tween クラスがおかしい。お~いほんとに大丈夫なの?AS3よ~。
こうなると、Tween クラスだけでなくAS3自体にまで疑いだす始末。もう一度参考書の Tween の欄をくまなく見る。すると、欄外に小さい文字で
「作成したTweenオブジェクトへの参照はグローバル変数などに代入して不要になるまで維持しないと、Tweenアニメーションの途中で停止することが稀にある」
と書かれていた。
おぉ~い。こうゆうコトはでっかい文字で頼みますよ~。
さらにネットではもっと詳しく書かれていた。たくさんのオブジェクトを使ったムービーを作ると、Flashがガベージコレクションでローカル変数を削除するときに Tween オブジェクトの参照まで削除してしまうことがあるので、 Tween が無効になるまでしっかりとメモリを確保しておかないといけないらいしい。
たしかに神経衰弱ゲームでは52個のオブジェクトを使ってるもんね・・・。
理由がわかれば問題なしですね。早速その修正を行ってみると、途中で止まるバグは無くなった。
おぉぉ~。やっぱAS3は頼もしい。AS3よ、あんたは偉い!
コロコロ、態度 変えるなよ
addEventListener(イベント、関数 ); のように記序すれば、あとはAS1のように使えるんだろう、と思っているとひっくり返されからご注意を・・・。
マウスクリックに関してはAS3には恐ろしい掟が待っている。
(ちなみにマウスクリックだけではなさそう。まだそこまで勉強は進んでいないのに、もうすでに腰が引けてます)
イベントリスナーで受け取るeventオブジェクトの項で書いたけど、ひと癖もふた癖もあるのがAS3だからね。
イベントオブジェクトには target というのと currentTarget という、ふたつのプロパティがある。AS1の考え方でいくと、イベントを受け取るインスタンスはひとつなので、なぜふたつもプロパティが準備してあるのか謎だった。そこで、調べてみると target の方はイベントをリスナーしたインスタンスの最下位の階層にあるムービークリップが入っていて、 currenTarget にはリスナーしたインスタンスが入っていた。最下位の階層を記録しておく意味があるのだろうか…? などと勝手に大きな勘違いをしていた。(非常に恥ずかしい)
マウスクリックイベントをよく使うのがボタンのムービークリップですね。AS1のころにやっていた方法で作るボタンは滑らかに変化する美しい、いわゆるFlashらしいボタンが簡単に作れた。
どうのようにやっていたかというと、まずボタンインスタンスの中にフレームを3つ作り、フレーム1にはマウスアウトのムービーが作られている btnOut というムービークリップを置く。フレーム2にはマウスオーバーのムービーが作られている btnOver というムービークリップを置く。そして3つ目のフレームにクリックされたときのムービーが作られている btnDown というムービークリップを置く。そしてそれぞれのムービーは放っておくとループ表示になってしまうので、それらのムービークリップの最終フレームには stop(); と書いておきます。
あとは、イベントに応じて、マウスオーバーなら gotoAndStop(2);とか、マウスダウンだったら gotoAndStop(3);などにフレームを移動させるだけで、そこに置かれているムービークリップが自動的に動き出すという仕組みで、非常に簡単に滑らかな動きをするボタンを拵えることができた。
AS3になればもっと簡単にできるだろうと期待していたが、そうは問屋が卸してくれない。
AS3にも動きが単発的な単純なボタンなら簡単に作れる方法はあった。参考書などにも書かれている方法で、次のようなものっす。
つくり方は簡単。
AS1のように、フレームを3つ作り、それぞれマウスアウトの絵、マウスオーバーの絵、マウスダウンの絵を置いておく。そして、新たにレイヤーをふたつ確保して、その中のひとつのレイヤーを3フレームに渡って、空のキーフレームを置きそれぞれのフレームに、フレームラベルを〝_up〟〝_over〟〝_down〟と書く。もうひとつ確保したレイヤーのフレーム1に次のスクリプトを書きます。
stop(); buttonMode = true; これだけ・・・。
どうなるかはsample-2をどうぞ。
サンプルムービーにはボタンのインスタンスである btn_mc とその内部のタイムラインの様子が表示されるようにしてあります。それがじゃまなときは〝説明部分を消す〟ボタンを押してください〟
マウスが載ればマウスオーバーの絵、マウスが外に出ればマウスアウト、マウスボタンを押せば押した絵に切り替わるだけの、CSSやJavaScriptでもできるような簡単なボタンだね。
せっかくFlashを使うのだから、AS1のときのように滑らかに変化するボタンを拵えたい、と思うのがFlashユーザーですよね。ところがこれには落とし穴が・・・。
sample-2を改造して、AS1でやっていたように各フレームにイベント時のムービーが作られたムービークリップを置いて試したのが、
sample-3
ところが、残念ながら ちゃんと動かない。
マウスオーバーまではちゃんと動いているが、クリックしても event はmouseOverのままだし、とうぜんダウンしたときのムービーが入っている btnDown ムービークリップは表示されない。
さらには、〝ボタンだよ〟という文字が入っている text_mc の上にマウスを持っていくと、target が btnBase から text_mc に変わる。どうも target というのは最下位階層のインスタンスを指しているようではないみたい。
何が悪いのだろうかと、持っている参考書を見ても target に関しては特に記序が無い。しかたなしにいつものようにネットの中をさまよう。そうするとエライもんで、なんとなく薄らぼんやりではあるが理解できた。
AS3ではリスナー登録した下層にあるすべてのムービークリップにイベントが伝わるらしい。だからボタンの中に別のムービークリップが入っているとそちらにイベントが伝わり、ボタンは正しく動かなくなる・・・ということみたい。
マウスダウンが起きてフレームが3へ移動すると、そこには新たに btnDown というムービークリップがあるので、そこへ向かって、マウスオーバーイベントが起きて、再びフレーム1へ戻ってしまっているのではないかと推測される。
ということは、マウスアクションを行うムービークリップの中に新たなムービークリップを入れてはいけないといことになる。それが証拠に btn_mc の中に一切のムービークリップが入っていないsample-2は正しく動いている。
しかしそれでは、単純なボタンしか作れないではないか・・・となるが、回避策はある。イベントを伝わらないようにすることができる。イベントを伝えたくないムービークリップのフレーム1に・・・。
mouseEnabled=false;
と記序すればそのムービークリップにはイベントは伝わらない。おかげでAS1で拵えたときと同じように正しく動き出したのが、
sample-4 だ。
イベントさえ伝わらなければよいのだから、ヒットエリアを変えるコトだってできる。
sample-5は、ボタン本体からズレた位置にあるムービークリップ(薄水色の楕円のムービークリップ)がこのボタンのヒットエリアとして設定してある。なのでマウスがその上に載ったときだけ反応する。
こんなボタンはあり得ないが、もしかしたらそんな状況のモノを作るかもしれないので、ひとまず勉強にはなった。
とにもかくにも、AS3はなぜこんなまわりくどいやり方をしなければいけないのだろうか。
先に進めば、これが感謝に変わるのかな?
AS3からはAS1やAS2でおなじみになっている on Press( ) などのイベント関係のステートメントは全廃になっている。代わりにaddEventListener(イベント,処理名)を使う。そして処理側で必ずイベントオブジェクトを受け取ることを義務づけられている。アウトローは許されない、無視するとエラーが出る。 例えば、btn_mcというボタンがマウスクリックされたら、何か処理するときは・・・。
bt_mc.addEventListener(MouseEvent.CLICK,pressFunc); function pressFunc(evt: MouseEvent):void { // クリック処理 }
とやる。
このとき、受け取った変数 evt に入れられたイベントオブジェクトのプロパティで target というのがイベントを受け取ったインスタンスを指していると、巷の参考書には書かれている。たしかに正確な記序だが、AS1に慣れていると勘違いしやすいので注意が必要。
AS1をやってきた人は、イベントが伝わるのはイベントを定義したインスタンスだけと思い込んでいる。なのでbtn_mcの下に(下の階層でも同じ)ムービークリップがあっても気にしなかったが、AS3ではムービークリップすべてにイベントが伝わると思っていたほうがよいみたい。
試しに、btn_mcの中にbtnBaseというムービークリップインスタンスを置いて、
クリック処理内で target が何を指すか見てみるスクリプト、sample-1を記序してみると・・・。
btn_mc.addEventListener(MouseEvent.CLICK,pressFunc); function pressFunc(evt: MouseEvent):void { // クリック処理 trace(evt.target.name);// btnBase と表示 trace(evt.currentTarget.name);// btn_mc と表示 }
targetが指すインスタンスとcurrentTargetが指すインスタンスが異なってくるので注意が必要。とりあえず、currentTarget の方を使用するとAS1のように扱うことができそうだな・・・と思っていたら、AS3はまだまだ奥深かい。執念深くAS1ユーザーを苦しめるのでありました。
サンプルムービーにはボタンのインスタンスである btn_mc とその内部のタイムラインの様子が表示されるようにしてあります。それがじゃまなときは〝説明部分を消す〟ボタンを押してください〟
AS3、恐ろしや~。
AS1では、stageに最初からあるタイムラインは、いわゆるrootといわれるFlashの一番上の階層にあたる部分になる。何階層も下がった位置にあるインスタンスから最上階のrootにある変数、例えばcounterの数値を、例えばcntという変数に読み込むときは…。
this.cnt=_root.counter
とやればOK。
だが、AS3でこれをやると、たちまちエラーになる。
AS3の場合は(変数cntはint型として)
var nRoot:Object= Object(root) var cnt:int=nRoot.counter とやるか、 var nRoot:Object=root as Object var cnt:int=nRoot.counter とやる。 データの型はObjectだが、MovieClip としてもOK。 _parentの場合も同じで、 var nParent:Object = Object(this.parent); varcnt:int=nParent.counter となる。
これがほんと、慣れるまで非常にまどろっこしい。
rootのメインタイムラインにgameOverというメソッドがあるか調べるには・・・。
nRoot = Object(root); trace(nRoot);// ← root1 と表示 trace(nRoot.gameOver);// ←これでgameOverというfunctionがあれば "function Function { } "という表示が出る
これが何の役に立つのかというと、gameOverメソッドが、どうしても正しく動かないときなど、gameOverというメソッドにバグがあるのか、それともgameOverというメソッドが認識されていないのか、確認したくなるときがある。
認識されていたら原因はgameOverメソッド内にあるというのが解るし、メソッドが認識されてなかったら、とうぜんその処理が動かないのは当たり前になるからね。
そゆこと・・・。
AS3では変数とプロパティの区別がなくなっている。そして、変数には何でも格納できる。ただし型を宣言しないとエラーになる。
変数をvalという名前にしたとすると、その中にどのようなモノを入れるかを宣言するのが型を指定するという意味。
例えば、valには正の整数だけしか入れないと決めたら、型は〝uint〟になるので、
var val:uint と書く。そのまま続けて初期値を入れるときは・・・。 var val:uint=25 とか書く。
何でも入るので、メソッドを入れることもできる。
例えば、変数 func に init() メソッドを入れるなら・・・。
var func:Function=init と書く。
こうすれば、場合によっては
funcの中を別のメソッドで上書きすれば、処理の流れを変えることができる。
Copyright(C) 2004. D-Space Keyoss.
All rights reserved.