您现在的位置是:首页 >技术交流 >学习 Python 之 Pygame 开发魂斗罗(十六)网站首页技术交流

学习 Python 之 Pygame 开发魂斗罗(十六)

_DiMinisH 2023-06-28 12:00:04
简介学习 Python 之 Pygame 开发魂斗罗(十六)

完成最终的魂斗罗

在上次的博客学习 Python 之 Pygame 开发魂斗罗(十五)中,我们加入了boss,至此,魂斗罗的主体部分已经完成了,接下来就是在其他地方加入一点敌人,设置进场动画,胜利动画,失败动画和音效了,在这篇博客中,我们加入音效和加入进场动画。

下面是图片的素材和源码,我把源码也放到了网盘

链接:https://pan.baidu.com/s/1X7tESkes_O6nbPxfpHD6hQ?pwd=hdly
提取码:hdly

1. 创建Sound类

import pygame


class Sound:
    def __init__(self, filename):
        self.filename = filename
        pygame.mixer.init()
        self.sound = pygame.mixer.Sound(self.filename)

    def play(self, loops = 0):
        self.sound.play(loops)

    def stop(self):
        self.sound.stop()

    def setVolume(self):
        self.sound.set_volume(0.2)
        return self

把该类导入到需要播放音效的类

2. 添加背景音乐

在主类的构造函数中加入如下代码,并且在run()函数中播放背景音乐

# 加载音乐
self.backgroundMusic = Sound('../Sound/1.mp3')

在这里插入图片描述

注意不要加入到循环中了

3. 添加玩家发射子弹音效

来到玩家1类,找到fire()函数,修改代码

    def fire(self, currentTime, playerBulletList):
        self.isFiring = True
        # 潜水状态下不能开火
        if not (self.isInWater and self.isSquating):
            if len(playerBulletList) < PLAYER_BULLET_NUMBER:
                if currentTime - self.fireLastTimer > 150:
                    Sound('../Sound/commonFire.mp3').play()
                    playerBulletList.append(Bullet(self))
                    self.fireLastTimer = currentTime

在这里插入图片描述

4. 增加击中boss要害音效

来到子弹类,修改collideEnemy()函数
在这里插入图片描述

5. 击中敌人音效

还是在子弹类的collideEnemy()函数中加入代码
在这里插入图片描述

    def collideEnemy(self, enemyList, explodeList):
        for enemy in enemyList:
            if pygame.sprite.collide_rect(self, enemy):
                if enemy.type == 3 or enemy.type == 4:
                    enemy.life -= 1
                    Sound('../Sound/hitWeakness.mp3').play()
                    if enemy.life <= 0:
                        self.isDestroy = True
                        enemy.isDestroy = True
                        explodeList.append(Explode(enemy, ExplodeVariety.BRIDGE))
                else:
                    Sound('../Sound/enemyDie.mp3').play()
                    self.isDestroy = True
                    enemy.isDestroy = True
                    explodeList.append(Explode(enemy))

由于博主没有其他的音效,只能添加这部分了,如果大家自己找到了音效,可以加入,让游戏变得更完整

6. 加入进场动画

在主类中加入加载进场动画函数

    def loadApproachAnimation(self):
        # 读取进场图片
        approach = pygame.image.load('../Image/Map/1/Background/First(Approach).png')
        approachRect = self.background.get_rect()
        approach = pygame.transform.scale(
            approach,
            (int(approachRect.width * 1),
             int(approachRect.height * 1))
        )
        approachRect.x = 0
        # 设置进场图片移动速度
        cameraAdaption = 3
        # 记录当前时间
        currentTime = 0
        # 创建一张黑色的图片,用来盖住选择图标
        image = pygame.Surface((50, 50)).convert()
        image.fill((0, 0, 0))
        # 记录是否播放音效,播放了就要画了
        isPlayed = False
        showTime = pygame.time.get_ticks()
        lastingTime = pygame.time.get_ticks()
        keys = ''
        while 1:
            MainGame.window.blit(approach, approachRect)
            
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    # 上上下下左右左右BABA A是跳跃键,B是射击键
                    if event.key == pygame.K_w:
                        keys += 'w'
                    elif event.key == pygame.K_s:
                        keys += 's'
                    elif event.key == pygame.K_j:
                        keys += 'b'
                    elif event.key == pygame.K_k:
                        keys += 'a'
                    elif event.key == pygame.K_RETURN:
                        if not isPlayed:
                            approachRect.x = -1435
                            Sound('../Sound/start.mp3').play()
                            currentTime = time.time()
                            isPlayed = True
                    
            # 让背景向右走这么多距离
            if approachRect.x > -1435:
                approachRect.x -= cameraAdaption
                
            if isPlayed:
                # 设置图标一闪一闪的
                if abs(lastingTime - pygame.time.get_ticks()) > 400:
                    if 1200 > abs(showTime - pygame.time.get_ticks()) > 0:
                        MainGame.window.blit(image, (190, 390))
                    else:
                        showTime = pygame.time.get_ticks()
                        lastingTime = pygame.time.get_ticks()
                    
            # 更新窗口
            pygame.display.update()
            # 设置帧率
            self.clock.tick(self.fps)
            fps = self.clock.get_fps()
            caption = '魂斗罗 - {:.2f}'.format(fps)
            pygame.display.set_caption(caption)
            
            # 如果时间超过60,就开始加载第一关
            if 100 > abs(time.time() - currentTime) * 10 > 60:
                print(keys)
                if keys == 'wwssbaba':
                    initPlayer1(30)
                break

