netlib.narod.ru | < Назад | Оглавление | Далее > |
Класс SpaceCamera немного сложнее, чем класс SimpleCamera, и даже класс ChaseCamera для гоночной игры выглядит проще. Главная причина сложности кода класса SpaceCamera в том, что это первый класс космической камеры, который я написал, и математика кватернионов не является простой вещью. Класс камеры поддерживает три режима: камера для меню, камера для игры и режим свободной камеры для тестовых модулей. Класс SpaceCamera из Rocket Commander XNA несколько проще, поскольку математика кватернионов убрана, и управление ракетой слегка упрощено, допуская только наклон и рыскание. Вращение ракеты вокруг оси Z теперь автоматически обрабатывается движком, что упрощает полет и не дает потерять ориентацию. Главная причина такого изменения — позволить игроку легко управлять ракетой с игрового пульта Xbox 360, что сложнее в оригинальной игре Rocket Commander, которая также поддерживает игровой пульт Xbox 360.
Киньте взгляд на наиболее важный метод в SpaceCamera, который обрабатывает весь пользовательский ввод и обновляет позицию камеры в каждом кадре:
/// <summary> /// Обработка пользовательского ввода для игры /// Это место, где происходит весь ввод в игре. /// </summary> private void HandlePlayerInput() { if (Player.lifeTimeMs < Player.LifeTimeZoomAndAccelerateMs) { float speedPercentage = Player.lifeTimeMs / (float)Player.LifeTimeZoomAndAccelerateMs; // Используем квадрат для лучшего эффекта ускорения Player.SetStartingSpeed(speedPercentage * speedPercentage); // Всегда перемещаемся вперед Translate(Player.Speed * BaseGame.MoveFactorPerSecond * Player.MovementSpeedPerSecond, MoveDirections.Z); if (Player.gameTimeMs < 100) { yawRotation = 0; pitchRotation = 0; pos = Vector3.Zero; } // if } // if
Показанный код в Rocket Commander увеличивает скорость ракеты и также сбрасывает значения вращения и местоположения, если игра только что запущена. Затем вы выполняете несколько проверок, закончена ли игра, и обрабатываете специальные случаи, чтобы позволить перемещение. Далее обрабатывается ввод с мыши и клавиатуры. В значительной степени это оригинальный код из самой первой, реализованной мной версии класса SpaceCamera; весь остальной код был добавлен позже для поддержки большего числа устройств ввода:
#region Поддержка мыши/клавиатуры 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) // Используем asdw (клавиатура qwerty), aoew (клавиатура Дворака) // или клавиши курсора (все клавиатуры?) для перемещения вокруг. // Примечание: Если вы хотите изменить какие-либо клавиши, // используйте пункт меню 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; // Ограничиваем до максимально возможной скорости if (Player.Speed > Player.MaxSpeedWithoutItem) Player.Speed = Player.MaxSpeedWithoutItem; } // if } // if // Подстраиваем текущую скорость под текущую скорость игрока float moveFactor = Player.Speed * maxMoveFactor; float slideFactor = maxSlideFactor; // Всегда перемещаемся вперед Translate(+moveFactor, MoveDirections.Z); // Сдвиг 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 // Вверх/вниз 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 для всех классов ввода. Очень хороша общая идея XNA объединить все устройства ввода в одном пространстве имен; единственную проблему создает отсутствие классов мыши для среды времени выполнения Xbox 360. Даже если класс не поддерживается, Microsoft должна была реализовать класс-заглушку, чтобы код, по крайней мере, компилировался без необходимости менять весь код ввода, который как вариант может использовать мышь. Ладно, все равно вы исправите это в вашем собственном классе Input.
Вот код для игрового пульта Xbox 360 из Rocket Commander XNA:
#region Поддержка ввода для пульта XBox360 controller // 2006-03-09: Добавлена поддержка Input rotationFactor = 3.0f * BaseGame.MoveFactorPerSecond; // Меняем поворот камеры, когда используется правый джойстик 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) // Используем левый джойстик для перемещения вокруг if (Input.GamePad.ThumbSticks.Left.Y != 0) { float oldPlayerSpeed = Player.Speed; Player.Speed += 0.75f * Input.GamePad.ThumbSticks.Left.Y * BaseGame.MoveFactorPerSecond; // Если произошло изменение, только уменьшаем топливо if (oldPlayerSpeed != Player.Speed) consumedAdditionalFuel = true; } // if // Сдвиг 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> /// Перемещение по осям X, Y или Z на заданную дистанцию /// </summary> /// <param name="amount">Дистанция</param> /// <param name="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 используется для вращения камеры. Рыскание поворачивает вас влево и вправо, а наклон — вверх и вниз. В оригинальной игре Rocket Commander здесь использовались кватернионы и они позволяли вам также вращаться вокруг ракеты. В Rocket Commander XNA ракета автоматически выравнивается для вас, чтобы упростить игру на Xbox 360.
/// <summary> /// Повороты вокруг осей наклона, рыскания и вращения /// </summary> /// <param name="axis">Ось</param> /// <param name="angle">Угол</param> private void Rotate(RotationAxis axis, float angle) { if (axis == RotationAxis.Yaw) yawRotation -= angle; else pitchRotation -= angle; } // Rotate(axis, angle)
Во всех классах камеры есть тестовые модули для их проверки. Если вы пробуете создать собственный класс камеры, удостоверьтесь, что тестируете его, или столкнетесь с проблемами.
netlib.narod.ru | < Назад | Оглавление | Далее > |