(五):动画模块及骨骼动画
动画模块核心存放在away3d.animators包里; Away3D支持下面几种动画格式: - VertexAnimator:顶点动画
- SkeletonAnimator:骨骼动画
- UVAnimator:UV动画
- SpriteSheetAnimator:二维切换动画
- ParticleAnimator:粒子动画
- PathAnimator:路径动画
这几种动画都有各自的特点及应用场景,一般而在3D游戏中应用得最广泛的是骨骼动画,因为骨骼动画是人物动画的核心,我们下半段会专门详解这个动画;
动画简介 核心类 IAnimator 提供控制动画播放的接口,具体的动画类型对应具体的实现类,如骨骼动画使用SkeletonAnimator类; 将该对象赋值到对应的Mesh的animator属性既可以控制该Mesh对象播放动画; 对于播放的所有动画都应该存放到IAnimationSet对象中; IAnimationSet 提供管理多个动画的容器,多个动画如奔跑或攻击都需要添加到对应的Set容器后才能进行播放; data包 动画所需的数据对象元变化(帧)信息; nodes包 一串变化组成的一个独立动画节点; states包 动画当前状态,从Nodes提取以供当前显示的动画元(帧)信息;
渲染流程 Away3D中的动画渲染是双线更新渲染的,一个更新位于AnimatorBase类的方法update中,负责更新动画数据,一个更新位于MaterialBase类的renderPass方法中,负责渲染绘制; 具体的更新都是更具当前时间来更新对应的State对象,更新具体流程可以具体的打断点查看,这里就不深入解读了。
骨骼动画 骨骼动画在网络上有大量的资料,大家可以去网上搜搜看,这里主要说一下Away3D中是如何处理骨骼动画的数据的; SkeletonJoint 由于多个关节之间是可以相互链接的(父关节变化时会影响到子关节),该对象用来保存关节的链接信息; Skeleton 骨骼对象包含了所有关节的链接信息(SkeletonJoint); JointPose 保存一个关节的信息,包括3个数据:名称、四元数(用于旋转)和转换信息; SkeletonPose 记录一个关键帧下所有的关节的信息(每个关节的位置及旋转数据),包含所有的关节对象(JointPose)列表; SkeletonClipNode 包含了一个骨骼动画的所有关键帧数据(SkeletonPose列表),同时还可以为每个关键帧指定一定的间隔; SkeletonClipState 更新特定时间点的骨骼数据,骨骼动画的插值运算; SkeletonAnimationSet 存放多个骨骼动画(SkeletonClipNode)的容器,使骨骼动画(SkeletonClipNode)和其name属性关联起来,配合SkeletonAnimator的play方法可以指定播放哪个骨骼动画(SkeletonClipNode); SkeletonAnimator 骨骼动画的播放类,可以设定到指定Mesh上,需要指定一个骨骼容器(SkeletonAnimationSet)和对应的骨骼对象(Skeleton);
Away3D物理引擎的简介与使用首先我们要了解的是AwayPhysics这个物理引擎并不是重头开始写的新物理引擎,而是使用Flascc技术把一个已经很成熟的Bullet物理引擎引入到了Flash中,同时为了让as3可以使用这个C++开发的物理引擎,AwayPhysics库编写了一些必要的AS3类使我们可以方便的使用它。
而为了方便区分和使用AwayPhysics里的所有类都使用了AWP作为类名前缀。 创建物理世界 要模拟一个物理世界,首先需要创建一个AWPDynamicsWorld的对象,该对象类似于Away3D中创建3D世界的View3D对象,同时每帧也需要类似View3D对象调用render方法一样调用AWPDynamicsWorld对象的step方法; 创建方法:
1 //获取物理世界 2 _physicsWorld = AWPDynamicsWorld.getInstance(); 3 //初始化, 主要包括初始化重力等 4 _physicsWorld.initWithDbvtBroadphase(); step方法一般使用下面的参数:
1 var _timeStep:Number = 1 / 60;//60表示帧率 2 _physicsWorld.step(_timeStep, 1, _timeStep); 关于该方法的更多信息可以参考这里;
而正常来说应该是先调用step方法模拟了物理世界之后在调用View3D的render方法来渲染3D世界;
该类有添加和移除各种刚体的方法,可以方便的添加需要使用物理引擎模拟的对象;
输出调试图形
如果我们需要查看调试的物件信息(可以查看到添加到物理世界的刚体的坐标系和形状),可以使用AWPDebugDraw类:
复制代码 1 private var _debugDraw:AWPDebugDraw; 2 3 //构造函数中创建 4 _debugDraw = new AWPDebugDraw(_view, _physicsWorld); 5 _debugDraw.debugMode |= AWPDebugDraw.DBG_DrawTransform; 6 7 //帧事件方法中调用绘制 8 _debugDraw.debugDrawWorld(); 复制代码 需要注意的一点是,debugDrawWorld这个方法会严重拉低运行的帧率,当然作为调试工具,我们不需要高效的运行效率,需要调试时别忘了这个类哦。
基础使用简介
我们搭建好了物理世界后就可以向物理世界中添加对象了:
首先,AwayPhysics提供了可以用来进行碰撞检测的多种3D形状,存放在awayphysics.collision.shapes包中,我们可以根据需要创建适合的碰撞形状; 然后,我们需要添加一个刚体(AWPRigidBody),将我们的碰撞形状和3D显示对象进行绑定; 最后,我们可以调整刚体的各种属性(如果调整刚体的坐标旋转等信息会实时同步到该刚体绑定的3D对象中),添加到物理世界中即可,当我们的刚体添加到物理世界后他的格子状态就都由物理引擎来模拟了; 示例代码:
复制代码 1 //创建地面 Mesh 2 var material:ColorMaterial = new ColorMaterial(0x252525); 3 material.lightPicker = lightPicker; 4 var mesh:Mesh = new Mesh(new PlaneGeometry(50000, 50000), material); 5 mesh.mouseEnabled = true; 6 mesh.addEventListener(MouseEvent3D.MOUSE_UP, onMouseUp); 7 _view.scene.addChild(mesh); 8 9 //创建地面形状和刚体 10 var groundShape:AWPStaticPlaneShape = new AWPStaticPlaneShape(new Vector3D(0, 1, 0)); 11 var groundRigidbody:AWPRigidBody = new AWPRigidBody(groundShape, mesh, 0); 12 //添加到物理世界 13 _physicsWorld.addRigidBody(groundRigidbody); 复制代码
碰撞检测
要接收碰撞检测事件需要开启一下标志,这样就可以接收事件了:
1 //开启碰撞侦听, AWPEvent.COLLISION_ADDED 事件被启用 2 _physicsWorld.collisionCallbackOn = true; 碰撞对象:
要使用碰撞检测我们就不用刚体对象(AWPRigidBody)了,要使用碰撞对象(AWPCollisionObject);
同时添加到物理世界时也要使用addCollisionObject方法;
碰撞对象可以添加多个射线,用于射线碰撞检测;
碰撞事件:
碰撞事件都被封装好了,有两个AWPEvent.COLLISION_ADDED和AWPEvent.RAY_CAST:
COLLISION_ADDED:当有另一个碰撞物体和自己发生碰撞时会抛出该事件,注意并没有COLLISION_REMOVED等表示碰撞结束的事件,这是由于每次调用step方法模拟时都会重新运算碰撞,所以如果存在碰撞就会一直抛出该事件。 RAY_CAST:如果添加过射线,那么射线和其它碰撞对象碰撞时也会受到该事件。 游戏应用 我们通过上面的代码可以模拟真实的物理世界,但这是不够的,更多的时候我们需要使用物理引擎来帮助我们实现游戏中的逻辑,而常见的需求是赛车游戏(车辆和地面与其它物体的碰撞)和全3D的RPG游戏(人物和高低不平的地面的碰撞)。 赛车: 由于AwayPhysics已经帮我们封装好了专门用来控制车辆的类,所以创建一个小赛车的游戏是十分简单的,下面说说会使用到的类: 车辆控制类: - AWPCompoundShape:这个类可以添加多个基础的形状来达到组合成一个复杂形状的目的,小车使用该类组合了两个长方体;
- AWPVehicleTuning:这个类用来设置车辆的调节属性;
- AWPRaycastVehicle:将AWPVehicleTuning和小车刚体进行绑定的类,并且最终会调用_physicsWorld.addVehicle方法添加到物理世界中;
- AWPRaycastVehicle.addWheel:该方法可以对指定的轮子对象进行绑定;
- AWPRaycastVehicle.getWheelInfo:该方法可以微调每个轮子的属性;
- AWPRaycastVehicle.applyEngineForce:该方法可以控制指定的轮子的引擎力,即踩油门,设置为负值可以倒车;
- AWPRaycastVehicle.setBrake:该方法可以控制指定的轮子的刹车;
- AWPRaycastVehicle.setSteeringValue:该方法可以控制指定的轮子的转向,即转弯;
地形生成类(直接加载模型作为地形): - AWPBvhTriangleMeshShape:我们将加载好的Mesh的geometry属性赋值到该对象后,就创建了一个和Mesh对象一致的刚体形状,再将该对象添加到刚体中即可作为自定义的地形使用。
地形生成类(使用高度图生成地形): - AWPTerrain:该对象是一个可视对象,是由一个高度位图创建的Mesh对象。
- AWPHeightfieldTerrainShape:将我们的AWPTerrain对象赋值到该对象后,就创建了一个和Mesh对象一致的刚体形状,再将该对象添加到刚体中即可作为自定义的地形使用。
RPG: AwayPhysics提供了一个关于行走的Demo,点击查看源码:Demo 地形生成同上,我们看看不一样的地方: - AWPGhostObject:该类用来连接一个形状对象和一个显示对象;
- AWPKinematicCharacterController:角色控制类,可以设置一个AWPGhostObject对象作为其控制的对象;
- AWPKinematicCharacterController.setWalkDirection:该方法接收一个3D向量作为移动的距离;
- AWPKinematicCharacterController.jump:该方法可以用来进行跳跃;
补充 除了我们谈到的几点外,大家还可以查看示例程序了解更多的使用技巧:
|