300行代码,教你用Python写个飞机大战

news2024/11/16 15:42:53

闲赋在家,甚是无聊,便萌发了研究经典小游戏:飞机大战的念头,想必大家可能玩过微信的这款小游戏,给我的感觉是这款游戏怎么可以做得这么好呢,操作简单,容易上手,简直是“老少皆宜”啊~

既然这款游戏这么棒,能否自己动手用 Python 来实现呢?事实证明是可以的。

先来看下飞机大战游戏最终实现的动态效果图。

文章末尾下方获取 

一. 动态效果图

二. 思路框架

plane_sprite.py文件内容
1.导入需要使用的模块
import random
import pygame

在导入pygame之前,需要先使用命令:

pip install pygame

进行包模块的安装

2.设置屏幕大小和刷新帧率等常量
3.创建继承于pygame.sprite.Sprite的基类GameSprite
4.创建继承于GameSprite的子类
  • Background背景子类

  • Enemy敌机子类

  • Hero英雄子类

  • Bullet子弹子类

plane_main.py文件内容
1. 导入plane_sprite.py文件中所有内容
2. 创建继承于Object的飞机大战主游戏类PlaneGame

(1). __init__初始化方法:

进行游戏开始的初始化操作,包含:创建游戏窗口,创建游戏的敌机,背景等精灵

(2). __create_sprites创建精灵方法:

负责创建不同角色的精灵,并将其添加至精灵组

(3). start_game游戏开始方法:

负责播放背景音乐,使用while循环来设置刷新帧率、事件监听、碰撞检测、更新绘制精灵组、更新显示屏幕图像

(4). __event_handler事件监听方法:

负责监听用户在游戏界面的操作,例如:关闭游戏窗口,左右方向键的移动等

(5). __check_collide碰撞检测方法:

负责检测子弹是否碰撞到敌机,敌机是否碰撞到英雄飞机,然后做出相应的操作

(6). __update_sprites更新精灵方法:

负责各个角色精灵的更新并绘制到屏幕,展示给用户

(7). __game_over游戏结束方法:

当检测到碰撞事件的发生,判断是否需要调用该方法来退出游戏

三. Python代码实现

plane_sprites.py文件内容如下:
import random
import pygame

# 屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 800, 800)
# 刷新的帧率
FRAME_PER_SEC = 80
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 2


class GameSprite(pygame.sprite.Sprite):
    """
    飞机大战游戏精灵
    """
    def __init__(self, image_name, speed=1):

        # 调用父类的初始化方法
        super().__init__()

        # 定义对象的属性
        self.image = pygame.image.load(image_name)
        self.rect = self.image.get_rect()
        self.speed = speed

    def update(self):

        # 在屏幕的垂直方向上移动
        self.rect.y += self.speed


class Background(GameSprite):
    """游戏背景精灵"""
    def __init__(self, is_alt=False):

        # 1.调用父类方法实现精灵的创建(image/rect/speed)
        super().__init__("./images/background2.jpeg")

        # 2.判断是否是交替图像,如果是,需要设置初始位置
        if is_alt:
            self.rect.y = -self.rect.height

    def update(self):

        # 1.调用父类的方法实现
        super().update()

        # 2.判断是否移出屏幕,如果移出屏幕,将图像设置到屏幕的上方
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y = -self.rect.height


class Enemy(GameSprite):
    """敌机精灵"""

    def __init__(self):

        # 1.调用父类方法,创建敌机精灵,同时指定敌机图片
        super().__init__("./images/enemy1.png")

        # 2.指定敌机的初始随机速度
        self.speed = random.randint(3, 15)

        # 3.指定敌机的初始随机位置
        self.rect.bottom = 0

        max_x = SCREEN_RECT.width - self.rect.width
        self.rect.x = random.randint(0, max_x)

    def update(self):

        # 1.调用父类方法,保持垂直方向的飞行
        super().update()

        # 2.判断是否飞出屏幕,如果是,需要从精灵组删除敌机
        if self.rect.y >= SCREEN_RECT.height:
            # print("飞机屏幕,需要从精灵组删除。。。")
            # kill方法可以将精灵从所有精灵组中移出,精灵就会被自动销毁
            self.kill()

    def __del__(self):
        # print("敌机挂了 %s" % self.rect)
        pass


