项目1 外星人入侵
第12章 武装飞船
Pygame,是一组功能强大而有趣的模块,可用于管理图形、动画乃至声音,让你能够更轻松地开发复杂的游戏。
创建游戏是趣学语言的理想方式。
12.1 规划项目
开发大型项目时,做好规划后再动手编写项目很重要。规划可确保你不偏离轨道,从而提高项目成功的可能性。
编写有关游戏《外星人入侵》的描述:
image.png
12.2 安装Pygame
Pygame项目托管在代码分享网站Bitbucket中。
对应于Python3.7版本的pygame下载地址:
https://pypi.org/project/Pygame/#files
(牢骚:真心不易啊,折腾这么久。卸载了以前安装的python,重新下载Anaconda镜像,再设置pip,再下载pygame)
image.png
12.3 开始游戏项目
12.3.1 创建Pygame窗口以及相应用户输入
# -*- coding:gbk -*-
import sys
import pygame
def run_game():
# 初始化游戏并创建一个屏幕对象
pygame.init()
screen = pygame.display.set_mode((1200,800))
pygame.display.set_caption("Alien Invasion")
# 开始游戏的主循环
while True:
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
pygame.init()初始化背景设置,让pygame能够正确地工作。
事件是用户玩游戏时执行的操作,如按键或移动鼠标。为让程序响应事件,编写一个事件循环,以侦听事件,并根据发生的事件执行响应的方法。
最后run_game()初始化游戏并开始主循环。
12.3.2 设置背景色
pygame默认创建一个黑色屏幕。
# -*- coding:gbk -*-
import sys
import pygame
def run_game():
# 初始化游戏并创建一个窗口
pygame.init()
screen = pygame.display.set_mode((1200,800))
pygame.display.set_caption("Alien Invasion2")
# 设置背景色
bg_color = (230,230,230)
# 开始游戏的主循环
while True:
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每次循环时都重绘屏幕
screen.fill(bg_color)
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
在pygame中,颜色是以RGB值指定的。(红色、绿色、蓝色值)
,每个值的可能取值范围都为0~255.颜色值(255,0,0)表示红色,(0,255,0)表示绿色,(0,0,255)表示蓝色。
12.3.3 创建设置类
# -*- coding:gbk -*-
class Settings():
"""存储《外星人入侵》的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
# 屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
创建Settings实例并使用它来访问设置。
# -*- coding:gbk -*-
import sys
import pygame
from settings import Settings
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 Invasion3")
# 开始游戏的主循环
while True:
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
12.4 添加飞船图像
加载图像,再使用pygame方法blit()绘制。
- 为游戏选择素材时,务必要注意许可。
- 在游戏中几乎可以使用任何类型的图像文件,但使用位图(.bmp)文件最为简单,因为pygame默认加载位图。虽然可配置pygame以使用其他文件类型,但有些文件类型要求你在计算机上安装相应的图像库。
- 选择图像时,要特别注意其背景色。请尽可能选择背景透明的图像,这样可使用图像编辑器将其背景设置为任何颜色。
- END - 2019/4/2 22:52
12.4.1 创建Ship类
# -*- coding:gbk -*-
import pygame
class Ship():
def __init__(self,screen):
"""初始化飞船并设置其初始位置"""
self.screen = screen
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
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
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
为加载图像,我们调用pygame.image.load(),这个函数返回一个表示飞船的surface,我们将这个surface存储到self.image中。
用get_rect()获取相应surface的属性rect。处理rect对象时,可使用矩形四角和中心的x/y坐标,通过设置这些值来指定矩形的位置。设置相应rect对象的属性:center、centerx、centery、top、bottom、left、right等。
注意:在pygame中,原点(0,0)位于屏幕左上角,向右下方移动时,坐标值将增大。在1200X800的屏幕上,原点位于左上角,而右下角的坐标为(1200,800)。
12.4.2 在屏幕上绘制飞船
# -*- coding:gbk -*-
import sys
import pygame
from settings import Settings
from ship import Ship
def run_game():
# 初始化pygame、设置和屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion4")
# 创建一艘飞船
ship = Ship(screen)
# 开始游戏主循环
while True:
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
不知道为什么飞船是在左下角,而不是中间?.png
问题已解决,原因在于ship设置中,self.rect.centerx误写成了self.rect_centerx
image.png
在创建屏幕后创建一个名为ship的Ship实例,必须在主while循环前面创建该实例,以免每次循环时都创建一艘飞船。填充背景后,调用ship.blitme()将飞船绘制到屏幕上,确保它出现在背景前面。
12.5 重构:模块game_functions
在大型项目中,经常需要在添加新代码前重构既有代码。重构旨在简化既有代码的结构 ,使其更容易扩展。
创建名为game_functions的新模块,将存储大量让游戏运行的函数。
12.5.1 函数check_events()
game_functions.py
# -*- coding:gbk -*-
import sys
import pygame
def check_events():
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
导入事件检查循环要使用的sys和pygame。
# -*- coding:gbk -*-
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化pygame、设置和屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion4_1")
# 创建一艘飞船
ship = Ship(screen)
# 开始游戏主循环
while True:
gf.check_events()
# 每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
在主程序文件中,不再需要直接导入sys,因为当前只在模块game_functions中使用了它。
12.5.2 函数update_screen()
# -*- coding:gbk -*-
import sys
import pygame
def check_events():
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
def update_screen(ai_settings,screen,ship):
"""更新屏幕上的图像,并切换到新屏幕"""
# 每次循环时都重绘图像
screen.fill(ai_settings.bg_color)
ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
新
# -*- coding:gbk -*-
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化pygame、设置和屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion4_1")
# 创建一艘飞船
ship = Ship(screen)
# 开始游戏主循环
while True:
gf.check_events()
gf.update_screen(ai_settings,screen,ship)
run_game()
12-1 蓝色天空:创建一个背景为蓝色的pygmae窗口
# -*- coding:gbk -*-
import sys
import pygame
def run_game():
"""初始化游戏,并创建一个屏幕"""
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Blue Screen")
# 设置背景色
bg_color = (0,0,255)
# 开始游戏主循环
while True:
"""检测键盘和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每次循环时都重绘屏幕
screen.fill(bg_color)
# 让最近绘制的屏幕可见
pygame.display.flip()
run_game()
image.png
12.6 驾驶飞船
控制屏幕图像的移动呢
12.6.1 响应按键
每当用户按键时,都将在pygame中注册一个事件。事件都是通过方法pygame.event.get()获取的,因此在函数check_events()中,我们需要指定要检查哪些类型的事件。每次按键都被注册为一个KEYDOWN事件。
检测到KEYDOWN事件时,我们需要检查按下的键是否是特定的键。
game_functions.py
import sys
import pygame
def check_events(ship):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
# 向右移动飞船
ship.rect.centerx += 1
alien_invasion.py
# 开始游戏主循环
while True:
gf.check_events(ship)
gf.update_screen(ai_settings,screen,ship)
12.6.2 允许不断移动
ship.py
# -*- coding:gbk -*-
import pygame
class Ship():
def __init__(self,screen):
"""初始化飞船并设置其初始位置"""
self.screen = screen
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
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
# 移动标志
self.moving_right = False
def update(self):
"""根据移动标志调整飞船的位置"""
if self.moving_right:
self.rect.centerx += 1
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
game_functions.py
# -*- coding:gbk -*-
import sys
import pygame
def check_events(ship):
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
def update_screen(ai_settings,screen,ship):
"""更新屏幕上的图像,并切换到新屏幕"""
# 每次循环时都重绘图像
screen.fill(ai_settings.bg_color)
ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
alien_invasion.py
# -*- coding:gbk -*-
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化pygame、设置和屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion4_1")
# 创建一艘飞船
ship = Ship(screen)
# 开始游戏主循环
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings,screen,ship)
run_game()
12.6.3 左右移动
image.pngimage.png
12.6.4 调整飞船的速度
image.pngimage.png
image.png
12.6.5 限制飞船的活动范围
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
12.6.6 重构check_events()
def check_keydown_events(event,ship):
"""相应按键"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
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(ship):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event,ship)
elif event.type == pygame.KEYUP:
check_keyup_events(event,ship)
12.7 简单回顾
12.7.1 alien_invasion.py
12.7.2 settings.py
12.7.3 game_functions.py
12.7.4 ship.py
12.8 射击
编写玩家按空格键时发射子弹(小矩形)的代码。子弹将在屏幕中向上穿行,抵达屏幕上边缘后消失。
12.8.1 添加子弹设置
def __init__(self):
--snip--
# 子弹设置
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60,60,60)
12.8.2 创建Bullet类
image.pngBullet类继承了我们从模块pygame.sprite中导入的Sprite类。
image.png
12.8.3 将子弹存储到编组中
创建一个编组(group)
12.8.4 开火
image.png image.png12.8.5 删除已消失的子弹
当子弹抵达屏幕顶端后消失,这仅仅是因为pygame无法在屏幕外面绘制他们。这些子弹实际上依然存在,它们的y坐标为负数,且越来越小。这是个问题,因为他们将继续消耗内存和处理能力。
需要将已消失的子弹删除,否则游戏所做的无谓工作将越来越多,进而变得越来越慢。
在for循环中,不应从列表或编组中删除条目,因此必须遍历编组的副本。
12.8.6 限制子弹数量
image.pngimage.png
12.8.7 创建函数update_bullets()
image.pngimage.png
12.8.8 创建函数fire_bullet()
image.png- END - 2019/4/6 15:17
网友评论