5

我正在努力做这个人正在做的事情,但我认为他的要求可能比我少,因为那篇文章中的答案似乎不适用于我的游戏。让我内联他的算法,这样我的问题就更容易理解了:

最简单的解决方案是从尾到头循环并将当前的位置设置为下一段的位置,即:segment[i].position = segment[i - 1].position

我认为我们的要求之间的主要区别是我希望在每个刻度上移动每块小于它自己的宽度/高度。例如:

在此处输入图像描述

假装这些正方形水平对齐(我把它画成未对齐的,因为我认为这样更容易看到发生了什么)。红色H是头部当前所在的位置。红色T是尾巴当前所在的位置。黑色H'是头部应该下一个刻度的位置。所以蛇从右向左移动。如果我使用上述算法,这些段不会重叠或开始分开吗?让我一步一步来玩:

  1. 创建 H'.position
  2. T.位置 = H.位置
  3. H.position = H'.position

这样做的结果将变为:

在此处输入图像描述

我可以使用什么算法来确保所有部件以相同的速度移动并保持相同的距离?


我会给出我的想法,但我对此持怀疑态度,因为我的研究没有显示其他人使用它:

每个段将存储它的坐标和方向。例如:[[50, 50, LEFT], [100, 50, LEFT]]。头部是索引 0,尾部是索引 1。 蛇移动的速度是 10,即使分段是 50x50

每个刻度我都会这样做:

  1. 如果按下鼠标,则用按下的方向覆盖nextDirection变量。否则,nextDirection无论它是最后一个勾号。在此示例中,假设有人按下UP
  2. 迭代数组并将方向应用于每个刻度。例如:[[40, 50, LEFT], [90, 50, LEFT]]
  3. 将方向从头转移到尾,并将头的新方向设置为nextDireciton。例如:[[40, 50, UP], [90, 50, LEFT]]
  4. 重复每个刻度。

这个算法看起来可行吗?我问的部分原因是因为它比其他人的算法更复杂,所以我觉得我做错了什么。而且,我对他的算法思考得越多,它似乎就越行不通。


改写我的问题

假设蛇的每个部分都是一个 20x20 像素的矩形。每个刻度,我希望头部向某个方向移动 5 个像素。 如何确保所有部分保持相互接触?

@Rafe 在下面的评论中的描述是:

考虑蛇在 step 占据的有序位置集,t最左边是尾巴,最右边是头部:{A, B, C, D, E}。在 stept+1处,蛇所占据的有序位置集是{B, C, D, E, F}尾巴从哪里移动A到哪里B,头部从哪里移动E到哪里F

而且我认为这个算法不起作用,因为:

是的,但如果A = B = C = D = E = F = 20px. 移动{A, B, C, D, E},使其{B, C, D, E, F}仅在右侧添加 20px 并从左侧移除 20px。这不是说他移动了 20px,而不是 5px? 我想移动 5px,而不是 20px 如果您说这是通过您的建议完成的,请说明如何。我没看到。

4

5 回答 5

3

我知道您忽略了网格,但是如何使蛇向前移动的距离一些数字均匀地考虑您的大块大小?

假设您仅向前移动块宽度/高度的一半。

现在你可以优化一下。

  • 启动一个计数器,n,它贯穿整个游戏。
  • 显示组成蛇 ( n = 0) 的块。让我们称之为snake_even.
  • 下一步移动 ( n = 1),通过将它们全部向前移动 1/2 单位来创建构成下一条蛇的块。让我们称之为snake_odd.
  • 对于所有后续移动,您将显示snake-evensnake_odd,但您可以创建snake_even(n+2)fromsnake_even(n)snake_odd(n+2)from ,snake_odd(n)只需将头部更改为新位置并在尾部书写。
  • 每当蛇吃东西时,将长度添加到snake_xxxx您所在的位置,然后将长度添加到另一个。

如果你只想向前移动高度的 1/5,你会做同样的事情,但是你需要跟踪五个数组而不是两个。

基于您添加的示例的附加信息(每步移动 5 像素的 20x20 像素段):

采取向右移动的 4 段蛇。分段大小为 20x20 像素,每次移动 5 像素。我将蛇定义为坐标列表(x, y)。我将用“H”标记头部,蛇将通过在列表中向右移动来循环,如果需要,循环回到开头。

// n = 0
snake_0 => H(60, 0), (40, 0), (20, 0), (0, 0)

