Python学习笔记50:游戏篇之外星人入侵(十一)
前言
本篇文章接着之前的内容,继续对游戏功能进行优化,主要是优化游戏状态以及对应的处理。
状态
一个游戏包含多种状态,这个状态是一个可以很复杂也可以很简单的内容。条件所限,我们这个游戏的状态就比较简单:
- 未开始
- 游戏中
- 暂停
- 结束
我们通过一个字段进行控制,并且将这个字段放置到setting
模块中。
class Setting:"""系统设置类"""def __init__(self):-- snip --# 游戏状态:0未开始,1游戏中,2暂停,3结束self.game_status = 0
处理状态
根据不同的状态值,我们先对main
模块进行简单的处理。
import pygame
from pygame.sprite import Groupimport alien_invasion.game_functions as gf
from alien_invasion.setting import Setting
from alien_invasion.ship import Shipdef run_game():"""启动游戏"""# 初始化pygamepygame.init()# 定义一个系统设置对象setting = Setting()# 新建窗口screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))# 窗口命名pygame.display.set_caption(setting.caption)# 定义一个飞船对象ship = Ship(setting, screen)# 创建子弹编组bullets = Group()# 创建外星人编组aliens = Group()# 创建编组内的外星人gf.create_fleet(setting, screen, aliens)while True:if setting.game_status == 0:passelif setting.game_status == 1:# 处理监听事件gf.check_event(ship, setting, screen, bullets)# 移动飞船ship.move()# 更新子弹位置gf.update_bullets(bullets, aliens, setting, screen)# 更新外星人gf.update_aliens(aliens, setting, ship)# 刷新屏幕gf.update_screen(setting, screen, ship, bullets, aliens)elif setting.game_status == 2:passelif setting.game_status == 3:passif __name__ == '__main__':run_game()
状态对应的业务
现在,我们要对状态思考响应的游戏业务。
这里直接描述一下我个人简单预定的功能:
- 启动游戏,弹出窗口,显示欢迎来到游戏,按回车键开始游戏。其他所有按键不生效。
- 在游戏中,按下回车暂停游戏;暂停游戏时按下回车继续游戏
- 开始游戏后,任意时刻按下
Esc
键退出游戏,回到黑色窗口,显示游戏介绍,暂停一秒关闭游戏。
代码实现
我们在第二步已经简单的对状态值进行了处理,接下来就根据上面的业务在对应的状态处理部分一一填充。
首先我们处理开始游戏的状态。
开始游戏
首先我们需要在setting.game_status == 0
的条件下新建一个not_start()
函数,传入参数setting
和screen
。这两个参数一个是要回写状态值到配置模块中,一个是渲染游戏窗口需要的一些属性。
修改main
模块中循环处理的部分如下:
-- snip --while True:# 没啥用,方便编写代码的时候看看代码执行情况print(setting.game_status)if setting.game_status == 0:# 处理没启动的业务逻辑gf.not_start(setting, screen)-- snip --
main
模块处理好以后,我们在gf
模块进行实际的业务代码编写。
在函数中,我们需要完成两个功能,一个是渲染文字,一个是监听按键事件,是否有开始游戏,那么代码编写如下:
def not_start(setting, screen):# 先渲染文字handle_text(screen)print("not_start")# 处理监听事件for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_RETURN:if setting.game_status == 0:setting.game_status = 1print("开始游戏")
这里监听事件的部分没有单独拉函数出来,主要是不影响阅读,不过因为渲染文字的函数有点行数并且也算一个比较独立的功能,所以又单独创建了一个函数,后面的结束也是如此。
另外虽然我们这个时候只监听是否按下回车键的这个事件,但是点击退出窗口的监听事件,在任何地方都不能忘了,不然到时候可能你的窗口关不了,只能去通过停止程序关闭。
监听事件的代码比较简单的,就是在确认是按下了回车,状态是0的时候,回写状态值即可。
我们看看文字渲染的代码。
文字渲染我们在项目开始之前介绍pygame
就提前讲过,相比大家都不陌生,看代码注释即可,代码如下:
def handle_text(screen):# 字体颜色pink = pygame.Color('#FFFFFF')# 使用Arial字体创建一个字体对象,32号,加粗,倾斜font = arial_bold = pygame.font.SysFont('Arial', 32, bold=True, italic=True)# 渲染文本text_surface1 = font.render("Welcome to the Game Of Alien Invasion", True, pink)# 获取文件的矩形区域text_rect1 = text_surface1.get_rect()# 设置文本Y坐标320,居中位置text_rect1.midtop = (screen.get_width() // 2, 320)# 渲染文本text_surface2 = font.render("Press The Enter Key To Start The Game", True, pink)# 获取文件的矩形区域text_rect2 = text_surface2.get_rect()# 设置文本Y坐标420,居中位置text_rect2.midtop = (screen.get_width() // 2, 420)# 绘制文本screen.blit(text_surface1, text_rect1)screen.blit(text_surface2, text_rect2)# 更新显示pygame.display.flip()
运行main模块,按下回车。
可以看到文字正常渲染,并且输出栏一直在出输出当前状态。
如果你觉得画面单调,可以自己加点东西渲染,pygame
渲染图片这些相比也不陌生了。
按下回车,游戏正常开始!
可以看到,已经进入到游戏页面,并且输出栏的状态值也变成了1。
游戏中
游戏中的处理比较简单,因为我们之前已经完成了游戏中的代码编写,所以我们只需要在游戏中的监听事件中加上回车键的监听事件暂停游戏。
ps: 这里其实也可以结束游戏,代码我先写上,但是不操作。业务代码也不复杂,就是多加一个Esc
键的监听事件。
gf
模块中的check_keydown_events()
函数代码修改如下:
def check_keydown_events(event, ship, setting, screen, bullets):"""响应按键"""if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_UP:ship.moving_top = Trueelif event.key == pygame.K_DOWN:ship.moving_bottom = Trueelif event.key == pygame.K_SPACE:fire(bullets, screen, setting, ship)elif event.key == pygame.K_q:sys.exit()elif event.key == pygame.K_RETURN:if setting.game_status == 1:setting.game_status = 2print("暂停游戏")elif event.key == pygame.K_ESCAPE:setting.game_status = 3print("游戏结束")
启动main
模块,开始游戏后再按回车,效果如下:
可以看到,我们的飞船,子弹,外星人全部暂停住了,输出栏一直打印状态也变成了2(暂停)。
屏幕中显示了一些文字,这些其实是暂停的业务。
我们马上进行暂停的业务代码编写。
暂停游戏
参考开始游戏的实现,我们在暂停的分支下调用一个函数stop()
。
main
模块循环部分代码如下:
-- snip --while True:# 没啥用,方便编写代码的时候看看代码执行情况print(setting.game_status)if setting.game_status == 0:# 处理没启动的业务逻辑gf.not_start(setting, screen)elif setting.game_status == 1:# 处理监听事件gf.check_event(ship, setting, screen, bullets)# 移动飞船ship.move()# 更新子弹位置gf.update_bullets(bullets, aliens, setting, screen)# 更新外星人gf.update_aliens(aliens, setting, ship)# 刷新屏幕gf.update_screen(setting, screen, ship, bullets, aliens)elif setting.game_status == 2:gf.stop(setting, screen)-- snip --
同样,我们去到gf
模块创建stop()
函数并实现相应的功能,代码如下:
-- snip --
def stop(setting, screen):handle_stop_text(screen)for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_RETURN:if setting.game_status == 2:setting.game_status = 1print("继续游戏")elif event.key == pygame.K_ESCAPE:setting.game_status == 3:print("结束游戏")
-- snip --
代码依旧分两部分实现,渲染文字和监听事件。在暂停的监听事件中我们和开始一样,监听关闭窗口,回车和结束,并在回车事件中回写状态值,让游戏继续运行,在Esc
时间中结束游戏。
文字渲染部分代码如下:
def handle_stop_text(screen):# 字体颜色pink = pygame.Color('#000000')# 使用Arial字体创建一个字体对象,32号,加粗,倾斜font = arial_bold = pygame.font.SysFont('Arial', 32, bold=True, italic=True)# 渲染文本text_surface1 = font.render("Game Stop", True, pink)# 获取文件的矩形区域text_rect1 = text_surface1.get_rect()# 设置文本Y坐标50,居中位置text_rect1.midtop = (screen.get_width() // 2, 320)# 渲染文本text_surface2 = font.render("Press The Enter Key To restore The Game", True, pink)# 获取文件的矩形区域text_rect2 = text_surface2.get_rect()# 设置文本Y坐标50,居中位置text_rect2.midtop = (screen.get_width() // 2, 420)# 绘制文本screen.blit(text_surface1, text_rect1)screen.blit(text_surface2, text_rect2)# 更新显示pygame.display.flip()
基本上就是复制开始的文字渲染,改了下文字内容。
效果的话这里就不展示了,就是暂停开始,开始暂停这一套。
结束游戏
在游戏中和暂停的时候,我们都可以通过按键Esc
实现游戏结束。
在main
模块的改动依旧是调用一个结束函数,但是结束函数不需要回写状态值,所以我们只需要一个screen
参数。
代码如下:
while True:# 没啥用,方便编写代码的时候看看代码执行情况print(setting.game_status)if setting.game_status == 0:# 处理没启动的业务逻辑gf.not_start(setting, screen)elif setting.game_status == 1:# 处理监听事件gf.check_event(ship, setting, screen, bullets)# 移动飞船ship.move()# 更新子弹位置gf.update_bullets(bullets, aliens, setting, screen)# 更新外星人gf.update_aliens(aliens, setting, ship)# 刷新屏幕gf.update_screen(setting, screen, ship, bullets, aliens)elif setting.game_status == 2:gf.stop(setting, screen)elif setting.game_status == 3:gf.end(screen)
gf
模块改动如下:
def end(screen):# 重新填充屏幕screen.fill((0, 0, 0))# 渲染文字handle_end_text(screen)# 休眠一秒sleep(1)# 退出pygame.quit()sys.exit()
和之前比对有一点不同,多了几部,其实没有特别含义,就是看起来流畅好看一点。
文字渲染代码如下:
def handle_end_text(screen):# 字体颜色pink = pygame.Color('#FFFFFF')# 使用Arial字体创建一个字体对象,32号,加粗,倾斜font = arial_bold = pygame.font.SysFont('Arial', 48, bold=True, italic=True)# 渲染文本text_surface1 = font.render("Game Over", True, pink)# 获取文件的矩形区域text_rect1 = text_surface1.get_rect()# 设置文本Y坐标50,居中位置text_rect1.midtop = (screen.get_width() // 2, screen.get_height() // 2)# 绘制文本screen.blit(text_surface1, text_rect1)# 更新显示pygame.display.flip()
运行效果如下:
结尾
今天的内容就是这些,设定状态值,并且在对应的状态中处理不同的逻辑,渲染不同的画面。
当然我们是学习,所以内容都比较简单,有兴趣的话可以深入一下加点自己的元素进去。
后面我们继续优化游戏功能,加油!!!
相关文章:

