【转】PV3D的小练习~太阳系八大行星

时间:2021-09-20 15:02:27

转自:http://hi.baidu.com/boycy/item/70d1ba53bc8c3a958c12eddf

http://www.cnblogs.com/flash3d/archive/2012/01/30/2331902.html

PV3D的小练习~太阳系八大行星

动画地址:http://hong-ming.cn/flash/8star.swf

有2M多,下载可能有点慢~多等等吧O(∩_∩)O~~

不知道为什么,在这里拖动舞台好像有点问题,直接点击下面的链接可以查看完整的功能

点击右边的几个按钮 可以跟踪查看所选的物体 然后点击左边的*查看按钮后可以鼠标拖动屏幕同时按方向键和CS感觉类似~其他就不多说了,玩玩就知道!

以下是这个动画的源代码 以后还会对注释进行加精,有问题欢迎留言!(今天实在是太困了=_=)

stop();//进入有代码的帧一般习惯停止下,以防止动画循环导致代码重复运行

stage.scaleMode=StageScaleMode.SHOW_ALL;//舞台的显示模式设置为全部显示不扭曲

import org.papervision3d.lights.PointLight3D;

importorg.papervision3d.materials.shadematerials.FlatShadeMaterial;

import org.papervision3d.objects.DisplayObject3D;

import org.papervision3d.objects.primitives.Sphere;

import org.papervision3d.view.Viewport3D;

import org.papervision3d.render.BasicRenderEngine;

import org.papervision3d.scenes.Scene3D;

import org.papervision3d.materials.utils.MaterialsList;

import org.papervision3d.cameras.Camera3D;

importorg.papervision3d.materials.BitmapMaterial;//以上是导入PV3D的相关类

var sunM:sunP=new sunP(100,100);

var MercuryM:MercuryP=new MercuryP(100,100);

var VenusM:VenusP=new VenusP(100,100);

var earthM:earthP=new earthP(100,100);

var MarsM:MarsP=new MarsP(100,100);

var JupiterM:JupiterP=new JupiterP(100,100);

var SaturnM:SaturnP=new SaturnP(100,100);

var UranusM:UranusP=new UranusP(100,100);

var NeptuneM:NeptuneP=newNeptuneP(100,100);//以上的sunM等等都是事先导入到库里面的位图,然后现在我们把它链接出来后进行实例化,以便我们在代码中能够使用这些位图,这里的位图数据做模型的贴图用

var size:Number=0.01;//这个是全局的大小参数,和实际数据是乘除关系,控制星球的半径(太阳除外)

var speed:Number=365;//这个是速度参数,也是乘除关系

var distance:Number=1000;//这个是星球间的距离参数,乘除关系,同时也控制着太阳的半径

var look:int=-1;//应该是个索引参数,0代表第一个行星的索引,1代表第二个……

var ifplay:Boolean=true;//播放的时候值设为true,暂停的时候反之

var iffree:Boolean=false;//*查看状态的时候值为true,否则反之

var star:Array=new Array();

var sun:Array=new Array();

sun.push({R:0.05,T:365,map:sunM});//把太阳的参数保存在数组里,R是半径,T是自转周期,map是贴图

star.push({R:0.38,T:87.70,a:7.0,r:2440,t:58.65,map:MercuryM,con:null,ball:null});

star.push({R:0.72,T:224.701,a:3.4,r:6051.8,t:-243.02,map:VenusM,con:null,ball:null});

star.push({R:1.00,T:365.2422,a:7.25,r:6378.15,t:1,map:earthM,con:null,ball:null});

star.push({R:1.52,T:686.98,a:1.8,r:3398,t:1.026,map:MarsM,con:null,ball:null});

star.push({R:5.20,T:4332.589,a:0,r:71492,t:0.41,map:JupiterM,con:null,ball:null});

star.push({R:9.54,T:10759.5,a:2.5,r:60268,t:0.426,map:SaturnM,con:null,ball:null});

star.push({R:19.23,T:30799,a:0.772,r:25559,t:0.646,map:UranusM,con:null,ball:null});

