当前位置: 首页 > news >正文

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()

状态对应的业务

现在,我们要对状态思考响应的游戏业务。

这里直接描述一下我个人简单预定的功能:

  1. 启动游戏,弹出窗口,显示欢迎来到游戏,按回车键开始游戏。其他所有按键不生效。
  2. 在游戏中,按下回车暂停游戏;暂停游戏时按下回车继续游戏
  3. 开始游戏后,任意时刻按下Esc键退出游戏,回到黑色窗口,显示游戏介绍,暂停一秒关闭游戏。

代码实现

我们在第二步已经简单的对状态值进行了处理,接下来就根据上面的业务在对应的状态处理部分一一填充。

首先我们处理开始游戏的状态。

开始游戏

首先我们需要在setting.game_status == 0的条件下新建一个not_start()函数,传入参数settingscreen。这两个参数一个是要回写状态值到配置模块中,一个是渲染游戏窗口需要的一些属性。

修改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()

运行效果如下:

在这里插入图片描述

结尾

今天的内容就是这些,设定状态值,并且在对应的状态中处理不同的逻辑,渲染不同的画面。

当然我们是学习,所以内容都比较简单,有兴趣的话可以深入一下加点自己的元素进去。

后面我们继续优化游戏功能,加油!!!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • RUM技术探索:前端监控数据采集与实践
  • CRITIC权重法
  • c++STL中list介绍,模拟实现和list与vector对比
  • 申请专利需要准备哪些材料?
  • 在Ubuntu 16.04上安装Docker Compose的方法
  • vue的nextTick是下一次事件循环吗
  • 新华三H3CNE网络工程师认证—路由基础
  • springboot+vue+mybatis汽车租赁管理+PPT+论文+讲解+售后
  • AI与PS:技术革命下的设计工具比较
  • 数学建模之数据分析【二】:什么是数据?
  • C语言中整数类型及其类型转换
  • 用Java手写jvm之模拟方法调用指令invokexxx和方法返回指令xreturn
  • 深入解析 Nginx 反向代理:配置、优化与故障排除
  • Visual Studio vs VSCode:深入剖析两款开发工具的优劣与应用场景
  • 网络安全 - 应急响应检查表
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Cookie 在前端中的实践
  • CSS3 变换
  • Go 语言编译器的 //go: 详解
  • js面向对象
  • springMvc学习笔记(2)
  • vuex 笔记整理
  • Yii源码解读-服务定位器(Service Locator)
  • 警报:线上事故之CountDownLatch的威力
  • 两列自适应布局方案整理
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 微信公众号开发小记——5.python微信红包
  • 小程序测试方案初探
  • 小李飞刀:SQL题目刷起来!
  • 移动端解决方案学习记录
  • 用 Swift 编写面向协议的视图
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • # 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
  • #{}和${}的区别是什么 -- java面试
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (13)Hive调优——动态分区导致的小文件问题
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (代码示例)使用setTimeout来延迟加载JS脚本文件
  • (第61天)多租户架构(CDB/PDB)
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)关于多人操作数据的处理策略
  • (转)一些感悟
  • 、写入Shellcode到注册表上线
  • .NET 4.0中的泛型协变和反变
  • .NET delegate 委托 、 Event 事件
  • .net framework4与其client profile版本的区别
  • .NetCore发布到IIS