物理碰撞演示,主要演示了两种物体类型之间的碰撞交互,关键技术有碰撞体定义和碰撞回调.
代码片段
碰撞边界划定:
function CollisionToy::createBackground( %this ) { // 精灵创建 %object = new Sprite(); // 静态物体 %object.BodyType = static; // 位置 %object.Position = "0 0"; // 尺寸 %object.Size = "100 75"; // 设置背景层,最远,最先绘制 %object.SceneLayer = 31; // 设置图像资源 %object.Image = "ToyAssets:highlightBackground"; // 设置融合色 %object.BlendColor = SlateGray; // 创建碰撞边界 %object.createEdgeCollisionShape( -50, -37.5, -50, 37.5 ); %object.createEdgeCollisionShape( 50, -37.5, 50, 37.5 ); %object.createEdgeCollisionShape( -50, 37.5, 50, 37.5 ); %object.createEdgeCollisionShape( -50, -34.5, 50, -34.5 ); // 加入场景 SandboxScene.add( %object ); }
障碍物创建:
function CollisionToy::createBlockers( %this ) { // 批量创建障碍物 for( %n = 0; %n < CollisionToy.MaxBlockers; %n++ ) { // 随机尺寸 %sizeX = getRandom(0.5, 10); %sizeY = 10 - %sizeX; // 创建 %object = new Sprite(); %object.BodyType = static; %object.Position = getRandom( -40, 40 ) SPC getRandom( -30, 30 ); %object.Layer = 30; %object.Size = %sizeX SPC %sizeY; // 创建碰撞边界,默认时使用自身的尺寸 %object.createPolygonBoxCollisionShape(); %object.Image = "ToyAssets:Blocks"; %object.Frame = getRandom(0,55); SandboxScene.add( %object ); } }
创建动态碰撞体:
function CollisionToy::createBalls( %this ) { // 批量创建碰撞球 for( %n = 0; %n < CollisionToy.MaxBalls; %n++ ) { // Create the sprite. %object = new Sprite() { // 设置Namespace,碰撞回调时需要确定方法的归属 class = "CollisionToyBall"; }; %object.Position = getRandom(-30,30) SPC getRandom(-30,30); %object.Size = 3; %object.Layer = 20; // 设置碰撞回复系数 %object.setDefaultRestitution( 1 ); // 设置摩擦力系数 %object.setDefaultFriction( 0.1 ); // 创建环形碰撞边界. %object.createCircleCollisionShape( 1.5 ); // 需要碰撞回调 %object.CollisionCallback = true; %object.Image = "ToyAssets:Football"; %object.Frame = 0; // 设置速度 %object.SetLinearVelocity( getRandom(-40,40) SPC getRandom(-30,30) ); %object.SetAngularVelocity( getRandom(-360,360) ); // Add the sprite to the scene. SandboxScene.add( %object ); } }
碰撞通告:
function CollisionToyBall::onCollision(%this, %object, %collisionDetails) { // 没有碰撞点返回(比如一方是传感器) if ( %collisionDetails.count <= 2 ) return; // 获取碰撞点(碰撞点可能是2个,这里忽略) %contactPosition = %collisionDetails._4 SPC %collisionDetails._5; // 创建一个十字动画来标注碰撞点 %object = new Sprite(); //%object.BodyType = static; %object.Position = %contactPosition; %object.Layer = 10; %object.Size = 3; %object.Image = "ToyAssets:Crosshair2"; %object.BlendColor = LimeGreen; %object.AngularVelocity = -180; %object.Lifetime = 3; %object.PickingAllowed = false; SandboxScene.add( %object ); }
回调的实现
在代码中我们没有看到如何设置碰撞回调的,下面需要说明一下:
onCollision的写法是固定的,引擎会寻找这个方法,如果有就会调用,但是它怎么知道是要调用CollisionToyBall的方法呢?
在Ball精灵创建的时候,我们设置了一个属性class,这个class在引擎中是simObject的属性变量mNamespace.
// Namespace Linking. addGroup("Namespace Linking"); addProtectedField("superclass", TypeString, Offset(mSuperClassName, SimObject), &setSuperClass, &defaultProtectedGetFn, &writeSuperclass, "Script SuperClass of object."); addProtectedField("class", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn, &writeClass, "Script Class of object."); endGroup("Namespace Linking");
在碰撞发布的时候:
if ( pSceneObjectA->isMethod("onCollision") ) { // Yes, so perform the script callback on it. Con::executef( pSceneObjectA, 3, "onCollision", pSceneObjectBBuffer, pMiscInfoBuffer ); } bool SimObject::isMethod( const char* methodName ) { if( !methodName || !methodName[0] ) return false; StringTableEntry stname = StringTable->insert( methodName ); if( getNamespace() ) return ( getNamespace()->lookup( stname ) != NULL ); return false; }
因此它能够找到上面CollisionToyBall::onCollision()的回调~
效果图: