AppleSeeker's Tech Blog
Welcome to AppleSeeker's space

为了允许游戏可以简单的使用追踪摄像机,我们将添加一个新的属性给MatrixCameraObject类,它可以放置目标对象的一个引用。如果这个属性,命名为ChaseObject,默认值为null,相机将完全像以前那样,仅按照它的位置和LookAtTarget坐标放置它本身。如果提供了游戏对象,然而,相机的行为将改变以便它围绕场景来跟随对象。

当操作视角设置模式时,相机有2个责任它必须实现每一个它的Update方法:它必须放置它本身在目标对象后面,并且它必须直接看到目标对象。让我们看下它是如何实现的。

首先,Update代码检查看下是否提供ChaseObject。如果不是,它申请默认的对象转换,不做任何事返回,如下面代码所示。

base.Update(gameTime);

// Do  we  have a chase object?
if (ChaseObject == null)
{
    // No, so simply  apply  the  identity  matrix
    // Calculate  and apply  the  standard  camera  transformations
    SetIdentity(); 
    ApplyStandardTransformations();
    return;
}

如果提供追踪对象,我们必须首先计算相机的位置。通过在当前相机位置和对象位置间找到距离来实现。最初相机的位置可能靠近对象本身,但是在一对帧中它将放置到它准备去捕捉的后面。

在相机和对象见的距离通过对象位置减去相机位置可以得到。结果值命名为delta,然后提供一个单元长度矢量来标准化。通过在相机中捕捉到的位置来找到矢量来定位相机的位置。

但是如果相机和对象正好在相同位置上?为了处理这个情况,我们总是在类级变量中存储所有最近距离的矢量,_lastChaseCamDelta将重新再使用这个0矢量的情况。Update代码部分可以在下面的代码中看到。

// Find the  vector  between the  current position and the  chase object  position 
delta  = Position - ChaseObject.Position;
// Normalize the  delta  vector delta.Normalize();
// If the  delta  is zero (the  camera  position is already  directly on the  chase
// object, which will happen  if the  object  stops  moving) retain the  last used delta
if (delta == Vector3.Zero)
{
    delta  = _lastChaseCamDelta;
}
else
{
    // Store  the  delta  for later use
    _lastChaseCamDelta = delta;
}

经过在相机和对象间计算方向,目前代码准备去构建相机的转换矩阵。它通过正确的在对象上部转换开始。从这里它一点点将对象转换回以便我们可以从后面看到它。执行这个转换的方向,我们已经计算到delta变量中。我们想要在相机和飞行间保持的距离来缩小这个方向的矢量。

在公共属性中定义了的距离称为ChaseDistance。设置它到正值将在目标对象后面定位相机。然而,它同样能设置负值,它将放到对象前面,回头看对象(通常向后移动)。在某些情况下,相机位置可以是有用的,但并不意味着,如果玩家控制了对象,他不能看到他正在行进的方向。

我们同样对于ChaseDistance也支持一个特殊的值。如果该值设置为0,我们将它当做“第一人称”模式,这意味着我们将直接从对象视角点看到,而不是从肩膀上看。不幸的是,如果我们告诉XNA在相同位置如相机位置去看,它会感到很困惑,因为它部知道该往哪个方向去实际对准相机。要解决这个问题,我们任然从对象位置减去一段很小的距离,通过乘以delta乘以0.01。

我们也允许相机指定高度来提高对象的位置。通常情况下,你将提供小的高度以便相机看上去朝对象轻微的下降。这个高度将被设置到ChaseElevation属性中。

下面代码将描述相机的Update代码段,用来转换相机的位置

// Transform the  camera  position to  position it relative to  the  chase object
SetIdentity();
// Translate  to  the  chase object's position
ApplyTransformation(Matrix.CreateTranslation(ChaseObject.Position));
// Apply the  chase distance. Are we  in first- or  third-person view?
if (ChaseDistance !=  0)
{
    // Third  person view
    // Translate  towards or  away  from the  object  based on the  ChaseDistance
    ApplyTransformation(Matrix.CreateTranslation(delta * ChaseDistance));
    // Apply the  vertical offset
    ApplyTransformation(Matrix.CreateTranslation(0, ChaseElevation,  0));
}
else
{
    // First person view
    // Translate  a tiny distance  back from the  view point
    ApplyTransformation(Matrix.CreateTranslation(delta * 0.01f));
}

现在相机放置到相对由距离和高度定义的对象。最后几个步骤是为了确保相机实际上是看上去朝着对象,然后为下一次更新准备更新相机位置。

为了设置相机所看到的方向,我们简单设置LookAtTarget属性到包含位置的追踪对象中。当相机的Draw方法执行时,它将为它的CreateLookAt矩阵使用该值,确保视角对象依旧在场景中央。

然后相机位置通过简单设置正确的在追踪对象上面来更新。下一次Update函数调用后,假设对象已经移动了,通过和相机位置对比它的新位置,它将再次能够决定对象移动的方向。、

相机的更新代码片段:设置相机的方向和位置

// Ensure that  we  are looking  at  the  chase object
LookAtTarget = ChaseObject.Position;

// Set the  camera  position to  exactly match the  chase object  position
// so that  we  can continue  to  follow it in the  next  update
Position = ChaseObject.Position;
posted on 2012-06-01 11:44  AppleSeeker(冯峰)  阅读(760)  评论(0编辑  收藏  举报