star.push({R:30.06,T:60152,a:1.769,r:24766,t:0.917,map:NeptuneM,con:null,ball:null});//以上是各星球的参数,R轨道半径,T公转周期,a轨道倾角,r星球半径,t自转周期,map贴图,con星球的容器对象,ball星球对象,另外关于AS3中数组的用法请参考帮助文档

var viewport:Viewport3D;//定义视窗

var scene:Scene3D;//定义3D场景

var camera:Camera3D;//定义摄像机

var renderer:BasicRenderEngine;//定义渲染引起,以上四个是建立一个基本的3D场景的四要素

viewport=new Viewport3D(1024,768);//用Viewport3D的构造函数建立一个1024*768大小的视窗

scene=new Scene3D();//构造一个3D场景

camera=newCamera3D();//构造一个摄像机,这里说明一下,为什么四要素要定义还要构造呢,定义可以理解为是开辟一块适合的空间用于构造,构造才是往这个空间里填充实质性的东西

renderer= new BasicRenderEngine();//构造一个渲染引擎

camera.z=-150;//将摄像机位置的Z坐标设为-150,在PV3D里面默认视角下,水平右方向是X正方向,竖直向上是Y正方向,垂直向里是Z正方向

stage.addChild(viewport);//这个工作是必须的,PV3D的内容全部在视窗里显示,所以要想看到PV3D的内容前提是必须可以看到视窗,所以必须把视窗添加到舞台的显示列表,显示列表的概念可以参考帮助文档

var sunS:Sphere;//定义一个球形物体,这个物体是用来当做太阳的

var sunMaterial:BitmapMaterial;//定义一个贴图,用来做太阳的贴图

sunMaterial=newBitmapMaterial(sun[0].map);//构造太阳的贴图,贴图的构造函数的参数是个BitmapData类型,这里的sun[0].map就是从我们库里面链接出来并创建的位图

sunS=newSphere(sunMaterial,sun[0].R*distance,15,15);//在这里解释下球体的构造函数参数,第一个是贴图数据类型,也就是上面刚刚构建的那个,第二个参数是半径,第三第四个分别是水平和竖直方向的段数,段数越高球体越圆越精细,当然对CPU的要求也就越高

scene.addChild(sunS);//把太阳球体添加到3D场景里面

for (var n:int=0; n<8; n++) {//这里用一个八次的循环一次性创建八个行星

star[n].con=newDisplayObject3D();//这里创建一个当做容器用的DisplayObject3D类,这个类,我们可以把它理解成是物质,球体摄像机包括还有正方体等等都是物质,所以DisplayObject3D类就是他们的父类,他们有共同的旋转,移动等等方法,这里为什么会要当做容器,主要是后面的公转方便

star[n].ball=new Sphere(newBitmapMaterial(star[n].map),star[0].r*size,15,15);//这里创建球体的方法和创建太阳一样,根据数组的索引我们可以访问每组星球的参数,从而可以用循环创建不同的球体

star[n].con.addChild(star[n].ball);//这里把球体加入到容器里面

star[n].ball.z=-star[n].R*distance;//然后球体相对于容器的Z坐标设置成公转轨道的半径

star[n].con.rotationX+=star[n].a;//对容器绕着X旋转一个倾角(轨道倾角)

star[n].con.rotationY+=Math.random()*360;//对容器绕着Y旋转一个随机角度,因为查了很多资料都不知道现在星球的初始状态,索性给它随机初始化^_^

scene.addChild(star[n].con);//把容易添加到场景(这个时候球体在容易里面,就好比是影片剪辑的嵌套原理一样,应该可以理解吧)

}

addEventListener(Event.ENTER_FRAME,process);//当进入帧的事件下发生函数process,实际上只要影片播放,Event.ENTER_FRAME这个事件就会被不断触发,于是process函数就会被不断反复执行,这个也是为什么画面可以动起来的原因了

