§10.4Space Camera类

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) /p>

{

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类解决了这个问题。

#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 name="direction" /> Direction

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 name="angle" /> Angle

private void Rotate(RotationAxis axis, float angle)

{

if (axis == RotationAxis.Yaw)

yawRotation -= angle; else pitchRotation -= angle;

} // Rotate(axis, angle)

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


发布时间:2008/9/28 8:06:59  阅读次数:4813

2006 - 2024,推荐分辨率1024*768以上,推荐浏览器Chrome、Edge等现代浏览器,截止2021年12月5日的访问次数:1872万9823 站长邮箱

沪ICP备18037240号-1

沪公网安备 31011002002865号