python - 我如何让球从所有矩形边上反弹
问题描述
我在让球从墙壁上弹起时遇到问题,并且将矩形放在中间我尝试使用 if 语句但无法让它工作任何帮助将不胜感激,或者如果有任何其他错误可能是已修复以进一步优化代码,这也将不胜感激。
import pygame, random
pygame.init()
screen = pygame.display.set_mode([700,500])
# Set up global variables
class Ball():
x = y = xspeed = yspeed = colour = rad = 0
class rec():
x = y = w = h = colour = 0
w = screen.get_width()
h = screen.get_height()
rec.x = w/2
rec.y = h/2
rec.w = w/7
rec.h = h/5
# Create a list of balls
balls = []
# Create ball and include in the list of balls
for i in range(1):
ball = Ball()
ball.x = random.randint(0,w-ball.rad-ball.rad)
ball.y = random.randint(0,h-ball.rad-ball.rad)
ball.xspeed = random.randint(-2,2)
ball.yspeed = random.randint(-2,2)
while ball.xspeed == 0 or ball.yspeed == 0:
ball.xspeed = random.randint(-2,2)
ball.yspeed = random.randint(-2,2)
ball.rad = random.randint(5,30)
ball.colour = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
if ball.x + ball.rad <= w and ball.y + ball.rad <= h:
balls.append(ball)
#Game loop
while True:
# ===================== HANDLE EVENTS (DO NOT EDIT) ===================== #
done = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
done = True
break
if done == True:
break
# ============================== MOVE STUFF ============================= #
for ball in balls:
ball.x = ball.x + ball.xspeed
ball.y = ball.y + ball.yspeed
# ============================== COLLISION ============================== #
for ball in balls:
if ball.x - ball.rad <= 0 :
ball.xspeed = ball.xspeed * -1
elif ball.x + ball.rad >= w:
ball.xspeed = ball.xspeed * -1
elif ball.y - ball.rad<= 0 :
ball.yspeed = ball.yspeed * -1
elif ball.y + ball.rad >= h:
ball.yspeed = ball.yspeed * -1
elif ball.x + ball.rad <= rec.x or ball.x - ball.rad >= rec.x + rec.w:
ball.xspeed = ball.xspeed * -1
elif ball.y + ball.rad <= rec.y or ball.y - ball.rad <= rec.y + rec.h:
ball.yspeed = ball.yspeed * -1
elif ball.x + ball.rad == rec.x + rec.w:
ball.xspeed = ball.xspeed * -1
elif ball.x + ball.rad == rec.x:
ball.xspeed = ball.xspeed * -1
elif ball.y +ball.rad == rec.y + rec.h:
ball.yspeed = ball.yspeed * -1
elif ball.y + ball.rad == rec.y:
ball.yspeed = ball.yspeed * -1
# ============================== DRAW STUFF ============================= #
screen.fill ((255,255,255))
for ball in balls:
pygame.draw.circle (screen, (ball.colour), (ball.x,ball.y), ball.rad)
pygame.draw.rect(screen, (0,255,0), (rec.x, rec.y, rec.w, rec.h))
# ====================== PYGAME STUFF (DO NOT EDIT) ===================== #
pygame.display.flip()
pygame.time.delay(20)
解决方案
计算球心到障碍物中心的距离
dx = ball.x - rect.centerx
dy = ball.y - rect.centery
移动球的方式是,一旦检测到碰撞,它正在接触球员但不与球员相交。仅当球的运动矢量指向“反”球的方向时,才反映球的运动。球可以通过以下方式反射到障碍物上pygame.math.Vector2.reflect_ip
:
v = pygame.math.Vector2(ball.xspeed, ball.yspeed)
if abs(dx) > abs(dy):
ball.x = rect.left-ball.rad if dx < 0 else rect.right+ball.rad
if (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0):
v.reflect_ip(pygame.math.Vector2(1, 0))
else:
ballposy = rect.top-ball.rad if dy < 0 else rect.bottom+ball.rad
if (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0):
v.reflect_ip(pygame.math.Vector2(0, 1))
ball.xspeed, ball.yspeed = v.x, v.y
另请参阅如何避免 PyGame 中圆形和矩形之间的小故障碰撞?
最小的例子:
import pygame, random
pygame.init()
screen = pygame.display.set_mode([700,500])
clock = pygame.time.Clock()
# Set up global variables
class Ball():
x = y = xspeed = yspeed = colour = rad = 0
class rec():
x = y = w = h = colour = 0
w = screen.get_width()
h = screen.get_height()
rect_list = [
pygame.Rect(w//4, h//4, w//7, h //5),
pygame.Rect(w*3//4, h*3//4, w//7, h //5)]
# Create a list of balls
balls = []
# Create ball and include in the list of balls
for i in range(1):
ball = Ball()
ball.x = random.randint(0,w-ball.rad-ball.rad)
ball.y = random.randint(0,h-ball.rad-ball.rad)
ball.xspeed = random.randint(-2,2)
ball.yspeed = random.randint(-2,2)
while ball.xspeed == 0 or ball.yspeed == 0:
ball.xspeed = random.randint(-2,2)
ball.yspeed = random.randint(-2,2)
ball.rad = random.randint(5,30)
ball.colour = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
if ball.x + ball.rad <= w and ball.y + ball.rad <= h:
balls.append(ball)
#Game loop
while True:
# ===================== HANDLE EVENTS (DO NOT EDIT) ===================== #
done = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
done = True
break
if done == True:
break
# ============================== MOVE STUFF ============================= #
for ball in balls:
ball.x = ball.x + ball.xspeed
ball.y = ball.y + ball.yspeed
# ============================== COLLISION ============================== #
for ball in balls:
if ball.x - ball.rad <= 0:
ball.xspeed = abs(ball.xspeed)
elif ball.x + ball.rad >= w:
ball.xspeed = -abs(ball.xspeed)
if ball.y - ball.rad<= 0 :
ball.yspeed = abs(ball.yspeed)
elif ball.y + ball.rad >= h:
ball.yspeed = -abs(ball.yspeed)
for rect in rect_list:
ball_rect = pygame.Rect((0,0), (ball.rad*2, ball.rad*2))
ball_rect.center = int(ball.x),int(ball.y)
if rect.colliderect(ball_rect):
v = pygame.math.Vector2(ball.xspeed, ball.yspeed)
dx = ball.x - rect.centerx
dy = ball.y - rect.centery
if abs(dx) > abs(dy):
ball.x = rect.left-ball.rad if dx < 0 else rect.right+ball.rad
if (dx < 0 and v[0] > 0) or (dx > 0 and v[0] < 0):
v.reflect_ip(pygame.math.Vector2(1, 0))
else:
ballposy = rect.top-ball.rad if dy < 0 else rect.bottom+ball.rad
if (dy < 0 and v[1] > 0) or (dy > 0 and v[1] < 0):
v.reflect_ip(pygame.math.Vector2(0, 1))
ball.xspeed, ball.yspeed = v.x, v.y
# ============================== DRAW STUFF ============================= #
screen.fill ((255,255,255))
for ball in balls:
pygame.draw.circle (screen, (ball.colour), (ball.x,ball.y), ball.rad)
for rect in rect_list:
pygame.draw.rect(screen, (0,255,0), rect)
# ====================== PYGAME STUFF (DO NOT EDIT) ===================== #
pygame.display.flip()
clock.tick(100)
推荐阅读
- sql - 如何在 Microsoft SQL Server 中创建数据透视表?
- haskell - GHCi/Haskell 对黑色典当 unicode 字符有什么问题?
- c# - How to add icons to the listview in windows Forms c#
- python - Python Flask: How do I get around 'ERROR in app: Exception on / [GET]'?
- amazon-web-services - How can I use IAM to invoke AppSync wtihin AWS Lambda?
- kotlin - 将调用 Fragment 使用的 ViewModel 共享给 ViewModels 使用的 DialogFragment
- python - 使用 python 'pefile' 模块解析 PE 文件
- html - 减小浏览器窗口大小时动态减小部分宽度
- node.js - 更新 npm 安装包 - npm ERR!代码 EINVALIDPACKAGENAME
- flutter - Flutter 中使用 SharedPreferences 的动态列表