如何处理Pygame中的精灵和碰撞

当用户按下“=”键时,我们希望能够添加精灵(一个球),并能够在按下“-”键时删除最近添加的精灵。但是,目前我们只能删除所有精灵,无法只删除最后一个。此外,精灵在碰撞时不会完全接触,有的时候精灵会卡住不动,还会穿过画面框架,这与我们的预期不符。这是第一次使用精灵组,希望能得到指导,让精灵的运行更加流畅。

2、解决方案
为了解决这个问题,我们首先需要对精灵组的remove方法进行修改。sprite.Group.remove(sprites)需要我们指定要从组中删除的精灵。这里,sprites应该是一个我们想要从组中删除的精灵或精灵列表。这意味着,要删除最后一个通过按键添加的球,我们需要保存一个球精灵列表,并从列表中弹出最近添加的项目,然后使用弹出结果作为要从组中删除的精灵。sprite.Group有一个.sprites()方法,它返回组中所有精灵的列表,按添加顺序排列。这个列表是从组中生成的,实际上不是与它的接口,所以对这个列表进行操作不会影响组。然而,我们仍然可以使用它来获取最后添加的精灵。

此外,对于精灵的碰撞问题,我们需要修改代码来解决。在原代码中,精灵与边界发生碰撞后,会反转速度。但这种方法可能导致精灵在边界附近不断反弹。为了解决这个问题,我们只能在精灵需要反弹时才反转速度。具体做法是,我们需要判断精灵是否越过边界,以及精灵的速度是否朝向更深的方向。只有满足这两个条件,我们才反转速度。

最后,为了解决精灵在没有接触时发生碰撞的问题,我们需要使用sprite.spritecollide()方法的collided参数。这个参数是一个回调函数,用于计算两个精灵是否发生碰撞。这里,我们可以使用collide_circle函数,它会根据精灵的半径来计算碰撞。

添加了以上修改后,我们的代码如下:

ball.py

import pygame
from pygame.locals import *


class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y, vx, vy):

        super().__init__();
        self.image = pygame.image.load("ball.png").convert()

        self.image.set_colorkey(pygame.Color(0, 0, 0))

        self.rect = self.image.get_rect()

        self.rect.x = x
        self.rect.y = y
        self.vx = vx
        self.vy = vy
        self.radius = self.rect.width/2

    def draw(self, SCREEN):
        SCREEN.blit(self.image, (self.rect.x, self.rect.y))

    def move(self, SCREEN, balls):
        l_collide = self.rect.x + self.image.get_width() + self.vx > SCREEN.get_width()
        r_collide = self.rect.x + self.vx < 0
        t_collide = self.rect.y + self.vy < 0
        b_collide = self.rect.y + self.image.get_height() + self.vy > SCREEN.get_height()

        a = pygame.sprite.spritecollide(self, balls, False, pygame.sprite.collide_circle)

        if len(a) > 1:
            self.vx *= -1
            self.vy *= -1


        if (l_collide and self.vx>0) or (r_collide and self.vx<0):
            self.vx *= -1


        if (t_collide and self.vy<0) or (b_collide and self.vy>0):
            self.vy *= -1

        self.rect.x += self.vx
        self.rect.y += self.vy

ball_animation.py

import pygame
import sys
import random
import math
from pygame.locals import *
from ball.ball import Ball
from random import randint

def ball_list(num):
    ball_list = pygame.sprite.Group()

    for x in range(num):
        rand_x = random.randint(0,400)
        rand_y = random.randint(0,400)
        vx = 4
        vy = 5

        ball_list.add(Ball(rand_x, rand_y, vx, vy))

    return ball_list

def main():
    pygame.init()

    FPS = 30
    FPS_CLOCK = pygame.time.Clock()

    # COLOR LIST
    BLACK = pygame.Color(0, 0, 0)

    # Code to create the initial window
    window_size = (500, 500)
    SCREEN = pygame.display.set_mode(window_size)

    # set the title of the window
    pygame.display.set_caption("Bouncing Ball Animation")

    # change the initial background color to white
    SCREEN.fill(BLACK)

    balls = ball_list(0)

    while True:  # <--- main game loop
        for event in pygame.event.get():
            if event.type == QUIT:  # QUIT event to exit the game
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if event.key == K_EQUALS:
                    balls.add(Ball(randint(0,400),randint(0,400), 4,5))
                if event.key == K_0:
                    try:
                        sprite_list = balls.sprites()
                        to_remove = sprite_list[-1] # Get last element of list
                        balls.remove(to_remove)
                    except IndexError:
                        print('There is no balls to take!')




        SCREEN.fill(BLACK)
        for x in balls:
            x.move(SCREEN,balls)
            x.draw(SCREEN)

        pygame.display.update()  # Update the display when all events have been processed
        FPS_CLOCK.tick(FPS)

if __name__ == "__main__":
    main()

这些修改可以解决精灵间的碰撞问题,并允许我们只删除最后添加的精灵。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值