python小游戏《外星人入侵》的主题与玩法升级

     在学过《python从入门到实践》后,我觉得项目一的小游戏-外星人入侵的主题与玩法有些单调,想为其增点色彩,在之后的一段时间里,我断断续续地产生新想法,每当觉得想法不错的时候,就会想方试法的将其实现。整个游戏的主题为夏目友人帐,因为能力有限,事实上我更想做一个剧情类游戏。python小游戏《外星人入侵》的主题与玩法升级_第1张图片

      外星人入侵原有的框架包含的class有ship,bullet,alien,记分板等等,我在此基础上,添加了一些增益效果和金币,并且通过消耗金币可以释放一些技能,创建了一些不同的敌人和boss,在ship碰到某些敌人会触发一定的限制效果,增加了ship阵亡的显示效果,背景音乐,封面等。所用图片都是网上搜索和自己截取经过ps处理的,图片的资源放在文末的链接。

先给大家看一下实际效果吧!

视频链接:

Python-pygame 《外星人入侵》升级_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1Yv411G7v4

Python-pygame小游戏《外星人入侵》主题玩法升级版_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1m3411y7gm图片,音乐资源(方便复现):链接:https://pan.baidu.com/s/1LA6hxg00qRZujnblPKCFJg 
提取码:bb33

一开始用的纯色背景,看起来颜色比较鲜明,这个做成GIF内存小点,能放的时间长点,

 封面:

 下面是整个程序所涉及的python文件:

python小游戏《外星人入侵》的主题与玩法升级_第2张图片

要想程序简洁高效,一定要学会面向对象的编程思想,根据不同对象的需求和特点,为之编写属性与方法,比如ship,它需要位置属性,图像属性等,还要为之制定绘制ship、更新位置等方法。

主模块: 对应alien_invasion.py文件,即程序要在该文件下运行,其他模块均为导入模块,我将主模块程序进行了简单分类,方便大家寻找使用。(代码略多,还可以重构优化)

下面是主模块init、游戏主循环、键盘鼠标事件响应,屏幕更新,还有背景音乐(这个是最后加上去的)

