简体   繁体   English

pygame 让球相互弹开

[英]pygame Get the balls to bounce off each other

I'm trying to get the balls to bounce off each other.我试图让球相互弹开。 I tried to do it using the reflect() method, but it doesn't work for some reason.我尝试使用reflect()方法来做到这一点,但由于某种原因它不起作用。 To detect the balls, I used groupcollide , since I couldn't think of a better way, maybe this is wrong?为了检测球,我使用了groupcollide ,因为我想不出更好的方法,也许这是错误的?

import pygame
import random

class Ball(pygame.sprite.Sprite):

    def __init__(self, startpos, velocity, startdir):
        super().__init__()
        self.pos = pygame.math.Vector2(startpos)
        self.velocity = velocity
        self.dir = pygame.math.Vector2(startdir).normalize()
        self.image = pygame.image.load("small_ball.png").convert_alpha()
        self.rect = self.image.get_rect(center = (round(self.pos.x), round(self.pos.y)))

    def reflect(self, NV):
        self.dir = self.dir.reflect(pygame.math.Vector2(NV))

    def update(self):
        self.pos += self.dir * 10
        self.rect.center = round(self.pos.x), round(self.pos.y)

        if self.rect.left <= 0:
            self.reflect((1, 0))
        if self.rect.right >= 700:
            self.reflect((-1, 0))
        if self.rect.top <= 0:
            self.reflect((0, 1))
        if self.rect.bottom >= 700:
            self.reflect((0, -1))

pygame.init()
window = pygame.display.set_mode((700, 700))
pygame.display.set_caption('noname')
clock = pygame.time.Clock()

all_balls = pygame.sprite.Group()

start, velocity, direction = (200, 200), 10, (random.random(), random.random())
ball_1 = Ball(start, velocity, direction)

start, velocity, direction = (200, 200), 10, (random.random(), random.random())
ball_2 = Ball(start, velocity, direction)

all_balls.add(ball_1, ball_2)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    all_balls.update()

    hits = pygame.sprite.groupcollide(all_balls, all_balls, False, False)
    for _, hit_sprites in hits.items():
        if len(hit_sprites) > 1:
            sprite_1 = hit_sprites[0]
            sprite_2 = hit_sprites[1]
            sprite_1.reflect((0, 1)) # not working
            print("hit!")

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), (0, 0, 700, 700), 1)
    all_balls.draw(window)
    pygame.display.flip()

small_ball.png

Define a circle by the ball Sprites and use the algorithm from the answer to Pygame how to let balls collide for a function, that can compute reflection of bouncing balls:用球精灵定义一个圆,并使用Pygame 如何让球碰撞的答案中的算法来计算弹跳球的反射:

def reflectBalls(ball_1, ball_2):
    v1 = pygame.math.Vector2(ball_1.rect.center)
    v2 = pygame.math.Vector2(ball_2.rect.center)
    r1 = ball_1.rect.width // 2
    r2 = ball_2.rect.width // 2
    if v1.distance_to(v2) < r1 + r2 - 2:
        nv = v2 - v1
        if nv.length() > 0:
            ball_1.dir = ball_1.dir.reflect(nv)
            ball_2.dir = ball_2.dir.reflect(nv)

Ensure that the balls have different initial positions:确保球具有不同的初始位置:

start, velocity, direction = (200, 200), 10, (random.random(), random.random())
ball_1 = Ball(start, velocity, direction)

start, velocity, direction = (300, 300), 10, (random.random(), random.random())
ball_2 = Ball(start, velocity, direction)

Alternatively you can avoid that the balls are sticking together by improving the bounce algorithm.或者,您可以通过改进弹跳算法来避免球粘在一起。 Only bounce the balls, if the next positions of the balls are closer then the current positions:只反弹球,如果球的下一个位置更接近当前位置:

def reflectBalls(ball_1, ball_2):
    v1 = pygame.math.Vector2(ball_1.rect.center)
    v2 = pygame.math.Vector2(ball_2.rect.center)
    r1 = ball_1.rect.width // 2
    r2 = ball_2.rect.width // 2
    d = v1.distance_to(v2)
    if d < r1 + r2 - 2:
        dnext = (v1 + ball_1.dir).distance_to(v2 + ball_2.dir)
        nv = v2 - v1
        if dnext < d and nv.length() > 0:
            ball_1.dir = ball_1.dir.reflect(nv)
            ball_2.dir = ball_2.dir.reflect(nv)

Test if each ball collides with any other ball:测试每个球是否与任何其他球碰撞:

ball_list = all_balls.sprites()
for i, b1 in enumerate(ball_list):
    for b2 in ball_list[i+1:]:
        reflectBalls(b1, b2)

Complete example:完整示例: repl.it/@Rabbid76/PyGame-BallsBounceOffrepl.it/@Rabbid76/PyGame-BallsBounceOff

import pygame
import random

class Ball(pygame.sprite.Sprite):

    def __init__(self, startpos, velocity, startdir):
        super().__init__()
        self.pos = pygame.math.Vector2(startpos)
        self.velocity = velocity
        self.dir = pygame.math.Vector2(startdir).normalize()
        self.image = pygame.image.load("small_ball.png").convert_alpha()
        self.rect = self.image.get_rect(center = (round(self.pos.x), round(self.pos.y)))

    def reflect(self, NV):
        self.dir = self.dir.reflect(pygame.math.Vector2(NV))

    def update(self):
        self.pos += self.dir * 10
        self.rect.center = round(self.pos.x), round(self.pos.y)

        if self.rect.left <= 0:
            self.reflect((1, 0))
            self.rect.left = 0
        if self.rect.right >= 700:
            self.reflect((-1, 0))
            self.rect.right = 700
        if self.rect.top <= 0:
            self.reflect((0, 1))
            self.rect.top = 0
        if self.rect.bottom >= 700:
            self.reflect((0, -1))
            self.rect.bottom = 700

pygame.init()
window = pygame.display.set_mode((700, 700))
pygame.display.set_caption('noname')
clock = pygame.time.Clock()

all_balls = pygame.sprite.Group()

start, velocity, direction = (200, 200), 10, (random.random(), random.random())
ball_1 = Ball(start, velocity, direction)

start, velocity, direction = (300, 300), 10, (random.random(), random.random())
ball_2 = Ball(start, velocity, direction)

all_balls.add(ball_1, ball_2)

def reflectBalls(ball_1, ball_2):
    v1 = pygame.math.Vector2(ball_1.rect.center)
    v2 = pygame.math.Vector2(ball_2.rect.center)
    r1 = ball_1.rect.width // 2
    r2 = ball_2.rect.width // 2
    d = v1.distance_to(v2)
    if d < r1 + r2 - 2:
        dnext = (v1 + ball_1.dir).distance_to(v2 + ball_2.dir)
        nv = v2 - v1
        if dnext < d and nv.length() > 0:
            ball_1.reflect(nv)
            ball_2.reflect(nv)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    all_balls.update()

    ball_list = all_balls.sprites()
    for i, b1 in enumerate(ball_list):
        for b2 in ball_list[i+1:]:
            reflectBalls(b1, b2)

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), (0, 0, 700, 700), 1)
    all_balls.draw(window)
    pygame.display.flip()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM