鱼C论坛

 找回密码
 立即注册
查看: 1170|回复: 4

pygame第一个小游戏(小球进洞游戏)出现的两个bug,不知道什么原因

[复制链接]
发表于 2021-2-5 20:36:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
bug1:当四个球进洞后,最后一个球跑出边界后消失了
bug2:有时候只有3或4个球进洞游戏就胜利了
这里的两个bug不是每次都会出现,我是测试时发现的问题
代码我自己照着小甲鱼老师打的,有一点点修改
import pygame
import sys
from pygame import *
from random import *
from math import *
from traceback import *

#定义 球 类,pygame.sprite.Sprite是python自带的一个基类(动画精灵),这里直接继承
class Ball(pygame.sprite.Sprite):
    def __init__(self,grayball_image,greenball_image,position,speed,bg_size,target):#初始化Ball类
        pygame.sprite.Sprite.__init__(self)#初始化pygame.sprite.Sprite类

        self.grayball_image=pygame.image.load(grayball_image).convert_alpha()#载入图片(灰色小球)
        self.rect=self.grayball_image.get_rect()#得到处理该图片(矩形图片)的方法

        self.greenball_image = pygame.image.load(greenball_image).convert_alpha()  # 载入图片(绿色小球)
        #因为绿色与灰色小球只有颜色不同,所有这里不再设置rect(形状之类的属性)
        self.rect.left,self.rect.top=position#得到左上角坐标(给出左上角坐标和图片就可以在屏幕生成一张矩形图片)
        self.side=[choice([-1,1]),choice([-1,1])]#设置速度方向(水平(左右)与竖直(上下))
        self.collide=False #是否碰撞
        self.speed=speed#得到小球速度
        self.width,self.height=bg_size[0],bg_size[1]#得到窗口尺寸
        self.radius=self.rect.width/2#得到小球半径
        self.target=target #为每一个小球设立一个特定的目标,当符合这个目标后小球响应相应事件(MYTIMER)
        self.control=False#检查小球是否在可控状态

    def move(self):#小球移动的方法
        if self.control:
            # 在可控状态下速度不区分方向(self.side),因为side=-1时会反方向加速度,与实际运动方向不符合,所以单独分开
            self.rect = self.rect.move(self.speed)
        else:
            self.rect=self.rect.move((self.speed[0]*self.side[0]),(self.speed[1]*self.side[1]))

        #当小球移出窗口边缘时的事件(上进下出,左进右出······)
        if self.rect.right<=0:
            self.rect.left=self.width
        elif self.rect.left>=self.width:
            self.rect.right=0
        elif self.rect.bottom<=0:
            self.rect.top=self.height
        elif self.rect.top>=self.height:
            self.rect.bottom=0

    def check(self,motion): #检测鼠标移动事件
        if self.target<motion<self.target+5:
            return True
        else:
            return False


'''
def collide_check(item,target):#碰撞检测,不建议自己写此模块
    col_balls=[]#存放有碰撞的球
    for each in target:
        #距离公式((x1-x2)^2+(y1-y2)^2)^(0.5)
        distance=sqrt(\
            pow((item.rect.center[0]-each.rect.center[0]),2)+\
            pow((item.rect.center[1] - each.rect.center[1]), 2))
        if distance<=(item.rect.width+each.rect.width)/2:
            col_balls.append(each)
    return col_balls
'''

class Glass(pygame.sprite.Sprite): # 创建 玻璃板 类
    def __init__(self, glass_image, mouse_image,bg_size):  # 初始化
        pygame.sprite.Sprite.__init__(self)

        self.glass_image=pygame.image.load(glass_image).convert_alpha()
        self.glass_rect=self.glass_image.get_rect()
        self.glass_rect.left,self.glass_rect.top=\
                            (bg_size[0]-self.glass_rect.width)//2,\
                            bg_size[1]-self.glass_rect.height

        self.mouse_image = pygame.image.load(mouse_image).convert_alpha()
        self.mouse_rect = self.mouse_image.get_rect()
        self.mouse_rect.left, self.mouse_rect.top = \
            self.glass_rect.left,self.glass_rect.top
        pygame.mouse.set_visible(False)