import sys
from time import sleep,time
import pygame.image
from bullet import *
from alien import *
from settings import Settings
from game_stats import Gamestats
from button import *
from scoreboard import *
from miaobi_r import Miaobir
from random import choice,randint
class AlienInvasion:
    """管理游戏资源和行为的类"""
    def __init__(self):
        """初始化游戏并创建游戏资源"""
        pygame.init()
        self.settings= Settings()
        self.screen=pygame.display.set_mode((self.settings.screen_width,self.settings.screen_height))
        pygame.display.set_caption("夏目友人帐")
        # 创建一个用于存储游戏统计信息的实例
        self.stats = Gamestats(self)
        self.ship=Ship(self,'images/ship.png')
        self.bullets=pygame.sprite.Group()
        self.jineng1=pygame.sprite.Group()
        self.aliens=pygame.sprite.Group()
        self.boss1=pygame.sprite.Group()
        self.miaobi=pygame.sprite.Group()
        self.jineng2_1duan=pygame.sprite.Group()
        self.jineng2_2duan=pygame.sprite.Group()
        self.heimao_bulletgroup=pygame.sprite.Group()
        self._create_fleet()
        self._create_miaobiqun()
        self.play_button=Button(self,'click to play~',255,255,255)
        self.replay_button=Button(self,'replay',255,255,255)
        self.music_button=Music_flag(self,'playing',255,255,255)
        self.youxishuoming=Youxishuoming(self,'Game Description',255,255,255)
        self.score_board=Scoreboard(self)
        self.history=History(self)
        self.miaobi_note=Miaobir(self)
        #self.clock=pygame.time.Clock()
        #self.current_time=pygame.time.get_ticks()

    def run_game(self):
        """开始游戏的主循环"""

        while True:
            self._check_events()
            self.music_update()
            if self.stats.game_active==True:
                if self.settings.jiluboss_time_flag:
                    self.settings.create_boss_time = time()
                    self.settings.jiluboss_time_flag=False

                self.ship.update()
                self.update_bullets()
                self.update_jineng1()
                self.update_jineng2_1duan()
                self.update_jineng2_2duan()
                self.update_aliens()
                self.update_boss1()
                self.update_heimaobullet()
                self.update_miaobi()
            self._update_screen()
            #self.clock.tick(100)

    def _check_events(self):
        """响应按键和鼠标事件"""
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                sys.exit()
            elif event.type==pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                if self.stats.ships_left==self.settings.ship_limit:
                    self._check_play_button(mouse_pos)
                    self._check_youxishuoming_button(mouse_pos)
                elif self.stats.ships_left==0:
                    self._check_replay_button(mouse_pos)

            elif event.type==pygame.KEYDOWN:
                self._check_keydown_events(event)

            elif event.type==pygame.KEYUP:
                self._check_keyup_events(event)

    def music1_start(self):
        pygame.mixer.init()  # 初始化
        pygame.mixer.music.load('musics/bgmusic1.mp3')  # 加载音乐文件
        pygame.mixer.music.play(-1)
    def music_update(self):
        if self.stats.game_active==False:
            if self.settings.music2_active == False:
                self.music2_start()
                self.settings.music2_active=True
        else:
            if self.settings.music1_active == False:
                self.music1_start()
                self.settings.music1_active = True

    def music2_start(self):
        pygame.mixer.init()  # 初始化
        pygame.mixer.music.load('musics/bgmusic2.mp3')  # 加载音乐文件
        pygame.mixer.music.play(-1)

    def _update_screen(self):
        """更新屏幕上的图像,并切换到新屏幕"""
        if self.stats.play_click==False:
            self.screen.blit(self.settings.background1,(0,0))
            if self.settings.show_youxishuoming_flag:
                self.screen.blit(self.settings.youxiguize_image,(0,0))
        if self.stats.play_click==True:
            #self.screen.fill(self.settings.bg_color)
            self.screen.blit(self.settings.background2, (0, 0))
            self.ship_show()
            for bullet in self.bullets.sprites():
                bullet.draw_bullet()
            #for heimaobullet in self.new_bulletgroup.copy():
            for bullet in self.heimao_bulletgroup.sprites():
                bullet.draw_bullet()
            self.jineng1.draw(self.screen)
            self.jineng2_1duan.draw(self.screen)
            self.jineng2_2duan.draw(self.screen)
            self.aliens.draw(self.screen)
            self.boss1.draw(self.screen)
            self.miaobi.draw(self.screen)
            self.score_board.show_score()
            self.shuaxin_history()
            self.history.show_history()
            self.miaobi_note.show_miaobi_note()
            self.miaobi_note.show_amount()
            self.music_button.draw_button()
            self.music_button.draw_note_image()

        if not self.stats.game_active:
            if self.stats.ships_left==self.settings.ship_limit and self.stats.play_click==False:
                if self.settings.show_youxishuoming_flag==False:
                    self.play_button.draw_button()
                    self.play_button.draw_note_image()
                self.youxishuoming.draw_button()
                self.youxishuoming.draw_youxishuoming_image()
                self.banquanshuoming.draw_button()
            elif self.stats.ships_left<=self.settings.ship_limit and self.stats.ships_left>0:
                self.play_button.draw_button()
                self.play_button.draw_note_pause_image()
            elif self.stats.ships_left==0:
                self.replay_button.draw_button()
                self.replay_button.draw_note_image()
                self.ship.center_ship()

        pygame.display.flip()

    def _check_keydown_events(self,event):
        if event.key==pygame.K_j:
            self._fire_bullet(self.settings.bullet_allowed)
        if self.stats.zifa_limit_flag==False:
            if event.key==pygame.K_u:
                if self.stats.amount>=5:
                    if len(self.jineng1) < self.settings.jineng1_bullet_allowed:
                        self._fire_jineng1()
                        self.stats.amount -= 5
                        self.miaobi_note.prep_miaobi_amount()
            if event.key==pygame.K_i:
                if self.stats.amount>=10:
                    self._fire_jineng2_1duan()
                    self.stats.amount-=10
                    self.miaobi_note.prep_miaobi_amount()
            if event.key==pygame.K_o:
                if self.stats.amount>=20:
                    self.jineng3_xiangyin()
        if event.key==pygame.K_TAB:
            if self.stats.ships_left<=3 and self.stats.ships_left>0:
                self.stats.game_active=False
                pygame.mouse.set_visible(True)
        if event.key==pygame.K_CAPSLOCK:
            if self.stats.ships_left <= 3 and self.stats.ships_left > 0:
                self.stats.game_active=True
        if event.key==pygame.K_RIGHT:
            self.ship.moving_right=True
        if event.key==pygame.K_LEFT:
            self.ship.moving_left=True
        if event.key==pygame.K_UP:
            self.ship.moving_up=True
        if event.key==pygame.K_DOWN:
            self.ship.moving_down=True

        if event.key==pygame.K_d:
            self.ship.moving_right=True
        if event.key==pygame.K_a:
            self.ship.moving_left=True
        if event.key==pygame.K_w:
            self.ship.moving_up=True
        if event.key==pygame.K_s:
            self.ship.moving_down=True
        if event.key==pygame.K_p:
            self.settings.music_switch*=-1
            if self.settings.music_switch == -1:
                self.music_button.msg='pause'
                pygame.mixer.music.pause()
            else:
                self.music_button.msg='playing'
                pygame.mixer.music.unpause()
            self.music_button._prep_msg()

        if event.key==pygame.K_ESCAPE:
            sys.exit()
    def _check_keyup_events(self,event):
        if event.key==pygame.K_RIGHT:
            self.ship.moving_right=False
        if event.key==pygame.K_LEFT:
            self.ship.moving_left=False
        if event.key==pygame.K_UP:
            self.ship.moving_up=False
        if event.key==pygame.K_DOWN:
            self.ship.moving_down=False

        if event.key==pygame.K_d:
            self.ship.moving_right=False
        if event.key==pygame.K_a:
            self.ship.moving_left=False
        if event.key==pygame.K_w:
            self.ship.moving_up=False
        if event.key==pygame.K_s:
            self.ship.moving_down=False

       下面是bullet的不同种类,创建,更新,检查碰撞等方法,bullet当然是技能的主要表现方式,普攻是单发(最多同时存在6发),技能1(散射),技能2(爆炸),我自认为技能2是游戏的亮点之一了,发射一个巨大的娘口三三,碰到目标后可以往16个方向释放猫爪。释放多个猫爪的情况,这里我通过创建列表存储update方法中要用到的位移参数,再通过循环遍历达到效果,但实际运行中,猫爪不会往指定的方向径直移动(其实这样的效果也蛮有意思的,所以就没再处理)。

    """bullet..."""
    def _fire_bullet(self,bullet_allowed):
        if len(self.bullets)= self.screen.get_rect().right:
                    self.jineng1.remove(bullet)
        self._check_jineng1_alien_collisions()

    def update_jineng2_1duan(self):
        self.jineng2_1duan.update()
        for bullet in self.jineng2_1duan.copy():
            if bullet.rect.bottom <= 0:
                self.jineng2_1duan.remove(bullet)
        self._check_jineng1_1duan_alien_collisions()

    def _check_jineng1_1duan_alien_collisions(self):
        #collisions = pygame.sprite.groupcollide(self.jineng2_1duan, self.aliens, True, True)
        for alien in self.aliens.sprites():
            for bullet in self.jineng2_1duan.sprites():
                if bullet.rect.colliderect(alien):
                     """if collisions:
                     for alien,aliens in collisions.values():
                     self.stats.score += self.settings.alien_point * len(aliens)"""
                     self.stats.score+=self.settings.alien_point
                     self.score_board.prep_score()
                     self.aliens.remove(alien)
                     self.jineng2_1duan.remove(bullet)
                     self._fire_jineng2_2duan(alien)
                     break

    def _fire_jineng2_2duan(self,alien):
        i=0
        while i<16:
            new_bullet=Jineng2_2duan(self,'images/maozhua1.jpg',alien)
            self.jineng2_2duan.add(new_bullet)
            i+=1

    def update_jineng2_2duan(self):
        pianyi_x=[0,0.5,1,2,1,2,1,0.5,0,-0.5,-1,-2,-1,-2,-1,-0.5]
        pianyi_y=[1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,0,1,1,1]
        i=0
        for bullet in self.jineng2_2duan.sprites():
            bullet.update(pianyi_x[i],pianyi_y[i])
            i+=1
            if i==15:
                i=0

        for bullet in self.jineng2_2duan.copy():
            if bullet.rect.bottom <= 0 or bullet.rect.right<=0 or bullet.rect.left >= self.screen.get_rect().right \
                    or bullet.rect.top>=self.screen.get_rect().bottom:
                    self.jineng2_2duan.remove(bullet)
        self._check_jineng1_2duan__alien_collisions()

    def _check_jineng1_2duan__alien_collisions(self):
        collisions = pygame.sprite.groupcollide(self.jineng2_2duan, self.aliens, True, True)
        if collisions:
            for aliens in collisions.values():
                self.stats.score += self.settings.alien_point * len(aliens)
                self.score_board.prep_score()

    def update_bullets(self):
        self.bullets.update()
        for bullet in self.bullets.copy():
            if bullet.rect.bottom <= 0:
                self.bullets.remove(bullet)
        self._check_bullet_alien_collisions()

       下面是关于alien的一些方法,有些检查碰撞的方法也在里面了,关于alien我创建了两种,一是黑猫(可以发射黑猫爪),二是紫发(忘了这妖怪叫啥了,ship碰到她会触发魅惑效果,期间不能使用技能),我是通过对image的判别来区分出两种不同的妖怪效果,这其中魅惑效果的时间计算要用到time()方法,后面的boss计时、miaobi计时出现也要用到。

    """alien..."""
    def _create_fleet(self):
        images = ['images/heimao.png', 'images/zifa.png']
        choose_image = choice(images)
        alien=Alien(self,choose_image)
        number_alien_x=4
        number_rows=2
        #创建群体
        i=1
        j=randint(0,5)
        while(i<=j):
            row_number=randint(0,number_rows)
            alien_number=randint(0,number_alien_x-1)
            self._create_alien(alien_number,row_number)
            i+=1

    def _create_alien(self,alien_number,row_number):
        images=['images/heimao.png','images/zifa.png']
        choose_image=choice(images)
        alien = Alien(self,choose_image)
        alien_width,alien_height=alien.rect.size
        alien.x = alien_width + 2 * alien_width * alien_number
        alien.rect.x = float(alien.x)
        alien.rect.y=float(alien.rect.height+1.5*alien.rect.height*row_number)
        self.aliens.add(alien)

    def update_aliens(self):
        h_time2=time()
        #print(f"h_time2:{h_time2}")
        h_time1=self.settings.create_bullet
        #print(f"h_time2-h_time1:{h_time2-h_time1}")

        if h_time2-h_time1>=1:
            self.create_heimao_bullets()
        self._check_fleet_edges()
        self.aliens.update()

        #检测飞船与目标的碰撞
        for alien in self.aliens.copy():
            if alien.rect.colliderect(self.ship):
                if self.settings.wudi_flag==True:
                    self.aliens.remove(alien)
                else:
                    if alien.image_prep=='images/zifa.png':
                        self.zifa_xiangyin()
                        self.aliens.remove(alien)
                    if alien.image_prep=='images/heimao.png':
                        self._ship_hit()
        #检测目标到达屏幕底端
        self._check_alien_bottom()

    def create_heimao_bullets(self):
        self.settings.create_bullet=time()
        for alien in self.aliens.sprites():
            if alien.image_prep=='images/heimao.png':
                new_bullet=Heimao_bullet(self,'images/heimaozhua.png',alien)
                self.heimao_bulletgroup.add(new_bullet)

    def update_heimaobullet(self):
        #for heimao_bullet in self.new_bulletgroup.copy():
        self.heimao_bulletgroup.update()
        self._check_heimaobullet_bottom()
        self._check_heimaobullet_ship_collision()

    def _check_heimaobullet_bottom(self):
        for bullet in self.heimao_bulletgroup.copy():
            if bullet.rect.top>self.screen.get_rect().bottom:
                self.heimao_bulletgroup.remove(bullet)

    def _check_heimaobullet_ship_collision(self):

        for heimaobullet in self.heimao_bulletgroup.sprites():
            if heimaobullet.rect.colliderect(self.ship):
                if self.settings.wudi_flag==True:
                    self.heimao_bulletgroup.remove(heimaobullet)
                else:
                    self._ship_hit()

    def _check_fleet_edges(self):
        for alien in self.aliens.sprites():
            if alien.a_check_edges():
                self.change_fleet_direction()
                break

    def change_fleet_direction(self):
        for alien in self.aliens.sprites():
            alien.rect.y+=self.settings.fleet_drop_speed
        self.settings.fleet_direction*=-1

    def change_miaobiqun_direction(self):
        for miaobi in self.miaobi.sprites():
            miaobi.rect.y+=self.settings.miaobiqun_drop_speed
        self.settings.miaobiqun_direction*=-1

    def _check_bullet_alien_collisions(self):
        #检查是否击中
        collisions = pygame.sprite.groupcollide(self.bullets,self.aliens,True,True)
        if collisions:
            for aliens in collisions.values():
                self.stats.score+=self.settings.alien_point*len(aliens)
                self.score_board.prep_score()
        #全部击中后清空子弹并再次生成目标
        if not self.aliens:
            self.bullets.empty()
            self._create_fleet()

            self.settings.increase_speed()  # 加速

    def _check_jineng1_alien_collisions(self):
        collision =pygame.sprite.groupcollide(self.jineng1,self.aliens,True,True)
        if collision:
            for aliens in collision.values():
                self.stats.score += self.settings.alien_point * len(aliens)
                self.score_board.prep_score()

    def _ship_hit(self):
        self.stats.ships_left-=1
        if self.stats.ships_left>0:
            self.score_board.prep_ships_sign()
            print(f"剩余:{self.stats.ships_left}")
            #zhuangji
            self.ship.image=pygame.image.load('images/zhuangji.png')
            self._update_screen()
            #暂停
            sleep(1.0)
            self.ship.image=pygame.image.load('images/ship.png')
            self._empty_all()
            self.heimao_bulletgroup.empty()
            #重绘
            self._create_fleet()
            self.ship.center_ship()
        else:
            self.stats.game_active=False
            self.score_board.prep_ships_sign()
            pygame.mouse.set_visible(True)

            print(f"剩余:{self.stats.ships_left}\nGame over!")

    def _check_alien_bottom(self):
        for alien in self.aliens.sprites():
            if alien.rect.bottom>=self.screen.get_rect().bottom:
                self._ship_hit() #像ship被撞到一样处理
                break

       下面是关于boss的一系列方法,关于boss我还没有设置攻击之类的(没什么想法),想做个动图效果(主要是因为图片制作麻烦)。boss设置了hp生命值,其实后来我想也可以给ship也添加hp属性,忙着上网课啥,就没改(主要是因为懒),想做的小伙伴可以参考boss的方法处理。

    """boss1"""
    def _create_boss1(self):
        self.settings.create_boss_time=time()
        boss1=Boss1(self,'images/boss1.png')
        self.boss1.add(boss1)

    def update_boss1(self):
        boss1_time2 = time()
        boss1_time1 = self.settings.create_boss_time
        #print(boss1_time2-boss1_time1)
        if (boss1_time2-boss1_time1) >= 30:
            self._create_boss1()

        self.boss1.update()
        self._check_boss1_bottom()
        self._check_boss1_gezhong_bullets_collision()

    def _check_boss1_bottom(self):
        for boss1 in self.boss1.copy():
            if boss1.rect.top>self.screen.get_rect().bottom:
                self._ship_hit()
                self.boss1.remove(boss1)

    def _check_boss1_ship_collision(self):
        if self.settings.wudi_flag==False:
            for boss1 in self.boss1.sprites():
                if boss1.rect.colliderect(self.ship):
                    self._ship_hit()
                    boss1.hp-=15

    def _check_boss1_gezhong_bullets_collision(self):
        for boss1 in self.boss1.sprites():
            for bullet in self.bullets.sprites():
                if boss1.rect.colliderect(bullet):
                    if bullet.image_prep=='images/maozhua.png':
                        boss1.hp-=1
                        print(boss1)
                    elif bullet.image_prep=='images/lanhei.png':
                        boss1.hp-=4
                    self.bullets.remove(bullet)
                    if boss1.hp==0:
                        self.hp_0(boss1,5)
            for bullet1 in self.jineng1.sprites():
                if boss1.rect.colliderect(bullet1):
                    self.jineng1.remove(bullet1)
                    boss1.hp-=1
                    print(boss1)
                    if boss1.hp==0:
                        self.hp_0(boss1,5)
            for bullet2 in self.jineng2_1duan.sprites():
                if boss1.rect.colliderect(bullet2):
                    self.jineng2_1duan.remove(bullet2)
                    self._fire_jineng2_2duan(boss1)
                    boss1.hp -= 1
                    print(boss1)
                    if boss1.hp==0:
                        self.hp_0(boss1, 5)
            for bullet3 in self.jineng2_2duan.sprites():
                if boss1.rect.colliderect(bullet3):
                    self.jineng2_2duan.remove(bullet3)
                    boss1.hp -= 1
                    print(boss1)
                    if boss1.hp==0:
                        self.hp_0(boss1,5)

    def hp_0(self,boss,beishu):
        self.boss1.remove(boss)
        self.stats.score += self.settings.alien_point * beishu
        self.score_board.prep_score()

       下面是关于miaobi的一些方法,miaobi也有两中,一种是真的喵币,拾取后可以通过消耗喵币释放技能,另一种是夏目,碰到后变身斑形态 ,变身过程我只弄了两张图,效果还行,变身期间无敌并且普攻换成另一种形态,并对boss伤害增加(变身的攻击其实我也是想弄个动画效果)

    """miaobi..."""
    def _create_miaobiqun(self):
        self.miaobi.create_time=time()
        images=['images/1.png','images/xiamu1.png']
        choose_image=choice(images)
        miaobi=Miaobis(self,choose_image)
        miaobi_width,miaobi_height=miaobi.rect.size
        available_space_x= self.settings.screen_width-(2*miaobi_width)
        number_miaobi_x=available_space_x//(2*miaobi_width)
        #print(number_alien_x)
        available_space_y=(self.settings.screen_height-3*miaobi_height)
        number_rows=available_space_y//(2*miaobi_height)
        #print(number_rows)

        #创建群体
        i=1
        while(i<=2):
            row_number=randint(0,number_rows)
            miaobi_number=randint(0,number_miaobi_x-1)
            self._create_miaobi(miaobi_number,row_number)
            i+=1

    def _create_miaobi(self,miaobi_number,row_number):
        images = ['images/1.png', 'images/xiamu1.png']
        choose_image = choice(images)
        miaobi = Miaobis(self, choose_image)
        miaobi_width,miaobi_height=miaobi.rect.size
        miaobi.x = miaobi_width + 2 * miaobi_width * miaobi_number
        miaobi.rect.x = miaobi.x
        miaobi.rect.y=miaobi.rect.height+1.5*miaobi.rect.height*row_number
        self.miaobi.add(miaobi)

    def update_miaobi(self):
        #self._check_miaobiqun_edges()
        self.miaobi.update()
        #检测飞船与喵币的碰撞
        for miaobi in self.miaobi.copy():
            if miaobi.rect.colliderect(self.ship):
                if miaobi.image_prep=='images/1.png':
                    self.stats.amount += 100
                    self.miaobi_note.prep_miaobi_amount()
                    self.miaobi.remove(miaobi)
                    self.stats.score += 10*self.settings.miaobi_point
                    self.score_board.prep_score()
                elif miaobi.image_prep=='images/xiamu1.png':
                    self.ship.image_prep='images/ban11.png'
                    self.ship.image=pygame.image.load(self.ship.image_prep)
                    self.settings.xiamu_time=time()
                    self.miaobi.remove(miaobi)

        if not self.miaobi:
            m_time1 = self.miaobi.create_time
            m_time2 = time()
            #print(m_time2 - m_time1)
            if m_time2 - m_time1 > 15:
                self._create_miaobiqun()
        # 检测喵币到达底部
        self._check_miaobi_bottom()

    def _check_miaobi_bottom(self):
        for miaobi in self.miaobi.copy():
            if miaobi.rect.top>=self.screen.get_rect().bottom:
                self.miaobi.remove(miaobi)
        if not self.miaobi:
            m_time1=self.miaobi.create_time
            m_time2=time()
            #print(m_time2-m_time1)
            if m_time2-m_time1>15:
                self._create_miaobiqun()

       下面的代码包含了检查鼠标事件、技能3响应(使自身变小持续三秒)、紫发响应、刷新历史、ship显示等方法,其中ship显示是个需要仔细处理的方法,因为技能变身,触碰变身的ship.image都不同,其中我设置了image_prep属性,能更好地处理传递参数和条件判断,在其他的对象中我也用到了这个方法。

    """..."""
    def _check_youxishuoming_button(self,mouse_pos):
        button_clicked=self.youxishuoming.youxishuoming_image_rect.collidepoint(mouse_pos)
        if button_clicked:
            if self.settings.show_youxishuoming_flag==False:
                self.settings.show_youxishuoming_flag=True
            else:
                self.settings.show_youxishuoming_flag=False

    def _check_play_button(self,mouse_pos):
        button_clicked = self.replay_button.rect.collidepoint(mouse_pos)
        if button_clicked and not self.stats.game_active:
            self.prep()
            self.stats.play_click=True

    def _check_replay_button(self,mouse_pos):
        button_clicked = self.replay_button.rect.collidepoint(mouse_pos)
        if button_clicked and not self.stats.game_active:
            self.settings.initialize_dynamic_settings()
            self._empty_all()
            self.stats.reset_stats()
            self.stats.amount=0
            self.prep()
            self._update_screen()

    def prep(self):
        print("Game start!")
        self.stats.game_active = True
        self.score_board.prep_score()
        self.shuaxin_history()
        self.score_board.prep_ships_sign()
        self.miaobi_note.prep_miaobi_amount()
        pygame.mouse.set_visible(False)

    def shuaxin_history(self):
        if self.stats.score>=self.stats.history:
            self.stats.history=self.stats.score
            self.history.prep_history()

    def zifa_xiangyin(self):
        self.ship.image_prep='images/zifaxiangyin.png'
        self.ship.image=pygame.image.load(self.ship.image_prep)
        self.ship.bianshen_time=time()
        self.stats.zifa_limit_flag=True
    def jineng3_xiangyin(self):
        self.ship.image_prep='images/jineng3xiangyin.png'
        self.ship.image = pygame.image.load(self.ship.image_prep)
        self.ship.suoxiao_time = time()

    def ship_show(self):
        if self.ship.image_prep=='images/ship.png':
            self.ship.blitme()

            """下述代码有待改进"""
        elif self.ship.image_prep=='images/ban11.png' or self.ship.image_prep=='images/ban22.png':
            xiamu_last_time2=time()
            xiamu_last_time1=self.settings.xiamu_time
            self.settings.wudi_flag = True
            if (xiamu_last_time2-xiamu_last_time1)<3:
                xiamu_time1=self.settings.xiamu_time
                xiamu_time2=time()
                if (xiamu_time2-xiamu_time1)<0.2:
                    self.ship.blitme()
                else:
                    self.ship.image_prep='images/ban22.png'
                    self.ship.image=pygame.image.load(self.ship.image_prep)
                    self.ship.blitme()
            else:
                self.settings.wudi_flag = False
                self.ship.image_prep = 'images/ship.png'
                self.ship.image=pygame.image.load(self.ship.image_prep)
                self.ship.blitme()

        elif self.ship.image_prep=='images/zifaxiangyin.png':
            end=time()
            start=self.ship.bianshen_time
            #print(end-start)
            if end-start<2:
                self.ship.blitme()
            else:
                self.ship.image_prep = 'images/ship.png'
                self.ship.image=pygame.image.load(self.ship.image_prep)
                self.ship.blitme()
                self.stats.zifa_limit_flag=False

        elif self.ship.image_prep=='images/jineng3xiangyin.png':
            end=time()
            start=self.ship.suoxiao_time
            #print(end-start)
            if end-start<2:
                self.ship.blitme()
            else:
                self.ship.image_prep = 'images/ship.png'
                self.ship.image=pygame.image.load(self.ship.image_prep)
                self.ship.blitme()

    def _empty_all(self):
        self.heimao_bulletgroup.empty()
        self.aliens.empty()
        self.bullets.empty()
        self.jineng1.empty()
        self.jineng2_1duan.empty()
        self.jineng2_2duan.empty()
        self.miaobi.empty()

