Alif’s Weekly Ramblings

May 30, 2009

Beginning Flash 3D with Away3D

Filed under: Game Development — Tags: , , , — harsanalif @ 5:24 am

Pada kesempatan kali ini, saya akan menulis tutorial dasar mengenai 3D didalam Flash.

Ada beberapa library 3D untuk Flash yang berbeda, antara lain Papervision3D, Away3D, Sandy3D, dan Alternativa3D. Saya sendiri akan menggunakan Away3D karena selain open source dan gratis untuk penggunaan komersial, ada beberapa fitur advanced yang unik serta style penggunaannya yang saya sukai.

PERSIAPAN

Pertama-tama, pergi ke tautan berikut: http://away3d.com/downloads , lalu unduh Source terakhir yang ada di halaman tersebut. Pada saat penulisan, versi stabil yang terakhir adalah versi 2.3.3 (untuk Flash Player 9) / 3.3.3 (untuk Flash Player 10). Untuk tutorial ini, saya akan menggunakan versi 2.3.3 untuk Flash Player 9. Akan lebih baik lagi bila anda bisa mengambil source yang lebih ter-update langsung dari repository Away3D di http://code.google.com/p/away3d/ .

Photobucket

Bila sudah selesai diunduh, extract file ZIP yang anda dapatkan di tempat yang mudah anda ingat, misalnya C:\flash\ .

Buat sebuah dokumen Flash baru menggunakan Flash IDE favorit anda. Disini saya akan menggunakan Adobe Flash CS3. Pilih File -> Publish Setting (shortcut Ctrl+Shift+F12) untuk membuka layar Publish Setting.

Pastikan version yang dipilih adalah Flash Player 9, dan ActionScript version yang terpilih adalah ActionScript 3.0.

Selanjutnya kita perlu menambahkan referensi library Away3D untuk file Flash yang baru saja dibuat ini. Tekan tombol Setting disamping ActionScript version, pada layar ActionScript 3.0 Setting yang muncul, tekan tombol Add New Path (bergambar tanda tambah/plus), lalu ketikkan alamat folder dimana library Away3D versi 2.3.3 tadi anda extract. Pada contoh disini, alamat yang saya ketikkan akan seperti berikut, C:\flash\away3d_2_3_3\ .

Photobucket

PENGETIKAN ACTIONSCRIPT

Setelah persiapan selesai dilakukan, sekarang kita bisa masuk kedalam code. Pilih keyframe pertama dan satu-satunya yang ada pada Timeline, lalu buka Actions panel (shortcut F9). Ketik code ActionScript berikut.

import away3d.containers.Scene3D;
import away3d.containers.View3D;
import away3d.core.base.Object3D;
import away3d.core.math.Number3D;
import away3d.primitives.Sphere;

var view:View3D = new View3D({x:275, y:200});
addChild(view);

var sphere:Object3D = new Sphere({material:"black#white", radius:100, segmentsW:10, segmentsH:8, y:0, x:0, z:0});
view.scene.addChild(sphere);

view.camera.position = new Number3D(0, 0, 1000);
view.camera.lookAt(sphere.position);

addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void
{
view.render();
}

PENJELASAN

Berikut pembahasan lebih detil mengenai script diatas.
Secara umum, struktur pemakaian Away3D bisa digambarkan seperti diagram berikut:

var view:View3D = new View3D({x:275, y:200});
addChild(view);

Pada saat melakukan inisialisasi View3D di contoh diatas, kita juga mengatur posisi x dan y view relatif pada layar Flash, yaitu x = 275 dan y = 200. Koordinat ini merupakan titik tengah bagi View3D.
Bila kita tidak mengatur properti Scene dan Camera, maka View3D akan membuat Scene dan Camera default.
Jangan lupa untuk menambahkan object View3D pada stage dengan addChild() agar hasil render terlihat di layar.

var sphere:Object3D = new Sphere({material:"black#white", radius:100, segmentsW:10, segmentsH:8, x:0 , y:0, z:0});
view.scene.addChild(sphere);

