9.相机控制类
上一个教程实现了相机类,而相机的控制是在Controller命名空间下的FpsCameraController类和FreeCameraController类实现的。
FpsCameraController类的代码如下,具体解释可参见2.3 创建一个第一人称射击游戏(FPS)的相机:Quake风格的相机。主要原理就是在这个类中改变camera.pose.Rotation和camera.pose.Position,而在CameraSceneNode类中根据这两个变量创建视矩阵。
namespace StunEngine.Controllers
{
/// <summary>
/// 控制一个相机对象。
/// 使用鼠标控制相机上下左右旋转,键盘控制前进后退左右平移。
/// 相机不能翻滚,只在水平面xz上移动。
/// </summary>
public class FpsCameraController : Controller
{
构造函数和成员变量
![]()
/// <summary>
/// 获取或设置相机允许俯仰的最大角度。
/// </summary>
public float Elevation
{
get { return elevation; }
set { elevation = value; }
}
![]()
/// <summary>
/// 主控制逻辑
/// </summary>
/// <param name="gameTime"></param>
public override void ControllerAction(GameTime gameTime)
{
if (camera == null)
{
camera = (CameraSceneNode)controlledNode;
//将鼠标初始位置设置为屏幕中央
//将鼠标初始位置设置为屏幕中央
Mouse.SetPosition(engine.GraphicsDevice.Viewport.Width / 2, engine.GraphicsDevice.Viewport.Height / 2);
originalMouseState = Mouse.GetState();
}
float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
ProcessInput(timeDifference);
}
![]()
private void ProcessInput(float ellapsedTime)
{
//相机的上下旋转
float cameraPitch = 0;
//相机的左右旋转
float cameraYaw = 0;
//前进后退
float movement = 0;
//左右平移
float stride = 0;
//相机每帧旋转和移动距离
float rotationPerFrame = ellapsedTime * camera.RotationSpeed;
float movementPerFrame = ellapsedTime * camera.MovementSpeed;
![]()
if (engine.IsActive)
{
//获取鼠标的当前状态
MouseState currentMouseState = Mouse.GetState();
![]()
//如果鼠标发生移动,则通过鼠标控制相机的俯仰和左右旋转
if (currentMouseState != originalMouseState)
{
//获取鼠标在水平和竖直方向的移动大小
float xDifference = currentMouseState.X - originalMouseState.X;
float yDifference = currentMouseState.Y - originalMouseState.Y;
![]()
//水平方向的移动控制相机的左右旋转
cameraYaw += rotationPerFrame * xDifference;
//竖直方向的移动控制相机的上下旋转
cameraPitch -= rotationPerFrame * yDifference;
![]()
//将光标重新设置到屏幕的中央
Mouse.SetPosition(originalMouseState.X, originalMouseState.Y);
}
}
![]()
//键盘控制相机的前后左右移动
if (Input.KeyboardUpPressed|| Input.Keyboard .IsKeyDown (Keys.W))
movement += movementPerFrame;
if (Input.KeyboardDownPressed|| Input.Keyboard .IsKeyDown(Keys.S))
movement -= movementPerFrame;
if (Input.KeyboardRightPressed|| Input.Keyboard.IsKeyDown(Keys.D))
stride += movementPerFrame;
if (Input.KeyboardLeftPressed || Input.Keyboard.IsKeyDown(Keys.A))
stride -= movementPerFrame;
![]()
//如果相机旋转或移动
if (cameraYaw != 0 || cameraPitch != 0 || movement != 0 || stride != 0)
{
//-------------------------
// 当相机旋转时
//-------------------------
if (cameraYaw != 0 || cameraPitch != 0)
{
//isDirty设为true表示需要更新相机
isDirty = true;
![]()
//将相机的俯仰限制在elevation范围之内
if (Math.Abs(cameraPitch + camera.AngleRotation.X) > elevation)
cameraPitch = Math.Sign(cameraPitch) * (elevation - Math.Abs(camera.AngleRotation.X));
![]()
//基于cameraPitch, cameraYaw设置相机的旋转。
if (cameraYaw != 0 || cameraPitch != 0)
{
Vector3 angleRotation = new Vector3(cameraPitch, cameraYaw, 0);
camera.AngleRotation += angleRotation;
camera.pose.Rotation = Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(-camera.AngleRotation.Y), MathHelper.ToRadians(camera.AngleRotation.X), 0);
}
}
![]()
//--------------------
// 当相机前后移动时
//--------------------
if (movement != 0)
{
//isDirty设为true表示需要更新相机
isDirty = true;
![]()
//计算前进后退的矢量
Vector3 forwardMove = camera.GetMoveForwardVector(movement);
camera.pose.Position += forwardMove;
}
![]()
//--------------------
// 当相机左右移动时
//--------------------
if (stride != 0)
{
//isDirty设为true表示需要更新相机
isDirty = true;
![]()
//计算左右平移的矢量
Vector3 strideMove = CameraSceneNode.GetMoveVector(Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(-camera.AngleRotation.Y)), Vector3.Right, stride*0.5f);
camera.Pose.Position += strideMove;
}
![]()
//更新相机
if (isDirty)
{
camera.UpdateViewMatrix(false);
isDirty = false;
}
}
}
}
}
FreeCameraController类的代码如下,具体解释可参见2.4 创建一个Freelancer风格的相机:使用四元数的3D旋转。大部分代码与FpsCameraController相同,不同之处在于键盘的左右键控制相机的左右旋转而不是左右平移,按照鼠标左键不放也可以控制相机的上下左右旋转,按Q和E键还可以绕Z轴滚动。
namespace StunEngine.Controllers
{
/// <summary>
/// 自由相机的控制器。
/// </summary>
public class FreeCameraController : Controller
{
构造函数和成员变量
![]()
/// <summary>
/// 主控制逻辑。
/// </summary>
/// <param name="gameTime"></param>
public override void ControllerAction(GameTime gameTime)
{
if (camera == null)
{
camera = (CameraSceneNode)controlledNode;
//将鼠标初始位置设置为屏幕中央
Mouse.SetPosition(engine.GraphicsDevice.Viewport.Width / 2, engine.GraphicsDevice.Viewport.Height / 2);
originalMouseState = Mouse.GetState();
}
![]()
float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
ProcessInput(timeDifference);
}
![]()
private void ProcessInput(float ellapsedTime)
{
//相机是否旋转
bool isRotation = false;
//相机的滚动
float cameraRoll = 0;
//相机的俯仰
float cameraPitch = 0;
//相机的左右旋转
float cameraYaw = 0;
//相机的移动
float movement = 0;
![]()
////相机每帧旋转和移动距离
float rotationPerFrame= ellapsedTime *camera.RotationSpeed ;
float movementPerFrame = ellapsedTime * camera.MovementSpeed;
![]()
if (engine.IsActive)
{
MouseState currentMouseState = Mouse.GetState();
//如果按住鼠标左键并且鼠标发生移动
if (Input.MouseLeftButtonPressed && currentMouseState != originalMouseState)
{
//获取鼠标在水平和竖直方向的移动大小
float xDifference = currentMouseState.X - originalMouseState.X;
float yDifference = currentMouseState.Y - originalMouseState.Y;
![]()
//水平方向的移动控制相机的左右旋转
cameraYaw += rotationPerFrame * xDifference;
//竖直方向的移动控制相机的上下旋转
cameraPitch -= rotationPerFrame * yDifference;
![]()
//将光标重新设置到屏幕的中央
Mouse.SetPosition(originalMouseState.X, originalMouseState.Y);
}
}
![]()
//键盘控制相机的前后左右移动和翻滚
if (Input.KeyboardUpPressed || Input.Keyboard.IsKeyDown(Keys.W))
movement += movementPerFrame;
if (Input.KeyboardDownPressed || Input.Keyboard.IsKeyDown(Keys.S))
movement -= movementPerFrame;
if (Input.KeyboardRightPressed || Input.Keyboard.IsKeyDown(Keys.D))
cameraYaw += rotationPerFrame;
if (Input.KeyboardLeftPressed || Input.Keyboard.IsKeyDown(Keys.A))
cameraYaw -= rotationPerFrame;
if (Input.Keyboard.IsKeyDown(Keys.Q))
cameraRoll -= rotationPerFrame;
if (Input.Keyboard.IsKeyDown(Keys.E))
cameraRoll += rotationPerFrame;
![]()
//如果相机旋转
if (cameraRoll != 0 || cameraPitch != 0 || cameraYaw != 0)
{
Vector3 angleRotation = new Vector3(cameraPitch, cameraYaw, cameraRoll );
camera.AngleRotation += angleRotation;
//设置相机的旋转
camera.pose.Rotation = Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(-camera.AngleRotation.Y), MathHelper.ToRadians(camera.AngleRotation.X), MathHelper.ToRadians(camera.AngleRotation.Z));
![]()
//isDirty设为true表示需要更新相机
isDirty = true;
isRotation = true;
}
![]()
//如果相机移动
if (movement != 0)
{
//isDirty设为true表示需要更新相机
isDirty = true;
![]()
//设置相机的位置
camera .pose .Position +=camera.GetMoveForwardVector(movement);
}
![]()
if (isDirty)
{
camera.UpdateViewMatrix(false );
isDirty = false;
}
}
}
}
发布时间:2010/1/14 下午3:33:38 阅读次数:7177