if __name__ == '__main__':
    #创建游戏实例并运行游戏
    ai=AlienInvasion()
    ai.run_game()

OK,到此主模块的程序就介绍完了,接下来就是导入模块的程序,如下:

ship.py:

import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
    """管理飞船的类"""
    def __init__(self,ai_game,image):
        """初始化飞船并设置其初始位置"""
        super().__init__()
        self.screen=ai_game.screen
        self.settings=ai_game.settings
        self.screen_rect=ai_game.screen.get_rect()
        self.bianshen_time=0
        self.suoxiao_time=0
        #加载飞船图像并获取其外接矩形
        self.image_prep=image
        self.image=pygame.image.load(self.image_prep)
        self.rect=self.image.get_rect()
        #对于每艘飞船,都将其放在屏幕的底部中央
        self.rect.midbottom=self.screen_rect.midbottom
        #飞船属性x,y存储小数值
        self.x=float(self.rect.x)
        self.y=float(self.rect.y)
        #移动标志
        self.moving_right=False
        self.moving_left=False
        self.moving_up=False
        self.moving_down=False

    def update(self):
        if self.moving_right and self.rect.x< self.screen_rect.right-100:
            self.x+= self.settings.ship_speed
        if self.moving_left and self.rect.x>0:
            self.x-= self.settings.ship_speed
        if self.moving_up and self.rect.y>0:
            self.y-= self.settings.ship_speed
        if self.moving_down and self.rect.bottom<= self.screen_rect.bottom:
            self.y+= self.settings.ship_speed
        self.rect.x=self.x
        self.rect.y=self.y

    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image,self.rect)

    def center_ship(self):
        """ship底部居中"""
        self.rect.midbottom=self.screen_rect.midbottom
        self.x=float(self.rect.x)
        self.y=float(self.rect.y)

