python - 使光标无法在 Sprite pygame中移动

标签 python python-3.x pygame

所以我的问题很简单:如何制作一个我的鼠标无法穿过的 Sprite ?我一直在尝试,发现了一种不可靠的方法,而且也很容易出问题。如果有人知道我该怎么做,请帮忙。

这是我当前正在使用的代码:

import pygame
import pyautogui
import sys
import time

pygame.init()
game_display = pygame.display.set_mode((800,600))
pygame.mouse.set_visible(True)
pygame.event.set_grab(True)
exit = False

class Wall(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((30, 100))
        self.image.fill((255, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.center = (200, 200)

    def collision(self):
        loc = pygame.mouse.get_pos()
        yy = loc[1]
        xx = loc[0]
        if yy >= self.rect.top and yy <= self.rect.bottom and xx >= self.rect.left and xx <= self.rect.right:
            if xx >= 200: 
                pyautogui.move(216 - xx, 0)
            if xx <= 200: 
                pyautogui.move(-xx + 184, 0)            

w = Wall()
all_sprites = pygame.sprite.Group()
all_sprites.add(w)
print(w.rect.top)
print(w.rect.bottom)
while (not exit):
    mouse_move = (0,0)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                exit = True 
    w.collision()
    clock = pygame.time.Clock()
    game_display.fill((0, 0, 0))
    clock.tick(30)
    all_sprites.update()
    all_sprites.draw(game_display)
    pygame.display.flip()
pygame.quit()

注意:请忽略我额外的导入语句,我稍后会使用它们。

最佳答案

要执行您想要的操作,您必须检查从前一个鼠标位置到新鼠标位置的直线是否与矩形相交。编写一个函数 IntersectLineRec 来检查交点并使用它并返回交点列表,按距离排序。 该函数返回一个包含点和距离的图列表:

例如

[((215.0, 177.0), 12.0), ((185.0, 177.0), 42.0)]
prev_loc = pygame.mouse.get_pos()

class Wall(pygame.sprite.Sprite):

    # [...]

    def collision(self):

        global prev_loc

        loc = pygame.mouse.get_pos()
        intersect = IntersectLineRec(prev_loc, loc, self.rect)
        prev_loc = loc

        if intersect:
            ip = [*intersect[0][0]]
            for i in range(2):
                tp = self.rect.center[i] if ip[i] == loc[i] else loc[i]
                ip[i] += -3 if ip[i] < tp else 3
            pyautogui.move(ip[0]-loc[0], ip[1]-loc[1])
            prev_loc = loc = ip

函数 IntersectLineRec 必须检查矩形 4 个角之间的 4 条外线之一是否与鼠标位置之间的线相交:

def IntersectLineRec(p1, p2, rect):
    iL = [
        IntersectLineLine(p1, p2, rect.bottomleft, rect.bottomright),
        IntersectLineLine(p1, p2, rect.bottomright, rect.topright),
        IntersectLineLine(p1, p2, rect.topright, rect.topleft),
        IntersectLineLine(p1, p2, rect.topleft, rect.bottomleft) ]
    iDist = [(i[1], pygame.math.Vector2(i[1][0] - p1[0], i[1][1] - p1[1]).length()) for i in iL if i[0]]
    iDist.sort(key=lambda t: t[1])
    return iDist

IntersectLineRec 检查由 to 点定义的无限线是否相交。然后它检查交点是否在由每条线定义的矩形中(该线是矩形的对角线):

def IntersectLineLine(l1_p1, l1_p2, l2_p1, l2_p2):
    isect, xPt = IntersectEndlessLineLine(l1_p1, l1_p2, l2_p1, l2_p2)
    isect = isect and PtInRect(xPt, l1_p1, l1_p2) and PtInRect(xPt, l2_p1, l2_p2)
    return isect, xPt

要检查一个点是否在轴对齐的矩形中,必须检查该点的两个坐标是否在矩形的坐标范围内:

def InRange(coord, range_s, range_e):
    if range_s < range_e:
        return coord >= range_s and coord <= range_e
    return coord >= range_e and coord <= range_s

def PtInRect(pt, lp1, lp2):
    return InRange(pt[0], lp1[0], lp2[0]) and InRange(pt[1], lp1[1], lp2[1])

无限线的交点可以这样计算:

def IntersectEndlessLineLine(l1_p1, l1_p2, l2_p1, l2_p2):

    # calculate the line vectors and test if both lengths are > 0
    P = pygame.math.Vector2(*l1_p1)
    Q = pygame.math.Vector2(*l2_p1)
    line1 = pygame.math.Vector2(*l1_p2) - P
    line2 = pygame.math.Vector2(*l2_p2) - Q
    if line1.length() == 0 or line2.length() == 0:
        return (False, (0, 0))

    # check if the lines are not parallel
    R, S = (line1.normalize(), line2.normalize())
    dot_R_nvS = R.dot(pygame.math.Vector2(S[1], -S[0]))
    if abs(dot_R_nvS) < 0.001:
        return (False, (0, 0))

    # calculate the intersection point of the lines
    # t  =  dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x))
    # X  =  P + R * t
    ptVec = Q-P
    t = ptVec.dot(pygame.math.Vector2(S[1], -S[0])) / dot_R_nvS
    xPt = P + R * t
    return (True, (xPt[0], xPt[1]))

观看动画:

关于python - 使光标无法在 Sprite pygame中移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54509869/

相关文章:

python - Conda:当前 osx-64 channel 中缺少依赖项

python - 根据另一列的 id 连接一列中的字符串

Python - PyGame - 学习向量/动画

python - 在pygame中实现曲线上的碰撞检测

python - 使用python将标题添加到制表符分隔的csv文件

python - Partition Equal Subset Sum 的解决方案性能(DP,哈希表)

python-3.x - tensorflow tensorflow.contrib.learn.Estimator 加载训练模型

python - str 到 python 3 中的时间对象

python - 类型错误 : must be pygame. 表面,而不是元组。 Python/Pygame 菜鸟

python - pytz 和 python-dateutil 有什么区别?