我目前正在使用pygame创建一个Python游戏,我的人工智能当前可以“看到”穿过墙壁并射击我的角色,但是人工智能不应该射击。我的问题是:如何防止这种情况?我已经考虑了一条从我的人工智能到我的角色的线碰撞,在这条线与墙壁相碰时,人工智能不会射击。任何帮助将不胜感激,非常感谢!
(x, y) → (x+width, y) # top
(x+width, y) → (x+width, y+height) # right
(x, y+height) → (x+width, y+height) # bottom
(x, y) → (x, y+height) # left
pygame.Rect.collidepoint()
的整个矩形是否相交。
当然,一旦您生成了所有这些点,就很容易不必理会2D线碰撞,但对于长线而言,代码必须进行大量检查。因此,首先测试2D交点确实可以加快速度。
pygame.Rect.clipline
:
返回被裁剪为完全位于矩形内部的线的坐标。如果线不与矩形重叠,则返回一个空元组。
e.g.:
rect = pygme.Rect(x, y, width, height)
if rect.clipline((x1, y1), (x2, y2)):
print("hit")
最简示例
import pygame
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
rect = pygame.Rect(180, 180, 40, 40)
speed = 5
lines = [((20, 300), (150, 20)), ((250, 20), (380, 250)), ((50, 350), (350, 300))]
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed
rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed
rect.centerx %= window.get_width()
rect.centery %= window.get_height()
color = "red" if any(rect.clipline(*line) for line in lines) else "green"
window.fill(0)
pygame.draw.rect(window, color, rect)
for line in lines:
pygame.draw.line(window, "white", *line)
pygame.display.flip()
pygame.quit()
exit()
基本上,pygame 没有任何方法或功能可以检测与线段的碰撞,这就是为什么我不得不想出下面要展示的解决方案。
使用以下 链接,在“公式/给定每条线段上的两个点”部分,您可以找到一个公式,以知道两条线是否相交,如果相交,则确切地在哪里。
基本思路是检查光源中的每个射线是否与矩形的四条边之一相交,如果是,则光线应该在矩形的同一侧结束。
import pygame, math
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Rays')
pygame.mouse.set_visible(False)
DENSITY = 500
RADIUS = 1000
run = True
while run:
screen.fill('black')
rect = pygame.Rect(50, 200, 100, 50)
pygame.draw.rect(screen, 'red', rect)
for i in range(DENSITY):
mouse_pos = pygame.mouse.get_pos()
pos_fin = (RADIUS * math.cos(2*math.pi / DENSITY * i) + mouse_pos[0], RADIUS * math.sin(2*math.pi / DENSITY * i) + mouse_pos[1])
if rect.collidepoint(mouse_pos) == False:
for extrem_1, extrem_2 in [(rect.bottomright, rect.topright), (rect.topright, rect.topleft), (rect.topleft, rect.bottomleft), (rect.bottomleft, rect.bottomright)]:
deno = (mouse_pos[0] - pos_fin[0]) * (extrem_1[1] - extrem_2[1]) - (mouse_pos[1] - pos_fin[1]) * (extrem_1[0] - extrem_2[0])
if deno != 0:
param_1 = ((extrem_2[0] - mouse_pos[0]) * (mouse_pos[1] - pos_fin[1]) - (extrem_2[1] - mouse_pos[1]) * (mouse_pos[0] - pos_fin[0]))/deno
param_2 = ((extrem_2[0] - mouse_pos[0]) * (extrem_2[1] - extrem_1[1]) - (extrem_2[1] - mouse_pos[1]) * (extrem_2[0] - extrem_1[0]))/deno
if 0 <= param_1 <= 1 and 0 <= param_2 <= 1:
p_x = mouse_pos[0] + param_2 * (pos_fin[0] - mouse_pos[0])
p_y = mouse_pos[1] + param_2 * (pos_fin[1] - mouse_pos[1])
pos_fin = (p_x, p_y)
pygame.draw.aaline(screen, 'white', mouse_pos, pos_fin)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
这可能不是最好的、最优化的代码,但最终你应该能得到一个可用的东西。
for x in range(ai_x, player_x)
来获取AI到玩家连线上的每个点,并检查该循环中每个点与墙壁的碰撞。 - furas