Python自学第二十一天——飞机大战项目实践(四)

作为新手自学Python的第二十一天,技术低微,希望可以通过这种方式督促自己学习。

个人学习环境:python3.9,PyCharm 2021.3.2 (Community Edition)


利用python完成飞机大战是一个非常经典的练手项目,本次主要内容是添加敌人飞机及战斗,并完成最终的打包操作。


在这一节中,我们会多封装一个Enemy类,通过检测子弹和敌人飞机的碰撞进行消灭敌机。从而完成最终的游戏制作。

# 导入pygame库
import pygame
# 导入pygame库中的一些常量
from pygame.locals import *
# 导入sys库中的exit函数
from sys import exit
from random import randint
​
# 定义窗口的分辨率
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 640
​
​
# 使用精灵模块(pygame.sprite),将游戏内的一类元素进行编组
# 玩家类
class Hero(pygame.sprite.Sprite):
​
    def __init__(self, hero_surface, hero_init_pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = hero_surface
        self.rect = self.image.get_rect()
        self.rect.topleft = hero_init_pos
        self.speed = 6
        self.is_hit = False
​
        # 子弹1的Group
        self.bullets1 = pygame.sprite.Group()
​
    # 控制射击行为
    def single_shoot(self, bullet1_surface):
        buttle1 = Buttle(bullet1_surface, self.rect.midtop)
        self.bullets1.add(buttle1)
​
    # 控制飞机移动
    def move(self, offset):
        x = self.rect.left + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
        y = self.rect.top + offset[pygame.K_DOWN] - offset[pygame.K_UP]
        if x < 0:
            self.rect.left = 0
        elif x > SCREEN_WIDTH - self.rect.width:
            self.rect.left = SCREEN_WIDTH - self.rect.width
        else:
            self.rect.left = x
​
        if y < 0:
            self.rect.top = 0
        elif y > SCREEN_HEIGHT - self.rect.height:
            self.rect.top = SCREEN_HEIGHT - self.rect.height
        else:
            self.rect.top = y
​
​
# 子弹类
class Buttle(pygame.sprite.Sprite):
​
    def __init__(self, buttle_surface, buttle_init_pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = buttle_surface
        self.rect = self.image.get_rect()
        self.rect.topleft = buttle_init_pos
        self.speed = 8
​
    # 控制子弹移动
    def update(self):
        self.rect.top -= self.speed
        # 子弹超出屏幕范围后,调用kill()移除
        if self.rect.top < -self.rect.height:
            self.kill()
​
​
#  敌人类
class Enemy(pygame.sprite.Sprite):
    def __init__(self, enemy_surface, enemy_init_pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = enemy_surface
        self.rect = self.image.get_rect()
        self.rect.topleft = enemy_init_pos
        self.speed = 2
​
        # 爆炸动画画面索引
        self.down_index = 0
​
    def update(self):
        self.rect.top += self.speed
        if self.rect.top > SCREEN_HEIGHT:
            self.kill()
​
​
def run_game():
    # 定义画面帧率
    FRAME_RATE = 60
​
    # 定义动画周期(帧率)
    ANIMATE_CYCLE = 30
​
    ticks = 0
    clock = pygame.time.Clock()
​
    # dict 字典
    offset = {pygame.K_LEFT: 0, pygame.K_RIGHT: 0, pygame.K_UP: 0, pygame.K_DOWN: 0}
​
    # 玩家坠毁图片索引
    hero_down_index = 1  # new
​
    # 初始化游戏
    pygame.init()  # 初始化 pygame
    screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])  # 初始化窗口
    pygame.display.set_caption('飞机大战')  # 设置窗口标题
​
    # 载入背景图
    background = pygame.image.load('./image/background.png')
​
    # 游戏结束图
    gameover = pygame.image.load('./image/gameover.png')
​
    # Hero图片
    hero1 = pygame.image.load('./image/me1.png')
    hero2 = pygame.image.load('./image/me2.png')
    hero3 = pygame.image.load('./image/me_destroy_1.png')
    hero4 = pygame.image.load('./image/me_destroy_2.png')
    hero5 = pygame.image.load('./image/me_destroy_3.png')
    hero6 = pygame.image.load('./image/me_destroy_4.png')
    hero_surface = [hero1, hero2, hero3, hero4, hero5, hero6]
    hero_pos = [200, 500]
​
    # bullet1模型
    buttle1_surface = pygame.image.load('./image/bullet1.png')
​
    # enemy图片
    enemy1_surface = pygame.image.load('./image/enemy1.png')
    enemy1_down_surface1 = pygame.image.load('./image/enemy1_down1.png')
    enemy1_down_surface2 = pygame.image.load('./image/enemy1_down2.png')
    enemy1_down_surface3 = pygame.image.load('./image/enemy1_down3.png')
    enemy1_down_surface4 = pygame.image.load('./image/enemy1_down4.png')
    enemy1_down_surface = [enemy1_down_surface1, enemy1_down_surface2, enemy1_down_surface3, enemy1_down_surface4]
​
    # 创建玩家
    hero = Hero(hero_surface[0], hero_pos)
​
    # 创建敌人组
    enemy1_group = pygame.sprite.Group()
​
    # 创建击毁敌人组
    enemy1_down_group = pygame.sprite.Group()
​
    # 事件循环(main loop)
    while True:
​
        # 控制游戏最大帧率
        clock.tick(FRAME_RATE)
​
        # 绘制背景
        screen.blit(background, (0, 0))
​
        # 改变飞机图片制造动画
        if ticks >= ANIMATE_CYCLE:
            ticks = 0
​
        # 改变飞机动画
        if hero.is_hit:
            if ticks % (ANIMATE_CYCLE // 2) == 0:
                hero_down_index += 1
            hero.image = hero_surface[hero_down_index]
            if hero_down_index == 5:
                break
        else:
            hero.image = hero_surface[ticks // (ANIMATE_CYCLE // 2)]
​
        # 射击
        if ticks % 10 == 0:
            hero.single_shoot(buttle1_surface)
​
        # 控制子弹
        hero.bullets1.update()
​
        # 绘制子弹
        hero.bullets1.draw(screen)
​
        # 产生敌机
        if ticks % 30 == 0:
            enemy = Enemy(enemy1_surface,
                          [randint(0, SCREEN_WIDTH - enemy1_surface.get_width()), -enemy1_surface.get_height()])
            enemy1_group.add(enemy)
​
        # 控制敌机
        enemy1_group.update()
​
        # 绘制敌机
        enemy1_group.draw(screen)
​
        # 检测敌机与子弹的碰撞
        enemy1_down_group.add(pygame.sprite.groupcollide(enemy1_group, hero.bullets1, True, True))
​
        for enemy1_down in enemy1_down_group:
            screen.blit(enemy1_down_surface[enemy1_down.down_index], enemy1_down.rect)
            if ticks % (ANIMATE_CYCLE // 2) == 0:
                if enemy1_down.down_index < 3:
                    enemy1_down.down_index += 1
                else:
                    enemy1_down_group.remove(enemy1_down)
​
        # 检测敌机与玩家的碰撞
        enemy1_down_list = pygame.sprite.spritecollide(hero, enemy1_group, True)
        if len(enemy1_down_list) > 0:
            enemy1_down_group.add(enemy1_down_list)
            hero.is_hit = True
​
        # 绘制飞机
        screen.blit(hero.image, hero.rect)
        ticks += 1
​
        # 更新屏幕
        pygame.display.update()
​
        # 处理游戏退出
        # 从消息队列中循环取
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
​
            # 控制方向
            if event.type == pygame.KEYDOWN:
                if event.key in offset:
                    offset[event.key] = hero.speed
            elif event.type == pygame.KEYUP:
                if event.key in offset:
                    offset[event.key] = 0
​
        # 移动飞机
        hero.move(offset)
​
    # 跳出主循环
    screen.blit(gameover, (90, 300))
​
    # 玩家坠毁后退出游戏
    while True:
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
​
​
run_game()
​

在Hero类中增加一个is_hit属性,用来检测敌人飞机和自己是否发生了碰撞,从而结束游戏的标志;

利用randint函数完成敌机随机生成在屏幕顶端,按一定时间间隔生成敌机;

使用Pygame自带的grouppcollide()函数检测子弹是否与敌机发生碰撞;

使用Pygame自带的spritecollide()函数检测飞机和敌机是否发生碰撞。

至此,游戏基础整体结构完成。

(五)打包成exe文件

代码编写完成以后我们需要将项目打包为exe文件才能够让别人也玩到我们做的飞机大战,我们使用pyinstaller来完成打包操作。

1、安装pipstaller

首先是安装pystaller,使用命令行执行

pip install pystaller

2、执行打包操作

先使用cmd打开你的py文件所在的文件夹,执行如下命令

pyinstaller -F -w -n AirplaneWars main.py

等待命令执行完毕,会发现目录下多出了几个文件夹

其中生成的exe文件存放在dist文件夹下,我们需要将我们的图片文件夹复制一份放入dist文件夹即可运行我们的AirplantWars.exe。

下面列出常用的pyinstaller选项。

-h,--help查看该模块的帮助信息
-F,-onefile产生单个的可执行文件
-D,--onedir产生一个目录(包含多个文件)作为可执行程序
-a,--ascii不包含 Unicode 字符集支持
-d,--debug产生 debug 版本的可执行文件
-w,--windowed,--noconsolc指定程序运行时不显示命令行窗口(仅对 Windows 有效)
-c,--nowindowed,--console指定使用命令行窗口运行程序(仅对 Windows 有效)
-o DIR,--out=DIR指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件
-p DIR,--path=DIR设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径
-n NAME,--name=NAME指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,今我们来学习Python中的字典(Dictionary)。 字典是一种无序的、可变的数据类型,它以键值对(key-value)的形式存储数据,其中键(key)必须是唯一的,而值(value)可以是任意数据类型。字典用花括号{}表示,每个键值对之间用逗号隔开。 下面是一个简单的字典示例: ``` my_dict = {'name': '张三', 'age': 18, 'gender': '男'} ``` 这个字典中,'name'、'age'、'gender'就是键,而'张三'、18、'男'就是相应的值。 可以使用`dict()`函数来创建一个字典,也可以使用`{}`来创建一个空字典。 接下来,我们来看一些常用的字典操作。 1. 访问字典元素 可以通过键来访问字典中的元素,例如: ``` print(my_dict['name']) # 输出:张三 ``` 如果键不存在,则会抛出KeyError异常。 2. 修改字典元素 可以通过键来修改字典中的元素,例如: ``` my_dict['age'] = 20 print(my_dict) # 输出:{'name': '张三', 'age': 20, 'gender': '男'} ``` 3. 添加字典元素 可以通过键来添加字典中的元素,例如: ``` my_dict['address'] = '北京市' print(my_dict) # 输出:{'name': '张三', 'age': 20, 'gender': '男', 'address': '北京市'} ``` 4. 删除字典元素 可以通过键来删除字典中的元素,例如: ``` del my_dict['gender'] print(my_dict) # 输出:{'name': '张三', 'age': 20, 'address': '北京市'} ``` 5. 字典长度 可以使用`len()`函数来获取字典的长度,例如: ``` print(len(my_dict)) # 输出:3 ``` 6. 字典遍历 可以使用`items()`方法来遍历字典中的每一个键值对,例如: ``` for key, value in my_dict.items(): print(key, value) ``` 输出: ``` name 张三 age 20 address 北京市 ``` 通过上述操作,我们可以初步了解字典的基本用法。在实际应用中,字典是非常重要的数据类型,它可以用来存储和处理各种复杂的数据结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei730050

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值