function process(evt:Event):void {

if (ifplay) {//在播放情况下执行下面代码

  sunS.rotationY-=speed/sun[0].T;//太阳自转

   for (n=0; n<8; n++){//用循环对八个行星进行批量操作

   star[n].con.localRotationY+=speed/star[n].T;//容易自转,其实就是行星的公转

   star[n].ball.localRotationY+=speed/star[n].t;//行星自转

   }

   if (!iffree){//在非*查看的情况下执行下面的代码(跟踪查看)

    if(look>=0) {

    camera.lookAt(star[look].ball);//根据索引选择跟踪查看的对象

    } else{

    camera.lookAt(sunS);//跟踪查看太阳

    }

   }

}

renderer.renderScene(scene,camera,viewport);//不断进行渲染,要是不渲染画面就停住了(类似于刷新)

}

bs.addEventListener(MouseEvent.CLICK,bsg);//点击太阳按钮,进行相应的设置

function bsg(event:MouseEvent):void {

camera.z=-150;

camera.x=0;

camera.y=0;//以上是摄像机坐标设置,把相机挪到一个合适的视角

speed=365;//对全局速度进行设置

look=-1;//跟踪视角的索引,表示跟踪太阳

iffree=false;//设置为非*视角

txt.text="太陽是距離地球最近的恆星,是太陽系的中心天體。太陽系質量的99.87%都集中在太陽。太陽系中的八大行星、小行星、流星、彗星、外海王星天體以及星際塵埃等,都圍繞著太陽運行(公轉)。";//下面显示的文字内容

}

b0.addEventListener(MouseEvent.CLICK,b0g);//下面的设置和太阳差不多,目的就是调节相机的位置和运行速度之类的

function b0g(event:MouseEvent):void {

camera.z=-500;

camera.x=0;

camera.y=0;

speed=365;

look=0;

iffree=false;

txt.text="水星最接近太陽,是太陽系中最小最輕的行星。水星在直徑上小於木衛三和土衛六。";

}

b1.addEventListener(MouseEvent.CLICK,b1g);

function b1g(event:MouseEvent):void {

camera.z=-800;

camera.x=0;

camera.y=0;

speed=365;

look=1;

iffree=false;

txt.text="八大行星之一,中國古代稱之為太白或太白金星。它有時是晨星,黎明前出現在東方天空,被稱為“啟明”;有時是昏星,黃昏後出現在西方天空,被稱為“長庚”。金星是全天中除太陽和月亮外最亮的星,猶如一顆耀眼的鑽石,於是古希臘人稱它為阿佛洛狄忒--愛與美的女神,而羅馬人則稱它為維納斯--美神。";

}

b2.addEventListener(MouseEvent.CLICK,b2g);

function b2g(event:MouseEvent):void {

camera.z=-1050;

camera.x=0;

camera.y=0;

speed=365;

look=2;

iffree=false;

txt.text="地球是距太陽第三顆,也是第五大行星";

}

b3.addEventListener(MouseEvent.CLICK,b3g);

function b3g(event:MouseEvent):void {

camera.z=-1600;

camera.x=0;

camera.y=0;

speed=365;

look=3;

iffree=false;

txt.text="火星為距太陽第四遠,也是太陽系中第七大行星";

}

b4.addEventListener(MouseEvent.CLICK,b4g);

function b4g(event:MouseEvent):void {

camera.z=-5300;

camera.x=0;

camera.y=0;

speed=3650;

look=4;

iffree=false;

txt.text="木星是離太陽第五顆行星,而且是最大的一顆,比所有其他的行星的合質量大2倍(地球的318倍)。被稱為“行星之王”。";

}

b5.addEventListener(MouseEvent.CLICK,b5g);

function b5g(event:MouseEvent):void {

camera.z=-9700;

camera.x=0;

camera.y=0;

speed=14600;

look=5;

iffree=false;

txt.text="土星是離太陽第六遠的行星,也是八大行星中第二大的行星";

}

b6.addEventListener(MouseEvent.CLICK,b6g);

function b6g(event:MouseEvent):void {

camera.z=-19280;

camera.x=0;

camera.y=0;

speed=29200;

look=6;

iffree=false;

txt.text="天王星是太陽系中離太陽第七遠行星,從直徑來看,是太陽系中第三大行星。天王星的體積比海王星大,質量卻比其小。";

}

b7.addEventListener(MouseEvent.CLICK,b7g);