alien.py: boss的类也放在这个文件中了,主要是为了使用继承

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    def __init__(self,ai_game,image):
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.image_prep = image
        self.image = pygame.image.load(self.image_prep)
        self.rect = self.image.get_rect()

        #每个外星人最初在屏幕左上角附近
        self.rect.x=self.rect.width-100
        self.rect.y=self.rect.height-100
        #存储外星人的精确水平位置
        self.x=float(self.rect.x)
        self.y=float(self.rect.y)

    def update(self):
        """移动"""
        self.x+=(self.settings.alien_speed*self.settings.fleet_direction)
        self.rect.x=self.x

    def a_check_edges(self):
        screen_rect=self.screen.get_rect()
        if self.rect.right>=screen_rect.right  or self.rect.left<=0:
            return True

class Miaobis(Alien):
    def __init__(self,ai_game,image):
        super().__init__(ai_game,image)
        self.create_time=0
        # 每个喵币最初在屏幕左上角附近
        self.rect.x = self.rect.width - 150
        self.rect.y = self.rect.height - 150
        # 存储喵币的精确水平位置
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def update(self):
        """移动"""
        self.y += self.settings.miaobi_speed
        self.rect.y = self.y

class Boss1(Alien):
    def __init__(self,ai_game,image):
        super().__init__(ai_game,image)
        self.hp=50
        self.rect.midtop = self.screen.get_rect().midtop
        self.rect.y = -100
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def update(self):
        self.y+=self.settings.boss1_speed
        self.rect.y=self.y

    def __repr__(self):
        return 'hp:%r' % (self.hp)