// Snake is moving to the right.
// n = 1 -- construct snake_1 from snake_0 and display that one (n % 4 = 1)
snake_1 => H(65, 0), (45, 0), (25, 0), (5, 0)

// n = 2 -- construct snake_2 from snake_1 and display that one (n % 4 = 2)
snake_2 => H(70, 0), (50, 0), (30, 0), (10, 0)

// n = 3 -- construct snake_3 from snake_2 and display that one (n % 4 = 3)
snake_3 => H(75, 0), (55, 0), (35, 0), (15, 0)

// n = 4 -- Now just move the head, and re-use all but the tail of snake_0
snake_0 => (60, 0), (40, 0), (20, 0), H(80, 0)

// n = 5
snake_1 => (65, 0), (45, 0), (25, 0), H(85, 0)

// n = 6
snake_2 => (70, 0), (50, 0), (30, 0), H(90, 0)

// etc.

现在我忘记考虑的一件事是每个部分需要移动的方向。这可以存储在坐标旁边。但我认为你可能已经理解了那部分。

于 2013-06-04T18:59:15.423 回答
1

下面是我如何实现这个算法:

基本上,我创建了一个Segment类。每个都有一个枢轴列表。每当头部改变方向时,我都会填充每个段中的枢轴列表。每当一个段与一个枢轴发生碰撞时,它就会改变到它前面的段的方向。然后我从它的列表中删除该枢轴。

一个缺点是你必须让蛇移动它自己大小的一个因子,否则它不会与枢轴碰撞。

于 2013-06-08T08:13:55.993 回答
0

在他的情况下,每个片段都只是移动到其前身的位置。

想想在它们的中心之间有一个实心条的段。如果这不正确,蛇会在移动时伸展并聚集在一起。

你和他的区别在于他有更长的实心条,所以没有重叠。

但是,如果条形图是移动的长度,则每个段将仅移动到前一个段之前的位置。头部是个例外,它将按照最后一次鼠标单击指定的方向移动。

现在......如果条的长度长于或短于运动的长度怎么办。

我认为,在这种情况下,您必须先移动头部,然后移动每个段,使其与前一个段(更靠近头部的段)的距离相同。

硬的部分是由于移动量不等于距离造成的。当头部改变方向时,第 2 段必须同时改变 X 和 Y,否则它与头部的距离将不再相同。

我建议你:

  1. 计算 H' 的位置。这是打勾后头部的位置。
  2. 计算从 T 到 H' 的方向和
  3. 沿着那个向量移动 T,直到它与 H 的距离合适。

有用的部分到此结束...

这部分(此处下方)不正确

我将把它留在这里,因为错误的是它移动了与头部移动相同的距离。它应该做的是将尾巴移动到与头部距离相同的位置。('oneTick' 与尾部无关。我们应该在开始时设置段之间的距离并使用该长度。)

假设“oneTick”是每个刻度移动的长度。而“方向”是向上、向下、向左或向右

if (direction == UP) H'.x = H.x - oneTick;
else if (direction == LEFT) H'.y = H.y - oneTick;
... more elses for the other directions ...

ratio = (H'.x - T.x) / (H'.y - T.y);
dy2 = oneTick * oneTick / (ratio * ratio + 1);
dy = Math.sqrt(dy2);
dx = ratio * dy;

T'.x = T.x + dx; // or minus depending on direction
T'.y = T.y + dy; // or minus ...

方向与H'.y - T.y(对于 y)的符号有关,对于 x 也是如此。

于 2013-06-04T18:47:03.303 回答
0

所以,蛇的头自由移动,你检查自我碰撞?

我看到的最简单的方法是在随后的帧中列出蛇头的位置,然后在之前的头部位置的每个第 k 个位置绘制其余部分。然后在下一帧,您将另一个头部位置附加到列表中,并在每个第 k 个位置再次绘制剩余的段。

如果蛇的速度是可变的,您还必须改变 k,以使蛇不伸展(也可能在头部位置之间插值)。这是简单的数学。

于 2013-06-04T19:38:25.890 回答
0

从规范来看,如果考虑蛇占据的位置,每一步只有头部和尾部发生变化。因此,您可以使用循环缓冲区来表示蛇并在 O(1) 时间而不是 O(n) 时间内更新其位置。

于 2013-06-05T01:06:17.763 回答