|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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()
复制代码
|
|