Fight Aliens 外星人展示/移动(左右/上下)
在根目录下新建 alien.py文件即外星人模块,这里把主循环中的代码做了封装,代码实现如下:
alien.py文件代码如下:
# -*- coding: utf-8 -*- # 作者: guos # 日期: 2023/3/30 import pygame from pygame.sprite import Sprite class Alien(Sprite): """ 表示外星人的类 """ def __init__(self, screen, gc): super().__init__() self.screen = screen self.gc = gc # sprite 中需要 image 和 rect # 当指定了这两个属性后,调用group的draw方法时会自动对图层进行绘制 # 约定优于配置 self.image = pygame.image.load("./data/alien.bmp") # 加载图片 self.rect = self.image.get_rect() # 获取外星人矩形 def update(self): """ 要更新外星人的位置 即 移动 :return: """ self.rect.x += self.gc.alien_dir * self.gc.alien_speed # 在这里更新方向的话导致部分外星人偏离位置,是因为每次偏移方向会有不同导致有的向左有的向右移动 # if self.check_side_edge(): # self.gc.alien_dir = - self.gc.alien_dir def check_side_edge(self): """ 检查飞船是否移动到边缘 :return: 到达边缘:True 没有:False """ return self.rect.x <= 0 or self.rect.right >= self.screen.get_rect().right
配置game_config.py文件代码更新如下:
# -*- coding: utf-8 -*- # 作者: guos # 日期: 2023/3/29 # 该模块[即一个py文件就是一个模块,命名小写开头]用来存储游戏的配置信息 class GameConfig: # 类名:大驼峰 def __init__(self): # 直接将配置信息,存储到GameConfig实例对象中 self.width = 800 # 游戏窗口宽度 self.height = 600 # 游戏窗口高度 self.title = 'Fight Aliens' # 外星人入侵 游戏标题 self.bg_color = (230, 230, 230) # 窗口背景颜色 self.ship_dir = 0 # 飞船移动的方向 -1 向左 1 向右 self.ship_speed = 2 # 飞船移动的速度 # 可以根据充值来提升武器的配置参数 self.bullet_color = (0, 0, 0) # 子弹的颜色 self.bullet_width = 3 # 子弹的宽度 self.bullet_height = 15 # 子弹的高度 self.bullet_speed = 1 # 子弹的速度 self.bullet_count = 3 # 限制子弹的数量【即满屏最多有三个】 self.alien_dir = 1 # 外星人的移动方向 1 向右移动 -1 向左移动 self.alien_speed = 1 # 外星人的移动速度 @property def size(self): # @property 使 size变为属性,可以直接 对象.size 来获取值 # 这里使用来属性方法,返回元组 来动态计算窗口的大小 return self.width, self.height
入口文件main.py文件代码更新如下:
# -*- coding: utf-8 -*- # 作者: guos # 日期: 2023/3/29 # 游戏的主文件,使用该文件来启动游戏 import pygame from pygame.sprite import Group from game_config import GameConfig from ship import Ship import game_func as gf # 创建配置对象 gc = GameConfig() # 初始化 pygame.init() # 设置窗口大小 screen = pygame.display.set_mode(gc.size) # 设置窗口的标题 pygame.display.set_caption(gc.title) # 创建一个飞船实例对象 ship = Ship(screen, gc) # 弹夹 -- 存放子弹的列表 # bullets = [] bullets = Group() # 创建 一个group来保存外星人 aliens = Group() gf.create_aliens(screen, gc, aliens) # 创建主循环 while True: gf.check_and_do_event(screen, gc, bullets, ship) gf.show_screen_all(screen, gc, ship, bullets, aliens)
把主循环中的逻辑抽离出来,用函数来封装一下后期好维护,新建game_func.py模块,代码如下:
# -*- coding: utf-8 -*- # 作者: guos # 日期: 2023/3/30 # 把主循环中的逻辑拆分为不同的功能函数模块 import pygame import sys from bullet import Bullet from alien import Alien # 显示屏幕上需要的物料 屏幕 飞船 子弹 外星人 def show_screen_all(screen, gc, ship, bullets, aliens): """ 显示屏幕上需要的物料 屏幕 飞船 子弹 外星人 :param screen: 屏幕对象 :param gc: GameConfig 配置实例 :param ship: 飞船实例 :param bullets: 子弹集合 :param aliens: 飞船集合 :return: """ # 设置窗口背景颜色, rgb值 screen.fill(gc.bg_color) # 外星人移动 aliens.update() # 检查外星人是否到边界,来改变其运动的方向,实现左右移动的效果 check_aliens(gc, aliens) # 绘制外星人【需要在背景后绘制】这里使用了Group的draw的方法,但前提是我们的image的属性,必须是这个不然无法实现 aliens.draw(screen) # 更新飞船的位置 必须在显示之前 ship.update() # 只更新类位置,但无法调用 bullets里每个元素的draw_bullet, 所以需要自己调用的都写到update里来实现 bullets.update() # 查看子弹数量是否有变化 # print(len(bullets)) # 飞船显示 ship.blit_ship() # 对窗口进行重绘 pygame.display.flip() # 处理主循环中处理事件函数 def check_and_do_event(screen, gc, bullets, ship): """ 处理主循环中处理事件函数 :param screen: 屏幕对象 :param gc: GameConfig 配置实例 :param bullets: 子弹合集 :param ship: 飞船实例 :return: """ # 处理事件 for event in pygame.event.get(): # 处理退出的事件 if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: # 键盘按下 check_and_do_keydown(event, screen, gc, bullets, ship) elif event.type == pygame.KEYUP: # 当键盘松开,如果此时为向左移动或者向右移动时 check_and_do_keyup(event, gc) # 处理键盘按下事件 def check_and_do_keydown(event, screen, gc, bullets, ship): """ 处理键盘按下事件 :param event: 事件对象 :param screen: 屏幕对象 :param gc: GameConfig 配置实例对象 :param bullets: 子弹合集 :param ship: 飞船实例 :return: """ if event.key == pygame.K_LEFT: # 向左移动,设置飞船的移动方向,而不是控制飞船移动 -1 # 这里把这个方向 放入到 配置对象里 gc.ship_dir = -1 elif event.key == pygame.K_RIGHT: # 向右移动 1 gc.ship_dir = 1 elif event.key == pygame.K_SPACE: # 限制子弹数量 if len(bullets) < gc.bullet_count: # 点击空格键开跑 创建子弹实例对象 # 当我们按下空格键后创建,并append到弹夹中 # bullets.append(Bullet(screen, gc, ship)) bullets.add(Bullet(screen, gc, ship)) # 处理键盘松开事件 def check_and_do_keyup(event, gc): """ 处理键盘松开事件 :param event: 事件对象 :param gc: GameConfig 配置实例 :return: """ # 何时将 ship_dir 设置为0 if gc.ship_dir == 1 and event.key == pygame.K_RIGHT or gc.ship_dir == -1 and event.key == pygame.K_LEFT: gc.ship_dir = 0 # 创建外星人 def create_aliens(screen, gc, aliens): """ 创建外星人 :param screen: 游戏屏幕对象 :param gc: GameConfig 配置实例 :param aliens: 外星人集合 :return: """ # 如何计算和设计 外星人的数量和位置 # 外星人的生存空间 screen_width = gc.width screen_height = gc.height alien = Alien(screen, gc) alien_width = alien.rect.width alien_height = alien.rect.height # 计算外星人每行的数量: 屏幕宽度 - 留有移动空间(两个外星人的宽度) 剩余空间 使每个外星人占自身宽度的两倍的位置 alien_col_count = int((screen_width - alien_width * 2) / (alien_width * 2)) # 计算外星人的行数 alien_row_count = int((screen_height - alien_height * 3) / (alien_height * 2)) # 创建外星人的外层循环,控制外星人的行数 for j in range(alien_row_count): # 根据计算出来的外星人每行数量来创建外星人 for i in range(alien_col_count): alien_obj = Alien(screen, gc) # 排列 ---外星人---外星人---外星人---外星人 【--- 代表一个外星人】 # x值: width * 1 width * 3 width * 5 width * 7 alien_obj.rect.x = alien_width * (1 + 2 * i) # 与顶部保持一个外星人的高度显示上看着更好一些 alien_obj.rect.y = alien_height * (1 + 2 * j) # 每行之间的距离算法和每行外星人间的距离算法一样 aliens.add(alien_obj) # 检查外星人是否到边界并在到达边界时向下移动 def check_aliens(gc, aliens): """ 检查外星人是否移动到边界 :param gc: GameConfig 配置模块实例 :param aliens: 外星人集合 :return: """ for alien in aliens.sprites(): if alien.check_side_edge(): gc.alien_dir = - gc.alien_dir # 改变方向的时候 改变外星人 y值 for alien1 in aliens: alien1.rect.y += 10 break