计算墙角和2D中的滑动

最近有一个新的项目,我不使用任何物理引擎,但它需要一些基本的phyiscs。 基本上这是一个2D的“自上而下”的游戏types。 我想增加一个光滑的墙壁碰撞比那些“跳跃”感觉更好。 所以这里是多么糟糕,我很容易用这种方式来计算碰撞点:

  1. 将速度添加到玩家的位置。
  2. 检查新的位置是否在墙上。
  3. 在那个“来自”的向量上倒退,直到达到第一个非碰撞位置。

现在我有了蓝色的位置,我想用这个紫色的角度来修改玩家的vector角度(我猜)。 因为我希望玩家到达那个位置时会发生下一件事情:

  • 玩家获得了墙的角度,然后走到旁边(当然,只有当玩家仍然按下键才能向上移动)就像大多数AAA 3D游戏一样。 例如TESV:天际。 如果你正朝一个非90°角的墙壁或物体移动,那么玩家将继续移动,但靠近墙壁/物体。

我已经在Google上search了解决scheme,但是这些解决scheme都不符合我的需求。
将不胜感激任何帮助。 谢谢!

编辑:

  • 绿线 :墙(最上面一个,最下面一个帮忙)
  • 紫点 :球员旧的位置
  • 蓝点 :玩家新位置(靠墙)
  • 红线 :新旧位置之间的vector

    编辑2:
    不能让它正常工作,在墙的边缘计算失败。 玩家在传送过程中有时会冻结。 (由于正在检查边缘的周期)

_

有多less游戏不是在碰撞被解决之后改变速度,而是解决碰撞的方式,或者在你的场景中,你如何find玩家新的位置(蓝色P)。

你解释说,你只是沿着vector回溯你的步骤来提出这个位置。 而不是做你所做的事情,解决冲突和实现这种滑动效果的相当常见的方法是通过投影。 这个和其他碰撞检测/解决方法在这里详细讨论。

通过使用投影,您将最终得到像您正在寻找的滑动效果,因为您正在使用尽可能最短的距离解决沿着墙的位置,而不是像下图所示简单地回溯您的步骤:

通过投影碰撞解决

引用上面关于通过投影解决碰撞的链接文章,下面是如何find投影向量和一个交互的例子可以在这里find。

将向量a投影到向量b上的公式是:

proj.x =(dp /(bx bx + by by))* bx; proj.y =(dp /(bx bx + by by))* by;

其中dp是a和b的点数:dp =(ax bx + ay by)

请注意,结果是一个向量; 另外,(bx bx + by by)就是b的长度。

如果b是单位vector,则(bx bx + by by)= 1,因此投影到b上减less为:

proj.x = dp * bx;

proj.y = dp * by;

要获得墙的vector,你只需要知道墙上的两个点。 它可能是两个角落,碰撞点和一个角落等。一旦你有两个点,你减去坐标来find结果向量。

例如给定P 1和Q 3,则P Q = Q·P

= PQ <3-1,5-2>

= PQ <2,3>;

如果你有一个图书馆,可以减去vector这更容易为你。 我不相信方向在这个计算中是重要的,但如果我错了,你发现你正在变得一个奇怪的行为,尝试减去相反的方向,看看是否有帮助。

这个答案将重点放在原帖中的陈述#3,并且是为了补充ToddersLegrande的答案

3。 在那个“来自”的向量上倒退,直到达到第一个非碰撞位置。

这个想法很容易失败,因为你已经发现了,幸运的是有一个封闭的解决scheme可用,我会在这里做深入的。


给定一条线上的一组点,将坐标插入线方程(y = m * x + b)产生一个方程组,该方程组可以被求解以find给定线的斜率截距forms。

从玩家的立场开始,我们断言:

然后我们还断言,速度之后的玩家的位置是在同一条线上:

有了足够的信息来定义现在可用的线,我们可以解决球员的斜线和拦截线的运动find:

应用相同的技术find墙的斜率和截距,得出:

通过求解由这两个直线方程构成的系统,我们find一个直接计算交点的(相当大的)公式,我已经把它作为代码格式化,以防万一你不熟悉最大值

Vec2 FindIntersection(Vec2 player,Vec2 motion,Vec2 wall1,Vec2 wall2) { return Vec2( -(motion.x*(wall1.x*wall2.y-wall1.y*wall2.x) +motion.x*player.y*(wall2.x-wall1.x)+motion.y*player.x *(wall1.x-wall2.x))/(motion.x*(wall1.y-wall2.y) +motion.y*(wall2.x-wall1.x)), -(motion.y*(wall1.x*wall2.y-wall1.y*wall2.x) +motion.x*player.y*(wall2.y-wall1.y)+motion.y*player.x *(wall1.y-wall2.y))/(motion.x*(wall1.y-wall2.y) +motion.y*(wall2.x-wall1.x)) ); } 

以下是我在Maxima上做的事情:

 (%i) FindIntersection(PlayerX,PlayerY, MotionX,MotionY, WallVert1X,WallVert1Y, WallVert2X,WallVert2Y) := ''(solve( subst(solve([PlayerY=pm*PlayerX+pb,(PlayerY+MotionY)=pm*(PlayerX+MotionX)+pb],[pm,pb]), subst(solve([WallVert1Y=wm*WallVert1X+wb,WallVert2Y=wm*WallVert2X+wb],[wm,wb]), [IntersectionY=pm*IntersectionX+pb,IntersectionY=wm*IntersectionX+wb] )), [IntersectionX,IntersectionY])); (%o) FindIntersection(PlayerX,PlayerY,MotionX,MotionY,WallVert1X,WallVert1Y,WallVert2X,WallVert2Y) := [IntersectionX=-(MotionX*(WallVert1X*WallVert2Y-WallVert1Y*WallVert2X) +MotionX*PlayerY*(WallVert2X-WallVert1X)+MotionY*PlayerX *(WallVert1X-WallVert2X))/(MotionX*(WallVert1Y-WallVert2Y) +MotionY*(WallVert2X-WallVert1X)), IntersectionY=-(MotionY*(WallVert1X*WallVert2Y-WallVert1Y*WallVert2X) +MotionX*PlayerY*(WallVert2Y-WallVert1Y)+MotionY*PlayerX *(WallVert1Y-WallVert2Y))/(MotionX*(WallVert1Y-WallVert2Y) +MotionY*(WallVert2X-WallVert1X))]