bullet.py: 存放各种bullet的类

import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
    """管理飞船所发射子弹的类"""
    def __init__(self,ai_game,image):
        """在飞船当前位置创建一个子弹对象"""
        super().__init__()
        self.screen=ai_game.screen
        self.settings=ai_game.settings
        self.image_prep=image
        self.image=pygame.image.load(self.image_prep)
        self.rect=self.image.get_rect()
        self.rect.midtop=ai_game.ship.rect.midtop
        self.x=float(self.rect.x)
        self.y=float(self.rect.y)

    def update(self):
        """向上移动子弹"""
        self.y-=self.settings.bullet_speed
        self.rect.y=self.y

    def draw_bullet(self):
        self.screen.blit(self.image, self.rect)

class Jineng1(Bullet):
    def __init__(self,ai_game,image):
        super().__init__(ai_game,image)

    def update(self,x):
        """各方位移动子弹"""
        self.x+=x
        self.y-=self.settings.bullet_speed
        self.rect.x=self.x
        self.rect.y=self.y

class Jineng2_1duan(Bullet):
    pass

class Jineng2_2duan(Bullet):
    def __init__(self,ai_game,image,mubiao):
        super().__init__(ai_game,image)
        self.rect.midtop = mubiao.rect.midbottom
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def update(self,x,y):
        self.x+=x
        self.y+=y
        self.rect.x=self.x
        self.rect.y=self.y