def main():
    pygame.init()
    grayball_image='b.png'#小球图片(gray)
    greenball_image='green_ball.png' #小球图片(green)
     #小球图片(green)
    foo=pygame.image.load(grayball_image)
    foo.get_rect()
    ball_diameter=foo.get_width()#得到小球直径
    #print(int(ball_radius))
    bg_image='bg.png'#背景图片
    glass_image='glass.png'
    mouse_image='hand.png'

    bg_size = width, height = 1024, 681
    screen=pygame.display.set_mode(bg_size)
    pygame.display.set_caption('Ball Game')
    # 初始化音效模块
    pygame.mixer.pre_init()
    pygame.mixer.init()

    '''
    sound_cat = pygame.mixer.Sound('cat.wav')  # 音效
    sound_cat.set_volume(0.2)                  # 调节音量
    sound_dog = pygame.mixer.Sound('dog.wav')
    sound_dog.set_volume(0.2)
    '''

    loser_sound=pygame.mixer.Sound('loser.wav') # 音效
    loser_sound.set_volume(0.2)                 # 调节音量
    laugh_sound = pygame.mixer.Sound('laugh.wav')
    laugh_sound.set_volume(0.2)
    winner_sound = pygame.mixer.Sound('winner.wav')
    winner_sound.set_volume(0.2)
    hole_sound = pygame.mixer.Sound('hole.wav')
    hole_sound.set_volume(0.2)

    #背景音乐播放完播放音效loser_sound和laugh_sound,同时游戏失败
    GAMEOVER=USEREVENT
    pygame.mixer.music.set_endevent(GAMEOVER)

    pygame.mixer.music.load('My Soul.ogg')  #背景音乐
    pygame.mixer.music.set_volume(0.2)      #调节音量
    pygame.mixer.music.play()             #播放背景音乐()
    pause=False
    loser=False  #设置游戏失败标志
    win=True     #设置成功通过标志

    background=pygame.image.load(bg_image).convert_alpha()#加载背景图片
    #(117,119,199,201)表示小球进黑洞只需要坐标(这里是左上角坐标)满足117<=x<=119,199<=y<=201就行(给3个像素的容错率)
    hole=[(117,119,199,201),(225,227,390,392),(503,505,320,322),(698,700,192,194),(906,908,419,421)] #黑洞的位置
    #hole=[(0,300,0,300),(301,600,0,300),(601,1024,0,300),(0,300,301,681),(301,1024,301,681)] #测试
    msgs = []
    msgs1=[]

    BALL_NUM=5
    balls=[]#存放小球的列表
    group=pygame.sprite.Group() #sprite.Group,用来判断与处理后面的碰撞情况设立的一个集合(set)

    for i in range(BALL_NUM):#创建(BALL_NUM)个小球并设置一些基础属性
        position=randint(0,width-ball_diameter),randint(0,height-ball_diameter)
        speed=[randint(1,10),randint(1,10)]
        ball=Ball(grayball_image,greenball_image,position,speed,bg_size,5*(i+1)) # 调用Ball类生成画面

        # 检查小球产生时会不会碰在一起,如果碰在一起,这些碰在一起的小球位置重置
        # pygame.sprite.spritecollide(sprite,group,dokill,collided=None)是pygame提供的碰撞检测方法
        # (4参数:1:单个球(对象)本身,2:其他球(对象),3:碰撞后对象是否消失,4:计算碰撞的回调函数,下面的按圆形计算)
        while pygame.sprite.spritecollide(ball,group,False,pygame.sprite.collide_circle):
            ball.rect.left,ball.rect.top=randint(0,width-ball_diameter),randint(0,height-ball_diameter)

        balls.append(ball)
        group.add(ball)

    glass=Glass(glass_image,mouse_image,bg_size)#创建下方中间的玻璃板
    motion=0#记录鼠标(这里是1s内)产生的事件数量
    MYTIMER=USEREVENT+1 # 创建计时器事件
    pygame.time.set_timer(MYTIMER,1000) # 设置计时器事件(1000ms时间内的事件数量)
    # 设置第一次键盘事件响应时间延迟0.1s,重复事件间隔0.1s才能再次响应
    pygame.key.set_repeat(100,100)

    clock=pygame.time.Clock()#帧率控制器




    running=True

    while running:
        for event in pygame.event.get():
            if event.type==pygame.QUIT: #判断相应事件是否触发(下面也一样)
                pygame.quit()
                sys.exit()#退出事件

            elif event.type==GAMEOVER:

                for each in balls:
                    each.speed=[0,0]
                    group.remove(each)
                if win: # 如果胜利了就不再响应失败的事件
                    msg1 = pygame.image.load('rookie.png').convert_alpha()
                    msg1_pos = (width - msg1.get_width()) // 2, (height - msg1.get_height()) // 2
                    msgs1.append((msg1, msg1_pos))
                    loser=True
                    loser_sound.play()
                    pygame.time.delay(2000)
                    laugh_sound.play()


            elif event.type==MYTIMER:
                if motion:
                    for each in group:
                        if each.check(motion):
                            each.speed=[0,0]
                            each.control=True
                    motion=0

            elif event.type==MOUSEMOTION:
                motion+=1

            elif event.type==KEYDOWN:
                if event.key==K_SPACE: # 按下空格键响应小球入洞
                    for each in group:
                        if each.control:
                            for i in hole:
                                if i[0]<=each.rect.left<=i[1] and i[2]<=each.rect.top<=i[3]:
                                    hole_sound.play()
                                    each.speed=[0,0] # 小球进黑洞后不再动了
                                    group.remove(each) # 移除进黑洞的小球(不会再碰撞了)
                                    temp=balls.pop(balls.index(each)) # 移除该小球(保留图像,移除其它一切属性和方法)
                                    balls.insert(0,temp) #将temp放到前面(保证进黑洞的小球在没进黑洞的小球底层绘制(先绘制的被后绘制的覆盖),也就是显示的优先级)
                                    hole.remove(i) # 小球进黑洞了,该黑洞也被移除(一个黑洞只能容纳一个小球)
                                if len(hole)==0: # 游戏胜利后(所有黑洞都有球了)
                                    pygame.mixer.music.stop()
                                    winner_sound.play()
                                    pygame.time.delay(3000)
                                    msg=pygame.image.load('win.png').convert_alpha()
                                    msg_pos=(width-msg.get_width())//2,(height-msg.get_height())//2
                                    msgs.append((msg,msg_pos))
                                    laugh_sound.play()
                                    win=False



                if event.key==K_w: # wsad代表给被control的小球 上下左右 加速度 加一
                    for each in group:
                        if each.control:
                            each.speed[1]-=1

                if event.key==K_s:
                    for each in group:
                        if each.control:
                            each.speed[1]+=1

                if event.key==K_a:
                    for each in group:
                        if each.control:
                            each.speed[0]-=1

                if event.key==K_d:
                    for each in group:
                        if each.control:
                            each.speed[0]+=1





        screen.blit(background,(0,0))#填充(绘制)背景
        screen.blit(glass.glass_image,glass.glass_rect) #绘制玻璃板,这一步与上一步步骤不能颠倒(否则背景会覆盖图片glass.png)

        glass.mouse_rect.left, glass.mouse_rect.top=pygame.mouse.get_pos()
        #限制我们的hand.png图片不能跑出glass.png图片外
        if glass.mouse_rect.left<glass.glass_rect.left:
            glass.mouse_rect.left=glass.glass_rect.left
        if glass.mouse_rect.left>glass.glass_rect.right-glass.mouse_rect.width:
            #图片hand.png不能超出图片glass.png右边
            #则图片hand.png左上角与图片glass.png右边界最小距离不能超过图片hand.png的宽度
            glass.mouse_rect.left=glass.glass_rect.right-glass.mouse_rect.width
        if glass.mouse_rect.top<glass.glass_rect.top:
            glass.mouse_rect.top=glass.glass_rect.top
        if glass.mouse_rect.top>glass.glass_rect.bottom-glass.mouse_rect.height:
            glass.mouse_rect.top=glass.glass_rect.bottom-glass.mouse_rect.height

        screen.blit(glass.mouse_image,glass.mouse_rect)

        for each in balls:
            each.move()#小球移动
            if each.collide:
                each.speed=[randint(1,10),randint(1,10)]
                each.collide=False
            if each.control:
                #在control状态下小球变为绿色
                screen.blit(each.greenball_image, each.rect)  # 绘制小球(green-control)
            else:
                screen.blit(each.grayball_image,each.rect) # 绘制小球(gray-uncontrol)

        for each in group:
            group.remove(each) # 排除自己与自己碰撞的情况
            # 如果碰撞,设置为反方向运动(速度方向相反,虽然不太符合实际情况)
            if pygame.sprite.spritecollide(each,group,False,pygame.sprite.collide_circle):
                each.side[0] = -each.side[0]
                each.side[1] = -each.side[1]
                each.collide=True
                if each.control:
                    each.side[0]=-1
                    each.side[1] = -1
                    each.control=False  #碰撞后小球变为不可控状态

            group.add(each)

        for msg1 in msgs1: # 绘制失败的画面
            if loser:
                screen.blit(msg1[0], msg1[1])

        for msg in msgs: # 绘制胜利后的“然而并没有什么卵用”图片
            screen.blit(msg[0],msg[1])


        pygame.display.flip()#更新画面
        clock.tick(30)#设置帧率


