前言

讲解完了所有的类,接下来就应该讲一下事件了。
在游戏的过程中,最重要的其实应当是在事件发生后进行反应并重新渲染

先贴game_function的代码:

import sys
import pygame
from bullet import bullet
from alien import Alien
from time import sleep
#退出游戏+飞船移动
def check_events(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets):"""响应键鼠事件"""for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()elif event.type == pygame.KEYDOWN:          #表示按下按键check_keydown_events(event,ai_settings,screen,ship,bullets)elif event.type == pygame.KEYUP:check_keyup_events(event,ship)elif event.type == pygame.MOUSEBUTTONDOWN:  #按下鼠标mouse_x,mouse_y = pygame.mouse.get_pos()check_play_button(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets,mouse_x,mouse_y)
#响应按下按键
def check_keydown_events(event,ai_settings,screen,ship,bullets):if event.key == pygame.K_RIGHT: #向右移动ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE:fire_bullet(ai_settings,screen,ship,bullets)elif event.key == pygame.K_q:sys.exit()
#响应抬起按键
def check_keyup_events(event,ship):if event.key == pygame.K_RIGHT:ship.moving_right = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falsedef check_play_button(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets,mouse_x,mouse_y):#在玩家点击play开启游戏button_clicked = play_button.rect.collidepoint(mouse_x,mouse_y)  #能检测是否点击在play方块处if button_clicked and not stats.game_active:#隐藏光标pygame.mouse.set_visible(False)#重置游戏stats.game_active = Truestats.reset_stats()sb.prep_score()sb.prep_high_score()sb.prep_level()sb.prep_ships()aliens.empty()bullets.empty()create_fleet(ai_settings,screen,stats,ship,aliens)ship.center_ship()ai_settings.initialize_dynamic_settings()   #恢复#刷新屏幕
def update_screen(ai_setting,screen,stats,sb,ship,aliens,bullets,play_button):screen.fill(ai_setting.bg_color)#绘制所有子弹for bullet in bullets:bullet.draw_bullet()#显示飞船ship.blitme()#显示外星人aliens.draw(screen)#显示得分sb.show_score()#如果游戏为停止状态,显示按钮if not stats.game_active:play_button.draw_button()#让最近绘制的屏幕可见pygame.display.flip()def update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets):bullets.update()"""更新子弹位置并删除已经消失的子弹"""for bullet in bullets:if bullet.rect.bottom <= 0:bullets.remove(bullet)check_bullet_alien_collisions(ai_settings,screen,stats,sb,ship,aliens,bullets)def check_bullet_alien_collisions(ai_settings,screen,stats,sb,ship,aliens,bullets):#检测是否击中,击中则删除对应的子弹和外星人collisions = pygame.sprite.groupcollide(bullets,aliens,True,True)"""笔记:这个方法是检测每一个子弹的rect和外星人的rect,返回值为一个字典,key为子弹,value为外星人。遍历两个编组,当两个rect重叠,那么方法在字典中增加一对键值,并且在原编组中删除这里的两个Boolean是对应子弹和外星人需要删除,如果是‘高能子弹’在击败外星人仍保留,那么我们就可以将第一个Boolean设置为false"""if collisions:for alien in collisions.values():#确保每一个外星人都会被算上分数,防止一个子弹对应多个外星人stats.score += ai_settings.alien_pointssb.prep_score()check_high_score(stats,sb)if len(aliens) == 0:#提升一个等级stats.level += 1sb.prep_level()#删除子弹并新建一群外星人bullets.empty()ai_settings.increase_sp()create_fleet(ai_settings,screen,stats,ship,aliens)def update_aliens(ai_settings,stats,screen,sb,ship,aliens,bullets):check_fleet_deges(ai_settings,aliens)aliens.update()check_aliens_bottom(ai_settings,stats,screen,sb,ship,aliens,bullets)#检测外星人和飞船的碰撞"""方法接受两个实参,一个是单个对象,另一个是编组"""if pygame.sprite.spritecollideany(ship,aliens):ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets)def fire_bullet(ai_settings,screen,ship,bullets):if len(bullets) < ai_settings.bullet_allowed:#创建一颗子弹,加到编组中new_bullet = bullet(ai_settings,screen,ship)bullets.add(new_bullet)def get_number_alien_x(ai_settings,alien_width):"""计算一行有多少个外星人"""available_space_x = ai_settings.screen_width - 2*alien_widthnumber_aliens_x = int(available_space_x/(2*alien_width))return number_aliens_xdef get_number_rows(ai_settings,ship_height,alien_height):"""计算能容纳多少行外星人"""#意思是在上边留一个高度,下边距离飞船两个的距离,防止贴脸available_space_y = (ai_settings.screen_height-3*alien_height-ship_height)  number_rows = int(available_space_y/(2*alien_height))return number_rowsdef create_alien(ai_settings,screen,aliens,alien_number,row_number):"""创建一个外星人并放置在编组中"""alien = Alien(ai_settings,screen)alien_width = alien.rect.widthalien.x = alien_width + 2*alien_width*alien_numberalien.rect.x = alien.xalien.rect.y = alien.rect.height + 2*alien.rect.height*row_numberaliens.add(alien)def create_fleet(ai_settings,screen,stats,ship,aliens):"""创建外星人群"""alien = Alien(ai_settings,screen)#第一个对象是用来计算相关数据的number_aliens_x = get_number_alien_x(ai_settings,alien.rect.width)number_rows = get_number_rows(ai_settings,ship.rect.width,alien.rect.height)for row_number in range(number_rows):for alien_number in range(number_aliens_x):create_alien(ai_settings,screen,aliens,alien_number,row_number)def check_fleet_deges(ai_settings,aliens):"""有外星人得到边界时"""for alien in aliens.sprites():if alien.check_edge():change_fleet_direction(ai_settings,aliens)breakdef change_fleet_direction(ai_settings,aliens):"""将外星人整体下调,并改变方向"""for alien in aliens.sprites():alien.rect.y += ai_settings.fleet_drop_speedai_settings.fleet_direction *= -1def ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets):"""响应外星人撞到船"""if stats.ships_left > 0:stats.ships_left -= 1#更新记分牌sb.prep_ships()#这里的逻辑是撞到了外星人就需要重新开始,将下一个飞船固定在中间并重新生成外星人bullets.empty()aliens.empty()create_fleet(ai_settings,screen,stats,ship,aliens)ship.center_ship()sleep(0.5)else:pygame.mouse.set_visible(True)stats.game_active = Falsedef check_aliens_bottom(ai_settings,stats,screen,sb,ship,aliens,bullets):"""检查是否有外星人到达底端"""screen_rect = screen.get_rect()for alien in aliens.sprites():if alien.rect.bottom >= screen_rect.bottom:#按照和飞船撞到外星人一样处理ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets)breakdef check_high_score(stats,sb):"""检查是否出现最高分"""if stats.score > stats.high_score:stats.high_score = stats.scoresb.prep_high_score()

