嵌套
嵌套就是指将一个对象嵌入另一个容器对象中,当我们移动容器对象的时候,嵌入的对象也跟着容器对象移动。确切的说,嵌套就是将对象打包在一起形成一个整体,通过控制容器对象来整体移动。
当使用PV3D实现太阳系运行效果时,嵌套能很好的解决他们之间旋转、旋转速度的问题。下面我们以Sun、Earth、Moon的运行讲解嵌套。
第一步,在场景中创建一个大小为60的Sun对象sun,它被加载进场景的(0,0,0)。
第二步,创建一个大小为20的Earth对象earth,很自然,我们也将它加载进场景,并设置位置为600。
(1) 使用rotationY(按照其父容器的Y旋转,即场景Y轴)让earth旋转。但是Earth并没有绕着场景原点旋转,而是像自转一样。
(2) 使用localRotationY(按照其自身Y轴旋转)让earth旋转。Earth也没有绕着场景原点旋转,而是自转(方向和rotationY相反)。
PV3D提供给我们的2种旋转都不能解决地球绕场景原点旋转。在这里需要注意的是:虽然rotation和localRotation旋转坐标系统不同,但是它们都是在其中点,依据坐标系统旋转的。因此我们只能看到earth绕自身旋转。
第三步,将earth加载进sun,而不是场景。此时sun和earth嵌套成一个整体,让容器对象sun进行rotation旋转,可以看到容器对象中的所有嵌入的对象都跟着旋转。下图虚线表示sun和earth嵌套成一个整体。
我们了解的太阳系是以太阳为参照的,因此太阳相对太阳系的其他行星是静止的。为了解决这个问题,可以使用容器类DisplayObject3D。
第四步,创建一个DisplayObject3D对象earthContainer,将其放入场景。然后将earth对象加载进earthContainer,并在刷屏方法中让earthContainer对象进行rotationY旋转。此时earthContainer和earth嵌套为一个整体,容器对象(earthContainer)旋转带动earth旋转,这样earth就能绕着场景原点旋转了。
现在要解决的是如何让月球绕地球旋转。在这里需要注意的是月球有2种运行:
Ø 一种是绕太阳(场景原点)旋转
Ø 一种是绕地球旋转
一种简单的解决方法是:将创建的Moon对象moon加载进earth中,并在刷屏方法中让earth自转(localRotation)。这样earth带动moon旋转,且earthContainer带动moon绕太阳旋转。
这种方法简单,但是月球绕地球旋转的速度和地球自转一样,因为月球的旋转是由地球自转带动的。为了跟好的模拟太阳系运行效果,我们可以设置一个DisplayObject3D容器在earth的中心,让容器带动moon的旋转。
第五步,创建一个容器moonContainer,并将其加载进earthContainer容器中(earthContainer绕场景原点旋转),设置moonContainer的位置和earth一样。此时将moon加载进moonContainer中。并在刷屏方法中设置moonContainer的旋转速度。
下面在FlashDevelop中运行的代码:
package
{
import flash.events.Event;
import mx.core.BitmapAsset;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Cylinder;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.view.BasicView;
/**
* ...
* @author yl
*/
[SWF(width = "800", height = "600", backgroundColor = "0x000000")]
public class SunSys extends BasicView
{
private var sun:Sphere;
private var earth:Sphere;
private var moon:Sphere;
private var earthContain:DisplayObject3D;
private var water:Sphere;
private var waterContain:DisplayObject3D;
private var moonContain:DisplayObject3D;
[Embed(source = "../assets/earth.jpg")] private var Earth:Class;
[Embed(source = "../assets/moon.jpg")] private var Moon:Class;
[Embed(source = "../assets/sun.jpg")] private var Sun:Class;
[Embed(source = "../assets/water.jpg")] private var Water:Class;
public function SunSys()
{
earthContain = new DisplayObject3D();
waterContain = new DisplayObject3D();
moonContain = new DisplayObject3D();
scene.addChild(waterContain);
scene.addChild(moonContain);
scene.addChild(earthContain);
var sunAsset:BitmapAsset = new Sun() as BitmapAsset;
var sunMaterial:BitmapMaterial = new BitmapMaterial(sunAsset.bitmapData);
sun = new Sphere(sunMaterial, 60, 20, 20);
scene.addChild(sun);
var waterAsset:BitmapAsset = new Water() as BitmapAsset;
var waterMaterial:BitmapMaterial = new BitmapMaterial(waterAsset.bitmapData);
water = new Sphere(waterMaterial, 15, 20, 20);
water.x = 200;
waterContain.addChild(water);
var earthAsset:BitmapAsset = new Earth() as BitmapAsset;
var earthMaterial:BitmapMaterial = new BitmapMaterial(earthAsset.bitmapData);
earth = new Sphere(earthMaterial, 20, 20, 20);
earth.x = 600;
earthContain.addChild(earth);
moonContain.position = earth.position;
earthContain.addChild(moonContain);
var moonAsset:BitmapAsset = new Moon() as BitmapAsset;
var moonMaterial:BitmapMaterial = new BitmapMaterial(moonAsset.bitmapData);
moon = new Sphere(moonMaterial, 10, 20, 20);
moon.x = 100;
moonContain.addChild(moon);
camera.y = 1000;
camera.z = -1000;
startRendering();
}
override protected function onRenderTick(e:Event = null):void {
super.onRenderTick();
earthContain.rotationY++;
earth.localRotationY += 30;
moonContain.rotationY += 5;
waterContain.rotationY += 3;
}
}
}