【译】装置制造者里的小绳砸(如何正确的做一款割绳子)

发表于2016-04-01
评论1 1.7k浏览

装置制造者里的小绳砸

注:我原本已在几周前的博客中发布了。

装置制造者Contraption Maker (CM)是一个使用Spotkin开发哒物理沙盒游戏。它使用一种改进的Loom工具以及几个不同的库/组件包括cocos2dx和Chipmunk。2014年夏整个游戏通过steam发布的早期测试版。

获得和现实的一样的绳索工作需要解决几个不同的问题。它主要是运动轨迹路线,别人已经实现了,我只要根据我的需要做出任何调整。只需要快速的预览,我就知道如何去通过CM中实现它们和修补一些漏洞。

基础知识

第一个决定是明确的,我要去模拟一根绳子滚动状态。确定哪些元素或绳滚动实现复杂的平衡既影响性能又影响设计。例如:在他们最后的形态为绳索不与任何发生碰撞。他们唯一的游戏功能是连接到任何一端的部件之间转移力的零件。这是一个在游戏设计和性能(执行速度)二者的决定。当然性能更好,因为没有必要计算所有的碰撞和物理,只需要计算在所需要的绳子上,所以绳子长度大大减少了。

这是相当典型的游戏设计和开发过程,你总是需要做各种权衡。相对的小家伙,狗狗,米老鼠,和足球尺寸的游戏设计决策为了更好的游戏可玩性扭曲真实性。



我不在Chipmunk的物理引擎使用内置的绳索。因为Chipmunk引擎没有内置的绳索–简单的设定。它确实有一大堆不同类型的限制,所以我的第一个想法是用那些来实现绳索。通过所以浏览可用的限制用滑动接头为两端的绳子似乎很明显。也许使用弹簧接头的所有点之间的绳子端点更好?

执行速度是一个大问题。人们玩CM将能够创造巨大的东♂西,其中可能包括非常多的长绳。好的,第一个想法,而不是用Chipmunk的一般弹簧限制,我会写一个更严格的自定义弹簧,最小的计算需要的还是模拟绳的一个焦点那看起来和现实发生的实际的行为一样。在写任何代码之前,我勾勒出了相当简单的想法。

限制绳端

滑动关节限制保持两点的Chipmunk的结构彼此在一个指定范围内。
它被赋予了两个机构彼此来限制一个最小的和最大的距离。因此,绳子一端连接于结构–或是一个CM结构的部分或者,在一个未连接的绳端的情况下,一个物理的结构在绳子的一端。

滑动接头用于处理一根绳子的两端的行为是最完美的。在CM的绳子上,最小的距离总是设置为零,最大的距离是绳子的长度。
在下面的简单设置中,一个滑动关节限制链接到该中心的静态结构的钩,同时也链接了一个偏移的动态结构的中心的方块。

好的,很棒,第一点,最简单的代码是别人已经写过的代码。现在是时候来模拟这两个端点之间的绳子,来看看当它是松弛的时候它是如何移动的。下面你可以看到绳子如何穿过砖墙。如上所述,绳索不与任何其他部分或与之碰撞。我唯一关心的是其内部的绳子运动确实像一根绳子。它并没有影响到物理本身以外的东西。要实现它话我需要把绳子断成单独的段,然后使其用绳子的方式移动。你可以看到每一个单独的片段,如下图中的紫色点。



为了让它看起来像是一根实际的绳子,用绳的材质替换紫色的点材质。材质加入了个别部分,旋转无缝。这里是同一个设置的紫色点材质替换为绳材质的图样:



内部绳物理的细节

有一次我坐了下来,一一在思考,我决定用Verlet来照顾所有的绳内段。它很好地解决了这个问题,并且代码非常快速地执行。过程是:

  • 使用每个段的当前位置和以前的位置来确定速度
  • 将此速度添加到当前段位置以获得新位置
  • 加入重力(步骤1-3在第一个代码摘录如下)
  • 每一次步长多次迭代,得到邻近的绳段固定距离。这是一个迭代过程,是在哪里越多迭代效果越好的解决方案。一种解决方案的执行速度与稳定性之间的折衷。每一次步长用七次迭代。(这是在下面的第二段代码段)

这四个步骤非常好的解释和说明这:http://blog.2and2.com.au/?p=883

这是一个代码,适用于速度和重力的每一个绳段步长。

重要的代码注释:原因是我提到的蝴蝶效应,所有的物理计算都是使用整数而不是floats,上面列出的代码是使用int(s)而不是floats。在我的固定点数系统中,有一些位转移以保持在1等于65536。代码很简单:

for (int i=0;i<;=lastIndex;i++)
 {
    // Gravity (assuming only in y axis)
    CMRopeSegment *seg = static_cast(mSegments->objectAtIndex(i));
    seg->mY -= gravityY;

    // Verlet
    int temp = seg->mX;
    seg->mX += (seg->mX - seg->mOldX);
    seg->mOldX = temp;
    temp = seg->mY;
    seg->mY += (seg->mY - seg->mOldY);
    seg->mOldY = temp;
 }


(偷懒)
And here is the code that makes multiple passes per time-step through all of the rope segments

