飞机大战小游戏(超详细)

人生苦短我用Python

偷学Python之最后的项目二:飞机大战小游戏(超详细)

古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。——苏轼

甜甜先说

这次用Python中的pygame模块来完成一个飞机大战的小游戏;基本思路是通过方向键来控制飞机的左右移动射击飞船。

成品效果

此博客是记录编写的全部流程,每次修改的代码也包括在内
看一下SCDN的统计字数在这里插入图片描述
当然,这里面大部分是代码,而且是一步一步的代码。如果跟着敲的话预计好几个小时,介意的话我开了另一帖,那个贴只有成品代码,传送门

安装pygame

要完成这个项目肯定要安装pygame第三方库,安装流程如下

  1. 首先通过命令行工具检测系统是否安装的pip工具

    python -m pip --version
    

    image-20200603085158803

    小甜是Windows系统,这里只提供Windows系统的检测方法

  2. 如果未安装则安装pip工具,安装则请跳过这一步

    python get-pip.py
    

    安装完毕以后退回第一步重新检测

  3. 安装pygame

    python -m pip install pygame --user
    

    或者通过pycharm安装第三个库,流程如下

    image-20200603090411763

    image-20200603090341028

  4. 通过import关键字导入第三方库

    import pygame
    

制作小飞机

搞起来

img

目标:创建一个可以左右移动的小飞机,用户可以通过空格space键来控制飞机发射子弹

创建背景

创建一个空背景

首先编写一个空的pygame窗口,文件名为plane_war.py

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame
import sys  # 用于退出游戏


def run_game():
    # 初始化游戏
    pygame.init()
    # 设置屏幕的分辨率
    screen = pygame.display.set_mode((1000, 600))  # 大小为1000px乘以600px

    # 打印其类型
    # print(type(screen))  # <class 'pygame.Surface'>

    pygame.display.set_caption("飞机大战")  # 标题
    # 存储背景的变量
    bg_img = pygame.image.load("./imgs/bg_img.png")  # 相对路径
    print(bg_img)
    # 开始游戏的主循环
    while True:

        # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
        for event in pygame.event.get():
            # 每次循环都会重新绘制屏幕
            screen.blit(bg_img, [0, 0])  # 绘制图像
            if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
                sys.exit()

        # 将完整显示Surface更新到屏幕
        pygame.display.flip()


run_game()

display.set_mode返回的是一个Surface数据类型

效果图

image-20200603101503072

创建设置类

一个游戏通常有n多个设置,如果每次想改变其中的某一个值的话在主文件中寻找容易眼花缭乱,现在创建一个新的文件settings.py,专门用来存储这些信息

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame


class Settings:
    """存储飞机大战的所有设置"""

    def __init__(self):
        # 屏幕设置
        self.screen_width = 1000
        self.screen_height = 600
        self.bg_img = pygame.image.load("./imgs/bg_img.png")

现在来改写plane_war.py

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame
import sys  # 用于退出游戏
from settings import Settings  # 引入settings.py


def run_game():
    # 初始化游戏
    pygame.init()
    # 设置屏幕的分辨率
    setting = Settings()
    screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))
    pygame.display.set_caption("飞机大战")  # 标题
    # 开始游戏的主循环
    while True:

        # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
        for event in pygame.event.get():
            # 每次循环都会重新绘制屏幕
            screen.blit(setting.bg_img, [0, 0])  # 绘制图像
            if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
                sys.exit()

        # 将完整显示Surface更新到屏幕
        pygame.display.flip()


run_game()

添加小飞机

这里用到的小飞机

c4a68ff7de93107ac0528244a33b66e4

绘制小飞机

现在图像也有了,来创建一个plane.py模块,其中有一个Plane类,来存储飞机的各种行为

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame


class Plane:
    def __init__(self, screen):
        # 初始化小飞机并设置其初始位置
        self.screen = screen

        # 加载图像,并获得其矩形区域
        self.img_plane = pygame.image.load("./imgs/plane.png")
        self.rect = self.img_plane.get_rect()  # 得到小飞机的的矩形区域
        self.screen_rect = self.screen.get_rect()  # 得到screen的矩形区域

        # 将小飞机放到底部中央
        self.rect.centerx = self.screen_rect.centerx  # 水平居中
        self.rect.bottom = self.screen_rect.bottom  # 底部

    def blitme(self):
        # 在指定位置绘制小飞机
        self.screen.blit(self.img_plane, self.rect)

get_rect会返回Surface的矩形的区域,.centerx.bottom是其两个属性

改写plane_war.py将小飞机绘制在屏幕上

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame
import sys  # 用于退出游戏
from settings import Settings  # 引入settings.py
from plane import Plane


def run_game():
    # 初始化游戏
    pygame.init()
    # 设置屏幕的分辨率
    setting = Settings()
    screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))  # 大小为1000px乘以600px
    pygame.display.set_caption("飞机大战")  # 标题

    # 创建小飞机
    plane = Plane(screen)
    # 开始游戏的主循环
    while True:

        # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
        for event in pygame.event.get():
            # 每次循环都会重新绘制屏幕
            screen.blit(setting.bg_img, [0, 0])  # 绘制图像
            plane.blitme()  # 将飞船绘制到屏幕上
            if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
                sys.exit()

        # 将完整显示Surface更新到屏幕
        pygame.display.flip()


run_game()

效果图

image-20200603112644866

创建一个存储运行函数的模块

为了不使plane_war.py太长而影响阅读,来创建一个名为game_func.py的模块,用其飞机大战运行的函数,使其逻辑更容易理解

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import sys
import pygame


def check_events():
    # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
            sys.exit()


