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 阅读次数:6984