class Hero(GameSprite):
    """英雄精灵"""

    def __init__(self):

        # 1.调用父类方法,设置image&speed
        super().__init__("./images/me1.png", 0)

        # 2.设置英雄的初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120

        # 3. 创建子弹的精灵组
        self.bullets = pygame.sprite.Group()

    def update(self):

        # 英雄在水平方向移动
        self.rect.x += self.speed

        # 控制英雄不能移出屏幕
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right

    def fire(self):
        for i in range(5):
            # 1.创建子弹精灵
            bullet = Bullet()

            # 2.设置精灵的位置
            bullet.rect.bottom = self.rect.y - i * 20
            bullet.rect.centerx = self.rect.centerx

            # 3.将精灵添加到精灵组
            self.bullets.add(bullet)


class Bullet(GameSprite):
    """子弹精灵"""

    def __init__(self):

        # 调用父类方法,设置子弹图片,设置初始速度
        super().__init__("./images/bullet1.png", -2)

    def update(self):

        # 调用父类方法,让子弹沿垂直方向飞行
        super().update()

        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()
plane_main.py文件内容如下:
from plane_sprites import *


class PlaneGame(object):
    """飞机大战主游戏"""

    def __init__(self):
        print("游戏初始化")

        # 1.创建游戏的窗口
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 2.创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 3.调用私有方法,完成精灵和精灵组的创建
        self.__create_sprites()

        # 4.设置定时器事件——创建敌机1s & 发射子弹0.5s
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)

    def __create_sprites(self):

        """创建背景精灵和精灵组"""
        bg1 = Background()
        bg2 = Background(True)

        self.back_group = pygame.sprite.Group(bg1, bg2)

        # 创建敌机的精灵组
        self.enemy_group = pygame.sprite.Group()

        # 创建英雄的精灵和精灵组
        self.hero = Hero()
        self.hero_group = pygame.sprite.Group(self.hero)

    def start_game(self):
        print("游戏正式开始。。。")
        pygame.mixer.init()
        pygame.mixer.music.load("./images/plane_background.mp3")
        pygame.mixer.music.play()

        while True:
            # 1.设置刷新帧率
            self.clock.tick(FRAME_PER_SEC)

            # 2.事件监听
            self.__event_handler()

            # 3.碰撞检测
            self.__check_collide()

            # 4.更新/绘制精灵组
            self.__update_sprites()

            # 5.更新显示
            pygame.display.update()

    def __event_handler(self):

        for event in pygame.event.get():

            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                PlaneGame.__game_over()
            elif event.type == CREATE_ENEMY_EVENT:
                # 创建敌机精灵
                enemy = Enemy()
                # 将敌机精灵添加到敌机精灵组
                self.enemy_group.add(enemy)
            elif event.type == HERO_FIRE_EVENT:
                self.hero.fire()

        # 使用键盘提供的方法获取键盘按键 - 按键元组
        keys_pressed = pygame.key.get_pressed()
        # 判断元组中对应的按键索引值
        if keys_pressed[pygame.K_RIGHT]:
            self.hero.speed = 5
        elif keys_pressed[pygame.K_LEFT]:
            self.hero.speed = -5
        else:
            self.hero.speed = 0

    def __check_collide(self):

        # 1.子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)

        # 2.敌机撞毁英雄
        enemies = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)

        # 3.判断列表长度
        if len(enemies) > 0:
            # 英雄牺牲
            self.hero.kill()

            # 结束游戏
            PlaneGame.__game_over()

    def __update_sprites(self):
        self.back_group.update()
        self.back_group.draw(self.screen)

        self.enemy_group.update()
        self.enemy_group.draw(self.screen)

        self.hero_group.update()
        self.hero_group.draw(self.screen)

        self.hero.bullets.update()
        self.hero.bullets.draw(self.screen)

    @staticmethod
    def __game_over():
        print("游戏结束")

        pygame.quit()
        exit()


