pygame 让球相互弹开 [英] pygame Get the balls to bounce off each other

查看:109
本文介绍了pygame 让球相互弹开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让球相互弹开.我尝试使用 reflect() 方法来做到这一点,但由于某种原因它不起作用.为了检测球,我使用了groupcollide,因为我想不出更好的方法,也许这是错误的?

导入pygame随机导入类球(pygame.sprite.Sprite):def __init__(self, startpos, velocity, startdir):super().__init__()self.pos = pygame.math.Vector2(startpos)self.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)))定义反射(自我,NV):self.dir = self.dir.reflect(pygame.math.Vector2(NV))定义更新(自我):self.pos += self.dir * 10self.rect.center = round(self.pos.x), round(self.pos.y)如果 self.rect.left <= 0:self.reflect((1, 0))如果 self.rect.right >= 700:self.reflect((-1, 0))如果 self.rect.top <= 0:self.reflect((0, 1))如果 self.rect.bottom >= 700:self.reflect((0, -1))pygame.init()窗口 = pygame.display.set_mode((700, 700))pygame.display.set_caption('无名')时钟 = pygame.time.Clock()all_balls = pygame.sprite.Group()开始,速度,方向 = (200, 200), 10, (random.random(), random.random())ball_1 = 球(开始,速度,方向)开始,速度,方向 = (200, 200), 10, (random.random(), random.random())ball_2 = 球(开始,速度,方向)all_balls.add(ball_1, ball_2)运行 = 真运行时:时钟滴答(60)对于 pygame.event.get() 中的事件:如果 event.type == pygame.QUIT:运行 = 错误all_balls.update()hits = pygame.sprite.groupcollide(all_balls, all_balls, False, False)对于 _, hits.items() 中的 hit_sprites:如果 len(hit_sprites) >1:sprite_1 = hit_sprites[0]sprite_2 = hit_sprites[1]sprite_1.reflect((0, 1)) # 不起作用打印(命中!")window.fill(0)pygame.draw.rect(window, (255, 0, 0), (0, 0, 700, 700), 1)all_balls.draw(窗口)pygame.display.flip()

解决方案

通过球精灵定义一个圆并使用答案中的算法

导入pygame随机导入类球(pygame.sprite.Sprite):def __init__(self, startpos, velocity, startdir):super().__init__()self.pos = pygame.math.Vector2(startpos)self.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)))定义反射(自我,NV):self.dir = self.dir.reflect(pygame.math.Vector2(NV))定义更新(自我):self.pos += self.dir * 10self.rect.center = round(self.pos.x), round(self.pos.y)如果 self.rect.left <= 0:self.reflect((1, 0))self.rect.left = 0如果 self.rect.right >= 700:self.reflect((-1, 0))self.rect.right = 700如果 self.rect.top <= 0:self.reflect((0, 1))self.rect.top = 0如果 self.rect.bottom >= 700:self.reflect((0, -1))self.rect.bottom = 700pygame.init()窗口 = pygame.display.set_mode((700, 700))pygame.display.set_caption('无名')时钟 = pygame.time.Clock()all_balls = pygame.sprite.Group()开始,速度,方向 = (200, 200), 10, (random.random(), random.random())ball_1 = 球(开始,速度,方向)开始,速度,方向 = (300, 300), 10, (random.random(), random.random())ball_2 = 球(开始,速度,方向)all_balls.add(ball_1, ball_2)定义反射球(球_1,球_2):v1 = pygame.math.Vector2(ball_1.rect.center)v2 = pygame.math.Vector2(ball_2.rect.center)r1 = ball_1.rect.width//2r2 = ball_2.rect.width//2d = v1.distance_to(v2)如果 d 0:ball_1.reflect(nv)ball_2.reflect(nv)运行 = 真运行时:时钟滴答(60)对于 pygame.event.get() 中的事件:如果 event.type == pygame.QUIT:运行 = 错误all_balls.update()ball_list = all_balls.sprites()对于 i, b1 在 enumerate(ball_list) 中:对于 ball_list[i+1:] 中的 b2:反射球(b1,b2)window.fill(0)pygame.draw.rect(window, (255, 0, 0), (0, 0, 700, 700), 1)all_balls.draw(窗口)pygame.display.flip()

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. To detect the balls, I used groupcollide, since I couldn't think of a better way, maybe this is wrong?

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()

解决方案

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:

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:

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()

这篇关于pygame 让球相互弹开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