问题描述
乒乓球拍移动得如此之快,以至于在检测到碰撞之前,球就在球拍内卷起.问题是用户输入将桨移动了一个像素,所以我不知道如何减慢它的速度.什么是修复?代码如下:
导入pygame、sys、os从 pygame 导入*从 pygame.locals 导入*白色 = (255, 255, 255)绿色 = (0, 255, 0)蓝色 = (0, 0, 128)红色 = (255,0,0)os.environ["SDL_VIDEO_CENTERED"]="1"显示大小=600DISPLAYSURF = pygame.display.set_mode((displaysize,displaysize))矩形宽度 = 50矩形高度= 50rectposx =0rectposy =0类播放器(对象):def __init__(self):self.rect = pygame.rect.Rect((rectposx, rectposy, rectwidth, rectheight))def handle_keys(self):键 = pygame.key.get_pressed()距离 = 1如果 key[pygame.K_LEFT] 和 (player.rect.x>0):self.rect.move_ip(-1, 0)如果 key[pygame.K_RIGHT] 和 (player.rect.x<600-rectwidth):self.rect.move_ip(1, 0)如果 key[pygame.K_UP] 和 (player.rect.y>0):self.rect.move_ip(0, -1)如果 key[pygame.K_DOWN] 和 (player.rect.y600:v[1]=-v[1]如果 player.rect.colliderect(ball):pygame.math.Vector2.reflect_ip(v,-v+5*pygame.math.Vector2(rectvelx,rectvely))#print (player.rect.x, rectposy, ball.x, ball.y)球质量=1矩形质量=5rectposx=rectposx1rectposy=rectposy1打印(五)#raise SystemExit("你赢了!")pygame.display.update()时钟滴答(120)
有两种策略可以解决这个问题.
以某种方式移动球,使其在检测到碰撞后接触玩家但不与玩家相交.例如:
dx = ballposx - player.rect.centerxdy = ballposy - player.rect.centery如果 abs(dx) >绝对(dy):ballposx = player.rect.left-ballrad 如果 dx
仅当球的运动矢量指向反对"方向时才反映球的运动.球.例如:
if abs(dx) >绝对(dy):如果 (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0):v.reflect_ip(pygame.math.Vector2(1, 0))别的:如果 (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0):v.reflect_ip(pygame.math.Vector2(0, 1))
另见
ball = pygame.Rect((0,0), (ballrad*2, ballrad*2))ball.center = int(ballposx),int(ballposy)如果 player.rect.colliderect(ball):dx = ballposx - player.rect.centerxdy = ballposy - player.rect.centery如果 abs(dx) >绝对(dy):ballposx = player.rect.left-ballrad 如果 dx
如果您想避免玩家将球推出窗外,您需要将球限制在窗外区域,并像台球一样将球反射到窗外:
min_x, min_y, max_x, max_y = 0, 0, window.get_width(), window.get_height()ballposx = ballposx + v[0]*dtballposy = ballposy + v[1]*dt如果 ballposx-ballrad 最大_x:ballposx = max_x-ballradv[0]=-v[0]如果 ballposy + ballrad >max_y:ballposy = max_y-ballradv[1]=-v[1]
另见
最小示例:
导入pygame类播放器(对象):def __init__(self, x, y, w, h):self.rect = pygame.rect.Rect(x, y, w, h)def handle_keys(self):键 = pygame.key.get_pressed()如果键[pygame.K_LEFT]:self.rect.left = max(20, self.rect.left - 1)如果键[pygame.K_RIGHT]:self.rect.right = min(window.get_height() - 20, self.rect.right + 1)如果键[pygame.K_UP]:self.rect.top = max(20, self.rect.top - 1)如果键[pygame.K_DOWN]:self.rect.bottom = min(window.get_width() - 20, self.rect.bottom + 1)def draw(self,surface):pygame.draw.rect(surface, (0, 0, 128), self.rect)pygame.init()窗口 = pygame.display.set_mode((240, 240))时钟=pygame.time.Clock()玩家 = 玩家(20, 20, 50, 50)v, vel = pygame.math.Vector2(1, 1), 0.5ballPosX, ballPosY, ballRadius = 120, 120, 10运行 = 真运行时:时钟滴答(120)对于 pygame.event.get() 中的事件:如果 event.type==pygame.QUIT:运行 = 错误player.handle_keys()min_x, min_y, max_x, max_y = 20, 20, window.get_width()-20, window.get_height()-20ballPosX += v[0] * velballPosY += v[1] * vel如果 ballPosX - ballRadius 最大_x:ballPosX = max_x - ballRadiusv[0] = -v[0]如果 ballPosY + ballRadius >max_y:ballPosY = max_y - ballRadiusv[1] = -v[1]ball = pygame.Rect((0,0), (ballRadius*2, ballRadius*2))ball.center = int(ballPosX),int(ballPosY)如果 player.rect.colliderect(ball):dx = ballPosX - player.rect.centerxdy = ballPosY - player.rect.centery如果 abs(dx) >绝对(dy):如果 dx
The pong paddle moves so fast that the ball winds up inside the paddle before the collision is detected. The problem is the user input moves the paddle by a single pixel so I don't know how to slow it down. What is the fix? Here is the code:
import pygame, sys, os
from pygame import*
from pygame.locals import*
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
RED = (255,0,0)
os.environ["SDL_VIDEO_CENTERED"]="1"
displaysize=600
DISPLAYSURF = pygame.display.set_mode((displaysize,displaysize))
rectwidth = 50
rectheight= 50
rectposx =0
rectposy =0
class Player(object):
def __init__(self):
self.rect = pygame.rect.Rect((rectposx, rectposy, rectwidth, rectheight))
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_LEFT] and (player.rect.x>0):
self.rect.move_ip(-1, 0)
if key[pygame.K_RIGHT] and (player.rect.x<600-rectwidth):
self.rect.move_ip(1, 0)
if key[pygame.K_UP] and (player.rect.y>0):
self.rect.move_ip(0, -1)
if key[pygame.K_DOWN] and (player.rect.y<600-rectheight):
self.rect.move_ip(0, 1)
def draw(self, DISPLAYSURF):
pygame.draw.rect(DISPLAYSURF, BLUE, self.rect)
def postext(self):
pygame.image.load(self.rect).convert_alpha()
pygame.init()
player =Player()
pygame.display.set_caption('Hello World!')
clock=pygame.time.Clock()
fontObj = pygame.font.Font(None,32)
textSurfaceObj = fontObj.render('Hello World!', True, GREEN, BLUE)
#textPosition =
dt=0.1
v = pygame.math.Vector2(5,5)
ballposx=200
ballposy=200
ballrad=10
#DISPLAYSURF.fill(WHITE)
#x=10
#y=10
#dx=5
#rectpos = pygame.Rect(x,y,50,50)
#rect = pygame.draw.rect(DISPLAYSURF, BLUE, rectpos)
pygame.display.update()
running = True
n=0
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.type==QUIT:
pygame.quit()
sys.exit
player.handle_keys()
ballposx=ballposx+v[0]*dt
ballposy=ballposy+v[1]*dt
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(textSurfaceObj,(0,0))
player.draw(DISPLAYSURF)
ball=pygame.draw.circle(DISPLAYSURF, GREEN, (int(ballposx),int(ballposy)), ballrad)
rectposx1=player.rect.x
rectposy1=player.rect.y
rectvelx=-(rectposx-rectposx1)/dt
rectvely=-(rectposy-rectposy1)/dt
if ballposx-ballrad<0:
v[0]=-v[0]
if ballposy-ballrad<0:
v[1]=-v[1]
if ballposx+ballrad>600:
v[0]=-v[0]
if ballposy+ballrad>600:
v[1]=-v[1]
if player.rect.colliderect(ball):
pygame.math.Vector2.reflect_ip(v,-v+5*pygame.math.Vector2(rectvelx,rectvely))
#print (player.rect.x, rectposy, ball.x, ball.y)
ballmass=1
rectmass=5
rectposx=rectposx1
rectposy=rectposy1
print (v)
#raise SystemExit("You win!")
pygame.display.update()
clock.tick(120)
There are 2 strategies to a void that.
Move the ball in the way, that it is touching the player but not intersecting the player once a collision is detected. e.g.:
dx = ballposx - player.rect.centerx dy = ballposy - player.rect.centery if abs(dx) > abs(dy): ballposx = player.rect.left-ballrad if dx < 0 else player.rect.right+ballrad else: ballposy = player.rect.top-ballrad if dy < 0 else player.rect.bottom+ballrad
Reflect the movement of the ball only if its movement vector points in a direction "against" the ball. e.g.:
if abs(dx) > abs(dy): if (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0): v.reflect_ip(pygame.math.Vector2(1, 0)) else: if (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0): v.reflect_ip(pygame.math.Vector2(0, 1))
See also Sometimes the ball doesn't bounce off the paddle in pong game
Applying these 2 fixes to your code the ball will reflect properly on the player. e.g.:
ball = pygame.Rect((0,0), (ballrad*2, ballrad*2))
ball.center = int(ballposx),int(ballposy)
if player.rect.colliderect(ball):
dx = ballposx - player.rect.centerx
dy = ballposy - player.rect.centery
if abs(dx) > abs(dy):
ballposx = player.rect.left-ballrad if dx < 0 else player.rect.right+ballrad
if (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0):
v.reflect_ip(pygame.math.Vector2(1, 0))
else:
ballposy = player.rect.top-ballrad if dy < 0 else player.rect.bottom+ballrad
if (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0):
v.reflect_ip(pygame.math.Vector2(0, 1))
If you want to avoid the player pushing the ball out of the window, you need to restrict the ball to the window area and reflect the ball off the edges of the window like a pool ball:
min_x, min_y, max_x, max_y = 0, 0, window.get_width(), window.get_height()
ballposx = ballposx + v[0]*dt
ballposy = ballposy + v[1]*dt
if ballposx-ballrad < min_x:
ballposx = ballrad+min_x
v[0]=-v[0]
if ballposy-ballrad < min_y:
ballposy = ballrad+min_y
v[1]=-v[1]
if ballposx + ballrad > max_x:
ballposx = max_x-ballrad
v[0]=-v[0]
if ballposy + ballrad > max_y:
ballposy = max_y-ballrad
v[1]=-v[1]
See also Use vector2 in pygame. Collide with the window frame and restrict the ball to the rectangular area respectively How to make ball bounce off wall with Pygame?.
When a collision is detected, the player's position must be restricted so that the ball can take place between the widow boundary and the player:
if abs(dx) > abs(dy):
if dx < 0:
ballposx = max(player.rect.left-ballrad, ballrad+min_x)
player.rect.left = int(ballposx)+ballrad
else:
ballposx = min(player.rect.right+ballrad, max_x-ballrad)
player.rect.right = int(ballposx)-ballrad
With these changes, the ball can even be "squeezed" between the edge of the window and the player:
Minimal example:
import pygame
class Player(object):
def __init__(self, x, y, w, h):
self.rect = pygame.rect.Rect(x, y, w, h)
def handle_keys(self):
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.rect.left = max(20, self.rect.left - 1)
if key[pygame.K_RIGHT]:
self.rect.right = min(window.get_height() - 20, self.rect.right + 1)
if key[pygame.K_UP]:
self.rect.top = max(20, self.rect.top - 1)
if key[pygame.K_DOWN]:
self.rect.bottom = min(window.get_width() - 20, self.rect.bottom + 1)
def draw(self, surface):
pygame.draw.rect(surface, (0, 0, 128), self.rect)
pygame.init()
window = pygame.display.set_mode((240, 240))
clock=pygame.time.Clock()
player = Player(20, 20, 50, 50)
v, vel = pygame.math.Vector2(1, 1), 0.5
ballPosX, ballPosY, ballRadius = 120, 120, 10
run = True
while run:
clock.tick(120)
for event in pygame.event.get():
if event.type==pygame.QUIT:
run = False
player.handle_keys()
min_x, min_y, max_x, max_y = 20, 20, window.get_width()-20, window.get_height()-20
ballPosX += v[0] * vel
ballPosY += v[1] * vel
if ballPosX - ballRadius < min_x:
ballPosX = ballRadius + min_x
v[0] = -v[0]
if ballPosY - ballRadius < min_y:
ballPosY = ballRadius + min_y
v[1] = -v[1]
if ballPosX + ballRadius > max_x:
ballPosX = max_x - ballRadius
v[0] = -v[0]
if ballPosY + ballRadius > max_y:
ballPosY = max_y - ballRadius
v[1] = -v[1]
ball = pygame.Rect((0,0), (ballRadius*2, ballRadius*2))
ball.center = int(ballPosX),int(ballPosY)
if player.rect.colliderect(ball):
dx = ballPosX - player.rect.centerx
dy = ballPosY - player.rect.centery
if abs(dx) > abs(dy):
if dx < 0:
ballPosX = max(player.rect.left-ballRadius, ballRadius+min_x)
player.rect.left = int(ballPosX)+ballRadius
else:
ballPosX = min(player.rect.right+ballRadius, max_x-ballRadius)
player.rect.right = int(ballPosX)-ballRadius
if (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0):
v.reflect_ip(pygame.math.Vector2(1, 0))
else:
if dy < 0:
ballPosY = max(player.rect.top-ballRadius, ballRadius+min_y)
player.rect.top = int(ballPosY)+ballRadius
else:
ballPosY = min(player.rect.bottom+ballRadius, max_y-ballRadius)
player.rect.bottom = int(ballPosY)-ballRadius
ballPosY = player.rect.top-ballRadius if dy < 0 else player.rect.bottom+ballRadius
if (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0):
v.reflect_ip(pygame.math.Vector2(0, 1))
window.fill((255, 255, 255))
pygame.draw.rect(window, (255,0,0), (18, 18, 203, 203), 2)
player.draw(window)
pygame.draw.circle(window, (0, 255, 0), (round(ballPosX), round(ballPosY)), ballRadius)
pygame.display.update()
pygame.quit()
exit()
这篇关于如何避免 PyGame 中圆形和矩形之间的小故障碰撞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!