if __name__ == "__main__":

    # 创建游戏对象
    game = PlaneGame()

    # 启动游戏
    game.start_game()

四. 小结

鼓励大家亲自动手实现一下这个小游戏,还是挺有趣的。代码注释较为详细,在实践过程中,可以仔细阅读以便于加深理解。

建议 Python 基础薄弱的童靴可以系统学习下下面推荐的这本书,从基础入门知识到 Python 的高阶知识,循序渐进夯实 Python 编程能力~

文章末尾下方获取 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/963503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023-09-02 LeetCode每日一题(最多可以摧毁的敌人城堡数目)

2023-09-02每日一题 一、题目编号 2511. 最多可以摧毁的敌人城堡数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 n &#xff0c;下标从 0 开始的整数数组 forts &#xff0c;表示一些城堡。forts[i] 可以是 -1 &#xff0c;0 或者 1 &#xff0c;其中&…

Android 1.1 背景相关与系统架构分析

目录 1.1 背景相关与系统架构分析 分类 Android 基础入门教程 1.Android背景与当前的状况 2.Android系统特性与平台架构 系统特性&#xff1a; 平台架构图&#xff1a; 架构的简单理解&#xff1a; 3.本节小结&#xff1a; 1.1 背景相关与系统架构分析 分类 Android 基础…

C++ 分割字符串数据

使用stringstream流&#xff08;已验证&#xff09; 引入头文件 #include <sstream> 功能实现&#xff1a; string keyValue "WTH01#WTH02#WTH03#WTH04#WTH05" string keys[6] { "" }; stringstream is(keyValue); string temp; int index 0;…

stable diffusion实践操作-采样sample

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、采样是什么&#xff1f;1.1 SD原理图1.2 SD中采样工作流程1.3 SD重复预测采样结果1.4 SD中采样方法列表1.4 SD中采样方法功能总结1.5 SD中常用采样方法 二、 SD中常用采样方法对比2.1 二次元-第一组2.1.…

YOLOv5训练自己的数据集并测试(以及踩坑记录)

YOLOv5是一个非常流行的图像识别框架&#xff0c;这里介绍一下使用YOLOv5给自己的数据集进行训练和测试 官方介绍文档&#xff1a;YOLOv5官方文档 基本流程&#xff1a; 下载必要的库和包&#xff0c;以及yolov5框架自制数据集&#xff1a;收集图像、视频数据&#xff0c;la…

从零开发JavaWeb入门项目--十天掌握

原文网址&#xff1a;从零开发JavaWeb入门项目--十天掌握_IT利刃出鞘的博客-CSDN博客 简介 这是一个靠谱的JavaWeb入门项目实战&#xff0c;名字叫蚂蚁爱购。从零开发项目&#xff0c;视频加文档&#xff0c;十天就能学会开发JavaWeb项目&#xff0c;教程路线是&#xff1a;搭…

Super Resolve Dynamic Scene from Continuous Spike Streams论文笔记

摘要 近期&#xff0c;脉冲相机在记录高动态场景中展示了其优越的潜力。不像传统相机将一个曝光时间内的视觉信息进行压缩成像&#xff0c;脉冲相机连续地输出二的脉冲流来记录动态场景&#xff0c;因此拥有极高的时间分辨率。而现有的脉冲相机重建方法主要集中在重建和脉冲相…

Windows 重新映射 CapsLock 大写锁定到 Ctrl

Windows 重新映射 CapsLock 大写锁定到 Ctrl 本要点中的这些方法适用于我的美国键盘布局。我不确定其他布局。如果出现问题&#xff0c;请恢复您的更改&#xff1b;删除您创建的注册表项&#xff08;并重新启动&#xff09;。 强烈推荐 方法5 ctrl2cap&#xff0c;因为不会影…

代码随想录第35天|860.柠檬水找零 , 406.根据身高重建队列(很多细节点注意一下),452. 用最少数量的箭引爆气球