这里需要解释几处

# 当按键按下,直接结束进场动画,播放音乐,让图标还是闪烁,一定时间后进入第一关
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        sys.exit()
    elif event.type == pygame.KEYDOWN:
        # 上上下下左右左右BABA A是跳跃键,B是射击键
        if event.key == pygame.K_w:
            keys += 'w'
        elif event.key == pygame.K_s:
            keys += 's'
        elif event.key == pygame.K_j:
            keys += 'b'
        elif event.key == pygame.K_k:
            keys += 'a'
        elif event.key == pygame.K_RETURN:
            if not isPlayed:
                approachRect.x = -1435
                Sound('../Sound/start.mp3').play()
                currentTime = time.time()
                isPlayed = True

这部分是让玩家按下回车后直接播放音乐,并且直接来到玩家选择界面(如下图),如果按下了上上下下左右左右BABA时,玩家就会30条名

在这里插入图片描述

if isPlayed:
    # 设置图标一闪一闪的
    if abs(lastingTime - pygame.time.get_ticks()) > 400:
        if 1200 > abs(showTime - pygame.time.get_ticks()) > 0:
            MainGame.window.blit(image, (190, 390))
        else:
            showTime = pygame.time.get_ticks()
            lastingTime = pygame.time.get_ticks()

这部分是让图标闪烁的,整体思想就是创建一块黑布(纯黑图片),一段时间把原来的图标盖住,一段时间不盖住,上面的代码就是实现这个功能,abs(lastingTime - pygame.time.get_ticks()) > 400 这个代码是不盖住的,lastingTime 是不盖住的时间,如果超过了400,就进入if语句体,让黑布显示出来,盖住图标,盖住的时间是1200 ,如果大于1200 了,就不盖住了。

注意导入模块,否则会出现如下报错

在这里插入图片描述

主类新增runGame()函数

    def runGame(self):
        self.loadApproachAnimation()
        self.run()

该函数是游戏的运行函数

修改main()函数

在这里插入图片描述
我们运行一下游戏,看看效果

可以看到界面慢慢移动,如果按下任意键,就会播放声音,播放完后过几秒会进入第一关

7. 解决玩家掉出地图死亡问题

在当前的游戏中,玩家掉落到山崖后,没有死亡,我们需要修改一下
来到主类的updatePlayerPosition()函数

增加如下代码

if tempPlayer.rect.y > 610:
    if MainGame.player1.damage(1):
        initPlayer1(MainGame.player1.life)

在这里插入图片描述
这段代码就是如果玩家的y坐标大于610,就算玩家死亡,重新加载玩家

8. 完善玩家游戏失败函数

把主类的isEnd属性变成类属性

在这里插入图片描述

在这里插入图片描述
增加endGame()函数

在这里插入图片描述

def endGame():
    MainGame.isEnd = True

这里需要修改一下逻辑,来到updateEnemyPosition()函数

在这里插入图片描述
把原来的endGame函数改为victory,表示玩家胜利了

我们先暂时定义一下这个函数

def victory():
    pass

在这里插入图片描述
之后继续修改endGame()函数逻辑

现在运行游戏,看看玩家没有生命了游戏会不会退出

发现是可以的

9. 总结

至此,魂斗罗整体就算完成了,由于博主没有通过的地图和爆炸的音效,这里没办法加入

大家接下来可以扩展,博主没有完善游戏结束和游戏胜利的界面,如果后面我找到了对应的素材,我会加入到游戏里,并且会发一个博客

坦克大战开发了一个星期完成了,比起坦克大战,魂斗罗写了大概一个半月了,其实可以很早可以完成,博主之前在准备考研复试,比较忙,这段时间算是没什么事情了,想着不能半途而废,把魂斗罗完成一下。

最后感谢各位小伙伴的学习和支持。

整体代码和素材我都会放到网盘,需要的小伙伴可以自己去拿哦。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。