准备

我们的外星人生成逻辑是这样的:
距离飞船两个外星人的距离,距离顶端一个外星人的距离
一行中每隔一个外星人的宽度生成一个外星人,同样是两边各留一个外星人的距离

create_fleet函数为创建外星人群:
首先创建了一个外星人案例,用来计算行数和列数,调用get_number_alien_x和get_number_rows计算;
随后双重for循环,调用创建一个外星人的函数creat_alien,分别确定当前x、y坐标,然后放在编组中。
没看错,还记得之前提到的精灵类吗,其中的Group编组就是专门对付这样多个对象的结构,还有很多方便的方法可以使用。

键鼠事件

需要管理的事件:

  • 按下左右键时,我们需要让飞船向对应方向移动(通过控制ship类中的方向Boolean变量)
  • 松开左右键,停止移动(将Boolean改为false)
  • 按下键盘,如果是"q"需要退出程序,如果是空格需要进行开火
  • 按下鼠标,如果是关闭窗口,需要退出程序;如果是在play按钮上,则需要开始游戏

先使用check_events函数检测所有的事件,然后进行筛选。
pygame.event.get()方法返回一个事件列表,我们遍历这个列表。
其中pygame.QUIT就是关闭窗口的事件,而sys.exit方法是用来结束的。

keydown和keyup则是键盘按下和抬起,调用的check_keydown/keyup_events()方法都还好。

play按钮事件

对于点击事件,check_play_button则涉及到了很多内容。
函数的目的是判断是否play按钮被点击,其中被点击的可能为第一次运行或者再来一局。

首先使用pygame.mouse.get_pos方法得到鼠标点击事件的位置,传入函数中;
在函数中对坐标进行判断,这里使用的是rect的collidepoint方法,传入一组xy就能判断坐标在不在矩形中。
当play按钮被点击,将会按顺序发生下列事件:

  • 隐藏光标,pygame.mouse.set_visible(Flase)
  • 将统计信息中的游戏状态设置为真,然后调用重置方法,将统计数据重置
  • 在数据重置后,调用记分牌的方法,将新数据进行渲染。
  • 调用编组empty方法,清空外星人和子弹(防止是再来一局)
  • 创建外星人群,将飞船调整到初始位置
  • 将设置中的数据恢复。