class Heimao_bullet(Bullet):
    def __init__(self,ai_game,image,alien):
        super().__init__(ai_game,image)
        self.rect.midbottom=alien.rect.midbottom
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)

    def update(self):
        self.y+=self.settings.heimao_bullet_speed
        self.rect.y=self.y

button.py:里面有play、replay、游戏说明按钮,还有music_flag这个其实一开始想通过鼠标点击来开关音乐,但是前面设置了游戏中隐藏鼠标,所以就设置了按键p来开关,这个button就只是为了显示image,这里可以进行一些优化。

import pygame.font
class Button():
    def __init__(self,ai_game,msg,t_R,t_G,t_B):
        """chushihua button 的属性"""
        self.screen=ai_game.screen
        self.screen_rect=ai_game.screen.get_rect()
        """设置按钮的属性"""
        self.width,self.height=200,50
        self.text_color=(t_R,t_G,t_B)
        self.font=pygame.font.SysFont('Times New Roman',40)
        #创建按钮的rect对象
        self.rect=pygame.Rect(0,0,self.width,self.height)
        self.rect.center=self.screen_rect.center
        # button标签只创建一次
        self.msg=msg
        self._prep_msg()
        # note_image图片
        self.note_image = pygame.image.load('images/heibai.png')
        self.note_pause_image = pygame.image.load('images/zanting.png')

    def _prep_msg(self):
        """将msg渲染成图像,并使其在按钮上居中"""
        self.msg_image=self.font.render(self.msg,True,self.text_color)
        self.msg_image_rect=self.msg_image.get_rect()
        self.msg_image_rect.midtop=self.rect.midbottom
        self.msg_image_rect.top=self.rect.bottom+20

    def draw_button(self):
        #self.screen.fill(self.button_color,self.rect)
        self.screen.blit(self.msg_image,self.msg_image_rect)

    def draw_note_image(self):
        self.note_image_rect=self.note_image.get_rect()
        self.note_image_rect.center=self.rect.center
        self.screen.blit(self.note_image,self.note_image_rect)

    def draw_note_pause_image(self):
        self.note_pause_image_rect=self.note_pause_image.get_rect()
        self.note_pause_image_rect.center=self.rect.center
        self.screen.blit(self.note_pause_image,self.note_pause_image_rect)