Python学习笔记50:游戏篇之外星人入侵(十一)
前言 本篇文章接着之前的内容,继续对游戏功能进行优化,主要是优化游戏状态以及对应的处理。 状态 一个游戏包含多种状态,这个状态是一个可以很复杂也可以很简单的内容。条件所限,我们这个游戏的状态就比较简单: 未…...

vue3踩坑问题记录
//vue3element-plus //1、placeholder换行显示 const startTxt ref() const contentText ref<any>() startTxt.value "请描述问题内容、例如:" historyData.prompt.forEach((el:any)>{contentText.value \n${el.question}}) <ElInputv-mo…...
Python 爬虫实战:Scrapy 框架详解与应用
🛠️ Scrapy 框架基本使用 Scrapy 是一个强大的 Python 爬虫框架,提供了用于提取和处理网页数据的功能。以下是 Scrapy 的基本使用步骤: 安装 Scrapy pip install scrapy创建 Scrapy 项目 scrapy startproject myproject这将生成一个基础…...

60 函数参数——关键参数
关键参数主要指调用函数时的参数传递方式,与函数定义无关。 通过关键参数可以按参数名字传递值,明确指定哪个值传递给哪个参数,实参顺序可以和形参顺序不一致,但不影响参数值的传递结果,避免了用户需要牢记参数位置和…...