if __name__=='__main__':
    try:       # 异常处理
        main()
    except SystemExit:
        pass
    except:
        print_exc()
        pygame.quit()
        input()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-5 22:59:13 | 显示全部楼层
说句老实话,基本上没什么人会愿意看你这300+的代码给你一个个抓bug的,吃力不讨好

建议你自己对着小甲鱼的代码,一个个对,把修改过的挨个改回来,每改一段试一下

就能发现自己问题出在哪儿了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-6 15:17:28 | 显示全部楼层
Daniel_Zhang 发表于 2021-2-5 22:59
说句老实话,基本上没什么人会愿意看你这300+的代码给你一个个抓bug的,吃力不讨好

建议你自己对着小甲 ...

哦哦,好的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-7 17:15:34 | 显示全部楼层
Daniel_Zhang 发表于 2021-2-5 22:59
说句老实话,基本上没什么人会愿意看你这300+的代码给你一个个抓bug的,吃力不讨好

建议你自己对着小甲 ...


找到原因了,212行的if语句要向前缩进一个tab,不然可能会陷入死循环,就是bug1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-7 19:11:33 | 显示全部楼层
zcn123 发表于 2021-2-7 17:15
找到原因了,212行的if语句要向前缩进一个tab,不然可能会陷入死循环,就是bug1

嗯嗯
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-16 14:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表