Untuk dapat melihat sebuah objek 3D, kita terlebih dahulu membuat sebuah objek Object3D. Pada contoh diatas, kita membuat sebuah salah satu objek 3D primitif Away3D, Sphere.
Beberapa properti yang diset pada saat inisialisasi objek adalah:
- material. Bisa diisi Bitmap, Sprite, atau MovieClip. Pada contoh diatas, material diberikan warna polos hitam dengan garis outline putih (black#white).
- radius. Parameter yang mengatur besar Sphere yang dibuat.
- segmentsW & segmentsH. Ini merupakan pengatur jumlah segmen yang membentuk Sphere. segmentsW merupakan jumlah segmen Sphere secara horizontal, sedangkan segmentsH merupakan jumlah segmen Sphere secara vertikal.
- x, y, dan z. Koordinat awal dari Sphere. Pada contoh diatas, Sphere diset tepat di tengah-tengah.
Jangan lupa untuk menambahkan objek Sphere pada view.scene menggunakan addChild() agar objek tersebut bisa diproses oleh Away3D.

view.camera.position = new Number3D(0, 0, 1000);
view.camera.lookAt(sphere.position);

Semua objek 3D pada Scene akan di-render melalui Camera. Kita mengatur ulang posisi Camera (yang dibuat secara default pada inisialisasi View3D) agar dapat melihat objek Sphere yang berada pada koordinat (0,0,0). Pada contoh diatas, kita memindahkan Camera ke posisi z = 1000.
Selain itu, agar Camera pasti melihat ke arah objek Sphere, kita set arah pandang Camera dengan lookAt() menggunakan parameter posisi Sphere (0,0,0).

addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void
{
view.render();
}

Hal terakhir yang harus dilakukan adalah, View3D harus melakukan render() secara rutin untuk memperbarui tampilan Object3D bila ada proses yang mengakibatkan perubahan pada dunia 3D didalamnya. Disini kita memakai cara sederhana menggunakan Event.ENTER_FRAME.

Hasil akhir:

Photobucket

That’s it! Gak susah kan? :D

Flash sendiri masih kesulitan untuk me-render dunia 3D yang kompleks secara smooth (fps >= 30) walau dengan dukungan Flash Player 10 sekalipun. Tapi ini bisa juga dibilang sebagai langkah awal yang memungkinkan dukungan 3D pada aplikasi/games Flash ke depannya. Sementara itu, kita bisa memakai Away3D untuk membuat mini games 3D simpel, aplikasi widget, virtualisasi data, atau sebagai sarana viral marketing sederhana. Dengan manajemen aset dan model yang baik, bukan tidak mungkin kita bisa menampilkan aplikasi/games yang menawan dalam dunia 3D di Flash menggunakan Away3D dengan segala keterbatasannya J

DEMO

Demo simpel buat nunjukin beberapa implementasi fitur yang sedikit lebih advanced yang ada di Away3D, antara lain lighting, normal map, dan load model 3D eksternal.

Photobucket

import away3d.containers.Scene3D;
import away3d.containers.View3D;
import away3d.containers.ObjectContainer3D;
import away3d.core.base.Object3D;
import away3d.loaders.Max3DS;
import away3d.loaders.Object3DLoader;
import away3d.primitives.Sphere;
import away3d.primitives.Plane;
import away3d.core.math.Number3D;
import away3d.core.render.Renderer;
import away3d.materials.Dot3BitmapMaterial;
import away3d.lights.DirectionalLight3D;
import away3d.core.utils.Cast;

//View initialization
var view:View3D = new View3D({x:275, y:200});
addChild(view);

//Load external 3D Model
var model:Object3DLoader = Max3DS.load("Plane.3ds",{rotationX:90,rotationY:90,z:700});
view.scene.addChild(model);

//Initialize normap map
var normalMap:Dot3BitmapMaterial = new Dot3BitmapMaterial(Cast.bitmap(Diffuse), Cast.bitmap(Normal));

//Const to determine how fast each sphere follow other.
const speed:int = 10;

var radiusSphere:int = 100;
var sphere_arr:Array = [];

//Dragon body initialization
initSpheres();
function initSpheres():void
{
for(var i:int=0;i<7;i++)
{
var sphere:Object3D;

if(i==0)
{
sphere = new Sphere({material:normalMap, radius:radiusSphere, segmentsW:6, segmentsH:6, x:0, y:0, z:0});
var eyeLeft:Object3D = new Sphere({material:"red", radius:20, segmentsW:3, segmentsH:3, x:-60, y:60, z:70});
var eyeRight:Object3D = new Sphere({material:"red", radius:20, segmentsW:3, segmentsH:3, x:60, y:60, z:70});

var container:ObjectContainer3D = new ObjectContainer3D();
container.addChild(eyeLeft);
container.addChild(eyeRight);
view.scene.addChild(container);
sphere_arr.push(container);
}
else sphere = new Sphere({material:normalMap, radius:radiusSphere, segmentsW:6, segmentsH:6, y:sphere_arr[sphere_arr.length-1].y, x:sphere_arr[sphere_arr.length-1].x, z:sphere_arr[sphere_arr.length-1].z-100});
view.scene.addChild(sphere);
sphere_arr.push(sphere);
radiusSphere*=0.75;
}
}

//Light initialization
initLight();
function initLight():void
{
var light:DirectionalLight3D = new DirectionalLight3D({color:0xFFFFFF, ambient:0.75, diffuse:0.85, specular:0.9});
light.x = 4000;
light.z = 4000;
light.y = 4000;
view.scene.addChild( light );
}

//Plane initialization
initPlane();
function initPlane():void
{
var plane:Object3D = new Plane({material:"black",x:0,y:-300,z:0,width:1000,height:1000,segmentsH:2,segmentsW:2});
view.scene.addChild(plane);
}

//Set camera position
view.camera.position = new Number3D(0, 100, 1000);

//Main render method
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void {
if(model.handle.x < 400)
{
model.handle.x += 10;
}else
{
model.handle.x = -400;
}

for(var i:int=0;i<sphere_arr.length;i++)
{
var sphere:Object3D = sphere_arr[i];
var prevSphere:Object3D;

if(i!=0) sphere.rotationY = getTimer() / 100;

if(i<=1)
{
prevSphere = sphere;
sphere.x += (-1*view.mouseX - sphere.x)/speed;
sphere.y += (-1*view.mouseY - sphere.y)/speed;
}
else
{
prevSphere = sphere_arr[i-1];
sphere.x += (prevSphere.x - sphere.x)/speed;
sphere.y += (prevSphere.y - sphere.y)/speed;
}
}

for(i=fire_arr.length-1;i>=0;i--)
{
Object3D(fire_arr[i]).z += 10;

if(fire_arr[i].z >= 600)
{
view.scene.removeChild(fire_arr[i]);
fire_arr.splice(i,1);
}
}

var pos:Number3D = sphere_arr[0].position;
pos.x/=2;
pos.y/=2;
pos.z/=2;
view.camera.lookAt(pos);
view.render();
}

//==========================================================Fire Creation
var fire_arr:Array = [];
var fireTimer:Timer = new Timer(120);
fireTimer.addEventListener(TimerEvent.TIMER,onCreateFire);
addEventListener(MouseEvent.MOUSE_DOWN,startCreatingFire);
addEventListener(MouseEvent.MOUSE_UP,stopCreatingFire);

function startCreatingFire(event:MouseEvent):void
{
fireTimer.start();
}
function stopCreatingFire(event:MouseEvent):void
{
fireTimer.stop();
}

function onCreateFire(event:TimerEvent):void
{
var fire:Object3D = new Plane({material:"Fire",x:sphere_arr[0].x,y:sphere_arr[0].y,z:sphere_arr[0].z,width:50,height:50,segmentsH:1,segmentsW:1});
fire.rotationX = 270;
fire.rotationZ = 180;
fire_arr.push(fire);
view.scene.addChild(fire);
}

Sebenarnya sih mau bikin naga, tapi gak bisa modelling 3D nya :p

Interaksinya sederhana, user bisa menggerakkan kepala naga dan badannya akan mengikuti arah gerakan. Sphere kepala naga bergerak mengikuti koordinat mouse, sedangkan Sphere lainnya (yang ada dibelakang) bergerak mengikuti posisi Sphere yang ada di depannya.
Sebuah model 3D eksternal di load dan digerakkan kekiri secara terus menerus (looping).
Bila user menahan tombol kiri mouse, maka naga akan mengeluarkan api (Object3D Plane dengan material MovieClip).
Bila user menunggu beberapa saat, maka efek normal map akan terlihat pada tubuh naga (ditandai dengan material yang terlihat sedikit timbul dan berkilauan).

Masih banyak implementasi menarik yang bisa dilihat di situs official Away3D (Away3D.com). Bila mau, silahkan oprek-oprek script diatas, dan lanjutkan dengan membaca dokumentasi Away3D (http://away3d.com/livedocs/).

File:

- Away3D.rar (5 Kb)
- DemoSphere.rar (1 Mb)

See u on next tutorial!

4 Comments »

  1. Dowo, lif. Save As ae. :p

    Btw, wajah baru nih, tapi prasaan aku gak pernah liat skin ini.

    Comment by anggayasha — June 6, 2009 @ 5:39 am

  2. Iya, kayaknya kepanjangan karena ada code en widthnya gak terlalu lebar.
    Ini termasuk di theme WordPress kok, cari aja theme yang namanya Black Hat.

    Comment by harsanalif — June 6, 2009 @ 7:42 am

  3. weits Mantap nih, ayo lif bikin tutorial away3d lagi yg based OOP yah kali ini..

    Comment by Fajars — July 9, 2009 @ 2:39 am

    • Sip lah. Nanti nunggu versi berikutnya keluar dl, sekalian kasih liat perbandingan versi FP10 yang jauh lebih gila kecepatannya :D

      Comment by harsanalif — July 10, 2009 @ 3:38 am


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.