【发布时间】:2015-10-10 17:24:12
【问题描述】:
我正在使用 Pygame 创建一个基于物理的游戏,其中玩家控制一个球。当您控制球时,它会沿指定方向加速(按住左箭头会在其移动速度上增加每帧 x 个像素)。由于球是……嗯……一个球,而且 Pygame 不支持球碰撞检测,我创建了一个具有自己的碰撞方法的新类。该方法有两个部分:如果球跑到矩形的角上,或者如果它跑到矩形的边上。问题与圆与侧碰撞有关。
球是基于一个矩形对象,因此有那些讨厌的角落。我不能使用简单的colliderect 方法,否则上述情况会检测到不应该存在的碰撞,并且它会与我的碰撞检测方法的第一部分重叠。相反,我选择在矩形和球矩形两边的中点之间使用collidepoint。
最后,问题的核心。我之前提到过球会加速。当球加速到某个点(即使它看起来静止不动)时,它会移动到足够远的位置进入矩形,以便圆上的另一个中点检测到“碰撞”。这个问题可能源于以下事实(对于球左侧的碰撞)我的代码将球的left 设置为等于矩形的right,因此当球加速到足以进入矩形时,它被移动到矩形的另一个面。
非常感谢您对我的包容,欢迎任何和所有建议。我要么正在寻找解决我的特定问题的方法,要么寻找一种更简洁的方式来处理碰撞检测。我的完整代码如下:
import pygame, sys, math
global Color
Color = {}
Color['white'] = (255,255,255)
Color['black'] = ( 0, 0, 0)
Color['red'] = (255, 0, 0)
Color['green'] = ( 0,255, 0)
Color['blue'] = ( 0, 0,255)
global WINDOWWIDTH, WINDOWHEIGHT
WINDOWWIDTH, WINDOWHEIGHT = 500, 500
class Ball():
def __init__(self, x, y, r):
self.rect = pygame.Rect(x, y, r, r)
self.radius = r/2
self.speed = [0, 0]
self.b_fact = 1
self.move = {'left':False, 'right':False, 'up':False, 'down':False}
self.new_dir = {'left':False, 'right':False, 'up':False, 'down':False}
def move_self(self):
if self.move['left']:
self.speed[0] -= 2
if self.move['up']:
self.speed[1] -= 2
if self.move['right']:
self.speed[0] += 2
if self.move['down']:
self.speed[1] += 2
if self.speed[0] < 0:
self.speed[0] += 1
if self.speed[1] < 0:
self.speed[1] += 1
if self.speed[0] > 0:
self.speed[0] -= 1
if self.speed[1] > 0:
self.speed[1] -= 1
self.rect.left += self.speed[0]
self.rect.top += self.speed[1]
def bounce(self, rectList):
for rect in rectList:
self.collide_rect(rect)
if self.rect.left <= 0:
self.rect.left = 0
self.new_dir['right'] = True
if self.rect.right >= WINDOWWIDTH:
self.rect.right = WINDOWWIDTH
self.new_dir['left'] = True
if self.rect.top <= 0:
self.rect.top = 0
self.new_dir['down'] = True
if self.rect.bottom >= WINDOWHEIGHT:
self.rect.bottom = WINDOWHEIGHT
self.new_dir['up'] = True
for key in self.new_dir:
if self.new_dir[key] and key=='left':
self.speed[0] *= (-1)*self.b_fact
if self.new_dir[key] and key=='right':
self.speed[0] *= (-1)*self.b_fact
if self.new_dir[key] and key=='up':
self.speed[1] *= (-1)*self.b_fact
if self.new_dir[key] and key=='down':
self.speed[1] *= (-1)*self.b_fact
self.new_dir[key] = False
def collide_rect(self, rect):
x1, y1, r = self.rect.centerx, self.rect.centery, self.radius
foundSide = 0
foundCorner = 0
side_list = ['left', 'right', 'bottom', 'top']
corner_list = ['topleft', 'topright', 'bottomleft', 'bottomright']
collision_list = []
for side in side_list:
if rect.collidepoint(eval('self.rect.mid'+side)):
collision_list.append(side)
for corner in corner_list:
x2, y2 = eval('rect.'+corner)[0], eval('rect.'+corner)[1]
dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
if dist < r:
if corner.find('left') > -1:
corner = corner.replace('left','right')
else:
corner = corner.replace('right','left')
if corner.find('top') > -1:
corner = corner.replace('top','bottom')
else:
corner = corner.replace('bottom','top')
collision_list.append(corner)
for direction in collision_list:
if direction.find('left') > -1:
self.rect.left = rect.right
self.new_dir['left'] = True
if direction.find('top') > -1:
self.rect.top = rect.bottom
self.new_dir['top'] = True
if direction.find('right') > -1:
self.rect.right = rect.left
self.new_dir['right'] = True
if direction.find('bottom') > -1:
self.rect.bottom = rect.top
self.new_dir['bottom'] = True
class BallGame():
def __init__(self):
pygame.display.set_caption("Ball is life")
pygame.init()
self.ball = Ball(0, 0, 30)
self.allRects = []
rect = pygame.Rect(60,60,50,50)
self.allRects.append(rect)
self.mainClock = pygame.time.Clock()
self.screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
self.basicFont = pygame.font.SysFont(None, 50)
def drawScreen(self):
self.screen.fill(Color['green'])
pygame.draw.ellipse(self.screen, Color['white'], self.ball.rect)
for rect in self.allRects:
pygame.draw.rect(self.screen, Color['black'], rect)
def mainloop(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for i in range(2):
k = (pygame.KEYUP, pygame.KEYDOWN)
if event.type == k[i]:
if event.key == pygame.K_LEFT:
self.ball.move['left'] = i
elif event.key == pygame.K_UP:
self.ball.move['up'] = i
elif event.key == pygame.K_RIGHT:
self.ball.move['right'] = i
elif event.key == pygame.K_DOWN:
self.ball.move['down'] = i
self.ball.move_self()
self.ball.bounce(self.allRects)
self.drawScreen()
pygame.display.update()
self.mainClock.tick(20)
Game = BallGame()
while True:
Game.mainloop()
【问题讨论】:
标签: python pygame collision-detection