文章目录
效果展示
代码部分
alien.py
"""
在游戏《外星人入侵》中,玩家控制着一艘最初出现在屏幕底部中央的飞船。玩家可以使用箭头键左右移动飞船,还可使用空格键进行射击。游戏开始时,一群外星
人出现在天空中,他们在屏幕中向下移动。玩家的任务是射杀这些外星人。玩家将所有外星人都消灭干净后,将出现一群新的外星人,他们移动的速度更快。只要有
外星人撞到了玩家的飞船或到达了屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后,游戏结束。
"""
"""主程序,游戏开始的位置"""
from setting import *
from ship import *
import game_function as gf
from pygame.sprite import Group
from game_stats import GameStats
from button import Button
def run_game():
pygame.init() # 初始化背景
ai_settings = Settings() # 初始化设置实例
screens = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height)) # 设置背景窗口大小
pygame.display.set_caption("Alien Invasion") # 设置窗口标题
# 实例
play_button = Button(screens, "PLAY") # PLAY按钮
stats = GameStats(ai_settings) # 游戏状态
ship = Ship(ai_settings, screens) # 飞船的实例
bullets = Group() # 创建子弹组
aliens = Group() # 创建外星人组
gf.creat_fleet(ai_settings, screens, ship, aliens) # 创建外星人大队
while True: # 游戏开始主循环
gf.check_events(ai_settings, screens, stats, play_button, ship, aliens, bullets) # 游戏的按键鼠标的监听事件
if stats.game_active: # 如果游戏的状态为真(即运行的情况下)的情况下
ship.update() # 刷新船只
gf.update_bullets(ai_settings, screens, ship, aliens, bullets) # 刷新子弹
gf.update_aliens(ai_settings, stats, screens, ship, aliens, bullets) # 刷新外星人
gf.update_screen(ai_settings, screens, stats, ship, aliens, bullets, play_button) # 屏幕刷新
run_game()
settings.py
"""游戏的初始化设置,各种初始数据存放处"""
class Settings(object): # 存储《外星人入侵》的所有设置
def __init__(self): # 初始化游戏设置
# 屏幕
self.screen_width = 1000
self.screen_height = 600
self.bg_color = (230, 230, 230)
# 飞船的数量初始值(即有三条命)
self.ship_limit = 3
# 子弹的样子
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 60, 60, 60
self.bullet_allowed = 20#一个屏幕内允许的子弹数
self.fleet_drop_speed = 10 # 外星人下坠的速度
self.speedup_scale = 1.5 # 每经过一轮之后,速度都增加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 # 外星人的速度
self.fleet_direction = 1 # 控制外星人的方向,1表示向右,-1表示向左
def increase_speed(self):
# 把子弹、外星人和飞船的移动速度提升到1.5倍
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor *= self.speedup_scale
bullet.py
"""存放子弹的基本信息"""
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
def __init__(self, ai_settings, screen, ship):
super(Bullet, self).__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height) # 创建子弹的rect对象
self.rect.centerx = ship.rect.centerx # 子弹的横坐标的位置相对飞船居中
self.rect.top = ship.rect.top # 设置子弹从飞船头上发射,两者顶部重合
self.y = float(self.rect.y) # 纵坐标转为浮点数
self.color = ai_settings.bullet_color # 读取settings中设置了的颜色
self.speed_factor = ai_settings.bullet_speed_factor # 读取settings中设置的速度
def update(self):
self.y -= self.speed_factor # 屏幕x轴在上面,所以子弹向上移动是用减的
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect) # 绘画子弹
ship.py
"""存放飞船的相关数据"""
import pygame
class Ship(object):
def __init__(self, ai_settings, screen):
# 设置飞船的初始值
self.screen = screen
self.ai_settings = ai_settings
self.image = pygame.image.load('images/ship.png') # 加载飞船
self.rect = self.image.get_rect() # 获得的rect对象
self.screen_rect = screen.get_rect() # 获得屏幕的rect对象
self.rect.centerx = self.screen_rect.centerx # 飞船横坐标初始位置居中
self.rect.bottom = self.screen_rect.bottom # 飞船底部与飞机底部重合
self.center = float(self.rect.centerx) # 转成浮点数
# 左右移动的标志,true为可以移动
self.moving_right = False
self.moving_left = False
def update(self):
# 向右移动的标志为true且实际位置不超过右边缘时,就向右移动,speed为速度,settings中定义了
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
# 向左移动的标志为true且实际位置不超过左边缘时,就向左移动,speed为速度,settings中定义了
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
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 # 把飞船放回屏幕中间
alien.py
"""外星人的相关数据"""
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
def __init__(self, ai_settings, screen):
super(Alien, self).__init__() # 继承pygame中的Sprite
self.screen = screen
self.ai_settings = ai_settings
self.image = pygame.image.load('images/alien.png') # 加载外星人的图像
self.rect = self.image.get_rect() # 获取该图像的rect对象
# 设置图像的位置(即x,y值)
self.rect.x = self.rect.width # 设置图像的横坐标为图像的宽
self.rect.y = self.rect.height # 设置图像的纵坐标为图像的高(即将图像放在屏幕左上角(0,0)点)
self.x = float(self.rect.x) # rect对应值只能为整数,这里将其转为字符串
def blitme(self):
self.screen.blit(self.image, self.rect) # 将该外星人图像移到屏幕中
def update(self):
# 外星人每一次移动都是在刷新屏幕
self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction) # 图像的横坐标等于速度乘以方向,方向1为右,-1为左
self.rect.x = self.x
def check_edges(self):
# 判断是否碰到屏幕边缘,碰到就改变方向
screen_rect = self.screen.get_rect() # 获取屏幕的rect对象
if self.rect.right >= screen_rect.right:
return True # 图像的右边缘超出了屏幕右边缘返回True
elif self.rect.left <= 0:
return True # 图像的左边缘小于0返回True,因为屏幕远点在左上角,左边缘为0
button.py
"""PLAY按钮的相关数据"""
import pygame.font # font可以将文本渲染到屏幕上
class Button():
def __init__(self, screen, msg): # 读取屏幕信息和要显示的文本
self.screen = screen
self.screen_rect = screen.get_rect() # 读取的屏幕rect()对象,以便设置按钮在屏幕中的位置
self.width, self.height = 200, 50 # 设置按钮的大小
self.button_color = (0, 255, 0) # 设置按钮的颜色
self.text_color = (255, 255, 255) # 设置按钮中文本的颜色
self.font = pygame.font.SysFont(None, 48) # 从pygame的font字体库中寻找字体,类型为默认类型,字体大小为48
self.rect = pygame.Rect(0, 0, self.width, self.height) # 创建这个按钮的rect对象
self.rect.center = self.screen_rect.center # 将按钮元素的中心点和屏幕元素的中心点重合(即居中)
self.prep_msg(msg) # 写入文本(即PLAY)
def prep_msg(self, msg):
self.msg_image = self.font.render(msg, True, self.text_color,
self.button_color) # 创建一个新的表面,并写入msg文本(类似图层的概念,创建一个新的带文字的图层)
self.msg_image_rect = self.msg_image.get_rect() # 获得该‘图层’的rect对象
self.msg_image_rect.center = self.rect.center # 将该rect对象中心点和按钮的中心点重合(即居中)
def draw_button(self):
self.screen.fill(self.button_color, self.rect) # 把整个按钮填充到屏幕上
self.screen.blit(self.msg_image, self.msg_image_rect) # 把刚才那个带文本的‘图层’移到屏幕上
game_stats.py
"""游戏状态检测"""
class GameStats():
def __init__(self, ai_settings):
self.ai_settings = ai_settings # 读取游戏的相关设置
self.reset_stats() # 重置飞船的数量
self.game_active = False # 开始游戏前,游戏的状态设为False(即不运行)
def reset_stats(self):
self.ships_left = self.ai_settings.ship_limit # 重置飞船的数量,让飞船的剩余量等于初始值
game_function.py
import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep
def check_events(ai_settings, screens, stats, play_button, ship, aliens, bullets):
for event in pygame.event.get(): # 监听鼠标键盘事件
if event.type == pygame.QUIT: # 如果监听到QUIT信号
sys.exit() # sys来退出游戏
# 监听到鼠标点击开始按钮
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
check_play_button(ai_settings, screens, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y)
# 监听到键盘按下
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screens, ship, bullets)
# 监听到键盘释放
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y):
# PYAY按钮相关操作
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y) # 检测是否有鼠标左键和右键的操作
if button_clicked and not stats.game_active: # (鼠标点击或游戏状态为False(即不运行的状态),就启动游戏)
pygame.mouse.set_visible(False) # 隐藏鼠标
ai_settings.initialize_dynamic_settings() # 初始化各部门的速度
stats.reset_stats() # 重置飞船的数量
stats.game_active = True # 游戏状态设置为True(即运行中)
aliens.empty()
bullets.empty() # 清空上轮游戏外星人和子弹在后台存的数据
creat_fleet(ai_settings, screen, ship, aliens) # 重新创建外星人大队
ship.center_ship() # 初始化飞船的位置
def check_keydown_events(event, ai_settings, screens, 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: # 空格键按下时
fire_bullet(ai_settings, screens, ship, bullets) # 开火(即发射子弹)
elif event.key == pygame.K_q: # 键盘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 update_screen(ai_settings, screens, stats, ship, aliens, bullets, play_button): # 更新屏幕
screens.fill(ai_settings.bg_color) # 每次循环都颜色填充
for bullet in bullets.sprites(): # 在子弹组中循环每一颗子弹
bullet.draw_bullet() # 绘制每一颗子弹
ship.blitme() # 更新飞船
aliens.draw(screens) # 屏幕上绘制外星人
if not stats.game_active:
play_button.draw_button() # 如果游戏没有运行,就绘制开始按钮
pygame.display.flip() # 让最近绘制的屏幕可见
def fire_bullet(ai_settings, screens, ship, bullets):
if len(bullets) < ai_settings.bullet_allowed:
new_bullet = Bullet(ai_settings, screens, ship)
bullets.add(new_bullet) # 子弹在允许的数量范围内,子弹群组添加新子弹
def update_bullets(ai_settings, screen, ship, aliens, bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet) # 如果子弹超出屏幕范围,删除子弹,否则就一直运行下去,程序运行量持续增加
check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)
def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets):
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) # 子弹和外星人碰撞就一起消失
if len(aliens) == 0:
bullets.empty()
ai_settings.increase_speed()
creat_fleet(ai_settings, screen, ship, aliens) # 如果外星人打完了就重新绘制外星人群组,并加速
def creat_fleet(ai_settings, screen, ship, aliens): # 创造外星人群组
alien = Alien(ai_settings, screen)
number_alien_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_alien_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_alien_x = int(available_space_x / (2 * alien_width))
return number_alien_x
def create_alien(ai_settings, screen, aliens, alien_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_height): # 计算总共放几行外星人
avaliable_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)
number_rows = int(avaliable_space_y / (2 * alien_height))
return number_rows
def update_aliens(ai_settings, stats, screens, ship, aliens, bullets):
check_fleet_edges(ai_settings, aliens) # 检查是否碰到屏幕边缘
check_aliens_bottom(ai_settings, stats, screens, ship, aliens, bullets) # 检查是否运动到底部
aliens.update()
if pygame.sprite.spritecollideany(ship, aliens):
ship_hit(ai_settings, stats, screens, 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, stats, screens, ship, aliens, bullets):
if stats.ships_left > 0:
stats.ships_left -= 1 # 外星人撞击飞船,就少了一条命
aliens.empty()
bullets.empty() # 清空屏幕的外星人和子弹从新开始
creat_fleet(ai_settings, screens, ship, aliens) # 创建新的外星人群组
ship.center_ship() # 飞船从新居中
sleep(0.5) # 暂停0.5秒
else:
stats.game_active = False
pygame.mouse.set_visible(True) # 如果没有飞船了(即没有命了,闯关失败),重置游戏状态并重新显示鼠标
def check_aliens_bottom(ai_settings, stats, screens, ship, aliens, bullets):
screen_rect = screens.get_rect()
for alien in aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
ship_hit(ai_settings, stats, screens, ship, aliens, bullets) # 如果飞船到屏幕的底部也相当于游戏失败,和飞船撞击外星人一样处理
break
相关模块的讲解
rect
pygame用rect来储存矩形坐标(rectangular coordinates)的对象
他也可以操作游戏元素,把游戏元素当成矩形对象来操作,选取rect对象相当于选中该元素然后对其进行操作,相关函数如下:
- 移动类型
pygame.Rect.copy() — 拷贝 Rect 对象
pygame.Rect.move() — 移动 Rect 对象
pygame.Rect.move_ip() — 原地移动 Rect 对象
pygame.Rect.inflate() — 放大和缩小 Rect 对象的尺寸
pygame.Rect.inflate_ip() — 原地放大和缩小 Rect 对象的尺寸
pygame.Rect.clamp() — 将一个 Rect 对象移动到另一个 Rect 对象的中心
pygame.Rect.clamp_ip() — 原地将一个 Rect 对象移动到另一个 Rect 对象的中心 - 逻辑类型
pygame.Rect.clip() — 获取两个 Rect 对象互相重叠的部分
pygame.Rect.union() — 将两个 Rect 对象合并
pygame.Rect.union_ip() — 原地将两个 Rect 对象合并
pygame.Rect.unionall() — 将多个 Rect 对象合并
pygame.Rect.unionall_ip() — 原地将多个 Rect 对象合并
pygame.Rect.fit() — 按照一定的宽高比调整 Rect 对象
pygame.Rect.normalize() — 翻转 Rect 对象(如果尺寸为负数) - 检查类型
pygame.Rect.contains() — 检测一个 Rect 对象是否完全包含在该 Rect 对象内
pygame.Rect.collidepoint() — 检测一个点是否包含在该 Rect 对象内
pygame.Rect.colliderect() — 检测两个 Rect 对象是否重叠
pygame.Rect.collidelist() — 检测该 Rect 对象是否与列表中的任何一个矩形有交集
pygame.Rect.collidelistall() — 检测该 Rect 对象与列表中的每个矩形是否有交集
pygame.Rect.collidedict() — 检测该 Rect 对象是否与字典中的任何一个矩形有交集
pygame.Rect.collidedictall() — 检测该 Rect 对象与字典中的每个矩形是否有交集
相关链接:
Python之Pygame.rect函数
rect模块详解
mouse模块
mouse就是用来监听鼠标事件用的
相关函数:
pygame.mouse.get_pressed() —— 获取鼠标按键的情况(是否被按下)
pygame.mouse.get_pos() —— 获取鼠标光标的位置
pygame.mouse.get_rel() —— 获取鼠标一系列的活动
pygame.mouse.set_pos() —— 设置鼠标光标的位置
pygame.mouse.set_visible() —— 隐藏或显示鼠标光标
pygame.mouse.get_focused() —— 检查程序界面是否获得鼠标焦点
pygame.mouse.set_cursor() —— 设置鼠标光标在程序内的显示图像
pygame.mouse.get_cursor() —— 获取鼠标光标在程序内的显示图像
相关链接:
mouse详解