以下为部分代码展示,更多完整核心代码详见源代码下载
一、思维导图
1、创建Pygame窗口及响应用户输入(主)
import sys
import pygame # 包含开发游戏需要的功能
from summer_day1.alien_invasion.settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
from time import sleep
from game_stats import GameStats
from button import BUtton
from scoreboard import Scoreboard
class AlienInvasion:
"""
掌握游戏资源和行为的类
"""
def __init__(self):
"""初始化游戏并创建游戏资源"""
pygame.init()
# 12.3.3创建设置类
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Alien Invasion")
self._init_parameters()
def _init_parameters(self):
"""引入其他各种"""
# 引入飞船
self.ship = Ship(self)
# 创建存储子弹的编组
self.bullets = pygame.sprite.Group()
# 创建存储外星人的编组
self.aliens = pygame.sprite.Group()
self._creat_fleet()
# 创建一个用于存储游戏统计信息的实例
self.stats = GameStats(self)
# 创建一个按钮
self.play_button = BUtton(self, "Play")
# 创建一个记分牌
self.sb = Scoreboard(self)
def run_game(self):
"""开始游戏的主循环"""
while True:
self._check_events()
if self.stats.game_active:
self.ship.update()
self._update_bullets()
self._update_aliens()
self._update_screen()
# 将run_game中的代码重构为以下两个辅助方法
def _check_events(self):
"""
响应按键和鼠标事件
:return:
"""
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
self._game_over() # 用sys中工具退出
elif event.type == pygame.KEYDOWN:
self.check_keydown_events(event)
elif event.type == pygame.KEYUP:
self.check_keyup_events(event)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos() # 获取单击位置
self._check_play_button(mouse_pos)
# 监视键盘的按下事件
def check_keydown_events(self, event):
if event.key == pygame.K_RIGHT:
# 向右一定飞船
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
# 向左
self.ship.moving_left = True
elif event.key == pygame.K_DOWN:
# 向下
self.ship.moving_down=True
elif event.key == pygame.K_UP:
#向上
self.ship.moving_up = True
# self.ship.rect.y -= 1
# 按q退出
elif event.key == pygame.K_q:
self._game_over()
# 按空格发射子弹
elif event.key == pygame.K_SPACE:
self._fire_bullet()
# 按p开始游戏,游戏开始后按此无效
elif event.key == pygame.K_p and not self.stats.game_active:
self._start_game()
elif event.key == pygame.K_ESCAPE:
# 按esc全屏
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
self.ship = Ship(self)
#按q暂停
elif event.key == pygame.K_s:
if self.stats.game_active:
self.stats.game_active = False
pygame.mouse.set_visible(True)
self.play_button._pre_msg("Continue")
else:
self.stats.game_active=True
pygame.mouse.set_visible(False)
# 监视键盘的松开事件
def check_keyup_events(self, event):
if event.key == pygame.K_RIGHT:
# 向右一定飞船
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
# 向左
self.ship.moving_left = False
elif event.key == pygame.K_DOWN:
# 向下
self.ship.moving_down=False
elif event.key == pygame.K_UP:
#向上
self.ship.moving_up = False
def _check_play_button(self, mouse_pos):
"""在玩家单击play按钮开始新游戏"""
# 检查鼠标单机位置是否在play按钮的rect内
button_clicked = self.play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.stats.game_active:
self._start_game()
def _start_game(self):
"""游戏开始"""
self.stats.reset_status()
self.stats.game_active = True
# 重置得分
self.sb.prep_score()
# 重置等级
self.sb.prep_level()
#重置初始飞船量
self.sb.prep_ships()
# 重置为初始速度
self.settings.initialize_dynamic_settings()
# 清空余下的外星人和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一群新的外星人并让飞船居中
self._creat_fleet()
self.ship.center_ship()
# 隐藏光标
pygame.mouse.set_visible(False)
def _fire_bullet(self):
"""
创建一颗子弹,并将其加入编组bullets中
:return:
"""
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
"更新子弹的位置并删除消失的子弹"
"更新子弹的位置"
self.bullets.update()
# 删除消失的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
# print(len(self.bullets))
self._check_bullet_alien_collisions()
def _check_bullet_alien_collisions(self):
"""响应子弹和外星人碰撞"""
# 检查是否有子弹击中了外星人,
# 如果是,则删除对应的外星人和子弹
# True就消失
# flase,true 则只有外星人消失
collisions = pygame.sprite.groupcollide(
self.bullets, self.aliens, True, True
) # 进行比较,观察是否重叠
if collisions:
for aliens in collisions.values():
self.stats.score += self.settings.alien_points * len(aliens) # 一颗子弹可能击中多个
self.sb.prep_score() # 更新一下得分
self.sb.check_high_score() # 更新一下最高分
self.start_new_level()
def start_new_level(self):
"""在外星人群体消失干净后进入下一等级"""
# 检查aliens是否为空
if not self.aliens:
self.bullets.empty() # 清空所有子弹
self._creat_fleet()
self.settings.increase_speed()
# 提高等级
self.stats.level += 1
self.sb.prep_level()
def _creat_fleet(self):
"""创建外星人群"""
# 先建个外星人看看x,y
alien = Alien(self)
alien_width, alien_height = alien.rect.size
available_space_x = self.settings.screen_width - (2 * alien_width) # 减去俩边边距的可用空间
number_aliens_x = available_space_x // (2 * alien_width) # 计算一行有多少个外星人
available_space_y = self.settings.screen_height - (3 * alien_height) - self.ship.rect.height # 减去俩边边距的可用空间
number_rows = available_space_y // (2 * alien_height) # 计算可以容纳几行外星人
# 创建第一行外星人
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._creat_alien(alien_number, row_number)
def _creat_alien(self, alien_number, row_number):
"""创建一个外星人并放在当前行"""
new_alien = Alien(self)
alien_width, alien_height = new_alien.rect.size # 获取个宽度,高度
new_alien.x = alien_width + 2 * alien_width * alien_number
new_alien.y = alien_height + 2 * alien_height * row_number
new_alien.rect.x = new_alien.x # 更新rect对象
new_alien.rect.y = new_alien.y # 更新rect对象
self.aliens.add(new_alien)
def _check_fleet_edges(self):
"""有外星人达到边缘时采取相应的措施"""
for alien in self.aliens.sprites():
if alien.check_edges():
self._change_fleet_direction()
break
def _change_fleet_direction(self):
"""将整体下移,并改变方向"""
for alien in self.aliens.sprites():
alien.rect.y += self.settings.alien_fleet_drop_speed
self.settings.alien_fleet_direction *= -1
def _update_aliens(self):
"""检查有木有外星人到边缘,并更新位置"""
self._check_fleet_edges()
self.aliens.update()
# 检查外星人和飞船的碰撞
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
# 检查是否有外星人到达了底部
self._check_aliens_bottom()
def _check_aliens_bottom(self):
"""检查是否有外星人到达了底部"""
screen_rent = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rent.bottom:
# 像飞船碰到一样处理
self._ship_hit()
break
def _ship_hit(self):
"""响应飞船被外星人撞到"""
if self.stats.ships_left > 0:
self.stats.ships_left -= 1
#更新剩余飞船数
self.sb.prep_ships()
# 清空剩下的外星人和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一群新的外星人
self._creat_fleet()
self.ship.center_ship()
# 暂停一下
sleep(0.5)
else:
self.stats.game_active = False
self.play_button._pre_msg("Play")
# 显示鼠标光标
pygame.mouse.set_visible(True)
# print("game over")
def _update_screen(self):
"""
更新屏幕上的图像,并切换到新的屏幕
"""
# 每次循环重绘
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
self.sb.show_score()
# 如果游戏处于非活动状态,则绘制play按钮
if not self.stats.game_active:
self.play_button.draw_button()
# 让最近绘制的屏幕可见
pygame.display.flip()
def _game_over(self):
with open('high_score.txt','w') as f:
high_score=str(self.stats.high_score)
f.write(high_score)
sys.exit()
if __name__ == "__main__":
ai = AlienInvasion()
ai.run_game()
2、飞船
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
"""
管理飞船的类
"""
def __init__(self, ai_game):
"""
初始化飞船并设置其初始位置
:param ai_game:
"""
super(Ship, self).__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# 加载飞船并获取其外接矩阵
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# 对于每艘新飞船,都将其放在屏幕底部中央
self.rect.midbottom = self.screen_rect.midbottom
# 在飞船属性中存储小数值
self.x = float(self.rect.x)
self.y = float(self.rect.y)
# 移动标志
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
def blitme(self):
"""
在指定位置绘画飞船
:return:
"""
self.screen.blit(self.image, self.rect)
def update(self):
"根据移动标志来调整飞船状态"
# 更新飞船而非rect对象的值
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
if self.moving_up and self.rect.top > 0:
self.y -= self.settings.ship_speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.ship_speed
# 根据self.x,y更新rect对象
self.rect.x = self.x
self.rect.y=self.y
def center_ship(self):
"""让飞船在屏幕底端居中"""
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
self.y = float(self.rect.y)
3、外星人
import pygame
from pygame.sprite import Sprite # 他是pygame本身自带的一个精灵
class Alien(Sprite):
"""
表示单个外星人
"""
def __init__(self, ai_game):
""" 初始化外星人并设置其起始位置"""
super(Alien, self).__init__()
self.screen = ai_game.screen
self.settings=ai_game.settings
# 加载外星人的图像并设置rect属性
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# 每个外星人最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# 储存外星人的精确水平
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def update(self):
""" 向右移动外星人"""
self.x+=(self.settings.alien_speed
*self.settings.alien_fleet_direction)
self.rect.x=self.x
def check_edges(self):
"如果外星人位于屏幕边缘,就返回True"
screen_rent=self.screen.get_rect()
if self.rect.right>=screen_rent.right or self.rect.left<=0:
return True
4、设置类
# 12.3.3创建设置类
class Settings:
"""
存储游戏中的谁有设置类
"""
def __init__(self):
"""
初始化游戏设置
"""
# 设置屏幕
self.screen_width = 1000
self.screen_height = 600
# 设置颜色
self.bg_color = (240, 240, 255)
#设置最大飞船量
self.ship_limit=3
# 设置子弹
self.bullet_width = 3
self.bullet_height = 5
self.bullet_color = (60, 60, 60)
# 设置最大存储子弹数
self.bullets_allowed = 3
#撞到边缘后的垂直速度
self.alien_fleet_drop_speed=3
#加快游戏节奏
self.speedup_scale=1.1
#分数的提高速度
self.score_scale=1.5
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
"""初始化随游戏进行而发生变化的设置"""
#设置子弹速度
self.bullet_speed = 1
# 设置船速度
self.ship_speed = 1
# 设置外星人移动速度
self.alien_speed = 0.5
# 1右-1左
self.alien_fleet_direction = 1
#击杀一个外星人的得分
self.alien_points=50
def increase_speed(self):
"""提高速度设置和外星人分数"""
#船,子弹,外星人
self.ship_speed*=self.speedup_scale
self.bullet_speed*=self.speedup_scale
self.alien_speed*=self.speedup_scale
#提高子弹量
self.bullets_allowed+=1
#单个外星人的得分
self.alien_points=int(self.alien_points*self.score_scale)
5、状态类
class GameStats:
"""跟踪游戏的统计信息"""
def __init__(self, ai_game):
"""初始化统计信息"""
self.settings = ai_game.settings
self.reset_status()
# 让游戏一开始处于非活动状态
self.game_active = False
# 最高得分
self.high_score = int(self.read_high_score())
# 显示等级
self.level = 1
def reset_status(self):
"""初始化在游戏运行期间可能变化的统计信息"""
self.ships_left = self.settings.ship_limit
self.score = 0
def read_high_score(self):
with open("high_score.txt")as f:
high=f.read()
return high