开火事件

在按下空格键,我们将调用fire函数。
首先别忘了我们有屏幕上最多子弹数限制(3枚),先判断子弹数量有没有超了,如果没有就创建一个子弹对象,并加入到编组中。

外星人更新

我们知道外星人的逻辑是不断左右移动(在alien类中的方法),如果碰到左右边界就向下移动10个像素;
如果碰到飞船或者是底端,则减少一条命或者结束游戏。

update_aliens函数:
首先检查外星人是否碰到左右边界,使用check_fleet_deges方法。
遍历每一个成员,如果有碰到的就调用change_fleet_direction方法,
改变外星人的移动方向(ai_setting中),并将每一个成员都向下移动10个像素。

然后调用alien的update方法,实现外星人的横向移动。

随后检查外星人是否接触到底部,使用check_aliens_bottom函数。
遍历每一个成员,如果和底端接触,则调用ship_hit函数(函数是处理飞船撞到外星人的,后面会提到)
这里属于偷了个懒,因为两者的处理结果相同。

最后使用pygame.sprite.spritecollodeany方法,传入单独对象和一个编组,用于判断是否有接触,如果有接触则调用ship_hit函数进行处理。
现在该提一下这个ship_hit函数了,目的是处理失败事件。
首先,不管是飞船碰到外星人还是外星人到底端,我们都需要将生命数减一,如果没有了直接结束游戏。
第一种情况:
将生命数减一,同时调用prep_ship更新记分牌;
将场上的外星人和子弹全部清空;
重新创建一波外星人并将飞船居中,挂起0.5秒继续游戏。

如果是要结束游戏,需要显示鼠标并将游戏状态设置为结束。

子弹更新

update_bullets函数。
首先调用bullet中的update方法,实现子弹的向上移动。
随后我们需要删除所有跑到屏幕之外的子弹,保证这些子弹不会占用子弹名额,并且防止卡顿。
最后判断是否有子弹和外星人发生碰撞,使用check_bullet_alien_collisions函数。

在check_bullet_alien_collisions函数中,我们使用了pygame.sprite.groupcollide方法:
参数:
传入两个编组,两个布尔型变量,这两个布尔型变量控制在判断碰撞之后是否删除对象。
这里的两个true代表在判断外星人和子弹相遇,就需要子弹和外星人都删除。
如果我们需要一个超能子弹,能连续穿过外星人,那么就需要将第一个Boolean设置为假。
返回值:
该函数的返回值是一个字典,key为子弹对象,value是外星人对象。
原理:
通过检测编组中每一个对象的rect和另一个编组对象的rect,如果发生重叠就在字典中添加一对键值,并且在原编组中删除

利用上述方法,我们将遍历字典中的每一个外星人,将分数添加到统计信息类stats。
在处理完分数之后,我们就需要检测最高分了:
使用check_high_score函数,通过判断统计类stats的状态来更新最高分和记分牌

最后别忘了需要检测外星人是否被消灭干净,在调用groupcollide方法之后,我们计算一下外星人编组的长度,如果长度为零,我们需要进行如下操作:

  1. 等级提升,并且使用prep_level渲染
  2. 删除屏幕上剩下的子弹
  3. 重新创建外星人
  4. 使用设置中的increase_sp方法加大难度

屏幕刷新

要明白,上述的函数除了计分板是在数据发生改变之后立即更新的,项外星人、子弹、飞船这些都是只修改了属性并没有渲染,所以我们采用了另外的函数进行统一处理。
update_screen函数:

  • 背景颜色填充(fill方法)
  • 绘制所有子弹
  • 显示飞船(指能发射子弹的那个,不是表示生命数的)
  • 显示外星人
  • 显示得分
  • 判断游戏状态,如果为停止则显示按钮
  • pygame.display.flip(),用于更新的方法

这里的子弹和外星人渲染方式是不一样的,虽然大家都是编组类型,但是因为外星人有图片而子弹是矩形框。

总结

虽然洋洋洒洒写了好多的函数,但是我们总结一下主要的部分,其实就是这样的:

(图片我在系列第一篇博客中发了xmind文件)
这样我们的事件就介绍完了,接下来的环节是介绍一下主函数的部分。

python实现外星人入侵——2

