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)

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

  • 相关阅读:
    redis命令参考(四) set集合
    redis命令参考(三) List列表相关
    redis命令参考(二)
    redis命令参考(一) SortedSet相关
    insert_into_on_dumplicate_key
    laravel深入分析
    开发中GBK+UTF8编码的处理
    ajax封装调用
    linux正则表达式的用法
    linux 如何保证使程序后台运行(nohup &)
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120233.html
Copyright © 2011-2022 走看看