class Music_flag(Button):
    def __init__(self,ai_game,msg,t_R,t_G,t_B):
        super().__init__(ai_game,msg,t_R,t_G,t_B)
        self.music_flag_image=pygame.image.load('images/music_flag.png')
        self.font = pygame.font.SysFont('Times New Roman', 30)
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.left=self.screen_rect.left
        self.rect.y=0
        # button标签只创建一次
        self.msg=msg
        self._prep_msg()
        # note_image图片
        self.note_image = pygame.image.load('images/heibai.png')
        self.note_pause_image = pygame.image.load('images/zanting.png')
        self.youxishuoming_image=pygame.image.load('images/xiaohuli.png')

    def _prep_msg(self):
        """将msg渲染成图像,并使其在按钮上居中"""
        self.msg_image = self.font.render(self.msg, True, self.text_color)
        self.msg_image_rect=self.msg_image.get_rect()
        self.msg_image_rect.y=65
        self.msg_image_rect.left=self.rect.left+50

    def draw_note_image(self):
        self.music_flag_image_rect=self.music_flag_image.get_rect()
        self.music_flag_image_rect.left=self.rect.left+10
        self.music_flag_image_rect.y=65
        self.screen.blit(self.music_flag_image,self.music_flag_image_rect)

class Youxishuoming(Button):
    def __init__(self,ai_game,msg,t_R,t_G,t_B):
        super().__init__(ai_game,msg,t_R,t_G,t_B)
        self.font = pygame.font.SysFont('Times New Roman', 30)
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        # button标签只创建一次
        self.msg=msg
        self._prep_msg()
        # note_image图片
        self.note_image = pygame.image.load('images/heibai.png')
        self.note_pause_image = pygame.image.load('images/zanting.png')
        self.youxishuoming_image=pygame.image.load('images/mao11.png')

    def _prep_msg(self):
        """将msg渲染成图像,并使其在按钮上居中"""
        self.msg_image = self.font.render(self.msg, True, self.text_color)
        self.msg_image_rect=self.msg_image.get_rect()
        self.msg_image_rect.y=20
        self.msg_image_rect.left=self.rect.left+30

    def draw_youxishuoming_image(self):
        self.youxishuoming_image_rect=self.youxishuoming_image.get_rect()
        self.youxishuoming_image_rect.top=self.msg_image_rect.bottom
        self.youxishuoming_image_rect.x=30
        self.screen.blit(self.youxishuoming_image,self.youxishuoming_image_rect)

game_stats.py: 这里面主要是游戏数据信息和标志属性

class Gamestats():
    def __init__(self,ai_game):
        """初始化统计信息"""
        self.game_active=False
        self.settings=ai_game.settings
        self.reset_stats()
        self.score=0
        self.amount=0
        self.history=0
        self.zifa_limit_flag=False
        self.create_m_limit=False
        self.play_click=False

    def reset_stats(self):
        """初始化在游戏运行期间可能变化的统计信息"""
        self.ships_left=self.settings.ship_limit
        self.score=0

miaobi_r.py:这个文件的类可以在button.py里面通过继承来实现,会简洁许多,作用是显示喵币标识和数量。

import pygame
class Miaobir():
    def __init__(self,ai_game):
        self.screen=ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        self.sb=ai_game.score_board
        self.stats=ai_game.stats
        self.settings=ai_game.settings
        self.image=pygame.image.load('images/miaobi_note.png')
        self.rect=self.image.get_rect()
        # 显示喵币信息的字体设置
        self.text_color = (169, 89, 30)
        self.font = pygame.font.SysFont(None, 48)
        # 准备喵币数图像
        self.prep_miaobi_amount()
        #位置
        self.rect.top=self.sb.score_rect.bottom+14
        self.rect.x=self.screen_rect.right-40

    def show_miaobi_note(self):
        self.screen.blit(self.image, self.rect)

    def prep_miaobi_amount(self):
        amount_str = f"{str(self.stats.amount)} x "
        self.miaobi_amount_image = self.font.render(amount_str, True, self.text_color)
        self.miaobi_amount_rect = self.miaobi_amount_image.get_rect()
        self.miaobi_amount_rect.right = self.rect.right - 40
        self.miaobi_amount_rect.top = self.rect.bottom-30

    def show_amount(self):
        self.screen.blit(self.miaobi_amount_image, self.miaobi_amount_rect)
