首页 > 解决方案 > 我如何让球从所有矩形边上反弹

问题描述

我在让球从墙壁上弹起时遇到问题,并且将矩形放在中间我尝试使用 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)

标签: pythonpygame

解决方案


计算球心到障碍物中心的距离

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)

推荐阅读