2d游戏矢量运动C#

时间:2013-12-17 14:12:41

标签: c# game-engine

我是游戏开发的新手,我遇到了问题。

我想知道每秒的新玩家位置,这里有一个例子:

玩家从(2.5; 2.5)开始,然后进入(6.5; 3.8)。 player movement vector

他的速度是每秒2个单位的速度,我想知道1秒后的玩家位置。所以像这样:

enter image description here

我想知道它每秒都是A但我根本不知道我怎么能这样做...... 我希望你能提前帮助我!

5 个答案:

答案 0 :(得分:3)

首先,您需要计算出所覆盖的总距离,这是您的向量。矢量是一个运动,而不是空间中的两个点。

然后你只需将每个维度x和y除以这种情况下的时间,即以测量单位(秒)为单位进行移动以获得每秒的距离。

然后将每个x和y乘以0的秒数,即示例中的1秒,以便在1秒后得到位置。

我不知道您的框架或库中有什么可用,但是一个好的Vector类将非常有用,您将希望能够直接对矢量实例进行数学运算,例如:

Point origin = sprite.Position; // Assumes some sprite object with a position.
Point dest = new Point(200,344); // Destination.

Vector totalTranslation = new Vector(dest.X - origin.X, dest.Y - origin.Y);
Vector perSecond = totalTranslation / 60; // assuming takes a minute to move.
Vector distanceMoved = perSecond * 4; // distance moved after 4 seconds.

Point newPosition = new Point(origin.X + distanceMoved.X, origin.Y + distanceMoved.Y);

sprite.Position = newPosition; // Or using some orchestration class...
spriteManager.Move(sprite, newPosition); // ...like this.

注意能够直接划分矢量。否则,你必须划分向量的每个空间维度并创建一个新的向量,或者做一个辅助类来做它。

在现实生活中,您可能希望基于毫秒计算。我不会使用固定的帧计数器,因为它可能看起来很讨厌,但是根据计时器完成所有工作。

正如我所说,一个好的库或不可变的Vector结构/类是这里的关键。然后是一个在方格纸上思考问题的案例。

此外,建立一个小功能的调色板,你可以链在一起做更酷,更大的东西。

另一个有趣的问题是使用缓动函数在给定时间之后计算坐标,以实现精灵在“落地”时减速的效果。

答案 1 :(得分:3)

  

他的速度是每秒2个单位。

我认为,'单位'的意思是'长度为1的矢量'。

首先,您需要计算AB矢量(运动矢量):

mov_vec = [xb-xa, yb-ya] = [6.5 - 2.5, 3.8 - 2.5] = [4, 1.3]

所以,我们知道,总单位的运动是[4,1.3]。我们需要规范化这个向量。归一化向量(单位向量)'norm_mov_vec'将与'mov_vec'成为同向,但它的长度为1.如果你想知道更多邻接单位向量,请参见this link

计算运动矢量的长度:

mov_vec_len = sqrt( 4^2 + 1.3^2 ) ~= 4.2059

计算标准化向量:

norm_mov_vec = [4/4.2059, 1.3/4.2059] ~= [0.9510, 0.3090]

就是这样。 'norm_mov_vec'是你的'单位运动矢量',所以如果玩家以每秒N个单位的速度向那个方向移动,你可以很容易地计算它在T秒后的位置:

pos_after_T_sec_with_speed_N_units_per_sec = start_pos +(N * T * norm_mov_vec)

编辑: 示例代码,使用XNA中的Vector2类型。无法测试,但我希望你能得到这个想法:

//In your case:
//start_pos = 'A' point
//end_pos = 'B' point
//time = number of seconds that elapsed
//speed = number of units per second
Vector2 calculatePosition(ref Vector2 start_pos, ref Vector2 end_pos, Uint32 time, Uint32 speed)
{
    Vector2 mov_vec = Vector2.Substract(end_pos, start_pos);

    Vector2 norm_mov_vec = Vector2.Normalize(mov_vec);

    Vector2 delta_vec = norm_mov_vec * time * speed;

    return Vector2.Add(start_pos, delta_vec);
}

答案 2 :(得分:2)

这不是编程,而是矢量数学,但无论如何:

您的播放器正在沿着矢量BA(B点减去A点)移动,这是

Direction Vector: ( 4.0 / 1.3 )

此向量的长度为:

SquareRoot(4.0 * 4.0 + 1.3 * 1.3) = 4.2

相同方向的矢量和长度的一个单位因此是两个分量除以长度4.2的矢量:

Direction Vector of length 1: (0.95 / 0.30)

由于你的玩家很快并且移动了两个单位,所以它将是双倍长度:

Direction Vector of length 2: (1.90 / 0.60)

现在每个勾选,分别为玩家坐标添加1.90和0.60,直到它们等于(大致)目标坐标。

答案 3 :(得分:0)

x-位移:6.5-2.5 = 4

y-位移:3.8-2.5 = 1.3

Math.sqrt((4n)(4n)+(1.3n)(1.3n))= 2

N = 2 / Math.sqrt(17.69)

x-displacement / second = 4n = 8 / Math.sqrt(17.69)= 1.90207

y-displacement / second = 1.3n = 2.6 / Math.sqrt(17.69)= 0.61817

所以在得到这些值之后,每秒计算位置真的很容易

答案 4 :(得分:0)

您可以使用(作为通用解决方案)这些简单的三角公式

  x = A.x + v * cos(fi) * t;
  y = B.y + v * sin(fi) * t;
  fi = atan2(B.y - A.y, B.x - A.x);

样本解决方案

// Since there's no common 2d Point double based type,
// let (x, y) point be represented as Tuple<Double, Double>
// where Item1 is x, and Item2 is y
public static Tuple<Double, Double> Move(Tuple<Double, Double> fromPoint,
                                         Tuple<Double, Double> toPoint,
                                         Double velocity,
                                         Double time) {
  Double fi = Math.Atan2(toPoint.Item2 - fromPoint.Item2, toPoint.Item1 - fromPoint.Item1);

  return new Tuple<Double, Double>(
    fromPoint.Item1 + velocity * Math.Cos(fi) * time,
    fromPoint.Item2 + velocity * Math.Sin(fi) * time);
}

...

for (int t = 0; t < 10; ++t) {
  Tuple<Double, Double> position = 
    Move(new Tuple<Double, Double>(2.5, 2.5), 
         new Tuple<Double, Double>(6.5, 3.8), 
         2.0, 
         t);

  Console.Write("t = ");
  Console.Write(t);
  Console.Write(" x = ");
  Console.Write(position.Item1);
  Console.Write(" y = ");
  Console.Write(position.Item2);
  Console.WriteLine();
}