def update_screen(screen, bg_img, plane):
    # 更新屏幕的图像
    # 每次循环都会重新绘制屏幕
    screen.blit(bg_img, [0, 0])  # 绘制图像
    plane.blitme()  # 将飞船绘制到屏幕上
    # 将完整显示Surface更新到屏幕
    pygame.display.flip()


check_events函数用来完成窗口不会关闭的功能

update_screen用来完成更新图像的功能,有3个形参,Surface对象、背景图像、小飞机函数

因为check_events完成了退出游戏的操作,所以plane_war.py就不需要sys模块了,更新后的plane_war.py如下

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame
from settings import Settings  # 引入settings.py
from plane import Plane
import game_func as fg


def run_game():
    # 初始化游戏
    pygame.init()
    # 设置屏幕的分辨率
    setting = Settings()
    screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))  # 大小为1000px乘以600px
    pygame.display.set_caption("飞机大战")  # 标题

    # 创建小飞机
    plane = Plane(screen)
    # 开始游戏的主循环
    while True:

        # 不关闭窗口
        fg.check_events()

        # 绘制图像
        fg.update_screen(screen, setting.bg_img, plane)



run_game()

控制小飞机

通过修改小飞机的坐标来完成移动,在用户按下方向键的时候小飞机的坐标进行有规律的变化

控制小飞机移动

当用户按键时,都会在pygame中注册一个事件,任何一个事件都是通过pygame.event.get()获取的,因此可以在函数体内,为每个按键都注册一个KEYDOWN事件。

现在将check_events函数改写,通过检测按下键位,来对小飞机进行移动

def check_events(plane):
    # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                # 小飞机往又移动
                plane.rect.centerx += 1

现在按一下小飞机移动一个像素,一般的游戏都是通过按下不送则一直移动,Pygame中的pygame.KEYUP可以检测用户是否松开按键

现在结合KEYDOWNKEYUP来完成一个持续移动

控制小飞机持续移动

来定义一个标志位,来判断用户是否按下按键,默认为Flase一旦检测到用户按下俺家则为True,小飞机就可以持续移动

由于小飞机是通过plane.py文件来控制的,对这个文件进行改写

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame


class Plane:
    def __init__(self, screen):
        # 初始化小飞机并设置其初始位置
        self.screen = screen

        # 加载图像,并获得其矩形区域
        self.img_plane = pygame.image.load("./imgs/plane.png")
        self.rect = self.img_plane.get_rect()  # 得到小飞机的的矩形区域
        self.screen_rect = self.screen.get_rect()  # 得到screen的矩形区域
        # print(self.screen_rect)

        # 将小飞机放到底部中央
        self.rect.centerx = self.screen_rect.centerx  # 水平居中
        self.rect.bottom = self.screen_rect.bottom  # 底部
        
        # 标志位
        self.mv_right = False
        
    # 定义一个调整小飞机位置的方法
    def update(self):
        # 根据标志位的调整小飞机的位置
        if self.mv_right:
            self.rect.centerx += 1

    def blitme(self):
        # 在指定位置绘制小飞机
        self.screen.blit(self.img_plane, self.rect)

update方法是标志位为True时,小飞机就开始移动

改写game_func.py中的check_events函数

def check_events(plane):
    # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                # 当用户按下键位时标志位为True
                plane.mv_right = True

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                # 当用户松开键位为false
                plane.mv_right = False

最后只要在plane_war.py中调用update方法就可以完成持续移动的操作

完成左右移动

用同样的方法完成向左移动

改写后的plane.py文件

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame


class Plane:
    def __init__(self, screen):
        # 初始化小飞机并设置其初始位置
        self.screen = screen

        # 加载图像,并获得其矩形区域
        self.img_plane = pygame.image.load("./imgs/plane.png")
        self.rect = self.img_plane.get_rect()  # 得到小飞机的的矩形区域
        self.screen_rect = self.screen.get_rect()  # 得到screen的矩形区域
        # print(self.screen_rect)

        # 将小飞机放到底部中央
        self.rect.centerx = self.screen_rect.centerx  # 水平居中
        self.rect.bottom = self.screen_rect.bottom  # 底部

        # 标志位
        self.mv_right = False
        self.mv_left = False

    # 定义一个调整小飞机位置的方法
    def update(self):
        # 根据标志位的调整小飞机的位置
        if self.mv_right:
            self.rect.centerx += 1

        if self.mv_left:
            self.rect.centerx -= 1

    def blitme(self):
        # 在指定位置绘制小飞机
        self.screen.blit(self.img_plane, self.rect)

改写后的game_func.py中的check_events函数

def check_events(plane):
    # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环),
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # QUIT用户请求程序关闭
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                # 当用户按下键位时标志位为True
                plane.mv_right = True
            elif event.key == pygame.K_LEFT:
                plane.mv_left = True

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                # 当用户松开键位为false
                plane.mv_right = False
            elif event.key == pygame.K_LEFT:
                plane.mv_left = False
调整速度

现在的小飞机一次是按1px来移动的,那速度是相当的缓慢,修改一下小飞机的移动速度

首先在setting.py中添加一行

self.plane_speed = 2.5

现在对plane.py做修改

"""
-*- coding:uft-8 -*-
author: 小甜
date:2020/6/3
"""
import pygame


class Plane:
    def __init__(self, screen, setting):
        # 初始化小飞机并设置其初始位置
        self.screen = screen
        self.setting = setting  # 实例化属性

        # 加载图像,并获得其矩形区域
        self.img_plane = pygame.image.load("./imgs/plane.png")
        self.rect = self.img_plane.get_rect()  # 得到小飞机的的矩形区域
        self.screen_r
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一碗周.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值