| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Python知识库 -> 还不懂飞机大战?最细学习笔记--全方位学习Pygame(附源码) -> 正文阅读 |
|
[Python知识库]还不懂飞机大战?最细学习笔记--全方位学习Pygame(附源码) |
一、飞机大战源码自取pygame强化面向对象程序设计 使用 安装 pygame
源码分享所有源码均在此公众号内:关注此公众号,回复 你也可以直接进行下载:https://download.csdn.net/download/weixin_51390582/87315776 二、pygame 快速入门
游戏的第一印象
1.游戏的初始化
创建游戏主窗口
2.图像绘制在游戏中,能够看到的游戏元素大多都是图像。图像文件初始是保存在磁盘上的,如果需要使用,第一步就需要被加载到内存 要在屏幕上看到某一个图像的内容,需要按照三个步骤:
绘制背景图像
理解游戏中的坐标系
案例演练
绘制英雄图像
理解
|
方法 | 职责 |
---|---|
create_sprites(self) | 创建所有精灵和精灵组 |
游戏循环 —— start_game()
会调用以下方法:
方法 | 职责 |
---|---|
event_handler(self) | 事件监听 |
check_collide(self) | 碰撞检测 —— 子弹销毁敌机、敌机撞毁英雄 |
update_sprites(self) | 精灵组更新和绘制 |
game_over() | 游戏结束 |
plane_main
plane_sprites
代码实现
plane_main.py
文件,并且设置为可执行import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战主游戏"""
def __init__(self):
print("游戏初始化")
def start_game(self):
print("开始游戏...")
if __name__ == '__main__':
# 创建游戏对象
game = PlaneGame()
# 开始游戏
game.start_game()
__init__()
代码如下:def __init__(self):
print("游戏初始化")
# 1. 创建游戏的窗口
self.screen = pygame.display.set_mode((480, 700))
# 2. 创建游戏的时钟
self.clock = pygame.time.Clock()
# 3. 调用私有方法,精灵和精灵组的创建
self.create_sprites()
def create_sprites(self):
pass
- 常量 —— 不变化的量
- 变量 —— 可以变化的量
应用场景
700
常量的定义
常量的好处
提示:Python 中并没有真正意义的常量,只是通过命名的约定 —— 所有字母都是大写的就是常量,开发时不要轻易的修改!
代码调整
plane_sprites.py
中增加常量定义import pygame
# 游戏屏幕大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
plane_main.py
中的窗口大小self.screen = pygame.display.set_mode(SCREEN_RECT.size)
start_game()
基础代码如下:def start_game(self):
"""开始游戏"""
print("开始游戏...")
while True:
# 1. 设置刷新帧率
self.clock.tick(60)
# 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()
def check_collide(self):
"""碰撞检测"""
pass
def update_sprites(self):
"""更新精灵组"""
pass
@staticmethod
def game_over():
"""游戏结束"""
print("游戏结束")
pygame.quit()
exit()
def create_sprites(self):
"""创建精灵组"""
# 背景组
self.back_group = pygame.sprite.Group()
# 敌机组
self.enemy_group = pygame.sprite.Group()
# 英雄组
self.hero_group = pygame.sprite.Group()
def update_sprites(self):
"""更新精灵组"""
for group in [self.back_group, self.enemy_group, self.hero_group]:
group.update()
group.draw(self.screen)
解决办法
1
张 完全和屏幕重合2
张在 屏幕的正上方self.rect.y += self.speed
rect.y >= 屏幕的高度
说明已经移动到屏幕下方rect.y = -rect.height
初始化方法
is_alt
判断是否是另一张图像
False
表示 第一张图像,需要与屏幕重合True
表示 另一张图像,在屏幕的正上方update() 方法
继承 如果父类提供的方法,不能满足子类的需求:
- 派生一个子类
- 在子类中针对特有的需求,重写父类方法,并且进行扩展
plane_sprites
新建 Background
继承自 GameSprite
class Background(GameSprite):
"""游戏背景精灵"""
def update(self):
# 1. 调用父类的方法实现
super().update()
# 2. 判断是否移出屏幕,如果移出屏幕,将图像设置到屏幕的上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
plane_main.py
中显示背景精灵create_sprites
方法中创建 精灵 和 精灵组update_sprites
方法中,让 精灵组 调用 update()
和 draw()
方法
create_sprites
方法
def create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background("./images/background.png")
bg2 = Background("./images/background.png")
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
update_sprites
方法
def update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
思考 —— 上一小结完成的代码存在什么样的问题?能否简化?
思考 —— 精灵初始位置的设置,应该由主程序负责?还是由精灵自己负责?
答案 —— 由精灵自己负责
初始化方法
is_alt
判断是否是另一张图像
False
表示 第一张图像,需要与屏幕重合True
表示 另一张图像,在屏幕的正上方在 plane_sprites.py
中实现 Background
的 初始化方法
def __init__(self, is_alt=False):
image_name = "./images/background.png"
super().__init__(image_name)
# 判断是否交替图片,如果是,将图片设置到屏幕顶部
if is_alt:
self.rect.y = -self.rect.height
修改 plane_main
的 __create_sprites
方法
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
运行备课代码,观察敌机的出现规律:
在 pygame
中可以使用 pygame.time.set_timer()
来添加 定时器, 所谓 定时器,就是 每隔一段时间,去 执行一些动作
set_timer(eventid, milliseconds) -> None
set_timer
可以创建一个事件
可以在游戏循环的事件监听方法中捕获到该事件
pygame.USEREVENT
来指定
USEREVENT
是一个整数,再增加的事件可以使用 USEREVENT + 1
指定,依次类推…定时器事件的监听
pygame.event.get()
可以获取当前时刻所有的事件列表event.type
是否等于 eventid
,如果相等,表示定时器事件发生pygame
的 定时器 使用套路非常固定:
eventid
set_timer
方法设置定时器事件plane_sprites.py
的顶部定义事件常量# 敌机的定时器事件常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
PlaneGame
的初始化方法中创建用户事件# 4. 设置定时器事件 - 每秒创建一架敌机
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
__event_handler
方法中增加以下代码:def __event_handler(self):
for event in pygame.event.get():
# 判断是否退出游戏
if event.type == pygame.QUIT:
PlaneGame.game_over()
elif event.type == CREATE_ENEMY_EVENT:
print("敌机出场...")
Enemy
类plane_sprites
新建 Enemy
继承自 GameSprite
update
方法,判断是否飞出屏幕class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
# 1. 调用父类方法,创建敌机精灵,并且指定敌机的图像
super().__init__("./images/enemy1.png")
# 2. 设置敌机的随机初始速度
# 3. 设置敌机的随机初始位置
def update(self):
# 1. 调用父类方法,让敌机在垂直方向运动
super().update()
# 2. 判断是否飞出屏幕,如果是,需要将敌机从精灵组删除
if self.rect.y >= SCREEN_RECT.height:
print("敌机飞出屏幕...")
演练步骤
create_sprites
,添加敌机精灵组
event_handler
,创建敌机,并且添加到精灵组
add
方法可以向精灵组添加精灵update_sprites
,让 敌机精灵组 调用 update
和 draw
方法演练代码
plane_main
的 create_sprites
方法# 敌机组
self.enemy_group = pygame.sprite.Group()
plane_main
的 update_sprites
方法self.enemy_group.update()
self.enemy_group.draw(self.screen)
elif event.type == CREATE_ENEMY_EVENT:
self.enemy_group.add(Enemy())
在导入模块时,建议 按照以下顺序导入
1. 官方标准模块导入
2. 第三方模块导入
3. 应用程序模块导入
修改 plane_sprites.py
增加 random
的导入
import random
使用 pygame.Rect
提供的 bottom
属性,在指定敌机初始位置时,会比较方便
bottom = y + height
y = bottom - height
修改 初始化方法,随机敌机出现 速度 和 位置
def __init__(self):
# 1. 调用父类方法,创建敌机精灵,并且指定敌机的图像
super().__init__("./images/enemy1.png")
# 2. 设置敌机的随机初始速度 1 ~ 3
self.speed = random.randint(1, 3)
# 3. 设置敌机的随机初始位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
敌机移出屏幕之后,如果 没有撞到英雄,敌机的历史使命已经终结
需要从 敌机组 删除,否则会造成 内存浪费
__del__
内置方法会在对象被销毁前调用,在开发中,可以用于 判断对象是否被销毁
def __del__(self):
print("敌机挂了 %s" % self.rect)
判断敌机是否飞出屏幕,如果是,调用 kill()
方法从所有组中删除
def update(self):
super().update()
# 判断敌机是否移出屏幕
if self.rect.y >= SCREEN_RECT.height:
# 将精灵从所有组中删除
self.kill()
120
像素0.5
秒发射一次子弹,每次连发三枚子弹左/右 方向键
,控制英雄在水平方向移动初始化方法
bullets
子弹精灵组 保存子弹精灵重写 update() 方法
增加 bullets
属性,记录所有 子弹精灵
增加 fire
方法,用于发射子弹
初始化方法
重写 update() 方法
plane_sprites
新建 Hero
类0
centerx = x + 0.5 * width
centery = y + 0.5 * height
bottom = y + height
class Hero(GameSprite):
"""英雄精灵"""
def __init__(self):
super().__init__("./images/me1.png", 0)
# 设置初始位置
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 120
__create_sprites
,添加 英雄精灵 和 英雄精灵组
__update_sprites
,让 英雄精灵组 调用 update
和 draw
方法__create_sprites
方法如下:# 英雄组
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
__update_sprites
方法如下:self.hero_group.update()
self.hero_group.draw(self.screen)
在
pygame
中针对 键盘按键的捕获,有 两种 方式
event.type == pygame.KEYDOWN
pygame.key.get_pressed()
返回 所有按键元组1
提问 这两种方式之间有什么区别呢?
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
print("向右移动...")
# 返回所有按键的元组,如果某个键被按下,对应的值会是1
keys_pressed = pygame.key.get_pressed()
# 判断是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
print("向右移动...")
结论
第一种方式 event.type
用户 必须要抬起按键 才算一次 按键事件,操作灵活性会大打折扣
第二种方式 用户可以按住方向键不放,就能够实现持续向某一个方向移动了,操作灵活性更好
演练步骤
Hero
类中重写 update
方法
speed
和 英雄 rect.x
进行叠加__event_handler
方法中根据 左右方向键 设置英雄的 速度
speed = 2
speed = -2
speed = 0
代码演练
Hero
类,重写 update()
方法,根据速度水平移动 英雄的飞机def update(self):
# 飞机水平移动
self.rect.x += self.speed
# 获取用户按键
keys_pressed = pygame.key.get_pressed()
if keys_pressed[pygame.K_RIGHT]:
self.hero.speed = 2
elif keys_pressed[pygame.K_LEFT]:
self.hero.speed = -2
else:
self.hero.speed = 0
在 Hero
类的 update()
方法判断 英雄 是否超出 屏幕边界
right = x + width
利用 right
属性可以非常容易的针对右侧设置精灵位置
def update(self):
# 飞机水平移动
self.rect.x += self.speed
# 判断屏幕边界
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
120
像素0.5
秒发射一次子弹,每次 连发三枚子弹pygame
的 定时器 使用套路非常固定:
eventid
set_timer
方法 设置定时器事件代码实现
Hero
中定义 fire
方法def fire(self):
print("发射子弹...")
plane_main.py
的顶部定义 发射子弹 事件常量# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
__init__
方法末尾中添加 发射子弹 事件# 每隔 0.5 秒发射一次子弹
pygame.time.set_timer(HERO_FIRE_EVENT, 500)
__event_handler
方法中让英雄发射子弹elif event.type == HERO_FIRE_EVENT:
self.hero.fire()
plane_sprites
新建 Bullet
继承自 GameSprite
update()
方法,判断子弹 飞出屏幕从精灵组删除class Bullet(GameSprite):
"""子弹精灵"""
def __init__(self):
super().__init__("./images/bullet1.png", -2)
def update(self):
super().update()
# 判断是否超出屏幕,如果是,从精灵组删除
if self.rect.bottom < 0:
self.kill()
演练步骤
Hero
的 初始化方法 中创建 子弹精灵组 属性plane_main.py
的 __update_sprites
方法,让 子弹精灵组 调用 update
和 draw
方法fire()
方法
代码实现
# 创建子弹的精灵组
self.bullets = pygame.sprite.Group()
fire()
方法def fire(self):
# 1. 创建子弹精灵
bullet = Bullet()
# 2. 设置精灵的位置
bullet.rect.bottom = self.rect.y - 20
bullet.rect.centerx = self.rect.centerx
# 3. 将精灵添加到精灵组
self.bullets.add(bullet)
fire()
方法,一次发射三枚子弹def fire(self):
for i in (1, 2, 3):
# 1. 创建子弹精灵
bullet = Bullet()
# 2. 设置精灵的位置
bullet.rect.bottom = self.rect.y - i * 20
bullet.rect.centerx = self.rect.centerx
# 3. 将精灵添加到精灵组
self.bullets.add(bullet)
pygame
提供了 两个非常方便 的方法可以实现碰撞检测:两个精灵组 中 所有的精灵 的碰撞检测
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
如果将 dokill
设置为 True
,则 发生碰撞的精灵将被自动移除
collided
参数是用于 计算碰撞的回调函数
rect
属性spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
dokill
设置为 True
,则 指定精灵组 中 发生碰撞的精灵将被自动移除collided
参数是用于 计算碰撞的回调函数
rect
属性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)
# 判断列表时候有内容
if len(enemies) > 0:
# 让英雄牺牲
self.hero.kill()
# 结束游戏
PlaneGame.__game_over()
所有源码均在此公众号内:关注此公众号,回复 飞机大战
、超级玛丽
、植物大战僵尸
获取源码,快点击我吧
最后,有任何问题,欢迎关注下面的公众号,获取第一时间消息、作者联系方式及每周抽奖等多重好礼! ↓↓↓
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/18 4:32:06- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |