Flash&ActionScript3の最近のブログ記事
サーバー上の画像を読み込んで、立方体を動かしてみましょう。
このやり方だと画像をサーバー上で読み込みますので、プログラムが苦手なweb担当者でも気軽に立方体の画像を変更することができます。難点は画像を読み込む間に立方体が黒く表示されることがあるかもしれない事です。
説明はいいからやり方を教えろという方向けの手順です。
- CubePic.asファイルをダウンロードしてFlashDevelopなどに取り込みます。
- FlashDevelopの場合asファイルはsrcフォルダに入れます。またsrcフォルダにはPV3Dから持って来たnochumpフォルダと orgフォルダも入れておきます。
- 書き出しサイズは315x250pxとします。FlashDevelopではメニューのプロジェクトからプロジェクトの設定で行います。
- binフォルダーの中にimagesフォルダを作成してimg0.jpgからimg5.jpgの画像ファイル6枚を入れてください。Embedを使用する場合はsrcフォルダに入れましたが今度はbinフォルダです。間違わないようにしましょう。
- コンパイルするとbinフォルダにswf拡張子のファイルができています。これがFlashファイルです。binフォルダに入っているファイルとフォルダをそのままサーバーの目的のフォルダににアップします。
- 画像を変更する場合はサーバーにアップしたimagesフォルダ内のimg0.jpgからimg5.jpgまでの画像を希望の画像に上書きします。必ずファイル名はimg0.jpgからimg5.jpgまでの画像を使用します。サーバー上の画像ファイルとswfファイルとhtmlファイルは必ずbinフォルダ内と同じ階層構造にします。そうしないと画像が正しく表示されません。
立方体を動かすソース
package { import flash.display.*; import flash.events.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; public class CubePic extends ReflectionView { private var cube:Cube; public function CubePic() { cube = createCube(); scene.addChild(cube); camera.y = 600; addEventListener(Event.ENTER_FRAME, onMove); } private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList(); var imgArr:Array = new Array(); for (var i:int = 0; i < 6; i++) { imgArr[i] = new BitmapFileMaterial('images/img'+i+'.jpg'); } var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left']; for (var j:int = 0; j < imgArr.length; j++ ) { var bitmap:BitmapFileMaterial = imgArr[j]; bitmap.smooth = true; materialsList.addMaterial(bitmap, faceArr[j]); } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1); return cube; } private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 50 * Math.sin(getTimer() / 4000); camera.z = 50 * Math.cos(getTimer() / 4000); startRendering(); } } }
ここから文法の説明です。
ソースについて
createMyCubeメソッドの定義
createMyCubeメソッドはCubeクラスをインスタンス化するための処理をメソッドにしてまとめたものです。createMyCubeメソッドの中身が前回のEmbedを使用したものと変わるだけです。他のソースは変更する必要がありません。
- MaterialsListをインスタンス化。MaterialsListとはキューブ体をインスタンス化する際に必要になる各側面のテクスチャーをリスト化するクラスです。
- 画像のクラスを配列にする
- for文で画像の配列をインスタンス化し、BitmapFileMaterialクラスをインスタンス化して画像をロードする。それを配列に代入しています。「3Dを描画する(4)〜カスタムクラス作成/画像の貼付け」で行った画像の張り付けを配列とfor文を使って処理しています。
- 各面を配列として格納します。
- BitmapFileMaterial型の変数に画像を代入します。
- addMaterialメソッドでmaterialsListに画像データを追加します
- materialsListを第1引数に入れてCubeクラスをインスタンス化します。
private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList();//--------------(1) var imgArr:Array = new Array();//-------------------------------(2) for (var i:int = 0; i < 6; i++) { imgArr[i] = new BitmapFileMaterial('images/img'+i+'.jpg');//-------(3) } var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left'];//------(4) for (var j:int = 0; j < imgArr.length; j++ ) { var bitmap:BitmapFileMaterial = imgArr[j];//---------------------(5) bitmap.smooth = true; materialsList.addMaterial(bitmap, faceArr[j]);//-------------------(6) } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1);//------------(7) return cube; }
次はHTML5とCSS3そしてJavaScriptに取り組みたいと思います。比較的簡単な内容から入るつもりです。ActionScriptについては機会をみて補填していきます。
<author Tahara>
もしよろしければ、下ボタンをクリックお願いします。
最初に戻って立方体を動かしてみましょう。
説明はいいからやり方を教えろという方向けの手順です。
- CubePic.asファイルをダウンロードしてFlashDevelopなどに取り込みます。Adbe Flash ではうまくいかないです。(FlashCS3以上ではEmbedは使えないし、その必要もないですね。画像はもっと簡単にクラス化できる訳ですから)
- FlashDevelopの場合asファイルはsrcフォルダに入れます。またsrcフォルダにはPV3Dから持って来たnochumpフォルダと orgフォルダも入れておきます。
- 書き出しサイズは315x250pxとします。FlashDevelopではメニューのプロジェクトからプロジェクトの設定で行います。
- srcフォルダーの中にimagesフォルダを作成してa.jpg,b.jpg,c.jpg,d.jpg,e.jpg,f.jpgの画像ファイル6枚を入れてください
- コンパイルするとbinフォルダにswf拡張子のファイルができています。これがFlashファイルです。
立方体を動かすソース
package { import flash.display.*; import flash.events.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; public class CubePicembed2 extends ReflectionView { [Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class; private var cube:Cube; public function CubePicembed2() { cube = createCube(); scene.addChild(cube); surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, onMove); } private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList(); var imgArr:Array = [A, B, C, D, E, F]; var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left']; for (var i:int = 0; i < imgArr.length; i++ ) { var bitmap:Bitmap = new imgArr[i]() as Bitmap; var bitmapData:BitmapData = new BitmapData(200, 200); bitmapData.draw(bitmap); var material:BitmapMaterial = new BitmapMaterial(bitmapData, true); material.smooth = true; materialsList.addMaterial(material, faceArr[i]); } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1); return cube; } private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 50 * Math.sin(getTimer() / 4000); camera.z = 50 * Math.cos(getTimer() / 4000); startRendering(); } } }
ここから文法の説明です。
Embedとは
Embedは謎が多いです。使い方だけ覚えてしまいましょう。
//Embed使用例 [Embed(source = 'images/a.jpg')] private var A:Class; var img:Bitmap = new A() as Bitmap;
通常Embedを使用した画像表示はEmbedでロードしたい画像のファイル名を指定し,クラス型の任意の名前のクラスとして宣言します。次にそのクラスを使用してBitmapとしてインスタンス化します。(asを使用してキャストしています)その後はこのBitmapをaddChildしてやれば表示することが出来ます。
ソースについて
以下はEmbedを使用して各画像をクラスとして宣言しています。
[Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class;
コンストラクタ
- Cubeクラスをインスタンス化するメソッドcreateMyCube()を実行。
- インスタンスcubeを表示リストに加えています。
- ENTER_FRAMEが実施されるごとに行われるリスナー関数 enterFrameHandleを宣言しています。
public function CubePicembed2() cube = createMyCube(); //--------------------------(1) scene.addChild(cube); //-----------------------------------(2) surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, enterFrameHandle);//-(3) }
createMyCubeメソッドの定義
createMyCubeメソッドはCubeクラスをインスタンス化するための処理をメソッドにしてまとめたものです。
以下Cube クラスのコンストラクタのパラメータです。
Cube(materials:MaterialsList, width:Number = 500, depth:Number = 500, height:Number = 500, segmentsS:int = 1, segmentsT:int = 1, segmentsH:int = 1, insideFaces:int = 0, excludeFaces:int = 0)
以下はMaterialsListクラスをインスタンス化して画像をそれぞれの面に設定し、最後にCubeクラスのインスタンス化で活用しています。
- MaterialsListをインスタンス化。MaterialsListとはキューブ体をインスタンス化する際に必要になる各側面のテクスチャーをリスト化するクラスです。
- 画像のクラスを配列にする
- キューブの面を配列にする
- for文で画像の配列をインスタンス化し、そのままBitmap型にキャストする
- 新規のBitmapDataクラスをインスタンス化する。サイズは縦横200px。なぜBitmapDataクラスが必要なのかは別途説明します。
- BitmapDataクラスのdrawメソッドで画像を描きます。
- BitmapMaterialをインスタンス化します
- materialをsmooth に表示させる処理
- addMaterialメソッドでmaterialsListに画像データを追加します
- materialsListを第1引数に入れてCubeクラスをインスタンス化します。
private function createMyCube():Cube { var materialsList:MaterialsList = new MaterialsList();//------------------(1) var imgClassArr:Array = [A, B, C, D, E, F];//---------------------------(2) var faceNameArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left'];//----(3) for (var i:int = 0; i < imgClassArr.length; i++ ) { var bitmap:Bitmap = new imgClassArr[i]() as Bitmap;//---------------(4) var bitmapData:BitmapData = new BitmapData(200, 200);//-----------(5) bitmapData.draw(bitmap);//-------------------------------------(6) var material:BitmapMaterial = new BitmapMaterial(bitmapData, true);//--(7) material.smooth = true;//---------------------------------------(8) materialsList.addMaterial(material, faceNameArr[i]);//----------------(9) } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1);//--------------(10) return cube; }
メソッドの詳細はPapervision3D 2.1 日本語 リファレンスガイドを参照してください。
onMove(e:Event)について
イベントのENTER_FRAMEが実行されるごとに実施されるリスナー関数です。
オブジェクトcubeのヨー(y軸を中心に回転)とピッチ(x軸を中心にした回転)、そしてy座標を決めカメラのx座標とz座標を決めてレンダリングを開始します。
startRendering();メソッドをsingleRender();と書き換えると鏡面効果が得られます。
private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 50 * Math.sin(getTimer() / 4000); camera.z = 50* Math.cos(getTimer() / 4000); startRendering(); }
一番下のstartRendering();メソドッドをsingleRender();メソッドに変更するだけで鏡面体が現れます。カメラの位置を多少変更します。
更に次のようにソースを一部加えると鏡面との境界面ができ上がります。
package { import flash.display.*; import flash.events.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; public class CubePicembed extends ReflectionView { [Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class; private var cube:Cube; private var earth:Plane; public function CubePicembed() { cube = createCube(); earth = createEarth(); scene.addChild(cube); scene.addChild(earth); surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, onMove); } private function createEarth():Plane { var earth:Plane = new Plane(new WireframeMaterial(0xFFFFFF, .5), 600, 600, 10, 10); earth.rotationX = 90; earth.rotationY = 20; earth.y = -100; return earth; } private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList(); var imgArr:Array = [A, B, C, D, E, F]; var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left']; for (var i:int = 0; i < imgArr.length; i++ ) { var bitmap:Bitmap = new imgArr[i]() as Bitmap; var bitmapData:BitmapData = new BitmapData(200, 200); bitmapData.draw(bitmap); var material:BitmapMaterial = new BitmapMaterial(bitmapData, true); material.smooth = true; materialsList.addMaterial(material, faceArr[i]); } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1); return cube; } private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 500 * Math.sin(getTimer() / 4000); camera.z = 500 * Math.cos(getTimer() / 4000); singleRender(); } } }
次は同じ立方体の回転でも画像の読み込みをサーバー上で行う方法です。
<author Tahara>
もしよろしければ、下ボタンをクリックお願いします。
今回は前回まで作成した3Dの球体を動かしてみましょう。
説明はいいからやり方を教えろという方への手順です。
- 前回までの方法で作成した3Dの球体のソースを用意します。
- addEventListenerでENTER_FRAMEイベントを待ち受けて リスナー関数を実行する。
- リスナー関数で球体を動かす処理を行う。
3D球体を動かすソース
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; import flash.events.Event public class Main4 extends BasicView { public function Main4():void { var sphere:Sphere = new Sphere(null,60,10,10); scene.addChild(sphere); stage.addEventListener(Event.ENTER_FRAME, onmove); var houkou:int =1; function onmove ():void { sphere.x += 10 * houkou; sphere.rotationY += 10 ; if (sphere.x < 0 || sphere.x > stage.stageWidth) { houkou *= -1; } } startRendering(); } } }
ここから文法の説明です。
addEventListeneとは
stage.addEventListener(Event.ENTER_FRAME, onmove);
「インスタンスbox_mcをクリックしたらtest()を実行する」といったインタラクティブ(対話式)な処理を考えたとき、この中には「1どこで、2何が起きたら、3どうする」の3つの要素が含まれています。このイベント処理をスクリプトではaddEventListener()というメソッドを使って設定します。書式は次のようになります。イベントが発生するオブジェクトに対して、イベントタイプとリスナー関数をペアにしてイベントリスナーとして追加します。
イベントターゲット.addEventListener(イベントタイプ,リスナー関数)
addEventListenerの引数は正確には次のとおりですが簡単なイベント処理を行うには第2引数まで指定して後は省略する場合があります。その他の引数の意味については別途特集で解説します。
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false)
イベントについてはイベントの概念資料をこちらのPDFで参照ください。
ENTER_FRAMEについて
ENTER_FRAMEは繰り返し発生するイベントです。フレームレートに合わせて繰り返し発生するフレーム再生イベントは、アニメーションで利用する繰り返しイベントとして最適なイベントです。デフォルトのフレームレートは毎秒12フレームなので、デフォルトのENTER_FRAMEの頻度は毎秒12回になります。
リスナー関数
function onmove ():void { sphere.x += 10 * houkou; sphere.rotationY += 10 ; if (sphere.x < 0 || sphere.x > stage.stageWidth) { houkou *= -1; }
sphere.x += 10 * houkou;はもう少し親切に書くとsphere.x = sphere.x + 10 * houkou;となります。物理運動の等速運動を行う動きはsphere.x += 10の部分で表されます。ENTER_FRAMEが発生するごとに10ピクセルだけ右に動くという意味です。
ちなみに、sphere.y += 10ではy軸に対して下に10ピクセル動くという意味になります。
sphere.rotationY += 10 ;はy軸を基準に時計回りに回転をさせています。地球の自転と逆の動きですね。
* houkouは方向を決めます。
if (sphere.x < 0 || sphere.x > stage.stageWidth)
if文でx軸が0またはステージの右側を出てしまったらという条件を表しています。
そしてその条件にあてはまったらhoukou *= -1にするというステートメントになっています。
マイナス1を積算することで動きを逆にするわけです。
ところで、このソースで動かしてみるとなんだか小さな範囲で動いています。if文の条件と違うと思いませんか。
実はこれはカメラの設定に原因があります。
trace(camera);を最後に入れてカメラの設定をトレースしてみるとx:0 y:0 z:-1000
という結果がでてきます。つまり明示的にカメラの設定を書かなければデフォルトのカメラの設定が使用されています。で、カメラの位置がx:0 y:0 z:-1000となっている訳です。
カメラの位置を明示的に示したい場合はstartRendering();の前にcamera.z = -500;などのように指定します。
camera.z = -500; startRendering();
円周運動させるにはsin、cosを使います。参考ソースです。
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; import flash.events.Event public class Main5 extends BasicView { public function Main5():void { var angle:Number = 0; var radius:Number = 600; var angleChange:Number = 5; var centerX:Number = stage.stageWidth/2; var centerY:Number = stage.stageHeight/2; var sphere:Sphere = new Sphere(null,60,10,10); scene.addChild(sphere); addEventListener(Event.ENTER_FRAME, onmove); function onmove ():void { var radian:Number = deg2rad(angle); sphere.x = centerX + radius * Math.cos(radian); sphere.y = centerY + radius / 3 * Math.sin(radian); sphere.rotationY = 10; angle += angleChange; angle %= 360; } function deg2rad(deg:Number):Number { return deg * (Math.PI/180) } startRendering(); } } }
<author Tahara>
もしよろしければ、下ボタンをクリックお願いします。
今回は前回まで作成した3Dの球体に画像を貼付けます。
まず、説明はいいからやり方を教えろという方向けの手順です。
- 前回までの方法で作成した3Dの球体のソースを用意します。
- 張り付ける画像sample.jpgをbinフォルダに用意します。
- BitmapFileMaterialクラスをインスタンス化します。
- Sphereクラスをインスタンス化する際の第1引数にnullではなく2でインスタンス化したオブジェクトを入れます。
あとは前回と同じです。簡単ですね。
3D球体を描くソース
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; public class Main extends BasicView { public function Main():void { var sphere:Sphere = new Sphere(null,600,30,30); scene.addChild(sphere); startRendering(); } } }
3D球体に画像を貼るソース
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; public class Main2 extends BasicView { public function Main2():void { var mat:BitmapFileMaterial = new BitmapFileMaterial("sample.jpg");//ここが新たに加わります。 var sphere:Sphere = new Sphere(mat,600,30,30);//第1引数に上でインスタンス化したオブジェクトを入れます。 scene.addChild(sphere); startRendering(); } } }
ここから文法の説明です。
var mat:BitmapFileMaterial
左側で変数matをBitmapFileMaterial 型で宣言しています。
new BitmapFileMaterial("sample.jpg")
右側ではsample.jpgファイルを引数に入れてnew演算子でインスタンス化しています。 ここで注意するのは画像sample.jpgはbinフォルダに入れるようにしてください。 (インターネットで公開する場合はswfファイルと同じ場所でかつ、swfファイルを埋め込んだhtmlと同じ場所にする必要があります)
つまり画像ファイルはコンパイル前に読み込まれるのではなく、コンパイル後に外部ファイルとして読み込まれます。 ということは、この画像を変更することでいつでも好きな画像を読み込ませることが可能だということなのです。
それから、通常は外部画像を読み込む場合下記のようなめんどうな手続きが必要です。今回使用したライブラリにはすでに下記のような処理が用意されており、メソッドに貼付けたい画像を指定するだけで良い訳です。至れり尽くせりですね。興味のある方はBitmapFileMaterialクラスの内容を確認してみると良いかもしれません。Loadの手続きが書かれているはずです。
<参考>Loaderクラス〜外部の画像ファイルを読み込む
画像を外部から読み込めるようにして、表示する画像を変更しやすく、汎用性に富んだものにすることができます。 画像を外部から読み込むには、Loaderクラスのload()メソッドの引数に画像のファイルパスを指定します。 ここで注意が必要なのは画像のパスはString型の文字列ではエラーになります。 この引数はURLRequestクラスを使用しなければなりません。
loader = new Loader(); var url:URLRequest = new URLRequest("img/photo1.jpg"); loader.load(url);
- Loader クラスは、SWF ファイルまたはイメージ (JPG、PNG、または GIF) ファイルをロードするために使用します。ロードを開始するには load() メソッドを使用します。ロードされた表示オブジェクトは Loader オブジェクトの子として追加されます。
- Loader クラスは、継承する次のメソッドをオーバーライドします。これは、Loader オブジェクトが持つことができるのは 1 つの子表示オブジェクト、つまりロードするオブジェクトに限られているためです。次のメソッドを呼び出すと例外がスローされます。メソッドは、addChild()、addChildAt()、removeChild()、removeChildAt()、および setChildIndex() です。ロードされた表示オブジェクトを削除するには、親の DisplayObjectContainer 子配列から Loader オブジェクトを削除する必要があります。
- 画像がLoderオブジェクトに追加されたときEvent.INITイベントが送出されます。
- Event.INITイベントを受け取るリスナーは通常だとLoderのオブジェクトloderと考えられがちですが、LoderInfoオブジェクトにする必要があります。LoderInfoオブジェクトとはロードした画像に関する情報を提供するオブジェクトです。
- LoderInfoオブジェクトを参照するにはLoderインスタンスのインスタンス変数のcontentLoderInfoを通して行う事ができます。
- ロード終了後の画像にアクセスするにはLoderオブジェクトのインスタンス変数contentで行う事ができます。
- または深度0の子を指定してアクセスするメソッドgetChildAt(0)でもアクセスできます。これはLodaerオブジェクトはただひとつの子をもつことしかできないことを利用したものです。
- 最後にロードした画像を表示リストに追加するにはaddChild()するだけです。表示リストに追加すると画像はLoderオブジェクトから自動的に削除されます。
参考 ここでLoader クラスとLoderInfoクラスの詳細についてはActionScript 3.0 コンポーネントリファレンスガイドで確認しましょう。
表示リストとは
表示リストとは、Flash Playerに表示されるすべてのオブジェクトの階層です。
階層の構成要素
- ステージ:すべての表示オブジェクトの最上位となる表示オブジェクトコンテナです。
- 表示オブジェクトコンテナ:表示オブジェクトの一種で、子を持つことができます。
- 表示オブジェクト:Flash Playerに表示されるすべてのオブジェクトは表示オブジェクトとなります。表示オブジェクトコンテナ以外の表示オブジェクトは子を持つことができません。
3種類の抽象クラス
- DisplayObjectクラス:画面上に表示する機能のみを持っている
- InteractiveObjectクラス:DisplayObjectを継承して、さらにキーボードやマウス操作に反応できるようにしたもの
- DisplayObjectContainerクラス:InteractiveObjectを継承して更に他のコア表示クラスのコンテナになれるクラス
これらから直接インスタンスは作成することができません。インスタンス化するにはそれぞれサブクラスを使用することになります。
上記DisplayObjectクラスなどの3種類のクラスのプロパティ、メソッド、イベントについてはActionScriptコンポーネントリファレンスガイドを参照してください。
子の追加
addChild();
表示リストに表示オブジェクトを追加するのは簡単な2つの手順だけです。
1. SpriteかMovieClipのインスタンスを作成 var sp:Sprite = new Sprite();
2. addChild();で表示をする
addChildAt();
使用例 addChildAt(myball,0);
addChild();メソッドは表示オブジェクトを表示リストの最後に追加します。それは一番上のインデックス(一番上)にオブジェクトを配置します。
addChildAt()は表示リストの特定の位置に追加することができます。第2引数の0が一番下。
removeChild();
表示リストからオブジェクトを削除するにはremoveChild();を使用します。
特定のレベルのオブジェクトの削除はremoveChildAt();を使用します。
removeChildAt(0);とするとzインデックス0のものを削除するとなります。
removeChild();は表示を消すだけでオブジェクトは削除されていませんので注意してください。
オブジェクトを削除するには参照している変数をnullにしてガベージコレクションに任せます。
<author Tahara>
もしよろしければ、下ボタンをクリックお願いします。
今回は具体的に球体の作成方法をまとめておきます。
文法はどうでもいいからとりあえず作りたい場合は次の手順です。
- FlashCS3以上かFlashDevelopを用意します。今回はフリーのFlashDevelopを使用して作成します。
- 新規プロジェクトを作成します。AS3 Projectを選択してAS3のプロジェクトを作成します。
- ライブラリを入手します。papervision3dのページからPapervision3D ActionScript 3.0 Library .ZIP をダウンロードします。
- プロジェクトマネージャに表示されるsrcフォルダの中にライブラリの nochump と orgを入れます。libに入れるのではなくsrcに入れますので間違わないようにしてください。
- 下記ソースをMain.asファイルにコピーします。
- プロジェクトをテストボタンをクリックして実行画面を確認します。
- bin フォルダに出来上がったswfの拡張子が付くファイルがあります。これが球体を描くFlashのファイルです。
ついでにindex.htmlファイルもできていますので、自分のページに流用することができます。FlashをHTMLに挿入する方法が解らない場合はこのソースを使用すればよいです。JavaScriptで表示させる仕組みになっていますので、このHTMLソースを使用する場合はbinにある各ファイル、フォルダを自分が使用する環境に入れておく必要があります。
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; public class Main extends BasicView { public function Main():void { var sphere:Sphere = new Sphere(null,600,30,30); scene.addChild(sphere); startRendering(); } } }
ここから文法です。
クラスのインスタンス化
さて、上のソースのコンストラクタの中のステートメントを見てみましょう。
var sphere:Sphere = new Sphere(null,600,30,30);
これは変数の宣言とクラスのインスタンス化を一度に行っているものです。
ActionScript3では変数の宣言は次のとおりです。この部分がjavaと少し違いますね。
var 変数名:型
インスタンス化は次のとおりです。
new コンストラクタ
コンストラクタがパラメータを持っていれば引数を入れてやります。
今回の場合は左側で var sphere:Sphere と変数宣言しています。
Sphereクラスの型を持ったsphereという変数を宣言しているのです。
右側はnew演算子を使用してSphereクラスをインスタンス化しています。
インスタンス化とは設計図を使って具体的な物にするイメージです。
では、もう少し詳しく見て行きましょう。
インスタンス化するSphereクラスを見てみましょう。Sphereクラスはライブラリの中にあります。
org/objects/primitives/Sphere.as
コンストラクタを見てください。
public function Sphere( material:MaterialObject3D=null, radius:Number=100, segmentsW:int=8, segmentsH:int=6 ) { super( material, new Array(), new Array(), null ); this.segmentsW = Math.max( MIN_SEGMENTSW, segmentsW || DEFAULT_SEGMENTSW); // Defaults to 8 this.segmentsH = Math.max( MIN_SEGMENTSH, segmentsH || DEFAULT_SEGMENTSH); // Defaults to 6 if (radius==0) radius = DEFAULT_RADIUS; // Defaults to 100 var scale :Number = DEFAULT_SCALE; buildSphere( radius ); }
4つのパラメータがありますね。つまりクラスをインスタンス化する場合には引数を指定する必要があるのです。
ただし、この場合はパラメータにそれぞれ初期値が設定されていますので省略は可能です。引数を省略した場合は初期値の球が描かれます。
Sphereコンストラクタのパラメータの内容
第1引数はマテリアル(3Dに貼付ける画像など)
第2引数は半径
第3引数は横セグメント
第4引数は縦セグメント
*セグメントとは3Dの形状の分割数のことです。セグメントを増やせばポリゴン数が増えて滑らかな表現になりますが、CPU負荷が高くなります。
super( material, new Array(), new Array(), null );
これはスーパークラスのコンストラクタです。スーパークラスについては継承の特集で別途やります。
さて、ここまで解ればあとはSphereクラスに何が書かれているのかブラックボックスの状態で構わないのです。
その使い方さえ解ればいいわけです。
それでは元に戻りましょう。今度は
scene.addChild(sphere);
について見ていきましょう。
addChild()とは出来上がったオブジェクトを画面に表示するためのメソッドです。引数にオブジェクト名を入れるとそのオブジェクトが表示されるものです。
表示についてActionScript3では表示リストという概念があります。これをしっかり理解しないと的確にActionScript3を使いこなせないでしょう。
次回表示リストについてやります。
<author Tahara>
もしよろしければ、下ボタンをクリックお願いします。
カスタムクラスの作成
球体を描くソース
package { import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; public class Main extends BasicView { public function Main():void { var sphere:Sphere = new Sphere(null,600,30,30); scene.addChild(sphere); startRendering(); } } }
描画結果
import文
任意のパッケージにあるコードは、別のパッケージ内にあるコードを参照できません。
別のパッケージにあるpublicのクラスにアクセスできるようにするには、importディレクティブを使用します。
今回ライブラリはsrcフォルダの中に入れます。ライブラリフォルダは2つでorgフォルダとnochumpフォルダです。
描画する球体ではorgフォルダ内のクラスを使用しますので下記のようにimportを行っています。
ワイルドカードのアスタリスク(*)を使えば、同じパッケージ階層のすべてのクラスを指定できます。アスタリスクを使って指定できるのはあくまで同じパッケージ階層であって、その階層以降のすべてを参照するものではありませんので注意してください。
import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import org.papervision3d.materials.*;
クラスの定義
クラス定義はキーワードclassで始め、その後クラス名を記述します。クラス名は慣習的に大文字で始めます。空白やダッシュを含んではいけません。数字から始めるこもできません。パッケージ名を同じにすると、例えば別ファイルに記述したクラスでも同じパッケージの一部とみなされます。一方クラス定義は複数のファイルにまたがることはできません。
クラス名とクラスのファイルは必ず同一にします。Mainクラスの場合はMain.asというファイル名にします。
デフォルトでは、任意のクラスはそのパッケージ内にあるコードからのみ使用することができます。定義されたパッケージの外からクラスを使用できるようにするにはpublic属性をつけて定義します。また、パッケージ内のみ使用できることを明示的に示したい場合はinternal属性を使用します。アクセス制御指定子を省略すると暗黙的にinternal属性となります。
public class Main extends BasicView
extends BasicView は BasicViewクラスを継承するという意味になります。
この場合はBasicViewクラスを継承したパッケージ外のクラスからも参照できるMainクラスを宣言するという意味になります。
継承はオブジェクト指向で非常に重要な仕組みです。継承については別に特集します。
*Adobeのコンパイラではメインクラスにはpublic属性をつけて定義する必要があります。
コンストラクタメソッド
コンストラクタメソッド(コンストラクタ)はクラスのインスタンスを初期化するために使用される、特別な命令セットです。コンストラクタメソッドの名前はクラス名と正確に一致させる必要があります。
コンストラクタメソッドのブロックステートメントはインスタンスを初期化するディレクティブが含まれます。クラスで明示的にコンストラクタメソッドを定義しないとそのクラスの新しいインスタンスで初期化を実行しないデフォルトのコンストラクタを提供します。通常たとえ空でもコンストラクタは常にクラスに含めるようにします。コンストラクタメソッドの暗黙的に制御指定子はpublicとなります。通常は明示的に必ずpublicをつけて記述します。
public function Main():void { var sphere:Sphere = new Sphere(null,600,30,30); scene.addChild(sphere); startRendering(); }
* アプリケーションのメインのコンストラクタはプログラム内で特別な役割を演じます。コンストラクタはアプリケーションの開始後すぐにコードを実行できる機会を提供するのです。つまりメインクラスのコンストラクタはプログラムの開始点と考えることができます。
もしよろしければ、下ボタンをクリックお願いします。
飛行機をまったくゼロから作れと言われたらどうしますか?
その場合に行うべき処理について思いをめぐらせてみてください。
まさかいきなり金属工場に行って溶接を始めたりはしないでしょう。
まずは飛行機の設計図の作成から始めるはずです
しかも何もないところから飛行機を作る場合には、一枚だけでなく、
飛行機の多くの部分(車輪や両翼、椅子、ブレーキなど)の
それぞれについて設計図を書く必要があるでしょう。
そして今度は部分ごとにそれぞれの設計図どおりに加工し、
それが終わったらマスターの設計図に従って組み立てていきます。
ActionScriptのオブジェクトは、空を飛ぶ飛行機が一連の設計図に基づいて相互に作用するパーツの集まりであるのと同じように、動作する一連のクラスに基づいて相互に作用するオブジェクトの集まりです。
ActionScriptのオブジェクトは、プログラム内の目に見えるものと目に見えない概念の両方を表しています。
オブジェクトの例としては数値、ボタン、カレンダーの日付、画像のぼかし効果などであったりします。
オブジェクトはクラスの具体化(インスタンス化)であり、クラスはオブジェクトの基になる設計図のことをいいます。
クラスとオブジェクトを使ってプログラムを構築することをオブジェクト指向プログラミングobject-oriented programming(OOP)といいます。