【问题标题】:Flawless mouse collision detection and movement with rectangular shapes完美的鼠标碰撞检测和矩形移动
【发布时间】:2016-02-16 06:43:40
【问题描述】:

我之前发布了一篇与我正在从事的这个项目相关的帖子,但我收到的信息还不够,所以我只是把这些都放在盘子里。我正在进行的项目是一款与http://cursors.io 非常相似的游戏。玩家控制游戏中的光标,该光标跟随鼠标。但是,光标不能移动到墙和块等对象之外。

第三种方法,光标卡在十字路口

Terminology:

Cursor - The ingame object
Mouse  - The player's actual cursor

我尝试了几种方法。

方法 1

我尝试在每一帧移动玩家鼠标顶部的光标,如果它在可碰撞的形状对象内,它不会移动该帧。然而,这 如果用户暂停游戏、将鼠标移动到屏幕上的另一个位置并取消暂停,则会导致问题。或者,即使用户移动鼠标的速度足够快,可以在单帧内穿过一个对象的距离,他们也能够通过它“小故障”。

方法2

我尝试的下一个方法是在玩家鼠标的方向上每帧将光标移动一定数量的像素,应用与方法 1 相同的检查方法。这导致移动不平稳、缓慢,担心如果设置的像素移动太高,它仍然会跳过非常薄的障碍物。

方法 3

我尝试的最后一种方法是使用线段交点。我会定义一条从光标到鼠标的主线,然后是每个可碰撞对象的边界线。当鼠标移动时,我会检查主线段是否与任何边界线相交,如果是,则记录下来。检查完所有边界线后,保留最近的交叉点。我会将光标移动到那个交点并称之为完成。如果没有发生交叉点,我只需将光标移动到鼠标上。但问题在于,一旦光标移动到交叉点,它就会卡住。交点停留在光标的新位置,因为它仍然在边界线的正上方。同样,我想不出一种方法让光标在边界线上滑动,跟随鼠标的 x 或 y 移动而不经过。


一些示例代码:


# ============
#  Approach 1
# ============
# Game loop {
if not any([i.contains(mousepos) for i in collideables]):
    cursorpos = mousepos
# }

# ============
#  Approach 2
# ============
speed = 5

# Game loop {
dx = copysign(1, mousepos[0]-cursorpos[0])
dy = copysign(1, mousepos[1]-cursorpos[1])
destx = dx*speed
desty = dy*speed
if not any([i.contains([destx, desty]) for i in collideables]):
    cursorpos = [destx, desty]
# }

# ============
#  Approach 3
# ============
def lineIntersection(line1, line2):
    # intersection code to determine x and y of intersection, as well
    # as the distance across line1 to the intersection
    if intersection:
        return [x, y, distance]
    return None

# Game loop {
closestIntersect = None
for collideable in collideables:
    for boundaryline in collideable:
        intersect = lineIntersection(mainline, boundaryline)
        if intersect:
            if not closestIntersect or intersect[2] < closestIntersect[2]:
                closestIntersect = intersect
if closestIntersect:
    cursorpos = intersect[0], intersect[1]
# }

【问题讨论】:

  • 存储最后一个“好”的光标点,如果下次检查失败,恢复它?与方法#1非常相似。否则,尝试将光标从对象推出到最近的边缘是一件很痛苦的事情,尤其是当您有非凸多边形时。
  • @AndyG 存储最后一个好的光标点根本没有帮助。用户仍然可以通过跳过对象来“忽略”对象。
  • 生活就是这样;物理引擎通常甚至不会理会这种情况,因为时间步长通常小到足以捕获它。薄障碍物和快速物体一直是个问题。当然,您可以尝试多种技术;设置光标的最大速度上限,并应用您的线交叉点的想法。我建议对线交点进行修改,以计算交点处的表面法线,并将光标沿该法线“碰撞”一点。

标签: python pygame collision-detection


【解决方案1】:

我觉得方法3的代码其实没问题,但是游戏循环中的相交测试应该过滤掉与鼠标位置重合的伪相交。 IE。测试if intersect and mouse_position != xy_from_intersect 而不是if intersect

【讨论】:

  • 这适用于整数坐标,但浮点坐标可能会有一些问题(我认为是这样)
  • 但是如果不计算光标正上方的交叉点,下一帧光标会跳过那条边界线。
  • @Eugene AFAICT 当且仅当鼠标光标恰好位于交叉点上时才会出现问题,因此整数与浮点数应该没有区别。
  • @Neon-Wizard 原始代码不依赖于交叉点,它简单地(并且巧妙地)采用交叉点和鼠标光标之间距离最短的一条线。我认为没有真正的理由来计算与这种方法的交叉点。 可能 发生的情况是,如果线条有一个差一个错误并且没有完全覆盖角点,则存在鼠标可以偷偷穿过的间隙。这是关卡设计的问题,只要确保端点不会留下空隙。
【解决方案2】:

方法 3 是正确的,但多了一个: 我认为你必须在这里考虑法线。如果边缘法线和光标移动方向的点积不为负,则可以安全地移动光标。 在这里,我们假设该形状的法线朝外。

编辑: 关于交叉点-我认为您可以通过检查至少一个交叉点的边缘与光标方向的正常点积是否为负数来解决此问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2013-10-12
    • 2016-08-31
    相关资源
    最近更新 更多