跟书《Python编程:从入门到实践》学习一段时间了,书中第一个项目就是开发小游戏《外星人入侵》。下面是跟书一步步开发的代码,代码后面的注释仅仅是个人理解。
效果图:
项目文件
项目目录:alien_invasion
图片目录:alien_invasion/images
图片:alien_invasion/images/ship.bmp、alien_invasion/images/alien.bmp
alien_invasion.py
主文件alien_invasion.py
创建一系列整个游戏都要用到的对象:存储在ai_settings
中的设置、存储在screen
中的主显示surface以及一个飞船实例。文件alien_invasion.py
还包含游戏的主循环,这是一个调用check_events()
、ship.update()
和update_screen()
的while循环。
要玩游戏《外星人入侵》,只需运行文件alien_invasion.py
。其他文件(settings.py
、game_functions.py
、ship.py
)包含的代码被直接或间接地导入到这个文件中。
import pygame
from pygame.sprite import Group #导入pygame模块下sprite子模块中的Group类
from settings import Settings #导入自定义的Settings类
from ship import Ship #导入自定义的Ship类
import game_functions as gf #导入自定义的game_functions类,并起别名为gf
from game_stats import GameStats #导入自定义的GameStats类
from button import Button #导入自定义的Button类
from scoreboard import Scoreboard #导入自定义的Scoreboard类
def run_game():
# 初始化pygame、设置和屏幕对象
pygame.init()
ai_settings = Settings() #实例化Settings类
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height)) #调用display模块的set_mode()方法设置屏幕大小
pygame.display.set_caption("Alien Invasion") #调用display模块的set_caption()方法设置标题
# 创建Play按钮
play_button = Button(ai_settings, screen, "Play") #实例化Button类
# 创建存储游戏统计信息的实例,并创建记分牌
stats = GameStats(ai_settings) #实例化GameStats类
sb = Scoreboard(ai_settings, screen, stats) #实例化Scoreboard类
# 创建一艘飞船、一个子弹编组和一个外星人编组
ship = Ship(ai_settings, screen) #实例化Ship类
bullets = Group() #实例化Group类
aliens = Group() #实例化Group类
# 创建外星人群
gf.create_fleet(ai_settings, screen, ship, aliens) #调用gf模块的create_fleet()函数
# 开始游戏的主循环
while True:
# 监视键盘和鼠标事件
gf.check_events(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets) #调用gf模块的check_events()函数,监测键盘和鼠标的事件
if stats.game_active:
ship.update() #调用Ship类的update()方法
gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) #调用gf模块的update_bullets函数,更新子弹的状态
gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets) #调用gf模块的update_aliens函数,更新外星人的状态
gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button) #调用gf模块的update_screen函数,更新屏幕的状态
run_game() #运行游戏
settings.py
文件settings.py
包含Settings
类,这个类包含方法__init__()
、初始化游戏设置的方法initialize_dynamic_settings()
、随游戏进程提高速度的方法increase_speed()
。
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 = 3 #设置子弹的宽度
self.bullet_height = 15 #设置子弹的高度
self.bullet_color = 60, 60, 60 #设置子弹的眼色
self.bullets_allowed = 5 #设置屏幕上最多同时存在的子弹数
# 外星人设置
self.alien_speed_factor = 1 #设置外星人的左右移动速度
self.fleet_drop_speed = 10 #设置外星人群的向下移动速度
# 以什么样的速度加快游戏节奏
self.speedup_scale = 1.1 #设置每轮游戏节奏加快速度
# 外星人点数的提高速度
self.score_scale = 1.5 #设置每轮外星人分数提高倍数
self.initialize_dynamic_settings() #调用initialize_dynamic_settings()函数初始化游戏参数
def initialize_dynamic_settings(self):
"""初始化随游戏进行而变化的设置"""
self.ship_speed_factor = 1.5
self.bullet_speed_factor = 5
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)
ship.py
文件ship.py
包含Ship
类,这个类包含方法__init__()
、管理飞船位置的方法update()
、在屏幕上绘制飞船的方法blitme()
以及让飞船在屏幕底部居中的方法center_ship()
。表示飞船的图像存储在文件夹images下的文件ship.bmp中。
import pygame
from pygame.sprite import Sprite #导入pygame模块下sprite子模块中的Sprite类
class Ship(Sprite):
def __init__(self, ai_settings, screen):
"""初始化飞船并设置其初始位置"""
super(Ship, self).__init__() #兼容python2.7,Ship类继承Sprite类属性
self.screen = screen
self.ai_settings = ai_settings
# 加载飞船图形并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp') #加载图片,创建图片对象
self.rect = self.image.get_rect() #调用get_rect()方法,获取image的属性rect
self.screen_rect = screen.get_rect() #调用get_rect()方法,将表示屏幕的矩形存储在self.screen_rect中
# 将每艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx #让飞船矩形centerx属性(中央x坐标)等于屏幕矩形centerx属性,x方向上居中
self.rect.bottom = self.screen_rect.bottom #让飞船矩形bottom属性等于屏幕矩形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: #当向右移动且飞船矩形right属性小于屏幕矩形right属性时
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0: #当向左移动且飞船矩形left属性大于0时
self.center -= self.ai_settings.ship_speed_factor
# 根据self.center更新rect对象
self.rect.centerx = self.center #如果是self.rect.centery = self.center,则飞船会上下移动,而不是左右移动
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect) #调用blit()方法将图片对象添加到窗口对象中
def