Python飞机大战实例有感——pygame如何实现“切歌”以及多曲重奏?

[TOC] #pygame如何实现“切歌”以及多曲重奏?

昨天晚上研究了好久pygame的音乐混合器mixer,出了很多问题后最终成功,不过学习本来也不可能一帆风顺的吗,下面我就来讲一讲我遇到的问题。 ##一、pygame实现切歌

初始化路径

1# 导库,需安装 2import pygame 3# 把路径赋值分别给三个变量,以便之后加载。 4music_file_path1 = "./sound/background.mp3" 5music_file_path2 = "./sound/background1.mp3" 6music_file_path3 = "./sound/dead.mp3" 7# 初始化混合器 8pygame.mixer.init()

###尝试一

开始尝试直接加载新的音乐,想着循环里有调用play方法,是不是直接调用load方法修改路径,就能播放其他音乐了呢?

1# 加载初始背景音乐 2pygame.mixer.music.load(music_file_path1) 3while True: 4 pygame.mixer.music.play() 5 if 死亡: 6 # 切换死亡音乐 7 pygame.mixer.music.load(music_file_path3) 8 for 检测按键 9 if 按键: 10 #重开游戏,并切换成初始背景音乐 11 pygame.mixer.music.load(music_file_path1) 12 if 达成条件进入第二关: 13 # 切换为第二关背景音乐 14 pygame.mixer.music.load(music_file_path2) 15 # 延时50ms之后进入下层循环 16 pygame.time.delay(50)

失败、、、没有完成切换音乐,只有播放初始音乐,切换的部分是静音的。

###尝试二

是不是可以考虑多开几个线程呢?之前java我就这么捣鼓过,这个算是写的比较乱的,主要还是不懂的太多。

1# 导库,系统自带的。 2import threading 3# 定义一个函数以便线程来执行。 4def bgm(music_file_path): 5 pygame.mixer.music.load(music_file_path) 6 pygame.mixer.music.play() 7 8... 9 10# 新建3个子线程 11thread1 = threading.Thread(bgm(music_file_path1)) 12thread2 = threading.Thread(bgm(music_file_path2)) 13thread3 = threading.Thread(bgm(music_file_path3)) 14# 启动线程1 15thread1.strat() 16while True: 17 if 死亡: 18 # 切换死亡音乐 19 thread3.strat() 20 for 检测按键 21 if 按键: 22 #重开游戏,并切换成初始背景音乐 23 thread1.strat() 24 if 达成条件进入第二关: 25 # 切换为第二关背景音乐 26 thread2.strat() 27 # 延时50ms之后进入下层循环 28 pygame.time.delay(50)

同样失败了,刚开始,运行的就是死亡时候的背景音乐,也就是说,只有最后加载的那个起作用了,在具体点说,此时的thread1, thread2, thread3已经是完全相同的了。

###尝试三

加了许多改变,bgm函数里加了初始化mixer,线程改为了在循环里运行匿名线程。(因为直接在循环里thread1.start()的话,会报错,说线程只能启动一次。)

1# 导库,系统自带的。 2import threading 3# 定义一个函数以便线程来执行。 4def bgm(music_file_path): 5 pygame.mi 6 pygame.mixer.music.load(music_file_path) 7 pygame.mixer.music.play() 8 9... 10 11while True: 12 # 默认音乐 13 threading.Thread(bgm(music_file_path1)).start() 14 if 死亡: 15 # 切换死亡音乐 16 threading.Thread(bgm(music_file_path3)).start() 17 for 检测按键 18 if 按键: 19 #重开游戏,并切换成初始背景音乐 20 threading.Thread(bgm(music_file_path1)).start() 21 if 达成条件进入第二关: 22 # 切换为第二关背景音乐 23 threading.Thread(bgm(music_file_path2)).start() 24 # 延时50ms之后进入下层循环 25 pygame.time.delay(50)

现在看也觉得怎么看怎么错的,不过这倒是给我提供了一个思路,只要每次切换音乐的时候重新初始化一下mixer就能播放新的了。

###成功

尝试不止三次,我只是找了3个可能比较有代表性的例子,希望大家能从中吸取经验,下面,我将展示成功的代码。

