2012年03月20日

FlashCS5.5とFlashDevelopでAIRアプリを作るvol.4 Papervision3Dで球状配置

sphere01
↑クリックでサンプル見れます。

Papervision3DでPlaneを球状に配置する方法を試してみました。三角関数使うのかと思ってたけど、Sphereの頂点を取れば簡単に出来る様子。手順としては、まず頂点取得用のSphere(球体)を作って、for文でpositionSphere.geometry.vertices[i].x,y,zを取得すれば良い様です。参考にしたのはコチラ。Papervision3D(PV3D)で plane の球体配置

今回やりたかったのは、
1.枚数不定のPlaneを
2.球状に順不同で配置して、
3.球体ぽくなるようPlaneを傾けて、
4.各PlaneをクリックするとそのPlaneを中央表示するようにカメラが移動する
という動き。

上記のBlogにあるように、Planeの傾きを実装する時にエラーがでます。「配列の一番目のPlaneが消えてしまいました」とありますが、試したところ、球体の底に配置したPlaneが消え、球体の天に配置したPlaneを中央表示するようカメラを移動させると、なぜか全Planeが消えてしまいました。またボタンを仕込んでみると、底のPlaneはなぜか背景に透明で存在しているような、不思議な挙動をしました。カメラが軸上にくると向きがおかしくなるとか、そういう感じのエラーなのかな?と思います。せっかくLookAt関数があるのだから使いたいので、底と天の頂点にはPlaneを配置しない方向でいくことにしました。

ということでソース。そのままコピペしてるだけなのでみっともないです。あしからず。別途マテリアル用のMovieClip(CARDクラス)と、このBGインスタンスを配置するMainクラス、Papervision3DとKTween、配列のシャッフル用にExArray.asが必要です。

package
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.materials.MovieMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.view.BasicView;
import net.kawa.tween.KTween;
import net.kawa.tween.easing.*;
import net.kawa.tween.KTJob;

/**
* ...
* @author sarustar
*/
public class BG extends BasicView
{
private var cardArr:Array = [];
private var cardNum:int = 150;
private var hankei:int = 1500; //円半径
private var positionSphere:Sphere;
private var cameraSphere:Sphere;
private var shufflePositionArr:Array;

public function BG()
{
trace("BG");
super(640, 480, true, true);
camera.fov = 45;
test();
function test()
{
for (var i:int = 0; i < cardNum; i++)
{
var cardMC:MovieClip = new MovieClip();
var crd:CARD = new CARD(cardMC, i);
var cardMaterial:MovieMaterial = new MovieMaterial(cardMC, true, true, true);
cardMaterial.interactive = true;
cardMaterial.doubleSided = true;
var myCard:Plane = new Plane(cardMaterial, 320, 180, 1, 1);
myCard.extra = i;
scene.addChild(myCard);
cardArr.push(myCard);
if (i == cardNum - 1)
{
positionSetting();
startRendering();
}
myCard.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, function(e:InteractiveScene3DEvent) {
trace("CLICK", e.target.extra);
cameraMove(e.target.extra);
});
myCard.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, function(e:InteractiveScene3DEvent) {
trace("OVER", e.target.extra);
});
}
}
}

public function positionSetting()
{
//(n*(n-1))+2
var seg:int = 3;
if (cardNum >= 3)
{
while ((seg * (seg - 1)) + 2 < cardNum+2)
{
trace("seg",seg);
seg++;
}
}
var positionArr:Array = [];
for (var j:int; j < (seg * (seg - 1) + 2)-2; j++)
{
positionArr.push(j+1);
}
shufflePositionArr = ExArray.shuffle(positionArr);
trace("shufflePositionArr : " + shufflePositionArr,"length",shufflePositionArr.length);
positionSphere = new Sphere(null, hankei, seg, seg);
cameraSphere = new Sphere(null, hankei + camera.focus*camera.zoom, seg, seg);
trace("seg", seg, "頂点", positionSphere.geometry.vertices.length);
for (var i:int = 0; i < cardNum; i++)
{
cardArr[i].x = positionSphere.geometry.vertices[shufflePositionArr[i]].x;
cardArr[i].y = positionSphere.geometry.vertices[shufflePositionArr[i]].y;
cardArr[i].z = positionSphere.geometry.vertices[shufflePositionArr[i]].z;
(cardArr[i] as Plane).lookAt(DisplayObject3D.ZERO);
}
}
public function cameraMove(targetID:int) {
trace("cameraMove.targetID", targetID);
var targetX:int = cameraSphere.geometry.vertices[shufflePositionArr[targetID]].x;
var targetY:int = cameraSphere.geometry.vertices[shufflePositionArr[targetID]].y;
var targetZ:int = cameraSphere.geometry.vertices[shufflePositionArr[targetID]].z;
var cameraTweenJob:KTJob = KTween.to(camera, 2, { x:targetX, y:targetY, z:targetZ }, Quad.easeOut);
}
}
}

32行目、42行目で、Planeのクリックを有効にしています。
43行目で、Planeの裏面を表示できるようにします。
34行目から61行目までで、配置用のPlaneを作って配列に収めています。その際extraにID番号を格納します。
68行目から75行目で、カードの増減に対応しています。
77行目から80行目で、天、底の頂点を除外しています。
83行目、SphereのW,Hの分割数は、計算をシンプルにするためsegで統一しました。頂点の数は、(seg*(seg-1))+2で算出できます。
84行目、カメラの位置決め用に、一回り大きいSphereを作成しました。Plane配置用の球体の半径+(camera.focus*camera.zoom)で、カメラを常に原点(Sphereの中心)に向けておけば、Planeを等倍表示できます。
91行目、lookAtです。

自作アプリに使おうと思ってここまでやってみたのですが、動き見てみたらあまり今回のアプリ向きじゃなかったので^^;これ以上は作らないかなーと思います。もしさらにやるなら、カードの枚数によって球体の半径を変えるように出来たら良いかなと。もしくは重ならないように各Planeのサイズ変えるか…メンドクサソウダナー

sarustar at 15:38│Comments(0)TrackBack(0)このエントリーをはてなブックマークに追加 mixiチェック Clip to Evernote ActionScript3 




トラックバックURL

>

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