python - PyGame 碰撞系统每隔一段时间才工作一次
问题描述
当我发现一个奇怪的错误时,我正试图为我的简单游戏制作一个有效的碰撞系统。有一个随机位置的矩形,以恒定的速度向上移动。然后还有一个位置随机的球,但可以使用箭头移动。当球击中矩形时,它应该与矩形一起上升,就好像矩形“抓住了球”一样,当球离开矩形时,它应该再次落下。
这是我的代码:
import time
import random
import pygame
from pygame.locals import *
pygame.init()
# Window size.
screen_width = 800
screen_height = 400
# Rectangle size and position.
position_x = random.randint(0, screen_width-150)
position_y = random.randint(0, screen_height-50)
r_width = random.randint(150, (screen_width - position_x))
r_height = 10
rect_gap = 50
velocity_r = 1
# Ball properties.
radius = 10
xcoor = random.randint((radius + 2), screen_width-r_width)
ycoor = 20
gravity = 1
velocity_b = 1
# colors
white = (255, 255, 255,)
black = (0, 0, 0)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
light_blue = (78, 231, 245)
dark_green = (37, 125, 0)
# Window.
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Keep Falling")
screen.fill(light_blue)
# Class for generating the Ball.
class Ball:
def __init__(self, screen, color, xcoor, ycoor, radius, ):
self.screen = screen
self.color = color
self.xcoor = xcoor
self.ycoor = ycoor
self.radius = radius
def draw(self, color, xcoor, ycoor, radius):
pygame.draw.circle(screen, color, (xcoor, ycoor), radius)
# Class for generating the
class Rectangle:
def __init__(self, screen, color, position_x, position_y, r_width, r_height):
self.screen = screen
self.color = color
self.position_x = position_x
self.position_y = position_y
self.r_width = r_width
self.r_height = r_height
def draw(self, color, position_x, position_y, r_width, r_height):
pygame.draw.rect(screen, dark_green, (position_x,
position_y, r_width, r_height))
# game loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill(light_blue)
time.sleep(0.005)
# Upward movement of the rectangle.
position_y -= velocity_r
# Teleportation of the triangle to the bottom.
if position_y < 0 - r_height:
position_y = screen_height+radius
key = pygame.key.get_pressed()
# Ball controls and collisions with the rectangle from the sides.
if key[pygame.K_LEFT]:
xcoor -= velocity_b
if xcoor < 0:
xcoor = screen_width
if ycoor > position_y and ycoor < (position_y + r_height) and xcoor == (position_x + r_width + radius):
xcoor += velocity_b
if key[pygame.K_RIGHT]:
xcoor += velocity_b
if xcoor > screen_width:
xcoor = 0
if ycoor > position_y and ycoor < (position_y + r_height) and xcoor == (position_x - radius):
xcoor -= velocity_b
# Teleporation of the ball to the top.
if ycoor > screen_height:
ycoor = 0
# Collision system.
if ycoor == (position_y+r_height+radius) and xcoor >= position_x and xcoor <= (position_x + r_width):
ycoor += velocity_b
if ycoor == (position_y - radius) and xcoor >= position_x and xcoor <= (position_x + r_width):
gravity = 0
ycoor -= velocity_r
if ycoor < 0:
ycoor = screen_height
if ycoor == (position_y - radius) and xcoor <= position_x or xcoor >= (position_x + r_width):
gravity = 1
# Falling of the ball.
ycoor += gravity
# Ball and rectangle display.
Rectangle.draw(screen, dark_green, position_x, position_y, r_width, r_height)
Ball.draw(screen, white, xcoor, ycoor, radius)
pygame.display.update()
pygame.quit()
我的碰撞系统基于球和矩形的坐标,如下所示:
# Collision system.
if ycoor == (position_y+r_height+radius) and xcoor >= position_x and xcoor <= (position_x + r_width):
ycoor += velocity_b
if ycoor == (position_y - radius) and xcoor >= position_x and xcoor <= (position_x + r_width):
gravity = 0
ycoor -= velocity_r
if ycoor < 0:
ycoor = screen_height
if ycoor == (position_y - radius) and xcoor <= position_x or xcoor >= (position_x + r_width):
gravity = 1
由于未知原因,在这种情况下,球只会每隔一次“被抓住”,否则它会从三角形中落下。
我想出了一个同样基于坐标的替代方案
while ycoor == (position_y - radius) and xcoor >= position_x and xcoor <= (position_x + r_width):
gravity = 0
ycoor -= velocity_r
if ycoor < 0:
ycoor = screen_height
使用这种方法也会导致错误。
- 球在第一次与三角形碰撞时落下,从第二个矩形开始,碰撞正常工作。
- 当球离开矩形时,它不会再次开始下落。在循环之后添加
gravity = 1
会导致球根本不与矩形碰撞。
是否有错误或我的代码在逻辑上存在缺陷,我应该重做整个碰撞检测系统?
感谢您的任何建议。
解决方案
问题是,矩形在每一帧中移动,球移动一个。结果,球的底部并不总是准确地碰到矩形的顶部。有时条件ycoor == (position_y - radius)
不满足。
您必须评估球的底部是否在矩形顶部的“范围内”:
if ycoor == (position_y - radius) and ...
if (position_y - radius - 1) <= ycoor <= (position_y - radius + 1) and ...
例如:
while run:
# [...]
if (position_y - radius - 1) <= ycoor <= (position_y - radius + 1) and xcoor >= position_x and xcoor <= (position_x + r_width):
gravity = 0
ycoor -= velocity_r
if ycoor < 0:
ycoor = screen_height
if (position_y - radius - 1) <= ycoor <= (position_y - radius + 1) and xcoor <= position_x or xcoor >= (position_x + r_width):
gravity = 1
无论如何,我建议使用一个pygame.Rect
对象,或者.collidepoint()
找到colliderect()
一个矩形和一个对象之间的碰撞。
rect1 = pygame.Rect(x1, y1, w1, h1)
rect2 = pygame.Rect(x2, y2, w2, h2)
if rect1.colliderect(rect2):
# [...]
例如:
run = True
while run:
# [...]
# Teleporation of the ball to the top.
if ycoor > screen_height:
ycoor = 0
rect_rect = pygame.Rect(position_x, position_y, r_width, r_height)
ball_rect = pygame.Rect(xcoor-radius, ycoor-radius, radius*2, radius*2)
if rect_rect.colliderect(ball_rect):
ycoor = position_y - radius
else:
# Falling of the ball.
ycoor += gravity
# Ball and rectangle display.
# [...]
推荐阅读
- symfony - 是否可以仅覆盖 Symfony 4 服务的某些参数而无需编译器通过?
- python-3.x - 如何将 Python DataFrame 转换为 NumPy 数组
- ios - 如何缩小 WKWebView?
- r - 尝试在 R 中使用转置矩阵函数,但结果是 t 检验
- javascript - React - 有大的静态/资产文件夹可以吗?
- imbalanced-data - 阈值移动以找到不平衡数据集分类的最佳成本
- python - 如何求和找到几个日期时间的平均值
- kql - Kusto 查询如何将表中的每一行作为参数进行迭代以在另一个表中查询?
- java - 如何修复 Java Swing JFrame 的大小错误
- c++ - 嵌套类的模板模板参数的可变类型模板参数和非类型模板参数如何相互约束?