scoreboard.py:显示分数和历史记录,这里也可以使用继承
import pygame.font
from ship import Ship
class Scoreboard():
    def __init__(self,ai_game):
        self.ai_game=ai_game
        self.screen=ai_game.screen
        self.screen_rect=ai_game.screen.get_rect()
        self.settings=ai_game.settings
        self.stats=ai_game.stats
        #显示得分信息的字体设置
        self.text_color=(169,89,30)
        self.font=pygame.font.SysFont(None,48)
        #准备得分图像
        self.prep_score()
        self.ships_sign = pygame.sprite.Group()
    def prep_score(self):
        """将得分转换为一幅渲染的图像"""
        score_str=f"score: {str(self.stats.score)}"
        self.score_image=self.font.render(score_str,True,self.text_color)
        #右上角显示得分
        self.score_rect=self.score_image.get_rect()
        self.score_rect.right=self.screen_rect.right-20
        self.score_rect.top=20
    def prep_ships_sign(self):
        self.ships_sign = pygame.sprite.Group()
        for ship_number in range(self.stats.ships_left):
            ship_sign=Ship(self.ai_game,'images/niangkou.png')
            ship_sign.rect.x=10+ship_number * (ship_sign.rect.width+3)
            ship_sign.rect.y=10
            self.ships_sign.add(ship_sign)
    def show_score(self):
        self.screen.blit(self.score_image,self.score_rect)
        self.ships_sign.draw(self.screen)

class History():
    def __init__(self,ai_game):
        self.ai_game = ai_game
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        self.settings = ai_game.settings
        self.stats = ai_game.stats
        self.text_color = (169, 89, 30)
        self.font = pygame.font.SysFont(None, 48)
    def prep_history(self):
        history_str = f"History: {str(self.stats.history)}"
        self.history_image = self.font.render(history_str, True, self.text_color)
        self.history_rect = self.history_image.get_rect()
        self.history_rect.midtop=self.screen_rect.midtop
    def show_history(self):
        self.screen.blit(self.history_image, self.history_rect)

settings.py:Settings类存储各个对象的设置,还有初始化设置等方法

import pygame
class Settings:
    """存储游戏中所有的设置的类"""
    def __init__(self):
        """初试化游戏的设置"""
        #屏幕设置
        self.screen_width=1200
        self.screen_height=780
        self.bg_color=(106,90,205)
        self.background1 = pygame.image.load('images/bg4 1200 780.png')
        self.background2=pygame.image.load('images/bg1 1200 780.jpg')
        #三三设置
        self.ship_limit=3
        self.ship_speed=1.2
        self.xiamu_time=0
        self.wudi_flag=False
        #子弹设置
        self.bullet_width=30
        self.bullet_height=15
        self.bullet_speed=1.5
        self.bullet_allowed=6
        self.jineng1_bullet_allowed=10
        #heimao目标设置
        self.alien_speed=0.8
        self.fleet_drop_speed=15
        self.fleet_direction=1 #right
        self.alien_point=10
        self.heimao_bullet_speed=1
        self.create_bullet = 0
        #boss1设置
        self.boss1_speed=0.1
        self.create_boss_time = 0.1
        self.c_b_limit=False
        self.jiluboss_time_flag=True
        #maobi目标设置
        self.miaobi_speed=0.4
        self.miaobiqun_drop_speed=10
        self.miaobiqun_direction=-1#left
        self.miaobi_point=1
        #加快节奏
        self.speedup_scale=1.1
        self.score_scale=1.3
        self.initialize_dynamic_settings()
        #背景音乐
        self.music1=pygame.mixer.music.load('musics/bgmusic1.mp3')
        self.music2 = pygame.mixer.music.load('musics/bgmusic2.mp3')
        self.music1_active= False
        self.music2_active = False
        self.music_switch=1
        #游戏说明
        self.youxiguize_image=pygame.image.load('images/youxiguize22.png')
        self.youxiguize_image_rect=self.youxiguize_image.get_rect()
        self.youxiguize_image_rect.x=300
        self.youxiguize_image_rect.y=200
        self.show_youxishuoming_flag=False
    def initialize_dynamic_settings(self):
        """初始化设置"""
        self.ship_speed = 1.0
        self.bullet_speed = 1
        self.alien_speed = 0.5
        self.alien_point=10
        self.fleet_direction = 1  # right

    def increase_speed(self):
        if self.ship_speed<=1.7:
            self.ship_speed*=self.speedup_scale
        if self.alien_speed<=1.5:
            self.alien_speed*=self.speedup_scale
            self.alien_point = int(self.alien_point * self.score_scale)
        if self.bullet_speed<=2.5:
           self.bullet_speed*=self.speedup_scale
        if self.alien_speed>1.5 and self.fleet_drop_speed<30:
            self.fleet_drop_speed*=self.speedup_scale

        #print(f"s:{float(self.ship_speed)} a:{float(self.alien_speed)}\nb:{float(self.bullet_speed)} p:{self.alien_point}")

结语:这就是游戏程序的全部内容啦,希望这篇文章能够帮助你,感兴趣的小伙伴欢迎交流!

你可能感兴趣的:(python,pygame,pycharm)