物理碰撞演示,主要演示了两种物体类型之间的碰撞交互,关键技术有碰撞体定义和碰撞回调.
代码片段
碰撞边界划定:
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()的回调~
效果图: