转自: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++);//那么相机向后移动
}
}
}