function b7g(event:MouseEvent):void {

camera.z=-30100;

camera.x=0;

camera.y=0;

speed=58400;

look=7;

iffree=false;

txt.text="海王星是環繞太陽運行的第八顆行星,也是太陽系中第四大天體(直徑上)。海王星在直徑上小於天王星,但質量比它大。";

}

st.addEventListener(MouseEvent.CLICK,stg);//点击播放按钮

function stg(event:MouseEvent):void {//播放参数为真

ifplay=true;

}

pu.addEventListener(MouseEvent.CLICK,pug);//暂停

function pug(event:MouseEvent):void {

ifplay=false;

}

editor.addEventListener(MouseEvent.CLICK,editorg);//显示作者按钮

function editorg(event:MouseEvent):void {

txt.text="陳鋆";

}

seefree.addEventListener(MouseEvent.CLICK,seefreeg);//点击*视角按钮,进入*查看模式

function seefreeg(event:MouseEvent):void {

iffree=true;//*查看设为真

txt.text="*視角操作提示:按方向上下鍵可以前進後退,鼠標按住再移動可以改變視角";

}

stage.addEventListener(MouseEvent.MOUSE_DOWN,MouseDown);//在舞台上按下鼠标的时候发生MouseDown函数

stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMove);//鼠标在舞台上移动发生MouseMove函数

stage.addEventListener(MouseEvent.MOUSE_UP,MouseUp);//鼠标在舞台上放开发生函数MouseUp

var roll:Boolean=false;//是否处于拖动状态的参数

var previousMouseX:Number=0;

var previousMouseY:Number=0;//临时储存鼠标的上一个位置

function MouseDown(event:MouseEvent):void {//按下鼠标的时候

if (iffree) {//当然要在*查看的状态下

   roll = true;//拖动被允许

   previousMouseX =event.stageX;

   previousMouseY =event.stageY;//获取按下鼠标的位置

}

}

function MouseUp(event:MouseEvent):void {//当鼠标放开的时候

if (iffree) {

   roll = false;//拖动被禁止

}

}

function MouseMove(event:MouseEvent):void {//当移动鼠标的时候

if (iffree) {//在*查看的状态下

   var differenceX:Number =event.stageX - previousMouseX;

   var differenceY:Number =event.stageY - previousMouseY;//鼠标新位置和上一时刻的位置的差值,其实就是鼠标坐标的增量

   if (roll) {//在可拖动的状态下

   camera.rotationY+=differenceX;

   camera.rotationX+=differenceY;//镜头往鼠标移动的方向移动

   previousMouseX = event.stageX;

   previousMouseY = event.stageY;//临时储存新的鼠标位置

   }

}

}

stage.addEventListener(KeyboardEvent.KEY_DOWN,keydown);//键盘有按键按下的情况发生keydown

stage.addEventListener(KeyboardEvent.KEY_UP,keyup);//键盘有按键放开的情况下发生keyup

stage.addEventListener(Event.ENTER_FRAME,go);//这个事件是上面讲过的连续发生事件,这里再连续发生go

var movt:Boolean=false;//向前移动参数

var movb:Boolean=false;//向后移动参数

var s:Number=0;

function keydown(event:KeyboardEvent):void {//有键盘按键按下

if (iffree) {//在*查看的情况下

   if (event.keyCode==38){//如果按下去的键的键控代码值为38,也即是按下方向键的向上

   movt=true;//那么向前移动被允许

   movb=false;//向后移动被禁止

   } else if (event.keyCode==40){//如果按下方向键向后

   movt=false;//向前移动被禁止

   movb=true;//向后移动被允许

   }

}

}

function keyup(event:KeyboardEvent):void {//按键被松开

if (iffree) {//在*查看的前提下

   movt=false;

   movb=false;//先前向后均被禁止

   s=0;

}

}

function go(event:Event):void {//这个事件是被不断触发的

if (iffree) {//在*查看的前提下

   if (movt) {//如果先前移动被允许

   camera.moveForward(s++);//那么相机就向前移动

   } else if (movb){//否则如果向后移动被允许

   camera.moveBackward(s++);//那么相机向后移动

   }

}

}