1# 定义3个变量来表示是否在播放哪首音乐。 2sound1, sound2, sound3 = True, True, True 3# 加载初始背景音乐 4pygame.mixer.music.load(music_file_path1) 5pygame.mixer.music.play() 6while True: 7 if 死亡: 8 # 切换死亡音乐 9 # 通过sound的True, False的值的改变,控制只有第一次进入这个判断条件的时候才会初始化混合器。防止出现每50ms加载一次音乐的开头50ms的情况。 10 if sound3: 11 pygame.mixer.init() 12 pygame.mixer.music.load(music_file_path3) 13 sound3 = False 14 sound1, sound2 = True, True 15 if pygame.mixer.get_busy != 1: 16 pygame.mixer.music.play() 17 for 检测按键 18 if 按键: 19 #重开游戏,并切换成初始背景音乐 20 if sound1: 21 pygame.mixer.init() 22 pygame.mixer.music.load(music_file_path1) 23 sound1 = False 24 sound2, sound3 = True, True 25 if pygame.mixer.get_busy != 1: 26 pygame.mixer.music.play() 27 if 达成条件进入第二关: 28 # 切换为第二关背景音乐 29 if sound2: 30 pygame.mixer.init() 31 pygame.mixer.music.load(music_file_path1) 32 sound2 = False 33 sound1, sound3 = True, True 34 if pygame.mixer.get_busy != 1: 35 pygame.mixer.music.play() 36 # 延时50ms之后进入下层循环 37 pygame.time.delay(50)

最终成功!

###总结

##二、如何在python多线程顺序执行的情况下实现音乐和音效同时播放?

这个其实挺简单的,就是我开始的时候被坑了,被坑的原因现在也不太清楚。。

###尝试一

1# 飞机的发射子弹类 2def launch_bullet: 3 sound = pygame.mixer.Sound("./sound/bullet.wav") 4 sound.play() 5# 敌机的被击毁判断 6if 敌机被击毁: 7 sound = pygame.mixer.Sound("./sound/boom.wav") 8 sound.play()

真的很简单的啊,就这样就应该可以了啊,结果它报错了,说unable to open file "./sound/bullet.wav",无奈,只能换方法。。

###尝试二

经过查阅发现了winsound这个模块,然后,testing...

1# 导入模块,系统自带的 2import winsound 3# 飞机的发射子弹类 4def launch_bullet: 5 winsound.PlaySound("./sound/bullet.wav", SND_NOSTOP) 6# 敌机的被击毁判断 7if 敌机被击毁: 8 winsound.PlaySound("./sound/boom.wav", SND_NOSTOP)

然后成功感受到了单线程的恶意。。。

###尝试三

于是就用多线程吧,结合java的经验,一定手到擒来的吧!

1# 再次尝试使用threading 2import threading 3import winsound 4# 飞机的发射子弹类 5def launch_bullet: 6 # 直接匿名函数先测试走起! 7 threading.Thread(winsound.PlaySound("./sound/bullet.wav", SND_NOSTOP)).start() 8# 敌机的被击毁判断 9if 敌机被击毁: 10 threading.Thread(winsound.PlaySound("./sound/boom.wav", SND_NOSTOP)).start()

有点错愕地发现失败了,跟之前一次的尝试结果一样,然后才知道原来python的多线程因为什么原因我忘了,还是顺序执行的。

尝试四

在网上了解到了多进程可以实现并发访问,于是

1# 系统自带 2import multiprocessing 3import winsound 4# 飞机的发射子弹类 5def launch_bullet: 6 multiprocessing.freeze__support() 7 p = multiprocessing.Process(winsound.PlaySound("./sound/bullet.wav", SND_NOSTOP)) 8 p.start() 9# 敌机的被击毁判断 10if 敌机被击毁: 11 multiprocessing.freeze__support() 12 p = multiprocessing.Process(winsound.PlaySound("./sound/boom.wav", SND_NOSTOP)) 13 p.start()

然后每射一发子弹,就给我打开一个新窗口,我。。。。

###成功

最后决定还是再给Sound一个机会,他文档上不是说只能加载wav和ogg吗?wav失败了,我再重新找一下ogg的素材吧。然后就成功了。就成功了。。。我捣鼓半天,结果是素材的原因。

1# 飞机的__init__方法里 2 self.sound = pygame.mixer.Sound("./sound/bullet.ogg") 3# 飞机的发射子弹类 4def launch_bullet: 5 self.sound.play() 6# 敌机的__init__方法里 7 self.sound = pygame.mixer.Sound("./sound/get_score.ogg") 8# 敌机的被击毁判断 9if 敌机被击毁: 10 self.sound.play()

具体第一次尝试为何失败我们仍未可知,也许是文件太大了?

###总结

真的是一次印象挺深刻的经历,深刻到我这篇全文都是没看之前的代码敲出来的,甚至学了个新单词mixer是混合器的意思。程序源码我会放在我的github上。

飞机大战源码

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )