zoukankan      html  css  js  c++  java
  • 输入和用户界面——SpaceCamera类

    SpaceCamera类

    SpaceCamera类比SimpleCamera类复杂得多,赛车游戏的ChaseCamera看起来倒简单点。主要的原因这是我写的第一个空间相机类,其中使用到的四元数的数学知识并不那么容易。该相机支持三种模式:菜单画面的相机,游戏中的相机,单元测试中的自由相机。Rocket Command游戏的SpaceCamera有点简单,因为四元数被删除了,只允许俯仰和偏航火箭,而火箭绕Z轴旋转被引擎自动处理,这使得飞行起来容易些,不容易迷失方向。这个变化的主要原因是为了使用Xbox 360手柄也能很好地控制火箭,难度比初版Rocket Commander大。

    快速浏览一下SpaceCamera中的重要方法,它们处理所有输入并更新相机位置:

    /// <summary>
    /// Handle player input for the game.
    /// This is where all the input happens in the game.
    /// </summary>
    private void HandlePlayerInput()
    {
      if (Player.lifeTimeMs < Player.LifeTimeZoomAndAccelerateMs)
      {
        float speedPercentage =
          Player.lifeTimeMs / (float)Player.LifeTimeZoomAndAccelerateMs;
        // Use quadradric product for better speed up effect
        Player.SetStartingSpeed(speedPercentage * speedPercentage);
    
        // Always move forward
        Translate(Player.Speed * BaseGame.MoveFactorPerSecond *
          Player.MovementSpeedPerSecond, MoveDirections.Z);
        if (Player.gameTimeMs < 100)
        {
          yawRotation = 0;
          pitchRotation = 0;
          pos = Vector3.Zero;
        } // if
      } // if

    前面的代码增加火箭速度,如果游戏刚刚开始,同时也重置旋转角度和位置。接下来,您检查游戏是否结束和处理特殊情况使之能移动。然后处理鼠标和键盘输入。这些是我初次实现SpaceCamera类的原始代码,更多代码在以后添加以支持更多的输入设备:

    #region Mouse/keyboard support
    if (Input.MouseXMovement != 0.0f ||
      Input.MouseYMovement != 0.0f)
    {
      float xMovement = Input.MouseXMovement;
      float yMovement = Input.MouseYMovement;
      Rotate(RotationAxis.Yaw, -xMovement * rotationFactor);
      Rotate(RotationAxis.Pitch, -yMovement * rotationFactor);
    } // if (Mouse.left.Pressed)
    
    // Use asdw (qwerty keyboard), aoew (dvorak keyboard) or
    // cursor keys (all keyboards?) to move around.
    // Note: If you want to change any keys, use Settings!
    if (Input.Keyboard.IsKeyDown(moveForwardKey) ||
      Input.Keyboard.IsKeyDown(Keys.Up) ||
      Input.Keyboard.IsKeyDown(Keys.NumPad8))
    {
      float oldPlayerSpeed = Player.Speed;
      Player.Speed += 0.75f * BaseGame.MoveFactorPerSecond;
    } // if
    if (Input.Keyboard.IsKeyDown(moveBackwardKey) ||
      Input.Keyboard.IsKeyDown(Keys.Down) ||
      Input.Keyboard.IsKeyDown(Keys.NumPad2))
    {
      float oldPlayerSpeed = Player.Speed;
      Player.Speed -= 0.75f * BaseGame.MoveFactorPerSecond;
    } // if
    
    if (Player.speedItemTimeout > 0)
    {
      Player.speedItemTimeout -= BaseGame.ElapsedTimeThisFrameInMs;
      if (Player.speedItemTimeout < 0)
      {
        Player.speedItemTimeout = 0;
        // Reduce to max. possible speed
        if (Player.Speed > Player.MaxSpeedWithoutItem)
          Player.Speed = Player.MaxSpeedWithoutItem;
      } // if
    } // if
    
    // Adjust current speed by the current player speed.
    float moveFactor = Player.Speed * maxMoveFactor;
    float slideFactor = maxSlideFactor;
    
    // Always move forward
    Translate(+moveFactor, MoveDirections.Z);
    
    // Slide
    if (Input.Keyboard.IsKeyDown(moveLeftKey) ||
      Input.Keyboard.IsKeyDown(Keys.Left) ||
      Input.Keyboard.IsKeyDown(Keys.NumPad4))
    {
      consumedAdditionalFuel = true;
      Translate(-slideFactor, MoveDirections.X);
    } // if
    if (Input.Keyboard.IsKeyDown(moveRightKey) ||
      Input.Keyboard.IsKeyDown(Keys.Right) ||
      Input.Keyboard.IsKeyDown(Keys.NumPad6))
    {
      consumedAdditionalFuel = true;
      Translate(+slideFactor, MoveDirections.X);
    } // if
    // Up/down
    if (Input.Keyboard.IsKeyDown(Keys.F))
    {
      Translate(+slideFactor, MoveDirections.Y);
    } // if
    if (Input.Keyboard.IsKeyDown(Keys.V))
    {
      Translate(-slideFactor, MoveDirections.Y);
    } // if
    #endregion

    为了支持Xbox 360下面的代码是在2006年初,这个游戏发布前的一天被添加的。实现Xinput很简单,我很高兴XNA在所有的输入类中都使用Xinput。把所有输入设备都放在一个命名空间中,这个主意很好,唯一的问题是Xbox 360运行时中没有鼠标类。就算这个类不支持,微软也应实现一个虚拟类,至少可以实现当鼠标可选时,用不着改变所有的输入代码。幸好,你以通过自己的Input类解决了这个问题。

    下面是Rocket Commander中的X360控制代码:

    #region Input support for the XBox360 controller
    // 2006-03-09: Added Input support
    rotationFactor = 3.0f * BaseGame.MoveFactorPerSecond;
    
    // Change camera rotation when right thumb is used.
    if (Input.GamePad.ThumbSticks.Right.X != 0.0f ||
      Input.GamePad.ThumbSticks.Right.Y != 0.0f)
    {
      float xMovement = Input.GamePad.ThumbSticks.Right.X;
      float yMovement = Input.GamePad.ThumbSticks.Right.Y;
      Rotate(RotationAxis.Yaw, -xMovement * rotationFactor);
      Rotate(RotationAxis.Pitch, yMovement * rotationFactor);
    } // if (Mouse.left.Pressed)
    
    // Use left thumb for moving around
    if (Input.GamePad.ThumbSticks.Left.Y != 0)
    {
      float oldPlayerSpeed = Player.Speed;
      Player.Speed += 0.75f * Input.GamePad.ThumbSticks.Left.Y *
        BaseGame.MoveFactorPerSecond;
    
      // Only decrease fuel if change happened
      if (oldPlayerSpeed != Player.Speed)
        consumedAdditionalFuel = true;
    } // if
    
    // Slide
    if (Input.GamePad.ThumbSticks.Left.X != 0)
    {
      consumedAdditionalFuel = true;
        Translate(slideFactor * Input.GamePad.ThumbSticks.Left.X * 2,
          MoveDirections.X);
      } // if
      #endregion
    } // HandlePlayerInput()

    你可以看到代码使用了大量的辅助方法,像Rotate,Translate、Input类中频繁使用的属性和从BaseGame类获得的有用的数值,如MoveFactorPerSecond。

    Translate方法沿着x , y ,或z轴移动目前的相机。 x轴是用来左右移动,在Rocket Commander中使用A和D键或方向键实现。 y轴用来上下移动而z轴用来前进后退。在Rocket Commander中z轴是最重要的,你沿着这根轴以极高的速度移动。

    /// <summary>
    /// Translate into x, y or z axis with a specfic amount.
    /// </summary>
    /// <param name="amount">Amount</param>
    /// <param name="direction">Direction</param>
    private void Translate(float amount, MoveDirections direction)
    {
      Vector3 dir =
        direction == MoveDirections.X ? XAxis :
        direction == MoveDirections.Y ? YAxis : ZAxis;
      pos += dir * amount;
    } // Translate(amount, direction)

    最后,Rotate旋转相机。Yaw是左右转动和Picth让你上下转动。原版本的Rocket Commander使用四元数,它还允许你翻滚火箭。在XNA版本的Rocket Commander中火箭自动调整,这样在Xbox 360上更容控制。

    /// <summary>
    /// Rotate around pitch, roll or yaw axis.
    /// </summary>
    /// <param name="axis">Axis</param>
    /// <param name="angle">Angle</param>
    private void Rotate(RotationAxis axis, float angle)
    {
      if (axis == RotationAxis.Yaw)
        yawRotation -= angle;
      else
        pitchRotation -= angle;
    } // Rotate(axis, angle)

    所有相机类都要通过单元测试进行测试。如果您尝试创建自己的相机类请务必对其进行测试,避免出错。

  • 相关阅读:
    python json 和 pickle的补充 hashlib configparser logging
    go 流程语句 if goto for swich
    go array slice map make new操作
    go 基础
    块级元素 行内元素 空元素
    咽炎就医用药(慢性肥厚性咽炎)
    春季感冒是风寒还是风热(转的文章)
    秋季感冒 咳嗽 怎么选药
    解决IE浏览器“无法显示此网页”的问题
    常用的 css 样式 记录
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120233.html
Copyright © 2011-2022 走看看