860.柠檬水找零 思路比较简单 class Solution {public boolean lemonadeChange(int[] bills) {//然后向你付 5 美元、10 美元或 20 美元//如果收到5&#xff0c;直接收下//如果收到10&#xff0c;需要付回去5//如果收到20&#xff0c;需要付回去105或者555//开始时我手上拥有…

java基础-----第八篇

系列文章目录 文章目录 系列文章目录一、Java类加载器二、双亲委托模型 一、Java类加载器 JDK自带有三个类加载器&#xff1a;bootstrap ClassLoader、ExtClassLoader、AppClassLoader。 BootStrapClassLoader是ExtClassLoader的父类加载器&#xff0c;默认负责加载%JAVA_HOME…

Ops实践 | 国产化KylinOS系统中快速部署企业内部高性能DNS服务器、时间同步服务器 (精选)...

各位看友&#xff0c;由于微信公众号推送机制改变&#xff0c;现在需要设置为星标才能收到的本公众号推送消息哟。关注回复【学习交流群】加入【安全开发运维】答疑交流群 请朋友们【多多点击文中的广告】&#xff0c;支持作者更新更多文章。 目录: 本文为作者原创文章&#xf…

c++数据结构之 队列

c数据结构 --- 队列 队列的特点队列的相关概念&#xff1a;队列的操作&#xff1a;队列的分类&#xff1a;演示例子简单的例子例子2、循环队列的C实现 队列的特点 队列&#xff08;Queue&#xff09;与栈一样&#xff0c;是一种线性存储结构&#xff0c;它具有如下特点&#x…

学习振弦采集模块的开发基本原理

飞讯教学篇&#xff1a;学习振弦采集模块的开发基本原理 振弦采集模块是一种用于测量物体振动、形变、压力等物理量的电子设备。它通过测量物体的振动变化&#xff0c;可以得出物体在不同条件下的动态特性&#xff0c;对于工程设计、科学研究、医学检测等领域都有广泛应用。本…

代码随想录笔记--二叉树篇

1--递归遍历 1-1--前序遍历 前序遍历&#xff1a;根→左→右&#xff1b; #include <iostream> #include <vector>struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode() : val(0), left(nullptr), right(nullptr) {}TreeNode(int x) : val(x), le…

6400万美元:苹果与SpaceX达成合作协议,推进苹果 SOS 卫星服务

根据最新披露的文件&#xff0c;苹果卫星服务提供商Globalstar近期与马斯克旗下的SpaceX达成一项重要合作协议&#xff0c;向SpaceX支付了6400万美元&#xff0c;用于在2023-2025年期间发射卫星&#xff0c;以进一步扩展苹果iPhone系列的SOS卫星服务。 这项卫星服务的主要目的是…

Citespace、vosviewer、R语言的文献计量学 、SCI

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…

中国太保首席数据库专家林春:先难后易,核心系统数据库升级复盘

P17 是中国太平洋保险&#xff08;以下简称太保&#xff09;关联关系最为复杂、商业数据库绑定程度最深、业务影响最多的核心系统之一。但就是这样一个对太保业务至关重要的系统却被选为数据库升级的“实验品”。当然&#xff0c;说是“实验品”只是因为这是太保第一次对关键的…

怎样来实现流量削峰方案

削峰从本质上来说就是更多地延缓用户请求&#xff0c;以及层层过滤用户的访问需求&#xff0c;遵从“最后落地到数据库的请求数要尽量少”的原则。 1.消息队列解决削峰 要对流量进行削峰&#xff0c;最容易想到的解决方案就是用消息队列来缓冲瞬时流量&#xff0c;把同步的直…

ArcGIS地块面积分割调整工具插件

地块分割调整工具可以实现将选定的图斑按照面积比例或者指定的面积&#xff0c;分割成多个图斑。 各个图斑的面积用逗号分隔&#xff0c;比例分割设置时&#xff0c;用整数表示。 面积分割时&#xff0c;最后一个图斑的面积可以不写&#xff0c;插件可以自动计算图斑的面积&a…

1448. 统计二叉树中好节点的数目(javascript)1448. Count Good Nodes in Binary Tree

给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,3,null,1,5] 输出&#xff1a;4 解释…