鱼C论坛

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

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

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

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

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

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

  1. import pygame
  2. import sys
  3. from pygame import *
  4. from random import *
  5. from math import *
  6. from traceback import *

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

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

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

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

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

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


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

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

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

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



  68. def main():
  69.     pygame.init()
  70.     grayball_image='b.png'#小球图片(gray)
  71.     greenball_image='green_ball.png' #小球图片(green)
  72.      #小球图片(green)
  73.     foo=pygame.image.load(grayball_image)
  74.     foo.get_rect()
  75.     ball_diameter=foo.get_width()#得到小球直径
  76.     #print(int(ball_radius))
  77.     bg_image='bg.png'#背景图片
  78.     glass_image='glass.png'
  79.     mouse_image='hand.png'

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

  86.     '''
  87.     sound_cat = pygame.mixer.Sound('cat.wav')  # 音效
  88.     sound_cat.set_volume(0.2)                  # 调节音量
  89.     sound_dog = pygame.mixer.Sound('dog.wav')
  90.     sound_dog.set_volume(0.2)
  91.     '''

  92.     loser_sound=pygame.mixer.Sound('loser.wav') # 音效
  93.     loser_sound.set_volume(0.2)                 # 调节音量
  94.     laugh_sound = pygame.mixer.Sound('laugh.wav')
  95.     laugh_sound.set_volume(0.2)
  96.     winner_sound = pygame.mixer.Sound('winner.wav')
  97.     winner_sound.set_volume(0.2)
  98.     hole_sound = pygame.mixer.Sound('hole.wav')
  99.     hole_sound.set_volume(0.2)

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

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

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

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

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

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

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

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

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




  136.     running=True

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

  142.             elif event.type==GAMEOVER:

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


  154.             elif event.type==MYTIMER:
  155.                 if motion:
  156.                     for each in group:
  157.                         if each.check(motion):
  158.                             each.speed=[0,0]
  159.                             each.control=True
  160.                     motion=0

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

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



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

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

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

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





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

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

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

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

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

  236.             group.add(each)

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

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


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


  244. if __name__=='__main__':
  245.     try:       # 异常处理
  246.         main()
  247.     except SystemExit:
  248.         pass
  249.     except:
  250.         print_exc()
  251.         pygame.quit()
  252.         input()





复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

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

就能发现自己问题出在哪儿了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

哦哦,好的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

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


找到原因了,212行的if语句要向前缩进一个tab,不然可能会陷入死循环,就是bug1
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

嗯嗯
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-28 03:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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