触摸操作在Windows手机7游戏开发第4部分捏
编程! - 4. 捏合,通过拉伸缩放子画面
关于此示例
在现代智能手机上,您可以使用两个手指(如图像查看器)来放大和缩小手指之间的间距。 您可以在 Windows 电话 7 附带的互联网资源管理器中执行相同的操作。 在 Windows 电话 7 中,这称为“捏合、拉伸”。
除了捏合和拉伸操作外,还有“点击”(轻击)或“轻拂”以快速跟踪屏幕。 这些操作统称为“手势”。
在这个程序中,我想通过捏和拉伸来放大和缩小屏幕上可见的子画面。 此外,直到上次,我们直接获取触摸屏信息并进行处理,但这次我想使用手势专用方法处理触摸操作。
此示例程序的目标
捏合和拉伸操作可放大和缩小子画面。
图 1:拉伸以放大子画面
程序 - 声明字段
字段声明中没有新类,但我们希望它具有纹理的中心坐标、子画面的放大率和捏合操作前两个触摸位置之间的距离。
<summary>
テクスチャー
</summary>
Texture2D texture;
<summary>
テクスチャーの中心座標
</summary>
Vector2 textureCenterPos;
<summary>
スプライトのスケール
</summary>
float scale = 1;
<summary>
前回の 2 点間の距離
</summary>
float previousLength = 0;
程序 - 启用手势
这一次,我们将只处理手势,但在默认状态下,我们无法使用任何手势。 若要获取每个手势信息,必须设置用于“触摸面板.启用 Gestures”属性的手势。
// タッチパネルでピンチのジェスチャーを有効にする
TouchPanel.EnabledGestures = GestureType.Pinch | GestureType.PinchComplete;
由于启用所有手势会影响性能,因此请确保仅设置要使用的手势。 在这里,我们设置“GestureType.Pinch”以获取捏合操作的信息,并设置“GestureType.PinchComplete”,指示捏合过程已完成。 设置位置在游戏构造函数中设置。
程序 - 加载纹理
纹理导入与以往没有什么不同,但这次我们计算了纹理的中心坐标。 在缩放子画面时,将中心坐标缩放为原点。
// テクスチャーをコンテンツパイプラインから読み込む
texture = Content.Load<Texture2D>("Texture");
// テクスチャーの中心座標を求める
textureCenterPos = new Vector2(texture.Width / 2, texture.Height / 2);
程序 - 获取手势信息
在 Game.Update 方法中获取手势信息(此处为捏合)。 手势处理是一种形式,您可以重复您启用的手势数。 我们不会使用以前使用的“触摸收集”结构。
// 次のジェスチャー情報が取得できる場合は true を返し続けます
while (TouchPanel.IsGestureAvailable)
{
// 次のジェスチャー情報を読み込みます
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.Pinch:
// ここにピンチ処理を記述します
break;
case GestureType.PinchComplete:
// ここにピンチ完了処理を記述します
break;
}
}
手势信息在 while 循环中检查“触控面板.可访问”属性的状态,并检查是否存在以下手势信息: 使用“触摸面板.ReadGesture”方法获取手势信息(如果有),包括:
“GestureSample.GestureType”存储包含哪些手势类型的信息,并基于这些类型在开关语句中分支处理。 在此示例中,在构造函数中,在“触摸面板.启用 Gestures”属性中设置了“Gesture 类型.Pinch”和“GestureType.PinchComplete”枚举类型,因此我们分别分支了该枚举。
程序 - 处理捏合手势
看到代码注释时,我们越早看到操作,我们就越容易总结我们在做什么,我们计算了前两个点之间的接触点距离与两个接触点之间的距离之间的差异,并根据差异增加或减少比例值。
case GestureType.Pinch:
// 現在の2点間の距離を求めます
float nowLength = (gs.Position - gs.Position2).Length();
if (previousLength == 0)
{
// 前回の2点間の距離が 0 の場合は
// 現在の2点間の距離を設定します
// 初回はスケール計算を行いません
previousLength = nowLength;
}
else
{
// 前回の2点間の距離との差分を計算します
float diffLength = nowLength - previousLength;
// ピンチ、ストレッチした距離に応じて
// スケールを変化させています
// 補正値は適当に設定します
scale = MathHelper.Max(scale + diffLength / 150, 0);
// 今回の距離を次の計算のために保持します
previousLength = nowLength;
}
break;
两个触摸位置可以分别在“GestureSample.Position”和“GestureSample.Position2”中获取。 通过减去两个获得的矢量,可以求和差异,然后调用 Vector2.Length 方法来确定两点之间的距离。
顺便说一下,当我们不执行捏合时,我们定义了上一个距离 0,因此,在开始捏合处理时,我们将在第二个和后续循环中分支处理。 因为第一次捏合时没有上次的距离,因此无需缩放。
此外,这一次,我们只使用两个属性“GestureSample.Position”和“GestureSample.Position2”,但还有其他属性“GestureSample.Delta”和“GestureSample.Delta2”属性,您可以在这里获取与上次触摸位置的差异信息。 每个属性各提供两个属性,用于多点触控,对于仅使用单点触摸的手势,请使用不带“2”的属性。
程序 - 捏合手势完成时的处理
当捏合手势完成时(当任一手指从触摸屏上松开时),前两个点之间的距离将恢复为 0。 最初,最好单独使用标志,但物理上不可能用两根手指触摸同一位置,因此,在距离为 0 时,我们将其定义为不执行捏合。 (如果分辨率较低,则可能触摸同一位置。)
case GestureType.PinchComplete:
// ピンチが終了した場合は保持している距離を 0 に戻して
// 完了したことにします
previousLength = 0;
break;
程序 - 绘制子画面
由于这只是子画面的绘制内容,因此不会详细介绍它,但我们将子画面放在屏幕的中心,并将计算的比例值作为子画面的中心作为原点进行缩放和绘制。
// スプライトの描画準備
spriteBatch.Begin();
// スプライトを描画する
spriteBatch.Draw(texture,
new Vector2(graphics.PreferredBackBufferWidth / 2,
graphics.PreferredBackBufferHeight / 2),
null,
Color.White,
0.0f,
textureCenterPos,
scale,
SpriteEffects.None,
0.0f);
// スプライトの一括描画
spriteBatch.End();
此示例摘要
这一次,我们讨论了手势专用处理。 示例仅创建捏合,但还有其他“轻拂”和“保持”。 有关手势类型的信息,请参阅 XNA 游戏工作室 4.0 帮助中的“GestureType 枚举”。
即使不使用手势专用方法或结构,也可以从 TouchPanel.GetState 方法获取的触摸信息中实现类似的实现,但在这种情况下,您需要自行计算多点触控 ID 管理、触摸时间、轻拂等速度。 通过使用仅手势方法,可以简化这些实现,并且任何游戏或应用程序都可以以相同的方式操作。
如果您自己创建触摸屏处理,并且可以使用类似的操作替换手势,则最好使用此方法。
编程! - 5. 在捏合过程中旋转子画面
关于此示例
通常,捏合是指“捏合”和“拉伸”,但 XNA Game Studio 4.0 的捏合操作并不特别局限于这两个操作,因此您可以在一个接触点周围执行另一个接触点周围的操作。
在这里,我想旋转子画面的方式。 顺便说一下,这次没有出现任何新方法或类,而是基于以前的缩放进行应用。
此示例代码中的说明与上一个缩放示例相同。
此示例程序的目标
通过旋转两个接触点,子画面将旋转。 以前的缩放过程也同时工作。
图 2:旋转接触点以旋转子画面
程序 - 声明字段
为上一个缩放程序添加了“子画面旋转量”和“上一个旋转角度”。 所有角度均以弧度计算。
<summary>
スプライトの回転量(radian)
</summary>
float rotate;
<summary>
前回の回転角度(radian)
</summary>
float previousAngle;
程序 - 旋转处理
旋转过程在捏合手势时完成,就像缩放时一样。
旋转计算是数学问题,因此不太详细,但您可以使用 Math.Atan2 方法获取 radian 的角度,以获得从接触点 1 到接触点 2 的差分矢量。 获取获取的角度与上次获取的角度之间的差异,并添加到子画面的旋转角度。
switch (gs.GestureType)
{
case GestureType.Pinch:
//===== スケール計算 =====//
// 前回と同じなので省略
//===== 回転計算 =====//
// 2点間のベクトルを求めます
Vector2 pinchVector = gs.Position2 - gs.Position;
// Atan2 で角度を求めます
float nowAngle = (float)Math.Atan2(pinchVector.Y,
pinchVector.X);
if (previousAngle == 0)
{
// 前回の角度が 0 の場合は
// 現在の角度を設定します
// 初回は回転計算を行いません
previousAngle = nowAngle;
}
else
{
// 前回の角度との差分をスプライトの回転角度に加算します
rotate += nowAngle - previousAngle;
// 今回の距離を次の計算のために保持します
previousAngle = nowAngle;
}
break;
case GestureType.PinchComplete:
// ピンチが終了した場合は保持している距離、角度を 0 に戻して
// 完了したことにします
previousLength = 0;
previousAngle = 0;
break;
}
程序 - 绘制子画面
绘制子画面没有重大更改。 将计算的旋转角度设置为 SpriteBacth.Draw 方法的第五个参数。
// スプライトの描画準備
spriteBatch.Begin();
// スプライトを描画する
spriteBatch.Draw(texture,
new Vector2(graphics.PreferredBackBufferWidth / 2,
graphics.PreferredBackBufferHeight / 2),
null,
Color.White,
rotate,
textureCenterPos,
scale,
SpriteEffects.None,
0.0f);
// スプライトの一括描画
spriteBatch.End();
此示例摘要
这一次,我试图通过捏操作旋转子画面。 我没有使用任何新的类,但您可能已经知道,根据提供的功能,可以应用它们。
最后
在演示示例时,我们讨论了使用 Windows 电话 7 和 XNA 游戏工作室 4.0 实现触摸交互。 内容包括单点触控、多点触控触摸信息的获取和操作,以及使用特定于手势的方法的触摸手势操作。
这一次,我们专注于触摸屏,但仍有一些功能尚未介绍。 在 Windows Phone 7 中,XNA 游戏工作室 4.0 中新增的输入功能包括加速度计输入和语音输入。 功能,不能完全介绍这一次,因为有一个有趣的功能,请享受检查的功能,你想使用。