Unity-如何在2D自上而下的游戏中将船现实地移动到一个点


14

我试图将帆船移动到我用鼠标单击的位置。该运动应该是现实的(船在其后方的桨桨桨),因此,如果鼠标左键单击,并且在船的前方,则该船之后应以弯曲的路径向那里移动,以便正确旋转

如果有人可以帮助我解决问题,我将非常高兴 船舶运动


1
正如您的图像似乎描绘了风帆:应该考虑风吗?有些操纵不可能与错误的风或缺少风有关。
没人

更重要的是,看起来逼真的帆船运动确实需要考虑风力。忽略它就像执行跳跃时忽略重力一样。您不一定需要特别详细的风模型,但是您需要牢记,您的船被风帆中的风(以及靠龙骨和舵的水)推动着。特别是,船舶不能直接在上风航行;他们需要在那儿打败自己。
Ilmari Karonen

通常,“定位点”可以分为旋转阶段和向前运动阶段。采取相同的方法,但要使旋转向前运动。示例每旋转x弧度将船向前移动y米
dnk drone.vs.drones 2015年

Answers:


7

看到这个页面

增加逼真的转弯

下一步是为我们的单元添加逼真的弯曲转弯,以使它们似乎不会在每次需要转弯时都突然改变方向。一个简单的解决方案包括使用样条曲线将陡峭的拐角平滑成转弯。尽管这解决了一些美学上的问题,但对于大多数单元而言,仍然导致物理上非常不现实的运动。例如,它可能会将水箱的突然转弯变成紧密的曲线,但弯曲的转弯仍会比水箱的实际作用更紧。

为了获得更好的解决方案,我们首先需要知道的是设备的转弯半径。转弯半径是一个非常简单的概念:如果您在车内的大型停车场中,将车轮向左旋转至尽可能远的距离并继续行驶一圈,则该转弯的半径就是您的转弯半径。大众甲壳虫的转弯半径将大大小于大型SUV的转弯半径,而人的转弯半径将大大小于笨拙的大型熊的转弯半径。

假设您在某个点(原点)并指向某个方向,并且您需要到达其他点(目标),如图5所示。最短的路径可以通过向左转而找到可以绕圈走直到您直接指向目的地,然后继续前进,或者右转并做同样的事情。 图5:确定从起点到终点的最短路径。

在图5中,最短的路线显然是底部的绿线。由于某些几何关系,该路径的计算非常简单,如图6所示。

图6:计算路径长度。

首先,我们计算点P的位置,该点是我们的转弯圆的中心,并且始终是距起点的半径r。如果我们从初始方向向右转,则意味着P与原点成一个(initial_direction-90)角,因此:

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

既然我们知道了中心点P的位置,我们就可以计算出从P到目的地的距离,如图中的h所示:

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

在这一点上,我们还想检查目的地是否在圆圈内,因为如果目的地不在,我们将永远无法到达目的地:

if (h < r)
    return false

现在我们可以计算段d的长度,因为我们已经知道了直角三角形另外两个边的长度,即h和r。我们还可以从直角三角形关系确定角度:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

最后,要找出要离开圆并从直线开始的点Q,我们需要知道总角度+,并且很容易确定为从P到目的地的角度:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

以上计算代表了右转的路径。可以用完全相同的方式计算左侧路径,除了我们在initial_direction加90以计算angleToP,然后使用-代替+之外。在计算完两者之后,我们只需查看哪个路径较短并使用该路径即可。

在我们对该算法及其后继算法的实现中,我们利用了一种数据结构,该数据结构最多存储四个不同的“线段”,每个线段可以是直线或曲线。对于此处描述的弯曲路径,仅使用两个部分:弧线和直线。数据结构包含一些成员,这些成员指定该段是弧线还是直线,段的长度及其起始位置。如果线段是直线,则数据结构还指定角度;对于圆弧,它指定圆心,圆弧的起始角度以及圆弧覆盖的总弧度。

一旦我们计算出了到达两点之间所需的弯曲路径,就可以轻松地计算出在任何给定时刻的位置和方向,如清单2所示。

清单2.计算特定时间的位置和方向。

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length

4
这个答案并没有真正研究船舶的物理学。我还发现它基本上是到另一个网站的链接和冗长的摘录(我不确定其合法性),这是有问题的。
没人

上一次我提供可解决所问问题的现有资源时,如果目标站点不再存在,则要求我包括链接的内容。现在,我被要求不包含内容。下定决心。
Draco18s不再信任SE 2015年

3
@ Draco18s:您应该做的是用您自己的话语总结链接材料的要点。(或者,更好的是,根据您自己的经验回答问题,仅将链接用作辅助材料或用于进一步阅读。)短引号通常可以,尤其是在无法避免的情况下(例如引用某人的确切姓名)表示他们确实在说什么的词语),但引用文章的大部分内容实际上超出了合理使用范围
Ilmari Karonen

如果该点在圆内,则可以稍微走一下再回来。
user253751

(注:另请参见meta.SE上的两个问题。)
Ilmari Karonen 2015年

7

作为简单的解决方案,正如我在评论中所说,您可以尝试以下方法:

考虑一个阶段,您将船指向目标方向,在该阶段中,您对船ip进行了旋转但也进行了向前运动。当飞船已经面向目标时,您可以应用全速前进。我在love2d中安排了一个测试,在这里按照ship更新方法进行。

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

在此处输入图片说明

动画示例(最终循环)显示了船舶无法到达目标的情况,因为转弯和前进速度的组合定义了转弯半径太大,在这种情况下可以减小“ turnForwordSpeed”或更好地使其变小取决于角度距离(a)和目标距离。


这是一个很好的答案,但对于OP来说可能不现实。与汽车不同的是,轮船实际上并没有“转弯半径”:大多数自(发动机/人)驱动的轮船实际上可以转角钱,而帆船则依靠风,并且实际上可以具有负的有效转角。航行时的半径,即在向左转弯会导致船舶向右漂移的意义上。船只具有的只是惯性(和阻力):它们不能立即转动或移动,一旦移动或转动,就需要一些时间和力量才能停止。不过,请+1。
Ilmari Karonen 2015年

非常感谢您的回答!!!:)先生,你是我的英雄!
DavidT

@DavidT然后,如果可以令人满意地解决您的问题,则考虑将其答案标记为可接受的答案。:)
MAnd

-2

Unity Nav网格系统,只需稍微浏览一下nav agent值,就可以完成您想要的操作。

导航网格物体非常简单易用。并且仅在自上而下的设置中可用(或至少仅适用于x / z移动)

Unity手册中有关设置导航网格物体的页面

基本上,您可以使用任何形状的网格来烘焙导航区域,并将导航代理添加到对象,并让它们在导航网格周围找到其路径


我发现Draco18s在这方面也没有答案。但是,您的答案不是真正的答案,更不是评论。
没人2015年

2
这是一个很好的建议,但是,要想得到一个好的答案,它需要有关实施的支持和信息。请添加一些有关配置导航网格物体的信息,以使其成为一个很好的答案。我认为这就是上述评论者想要说的:)
sirdank
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.