python如何优雅的打飞机
这是一个打飞机的游戏,结构如下:

其中images中包含的素材为

命名为alien.png

命名为ship.png
游戏效果运行是这样的:

敌军,也就是体型稍微大点的,在上方左右移动,并且有规律向下移动。我军目标,消灭所有飞机。但是屏幕上最多只展现3颗子弹。
一旦,我军飞机与敌军飞机碰撞,或者敌军飞机抵达底部。我军损失一条生命,一共三条。
敌军飞机全部消灭完,则到下一关,移动速度会更快。
我军每消灭一架敌军飞机获得积分,积分最高者会在界面显示。
游戏源码如下:
#alien_invasion.py
#主程序文件
"""
创建Pygame窗口响应以及用户输入
"""
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Alien
from game_stats import GameStats
from button import Button
from Scoreboard import Scoreboard
def run_game():
#初始化游戏并且创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建play按钮
play_button = Button(ai_settings, screen, "PLAY~")
#创建一个用户存储游戏统计信息的实例
stats = GameStats(ai_settings)
sb = Scoreboard(ai_settings, screen, stats)
#创建一艘飞船
ship = Ship(ai_settings,screen)
#创建一个用户存储子弹的编组
bullets = Group()
#创建一个外星人
aliens = Group()
#创建外星人群
gf.create_fleet(ai_settings, screen,ship, aliens)
#开始游戏主循环
while True:
#监视键盘和鼠标事件
gf.check_events(ai_settings, screen, stats,sb, play_button, ship, aliens,bullets)
if stats.game_active:
ship.update()
#删除已消失的子弹
gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets)
gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets)
gf.update_screen(ai_settings, screen,stats, sb, ship, aliens, bullets, play_button)
#让最近绘制的屏幕可见
pygame.display.flip()
run_game()
#alien.py
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
def __init__(self,ai_settings, screen ):
"""初始化外星人并且设置起始位置"""
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载外星人图像,并且设置其rect属性
self.image = pygame.image.load("images/alien.png")
self.rect = self.image.get_rect()
#每个外星人最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
#存储外星人的准确位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置绘制外星人"""
self.screen.blit(self.image, self.rect)
def check_edges(self):
"""如果外星人出于屏幕边缘,就返回True"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right:
return True
elif self.rect.left <= 0:
return True
def update(self):
"""向左或者右移动的外星人"""
self.x += (self.ai_settings.alien_speed_factor *
self.ai_settings.fleet_direction)
self.rect.x = self.x
#bullet.py
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""一个对飞船发射的子弹进行管理的类"""
"""Bullet类继承了我们从模块pygame.sprite中导入的Sprite类"""
def __init__(self, ai_settings, screen, ship):
"""在飞船所处的位置创建一个子弹对象"""
"""为创建子弹实例,需要向__init__()传递
ai_settings、screen和ship实例,还调用了super()来继承Sprite。
"""
super().__init__()
self.screen = screen
"""
在(0.0)处创建一个表示子弹的矩形,再设置正确的位置
我们创建了子弹的属性rect。子弹并非基于图像的,因此我们必须使用pygame.Rect()
类从空白开始创建一个矩形
"""
self.rect = pygame.Rect(
0,0,ai_settings.bullet_width,ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx #将子弹的centerx设置为飞船的rect.centerx
self.rect.top = ship.rect.top #子弹的rect的top属性设置为飞船的rect的top属性
#存储用小数表示的子弹位置
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""向上移动子弹"""
#更新表示移动子弹的位置的小数值
self.y -= self.speed_factor
#更新表示子弹的rect的位置
self.rect.y = self.y
def draw_bullet(self):
"""在屏幕上绘制子弹"""
pygame.draw.rect(self.screen, self.color, self.rect)
#button.py
import pygame.font
class Button():
def __init__(self, ai_settings, screen, msg):
"""初始化按钮的属性"""
self.screen = screen
self.screen_rect = screen.get_rect()
#设置按钮的尺寸和其他属性
self.width, self.height = 200, 50
self.button_color = (0, 250, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
#创建按钮的rect对象,并且让它居中
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
#按钮的标签只需要创建一次
self.prep_msg(msg)
def prep_msg(self, msg):
self.msg_image = self.font.render(msg, True, self.text_color,self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
# 绘制一个用颜色填充的按钮,再绘制文本
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect)
#game_functions.py
import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep
def check_keydown_events(event, ai_settings,screen,ship,bullets):
"""响应按键"""
if event.key == pygame.K_RIGHT:
#向右→移动
ship.moving_right = True
elif event.key == pygame.K_LEFT:
#向左移动
ship.moving_left = True
elif event.key == pygame.K_SPACE:
# 创建一颗子弹,并将其加入到编组bullets中
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 = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
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_play_button(
ai_settings, screen, stats, sb, play_button, ship, aliens,bullets, mouse_x, mouse_y):
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
if button_clicked and not stats.game_active:
# 重置游戏设置
ai_settings.initialize_dynamic_settings()
# 隐藏光标
pygame.mouse.set_visible(False)
#重置游戏
stats.reset_start()
stats.game_active = True
#重置记分牌图像
sb.prep_score()
sb.prep_high_score()
sb.prep_level()
sb.prep_ships()
# 清空外星人列表和子弹列表
aliens.empty()
bullets.empty()
# 创建一群新的外星人,并让飞船居中
create_fleet(ai_settings, screen, ship, aliens)
ship.center_ship()
def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets,play_button):
"""更新屏幕的图像,并且切换到新的屏幕"""
#每次循环时都会重新绘屏
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
aliens.draw(screen)
#显示得分
sb.show_score()
# 如果游戏处于非活动状态,就绘制Play按钮
if not stats.game_active:
play_button.draw_button()
#让最近绘制的屏幕可见
pygame.display.flip()
def update_bullets(ai_settings, screen,stats, sb, ship, aliens, bullets):
"""更新子弹的位置,并且删除已消失的子弹
在for循环中,不应从列表或编组中删除条目,因此必须遍历编组的副本。
我们使用了方法copy()来设置for循环
"""
bullets.update()
for bullet in bullets.copy():
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)
if len(aliens) == 0:
#删除现有的子弹并新建一群外星人
bullets.empty()
ai_settings.increase_speed() #新游戏加速
#print(ai_settings.alien_speed_factor)
create_fleet(ai_settings, screen, ship, aliens)
stats.level += 1
sb.prep_level()
if collisions:
for aliens in collisions.values():
stats.score += ai_settings.alien_points * len(aliens)
sb.prep_score()
check_high_score(stats, sb)
def fire_bullet(ai_settings, screen, ship, bullets):
"""如果还没有到达限制,就发射一颗子弹"""
#创建新子弹,并将其加入到编组bullets中
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def create_fleet(ai_settings, screen, ship, aliens):
"""创建外星人群"""
#创建一个外星人并且计算一行可以容纳多少个外星人
#外星人间距为外星人的宽度
alien = Alien(ai_settings, screen)
number_aliens_x = get_number_aliens_x(ai_settings,alien.rect.width)
number_rows = get_number_rows(ai_settings, ship.rect.height, 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 get_number_aliens_x(ai_settings, alien_width):
"""计算每行可以容纳多少飞机"""
available_space_x = ai_settings.screen_width - 2 * alien_width
number_aliens_x = int(available_space_x / (2 * alien_width))
return number_aliens_x
def create_alien(ai_settings, screen, aliens, alien_number, row_number): #这里的row_number来自哪里?
"""创建一个外星人并把它放在当前行列"""
alien = Alien(ai_settings, screen)
alien_width = alien.rect.width
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
aliens.add(alien)
def get_number_rows(ai_settings, ship_height, alien_hight):
"""计算屏幕可以容纳几行外星人"""
available_space_y = (
ai_settings.screen_height - (3*alien_hight) - ship_height)
number_rows = int(available_space_y / (2*alien_hight))
return number_rows
def update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets):
"""更新外星人的位置"""
check_fleet_edges(ai_settings,aliens)
aliens.update()
#检测外星人和飞船之间的碰撞
if pygame.sprite.spritecollideany(ship, aliens):
ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)
check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens, bullets)
def check_fleet_edges(ai_settings, aliens):
"""有外星人撞到边缘时候采取的措施"""
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai_settings, aliens)
break
def change_fleet_direction(ai_settings,aliens):
"""整体外星人向下移动,并且改变方向"""
for alien in aliens.sprites():
alien.rect.y += ai_settings.fleet_drop_speed
ai_settings.fleet_direction *= -1
def ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets):
"""响应被外星人撞到的飞船"""
#ship_left -1
if stats.ship_left > 0:
stats.ship_left -=1
#清空外星人列表和子弹列表
aliens.empty()
bullets.empty()
sb.prep_ships()
#创建一群新的外星人,并将飞船放到屏幕底端中央
create_fleet(ai_settings, screen, ship, aliens)
ship.center_ship()
#暂停
sleep(0.5)
else:
stats.game_active = False
pygame.mouse.set_visible(True)
def check_aliens_bottom(ai_settings, screen, stats, 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, screen, stats, sb, ship, aliens, bullets)
break
def check_high_score(stats, sb):
if stats.score > stats.high_score:
stats.high_score = stats.score
sb.prep_high_score()
#game_stats.py
class GameStats():
"""游戏统计信息"""
def __init__(self,ai_settings):
"""初始化统计信息"""
self.ai_settings = ai_settings
self.reset_start()
#游戏一开始就是非活动状态
self.game_active = False
# 在任何情况下都不应重置最高得分
self.high_score = 0
def reset_start(self):
"""初始化在游戏运行期间可能变化的统计信息"""
self.ship_left = self.ai_settings.ship_limit
self.score = 0
self.level = 1
#Scoreboard.py
import pygame.font
from pygame.sprite import Group
from ship import Ship
class Scoreboard():
"""显示信息得分的类"""
def __init__(self, ai_settings, screen, stats):
self.screen = screen
self.screen_rect = screen.get_rect()
self.ai_settings = ai_settings
self.stats = stats
#显示得分信息时使用的字体设置
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)
#准备初始得分图像 和最高得分
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ships()
def prep_score(self):
rounded_score = int(round(self.stats.score, -1))
score_str = "{:,}".format(rounded_score)
self.score_image = self.font.render(
score_str,True, self.text_color, self.ai_settings.bg_color)
#将得分放在屏幕右上角
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right -20
self.score_rect.top = 20
def show_score(self):
self.screen.blit(self.score_image, self.score_rect)
self.screen.blit(self.high_score_image, self.high_score_rect)
self.screen.blit(self.level_image, self.level_rect)
self.ships.draw(self.screen)
def prep_high_score(self):
"""渲染最高分为图像"""
high_score = int(round(self.stats.high_score,-1))
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.font.render(high_score_str, True,
self.text_color, self.ai_settings.bg_color)
#最高得分在顶部中央
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.screen_rect.top
def prep_level(self):
"""将等级转换为渲染的图像"""
self.level_image = self.font.render(str(self.stats.level), True,
self.text_color, self.ai_settings.bg_color)
#位置
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10
def prep_ships(self):
self.ships = Group()
for ship_number in range(self.stats.ship_left):
ship = Ship(self.ai_settings, self.screen)
ship.rect.x = 10 + ship_number * ship.rect.width
ship.rect.y = 10
self.ships.add(ship)
#settings.py
class Settings():
"""
存储游戏所有设置的类
"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 飞船的设置
self.ship_speed_factor = 1.5
self.ship_limit = 3
#子弹设置
self.bullet_speed_factor = 3
self.bullet_width = 1 #这里更改子弹的宽度
self.bullet_height = 15
self.bullet_color = 60, 60, 60
self.bullets_allowed = 300 #这里更改子弹的个数
# 外星人设置
self.fleet_drop_speed = 10 #默认10
# 以什么样的速度加快游戏节奏
self.speedup_scale = 1.1
#分数的提高速度
self.score_scale = 1.5
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
#初始化随游戏进行而变化的设置
self.ship_speed_factor = 1.5
self.bullet_speed_factor = 3
self.alien_speed_factor = 1
# fleet_direction为1表示向右;为-1表示向左
self.fleet_direction = 1
#积分
self.alien_points = 50
def increase_speed(self):
#提高速度设置
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor *= self.speedup_scale
self.alien_points = int(self.alien_points * self.score_scale)
print(self.alien_points)
#ship.py
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
def __init__(self, ai_settings, screen):
"""初始化飞船并设置其初始位置"""
super(Ship, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.png') #加载图像
self.rect = self.image.get_rect() #获取图像的大小
self.screen_rect = screen.get_rect() #获取窗口的大小
#将新船放在屏幕底部中央位置
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 在飞船的属性center中存储小数值
self.center = float(self.rect.centerx)
#移动标志
self.moving_right = False
self.moving_left = False
def update(self):
"""根据移动标志调整飞船的位置"""
# 更新飞船的center值,而不是rect
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
# 根据self.center更新rect对象
self.rect.centerx = self.center
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)
def center_ship(self):
"""让飞船在屏幕上居中"""
self.center = self.screen_rect.centerx
python如何优雅的打飞机的更多相关文章
- python 如何优雅地退出子进程
python 如何优雅地退出子进程 主进程产生子进程,子进程进入永久循环模式.当主进程要求子进程退出时,如何能安全地退出子进程呢? 参考一些代码,我写了这个例子.运行之后,用kill pid试试.pi ...
- 让Python更优雅更易读(第二集)
友情链接 让Python更优雅更易读(第一集) 1.装饰器 1.1装饰器特别适合用来实现以下功能 运行时校验:在执行阶段进行特定校验,当校验通不过时终止执行. 适合原因:装饰器可以方便地在函数执行前介 ...
- python实战===如何优雅的打飞机
这是一个打飞机的游戏,结构如下: 其中images中包含的素材为 命名为alien.png 命名为ship.png 游戏效果运行是这样的: 敌军,也就是体型稍微大点的,在上方左右移动,并且有规律 ...
- <转> Python的优雅技巧
枚举 不要这么做: 全选复制放进笔记 i = 0 for item in iterable: print i, item i += 1 而是这样: 全选复制放进笔记 for i, item in en ...
- 使用Python以优雅的方式实现根据shp数据对栅格影像进行切割
目录 前言 涉及到的技术 优雅切割 总结 一.前言 前面一篇文章(使用Python实现子区域数据分类统计)讲述了通过geopandas库实现对子区域数据的分类统计,说白了也就是如何根据一 ...
- 让你的 Python 代码优雅又地道
示例代码和引用的语录都来自Raymond的演讲.这是我按我的理解整理出来的,希望你们理解起来跟我一样顺畅! 遍历一个范围内的数字 for i in [0, 1, 2, 3, 4, 5]: print ...
- python之基础总结(飞机大战)
一.学习python有一段时间了,总体上手还是挺好的,但是有些东西还是和Java存在着一定的区别,这里主要是通过学习,然后自己去编写一个案例.从中学习到的一些东西,这里分享出来,如果存在不正确的地方还 ...
- 关于python - 更优雅的技巧
枚举 不要这么做: i = 0 for item in iterable: print i, item i += 1 而是这样: for i, item in enumerate(iterable): ...
- 一个Python中优雅的数据分块方法
背景 看到这个标题你可能想一个分块能有什么难度?还值得细说吗,最近确实遇到一个有意思的分块函数,写法比较巧妙优雅,所以写一个分享. 日前在做需求过程中有一个对大量数据分块处理的场景,具体来说就是几十万 ...
随机推荐
- iOS9 系统分享调用(UIActivityViewController)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/49615109 ...
- How to configure ODBC DSN in Client to access remote DB2 for Windows
How to configure ODBC DSN in Client to access remote DB2 for Windows MA Gen feng (Guangdong Unito ...
- python标准库之MultiProcessing库的研究 (1)
MultiProcessing模块是一个优秀的类似多线程MultiThreading模块处理并发的包之前接触过一点这个库,但是并没有深入研究,这次闲着无聊就研究了一下,算是解惑吧.今天先研究下appl ...
- Android布局优化:include 、merge、ViewStub的详细总结
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本篇博客主要是对上篇博客的补充Android性能优化之UI渲染性能优化, 没有什么新东西,觉得应该是都掌握的玩意,写出来也只是自己做个小小的总结. ...
- PHP单元测试使用
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类, ...
- [Other]在 Docker 当中搭建 Docfx 站点
一.简介 Docfx 是微软开发的一款开源的文档生成工具,其默认支持 C# 与 VB.Net 这两种项目的文档生成,支持 DotNetCore 项目,并且还可以打包成一个静态的 Web 站点,而且还支 ...
- xml与object 之间的ORM
xml映射为object对象,同时object对象,以xml来表示: public class Tools { private static XmlNodeList SelectNodes(strin ...
- Java语言概论
第1章 ■ Java的发展简史及特点 ■ J2SDK的下载与安装 ■ Java应用程序的编写 ■ Eclipse的下载及使用 ■ 正确安装使用J2SDK ■ 使用记 ...
- div学习之div中dl-dt-dd的详解
dl dt dd认识及dl dt dd使用方法 <dl> 标签用于定义列表类型标签. dl dt dd目录 dl dt dd介绍 结构语法 dl dt dd案例 dl dt dd总结 一. ...
- 如何将程序集安装到全局程序集缓存GAC
针对一些类库项目或用户控件项目(一般来说,这类项目最后编译生成的是一个或多个dll文件),在程序开发完成后,有时需要将开发的程序集(dll文件)安装部署到GAC(全局程序集缓存)中,以便其他的程序也可 ...