| 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 | < Назад | Оглавление | Далее > |