// Run a few iterations to process all the links (defaults to 7 steps)
 for (int step=0;step  {
    CMRopeSegment *prevSeg = static_cast(mSegments->objectAtIndex(0));
    for (int i=1;i     {
       CMRopeSegment *seg = static_cast(mSegments->objectAtIndex(i));
       int dx = seg->mX - prevSeg->mX;
       int dy = seg->mY - prevSeg->mY;

       // Custom integer version of square root function
       int dist = tmSqrtShiftedInt32(dx * (tmInt64)dx + dy * (tmInt64)dy);

       // Keep in a sane range to prevent divide by zero from happening
       if (dist < 128)
          dist = 128;

       seg->mLength = dist;

       int delta = seg->mAdjustedLength - dist;
       tmInt64 percent = (delta * FLOAT_TO_INT64(0.7f)) / dist;
       int offsetX = (int)INT64_SHIFT_DOWN(dx * percent);
       int offsetY = (int)INT64_SHIFT_DOWN(dy * percent);

       if (i == 1 && firstIndex != 0)
       {
          seg->mX += offsetX;
          seg->mY += offsetY;
       }
       else if (i != 1 || firstIndex == 0)
       {
          prevSeg->mX -= offsetX;
          prevSeg->mY -= offsetY;
       }
       else if (i != (mNumSegments-1) || lastIndex == (mNumSegments-1))
       {
          seg->mX += offsetX;
          seg->mY += offsetY;
       }

       prevSeg = seg;
    }
 }


在Verlet integration的运行,滑动关节限制首先调整在绳子两端的物体的位置,第一和最后一个绳段被设置为从那里的滑动接头计算出机构的位置。这些第一和最后一段不会由Verlet integration改变,但这两者之间的所有片段都被改变了。上面的代码是运行调整Verlet内部绳段的各个片段,给我们很好的绳状运动,但他们没有力量转移在绳子两端的结构。

verlets给出“弹性”的结果,可以减少通过增加迭代次数的每个步长。装置制造商使用7次迭代每步长。你可以看到下面的差异,使用两种不同的迭代算法,2个集成步骤需要更长的时间来移动剩余部分相比21步版本..这里不太明显,但在游戏中要注意的问题是,在游戏中要注意的步太小了。


滑轮

两个部件之间的直接的绳物理链接已完成。接下来就是添加滑轮。Chipmunk没有滑轮的支持,但我确实发现了一些代码,由罗伯特布莱克伍德(Robert Blackwood)基于Box2D的滑轮用Chipmunk写出的。我采用了,为了与我们的系统很好的工作而修改了它,终于有了滑轮用了,虽然有些问题我会在下面提到。在两个绳段挂的第一个和最后一个滑轮发生物理反应。一根绳子,两滑轮的所有部分被视为一个没有物理处理的直线。滑轮的一端绳子上的任何松弛只发生在绳子上的部分。


滑轮几乎完全奏效,但是有一个非常明显的问题,那就是绳子的每个末端的物体结构都有完全不同的质量。这是一个典型的问题,在物理引擎,如果你有2个机构,两者之间的比例非常大的物理力能让游戏瞬间爆炸。



这是一个相当明显的问题,但也存在其他问题,部件的差异并不是很合适,和上面不一样,但仍有。
该系统可以在一个状态下,作用在物体上的力来回荡导致卡物体或减慢绳端上滑轮系统的一端。像这样的问题是很难跟踪和修复的,因为有这么多的数字和不同的力被应用在不同的地方。这里是一个日志输出的例子,我可以用来跟踪物理问题:



使用气球/铁球作为一个好的测试用例,通过冲量和缓存的冲量跟踪。当气球撞到滑轮上的时候,看起来能量并没有被丢失,所以,你猜是什么,因为气球没有撞到滑轮上,在滑轮上没有和滑轮发生碰撞。确定问题-下一步问题解决方案。

在装置制造商没有发生碰撞,因为这允许它们被放置时可能与墙壁和其他部分重叠。但这并没有正确解决的情况如上图,在滑轮一端的绳子的长度为零。

为了解决这个问题,我在这一点上加了一个特殊的碰撞形状当绳子连接滑轮。在滑轮上这种特殊的碰撞形状,然后,这种特殊的碰撞形状只会与另一个特设碰撞形状碰撞,在绳子连接到一个零件的部分只会与另一个特设形状碰撞。

现在零件和滑轮碰撞的物理系统可以在固件上应用正确的力。这在同一滑轮系统上,因为在气球正确与滑轮碰撞,你可以看到气球在滑轮上反弹。成功!CM世界上一切都运行的很好。



{
(甜橙子君 译制);
(什么都不说了请务必给我几百QB当做饭钱);
(翻译是很累的);
}

看了上面的文章 热爱游戏创作的你是不是已经开始热血沸腾了呢?是不是迫不及待的想加入游戏团队成为里面的一员呢?

福利来啦~赶快加入腾讯GAD交流群,人满封群!每天分享游戏开发内部干货、教学视频、福利活动、和有相同梦想的人在一起,更有腾讯游戏专家手把手教你做游戏!

腾讯GAD游戏策划交流群486822377Gad策划交流群

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引