Python小游戏功能bug

下面是我写的一段小游戏,但是有两个问题我没有达到预期
1 是判断小球与挡板撞击时有Bug,当与挡板侧面撞击时,球不是反弹而是不规则移动
2 希望设计关卡,当撞击挡板次数达到要求,游戏自动进入下一关,但是没有实现
请学霸们帮我修正下这段程序


#反弹球游戏设计

from tkinter import *
import time
import random

top=Tk()
top.title("反弹球游戏")
cvsWidth=600
cvsHeight=600

var=StringVar()
Label(top,textvariable=var).pack()

canvas=Canvas(top,width=cvsWidth,height=cvsHeight,bg="lightgreen")
canvas.pack()

BoardWidth=80
BoardHeight=10

class Board():
    def __init__(self):
        self.canvas=canvas
        self.bdwidth=BoardWidth
        self.bdheight=BoardHeight
        self.stepx=3
        self.Board=self.canvas.create_rectangle(cvsWidth//2-self.bdwidth//2,\
                                                cvsHeight-40-self.bdheight//2,\
                                                cvsWidth//2+self.bdwidth//2,\
                                                cvsHeight-40+self.bdheight//2,fill="black")
        self.canvas.bind_all("<KeyPress-Left>",self.__moveLeft)
        self.canvas.bind_all("<KeyPress-Right>",self.__moveRight)
    def __moveLeft(self,event):
        self.canvas.move(self.Board,-self.stepx,0)
        if self.canvas.coords(self.Board)[0]<=0:
            self.canvas.moveto(self.Board,0,cvsHeight-40-self.bdheight//2)
    def __moveRight(self,event):
        self.canvas.move(self.Board,self.stepx,0)
        if self.canvas.coords(self.Board)[2]>=cvsWidth:
            self.canvas.moveto(self.Board,cvsWidth-self.bdwidth,cvsHeight-40-self.bdheight//2)

playBoard=Board()

class Ball():
    
    def __init__(self,r,board):
        self.hitCount=0
        self.canvas=canvas
        self.r=r
        self.board=board
        self.vx=random.choice([-4,-3,-2,-1,1,2,3,4])
        self.vy=3
        self.hitBottom=False
        self.ball=self.canvas.create_oval(cvsWidth//2-self.r,50-self.r,\
                                          cvsWidth//2+self.r,50+self.r,fill="red")

    def __isHitBottom(self):
        if self.canvas.coords(self.ball)[3]>=cvsHeight:
            self.hitBottom=True
    def getHitCount(self):
        return self.hitCount
    
    def __hitWall(self):
        if self.canvas.coords(self.ball)[0]<=0:
            self.vx=-self.vx
        if self.canvas.coords(self.ball)[2]>=cvsWidth:
            self.vx=-self.vx
        if self.canvas.coords(self.ball)[1]<=0:
            self.vy=-self.vy
        if self.__isHitBoard():
            self.vy=-self.vy

    def __isHitBoard(self):
        if self.canvas.coords(self.ball)[0]+self.r>=self.canvas.coords(self.board.Board)[0] \
           and self.canvas.coords(self.ball)[0]+self.r<=self.canvas.coords(self.board.Board)[2]:
            if self.canvas.coords(self.ball)[3]>=self.canvas.coords(self.board.Board)[1] \
               and self.canvas.coords(self.ball)[3]<=self.canvas.coords(self.board.Board)[3]:
                self.hitCount+=1
                var.set(f"Win:{self.hitCount}")
                return True
        return False
    
    def ballMove(self):
        while not self.hitBottom:
            self.canvas.move(self.ball,self.vx,self.vy)
            self.__hitWall()
            self.__isHitBottom()
            top.update()
            time.sleep(0.03)

第几关=1
iscontinue=True
while iscontinue:
    Ball.hitCount=0
    playBall=Ball(10,playBoard)
    playBall.ballMove()
    if playBall.hitBottom:
        canvas.delete(playBall.ball)
        print("Game Over")
        iscontinue=False
    if playBall.getHitCount()>=1+(第几关-1)*1:
        print(f"通过第{第几关}关")
        canvas.delete(playBall.ball)
        continue
    第几关+=1
        
top.mainloop()

  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7478086
  • 这篇博客也不错, 你可以看下Python安装及Bug提示(持续更新)
  • 除此之外, 这篇博客: python入门(大概是目前最容易理解的内容)中的 2、解决bug三步走 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 第一步:查看错误页面

    第二步:看错误的行号

    第三步:根据具体的错误,具体分析

  • 您还可以看一下 张旭老师的【造物者】手把手带你做快递管理系统课程中的 快递插入Bug修改小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    我可以尝试解决这个问题。

    第一个问题,即小球与挡板侧面撞击时不规则移动,可以通过修改小球碰到挡板侧面时的反弹方式解决。具体来说,可以通过判断小球与挡板碰撞时的相对位置,来决定小球的反弹方式。如果小球在挡板的左边或右边撞上,应该让小球在水平方向上反弹,即x方向的速度取相反数,y方向速度不变;如果小球在挡板的上方或下方撞上,则应该让小球在垂直方向上反弹,即y方向速度取相反数,x方向速度不变。

    代码如下:

    if ball.rect.right >= paddle.rect.left and ball.rect.left <= paddle.rect.right:
        # 球与挡板左右边缘相交,进行水平反弹
        ball.y_speed = -ball.y_speed
        if ball.rect.centerx < paddle.rect.centerx:
            ball.x_speed = -abs(ball.x_speed)
        else:
            ball.x_speed = abs(ball.x_speed)
    elif ball.rect.bottom >= paddle.rect.top and ball.rect.top <= paddle.rect.bottom:
        # 球与挡板上下边缘相交,进行垂直反弹
        ball.x_speed = -ball.x_speed
    

    第二个问题,即如何实现自动进入下一关,可以通过设立计数器,统计小球与挡板撞击的次数,从而确定是否进入下一关。具体来说,当小球与挡板撞击时,计数器加1;当计数器的值达到某个阈值时,即小球与挡板撞击的次数达到规定的次数时,自动进入下一关。

    代码如下:

    # 在主循环里添加以下代码
    if pygame.sprite.collide_rect(ball, paddle):
        # 球与挡板相撞,计数器加1
        hit_count += 1
        if hit_count >= MAX_HIT:
            # 进入下一关
            level += 1
            hit_count = 0
            reset_ball_and_paddle()
    

    其中,MAX_HIT为小球与挡板碰撞的次数阈值,level为当前游戏的关卡数,reset_ball_and_paddle()函数用于初始化小球和挡板的位置和速度。

    完整代码如下:

    import pygame
    import random
    
    # 常量定义
    SCREEN_SIZE = (640, 480)
    BALL_SIZE = (20, 20)
    PADDLE_SIZE = (100, 20)
    BALL_SPEED = [5, 5]
    PADDLE_SPEED = 10
    MAX_HIT = 5  # 撞击阈值,达到此值自动进入下一关
    FONT_SIZE = 32
    FONT_COLOR = (255, 255, 255)
    
    # 初始化游戏
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE)
    pygame.display.set_caption("Paddle Ball Game")
    font = pygame.font.Font(None, FONT_SIZE)
    
    # 定义小球类
    class Ball(pygame.sprite.Sprite):
        def __init__(self, x, y, x_speed, y_speed, width, height):
            super().__init__()
            self.image = pygame.Surface([width, height])
            self.image.fill((255, 255, 255))
            pygame.draw.ellipse(self.image, (255, 0, 0), [0, 0, width, height])
            self.rect = self.image.get_rect()
            self.rect.centerx = x
            self.rect.centery = y
            self.x_speed = x_speed
            self.y_speed = y_speed
    
        def update(self):
            self.rect.move_ip(self.x_speed, self.y_speed)
            if self.rect.left < 0 or self.rect.right > SCREEN_SIZE[0]:
                self.x_speed = -self.x_speed
            if self.rect.top < 0:
                self.y_speed = -self.y_speed
            if self.rect.bottom >= SCREEN_SIZE[1]:
                return True
            return False
    
        def reset(self, x, y, x_speed, y_speed):
            self.rect.centerx = x
            self.rect.centery = y
            self.x_speed = x_speed
            self.y_speed = y_speed
    
    # 定义挡板类
    class Paddle(pygame.sprite.Sprite):
        def __init__(self, x, y, width, height):
            super().__init__()
            self.image = pygame.Surface([width, height])
            self.image.fill((255, 255, 255))
            pygame.draw.rect(self.image, (0, 0, 255), [0, 0, width, height])
            self.rect = self.image.get_rect()
            self.rect.centerx = x
            self.rect.centery = y
    
        def update(self):
            pass
    
        def reset(self, x, y):
            self.rect.centerx = x
            self.rect.centery = y
    
    # 定义游戏初始化函数
    def init_game():
        global ball, paddle, level, hit_count
        ball = Ball(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] // 2, *BALL_SPEED, *BALL_SIZE)
        paddle = Paddle(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - PADDLE_SIZE[1] - 10, *PADDLE_SIZE)
        level = 1
        hit_count = 0
    
    # 定义重新开始游戏的函数
    def restart_game():
        global ball, paddle, level, hit_count
        init_game()
        ball.reset(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] // 2, *BALL_SPEED)
        paddle.reset(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - PADDLE_SIZE[1] - 10)
        level = 1
        hit_count = 0
    
    # 定义重置小球和挡板的函数
    def reset_ball_and_paddle():
        global ball, paddle
        ball.reset(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] // 2, *BALL_SPEED)
        paddle.reset(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - PADDLE_SIZE[1] - 10)
    
    # 定义主循环
    def main_loop():
        global level, hit_count
        clock = pygame.time.Clock()
        running = True
        while running:
            # 处理事件
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE:
                        restart_game()
    
            # 绘制画面
            screen.fill((0, 0, 0))
            screen.blit(font.render("Level: {}".format(level), True, FONT_COLOR), (10, 10))
            screen.blit(font.render("Hits: {}".format(hit_count), True, FONT_COLOR), (10, 40))
            ball.update()
            paddle.update()
            screen.blit(ball.image, ball.rect)
            screen.blit(paddle.image, paddle.rect)
    
            # 碰撞检测
            if pygame.sprite.collide_rect(ball, paddle):
                # 球与挡板相撞,计数器加1
                hit_count += 1
                if hit_count >= MAX_HIT:
                    # 进入下一关
                    level += 1
                    hit_count = 0
                    reset_ball_and_paddle()
    
            # 更新画面
            pygame.display.flip()
            clock.tick(60)
    
    if __name__ == "__main__":
        init_game()
        main_loop()
        pygame.quit()
    

    注意:上述代码只是对小球与挡板的碰撞进行了检测,如果游戏中还有其他需要碰撞检测的对象,需要自行添加碰撞检测的代码。

1.仔细检查__isHitBoard里的逻辑,反正我是没怎么看懂你if里到底在判断什么
2.hitCount只是在自加,根本没有任何地方去判断它的大小呀

# 反弹球游戏设计

from tkinter import *
import time
import random

top = Tk()
top.title("反弹球游戏")
cvsWidth = 600
cvsHeight = 600

var = StringVar()
Label(top, textvariable=var).pack()

canvas = Canvas(top, width=cvsWidth, height=cvsHeight, bg="lightgreen")
canvas.pack()

BoardWidth = 80
BoardHeight = 10

class Board():
    def __init__(self):
        self.canvas = canvas
        self.bdwidth = BoardWidth
        self.bdheight = BoardHeight
        self.stepx = 3
        self.Board = self.canvas.create_rectangle(
            cvsWidth//2-self.bdwidth//2,
            cvsHeight-40-self.bdheight//2,
            cvsWidth//2+self.bdwidth//2,
            cvsHeight-40+self.bdheight//2,
            fill="black"
        )
        self.canvas.bind_all("<KeyPress-Left>", self.__moveLeft)
        self.canvas.bind_all("<KeyPress-Right>", self.__moveRight)

    def __moveLeft(self, event):
        self.canvas.move(self.Board, -self.stepx, 0)
        if self.canvas.coords(self.Board)[0] <= 0:
            self.canvas.moveto(self.Board, 0, cvsHeight-40-self.bdheight//2)

    def __moveRight(self, event):
        self.canvas.move(self.Board, self.stepx, 0)
        if self.canvas.coords(self.Board)[2] >= cvsWidth:
            self.canvas.moveto(self.Board, cvsWidth-self.bdwidth, cvsHeight-40-self.bdheight//2)

playBoard = Board()

class Ball():
    def __init__(self, r, board):
        self.hitCount = 0
        self.canvas = canvas
        self.r = r
        self.board = board
        self.vx = random.choice([-4, -3, -2, -1, 1, 2, 3, 4])
        self.vy = 3
        self.hitBottom = False
        self.ball = self.canvas.create_oval(
            cvsWidth//2-self.r, 50-self.r,
            cvsWidth//2+self.r, 50+self.r,
            fill="red"
        )

    def __isHitBottom(self):
        if self.canvas.coords(self.ball)[3] >= cvsHeight:
            self.hitBottom = True

    def __hitWall(self):
        if self.canvas.coords(self.ball)[0] <= 0 or self.canvas.coords(self.ball)[2] >= cvsWidth:
            self.vx = -self.vx
        if self.canvas.coords(self.ball)[1] <= 0:
            self.vy = -self.vy
        if self.__isHitBoard():
            self.vy = -self.vy

    def __isHitBoard(self):
        ball_coords = self.canvas.coords(self.ball)
        board_coords = self.canvas.coords(self.board.Board)
        if (
            ball_coords[2] >= board_coords[0] and
            ball_coords[0] <= board_coords[2] and
            ball_coords[3] >= board_coords[1] and
            ball_coords[3] <= board_coords[3]
        ):
            self.hitCount += 1
            var.set(f"Win:{self.hitCount}")
            return True
        return False

    def ballMove(self):
        while not self.hitBottom:
            self.canvas.move(self.ball, self.vx, self.vy)
            self.__hitWall()
            self.__isHitBottom()
            top.update()
            time.sleep(0.03)

def start_next_level():
    global playBall, 第几关
    canvas.delete(playBall.ball)
    第几关 += 1
    playBall = Ball(10, playBoard)
    playBall.ballMove()
    if playBall.hitBottom:
        canvas.delete(playBall.ball)
        print("Game Over")

第几关 = 1
iscontinue = True
playBall = None

while iscontinue:
    playBall = Ball(10, playBoard)
    playBall.hitCount = 0
    playBall.ballMove()

    if playBall.hitBottom:
        canvas.delete(playBall.ball)
        print("Game Over")
        iscontinue = False

    if playBall.getHitCount() >= 1 + (第几关-1) * 1:
        print(f"通过第{第几关}关")
        start_next_level()

top.mainloop()