python实现外星人入侵——3.事件分析相关推荐

  1. 事件分析法python实现分析事件对股价的冲击

    我本身在做非全日制研究生的作业,于是我把研究过程用到的代码开源了,供更多的金融和经济专业的同学借鉴. 事件研究法(EventStudy)用于评估某一事件的发生或信息的发布,是否会改变投资人的决策,进而 ...

  2. Python+Pandas读取Excel文件分析关系最好的两个演员

    董老师又双叒叕送书啦,6本<Python程序设计基础与应用(第2版)> 推荐图书: <Python程序设计(第3版)>,(ISBN:978-7-302-55083-9),董付国 ...

  3. Python爬取并简单分析2024年普通高校招生专业(专业类)选考科目要求

    推荐教材: <Python网络程序设计(微课版)>,ISBN:978-7-302-58312-7,董付国,清华大学出版社,2021年8月出版,京东.当当.淘宝均有销售 配套资源: 教学大纲 ...

  4. 针对巴基斯坦的某APT活动事件分析

    本文讲的是针对巴基斯坦的某APT活动事件分析, 事件背景 2017年6月,360威胁情报中心发现了一份可疑的利用漏洞执行恶意代码的Word文档,经过分析后,我们发现这有可能是一起针对巴基斯坦的政府官员 ...

  5. python商品评论数据采集与分析可视化系统 Flask框架 requests爬虫 NLP情感分析 毕业设计 源码

    一.项目介绍 python商品评论数据采集与分析可视化系统 Flask框架.MySQL数据库. requests爬虫.可抓取指定商品评论.Echarts可视化.评论多维度分析.NLP情感分析.LDA主 ...

  6. Kaggle(Gun Violence Data)—美国枪支暴力事件分析(1)和(2)

    Kaggle(Gun Violence Data)-美国枪支暴力事件分析(1) 数据来源为kaggle:https://www.kaggle.com/jameslko/gun-violence-dat ...

  7. 利用Python进行简单杜邦分析

    利用Python进行简单杜邦分析 "巧妇难为无米之炊",找不到数据,量化分析.财务报表分析也就无从谈起.对于分析者来说,获取数据是量化分析的第一步.Python的一个强大功能之一就 ...

  8. python 安卓app 缺点_用python对android APP进行分析2

    文章接着前一篇文章<用python对android APP进行分析1>的内容 转换其他列数据类型 data.Reviews=data['Reviews'].astype(np.int,in ...

  9. Python Project- Alien_invasion(外星人入侵)

    目录 > 武装飞船 > 开始游戏项目 > 创建pygame窗口以及相应用户输入 >> 初始化程序 >> 创建surface对象 >> 事件监听 & ...

最新文章

  1. 中台辨析:架构的演进趋势
  2. ai包装插件_找AI插件很费劲,一次给你66款AI插件合集!每一款都是设计师常用...
  3. 云计算hcie贴吧_专业介绍|计算机网络技术
  4. 11210怎么等于24_想要消耗100大卡热量,怎么做才最简单?
  5. 二线城市,存款多少可以退休?
  6. Python 学习笔记 - 协程
  7. 总结MySQL建表、查询优化实用小技巧
  8. Flex和Flash之间相互调用
  9. html5鼠标悬停遮罩,js实现鼠标移动到图片产生遮罩效果
  10. 火星坐标系解密-iDesktopX空间数据处理
  11. 机器视觉培训教程-镜头的基本知识
  12. c语言怎么用setw输出每行6个,setw和setfill控制输出间隔
  13. Mac电脑如何快速回到桌面?
  14. c语言 最长单词,c语言求最长公共单词
  15. 基于Springboot框架的登录注册页面
  16. 极速办公Word文档的查找和替换功能键在哪?
  17. 读书笔记软件调试之道 :问题的核心-重现问题
  18. 以太坊的交易树和收据树
  19. 语雀导出html,博客搭建
  20. 一些自己面试unity3D 程序员的面经

热门文章

  1. python数据可视化(matplotlib,seaborn,plotly)
  2. Hive(23):实例:网站流量分析
  3. GPS信号接收机的频偏和相位锁定matlab仿真
  4. C++实现黑白棋算法
  5. 晒晒这些让人崩溃的话
  6. 《软技能,代码之外的生存指南》--教你如何当一名程序员
  7. openwrt上网行为控制_深信服全网行为管理AC重磅发布!
  8. 下载安卓手机app内不允许下载的视频
  9. 使用urllib.request库获取cookie登录
  10. 微信小程序配置每个页面的标题名称