wps 最新 2019 专业版 下载安装教程,解锁全部功能,免费领取
文章目录 前言软件介绍软件下载安装步骤激活步骤小福利(安卓APP)软件介绍软件下载安装步骤 前言 本篇文章主要针对WPS2019专业版的安装下载进行详细讲解,软件已激活,可放心使用;并且可以进行账号登录,进行…...

前端(三):Ajax
一、Ajax Asynchronous JavaScript And XML,简称Ajax,是异步的JavaScript和XML。 作用:数据交换,通过Ajax可以给服务器发送请求,并获取服务器响应的数据。异步交互:可以在不重新加载整个页面的情况下&…...

启动 /使用/关闭 Redis 服务器
1. Linux 启动 Linux 系统启动 Redis 有两种方法,分别是前台启动,后台启动,两者各有差异; (1)前台启动 首先,需要进入 bin 路径(安装路径不同输入的命令也不同); 个人的命令(一般…...

Linux系统中的高级SELinux安全策略定制技术
随着信息技术的发展,计算机系统的安全性变得越来越重要。在开源世界中,Linux作为一种广泛应用的操作系统,其安全性一直备受关注。其中,SELinux(Security-Enhanced Linux)作为Linux系统中的一个安全模块&…...
使用 Ansible Blocks 进行错误处理
注:机翻,未校。 How to Use Ansible Blocks Make your Playbooks more readable and maintainable using Blocks feature in Ansible. 使用 Ansible 中的块功能使 Playbook 更具可读性和可维护性。 Jul 15, 2024 — LHB Community How to Use Ansible…...
java中的静态变量和实例变量的区别
java中的静态变量和实例变量的区别 在Java中,静态变量(也称为类变量)和实例变量是两种不同类型的变量,它们在多个方面存在显著的区别。以下是它们之间的一些主要区别: 存储位置 静态变量:存储在方法区&am…...
【Effecutive C++】条款02 尽量以const, enum, inline替换 #define
Prefer consts, enums, and inline to #define. 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#define不被视为语言的一部分。那正是它的问题所在。当你做出这样的事情: #define ASPECT_RATIO 1.653记号名称ASPECT_RATIO也许从未被编译…...
leetcode-226. 翻转二叉树
题目描述 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 输入:root [2,1,3] 输出:[2,3,1]…...

用的到linux-tomcat端口占用排查-Day5
前言: 最近使用tomcat搭建了一套测试环境的应用,整个搭建过程也很简单,就是将部署包上传至服务器☞解压☞启动tomcat服务器,当然服务器也是成功启动了,但是发现前端应用报404,具体如下图所示。 一、现象及思…...

mqtt协议详解(0)初步认识mqtt
文章目录 1. 介绍2. 主要特性3. 架构1. 介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种构建在TCP/IP协议之上的轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境,例如IOT。 MQTT 协议于 1…...

Java语言程序设计基础篇_编程练习题*16.7 (设置时钟的时间)
*16.7 (设置时钟的时间) 编写一个程序,显示一个时钟,并通过在三个文本域中输入小时、分钟和秒 钟来设置时钟的时间,如图16-38b 所示。使用程序清单14-21的ClockPane改变时钟大小使其居于面板中央 习题思路 实例化一个ClockPane(在程序清单1…...

YOLOv8新版本支持实时检测Transformer(RT-DETR)、SAM分割一切
原文:YOLOv8新版本支持实时检测Transformer(RT-DETR)、SAM分割一切 - 知乎 (zhihu.com) 一、SAM 分割任何模型 (Segment Anything Model - SAM) 是一种突破性的图像分割模型,可实现具有实时性能的快速分割。 项目地址 https://github.com/facebookresearch/segment-…...

【传输层协议】UDP和TCP协议
文章目录 UDP协议UDP特点UDP的缓冲区基于UDP的应用层协议 TCP协议6位标志位:确认应答机制超时重传机制连接管理机制(握手和挥手)服务端状态转换过程客户端状态转换过程TIME_WAIT状态CLOSE_WAIT状态 为什么是三次握手和四次挥手滑动窗口如果发…...

Java Excel复杂表头,表头合并单元格
Java Excel复杂表头,表头合并单元格 效果预览 一、maven依赖 <!--操作excel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version><scope>test</…...

Java整合腾讯云发送短信实战Demo
简介 在现代应用开发中,短信服务是非常重要的功能之一。它可以用于用户验证、通知等各种场景。本文将介绍如何使用Java整合腾讯云短信服务,并提供一个完整的实战示例代码。 环境准备 在开始之前,确保你已经完成以下准备工作: 注…...

电路中电阻,电容和电感作用总结
电阻作用 1,上拉电阻 电阻的连接一般是一端接上拉的电源(一般与芯片信号的电压值相匹配),另一端连接芯片引脚所对应的信号大概如下图 功能:一、预置某些引脚的功能,例如复位信号拉高(失能&…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...