#Python# Alien Invasion项目(三)

南门向荣
2023-12-01

实现子弹发射

在settings模块中更新子弹设置
settings.py

class Settings:
    '''存储所有设置'''

    def __init__(self):
        '''初始化游戏设置'''
        # 屏幕设置
        self.screen_width = 1200 # 窗口宽度为1200像素
        self.screen_height = 800 # 窗口高度为800像素
        self.bg_color = (230,230,230) # 创建名为bu_color的背景色 以RGB值为参数指定
        # 飞船设置
        self.ship_speed_factor = 1.5 # 飞船速度设置
        # 子弹设置
        self.bullet_speed_factor = 1 # 子弹速度
        self.bullet_width = 3 # 子弹大小
        self.bullet_height = 15
        self.bullet_color = 60,60,60 # 子弹颜色
        self.bullet_allowed = 3 # 同屏最大子弹数

创建储存Bullet类的模块bullet,其中包含Bullet类的属性及方法
bullet.py

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    '''对飞船发射的子弹进行管理的类'''
    
    def __init__(self,ai_settings,screen,ship):
        super().__init__()
        self.screen = screen
        #再(0,0)处创建一个表示子弹的矩形,再设置正确的位置
        self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height) 
        # pygame.Rect(lefe,top,width,height) 
        # left指矩形到左边界距离,top指矩形到上边界距离
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        # 存储用小数表示子弹位置
        self.y = float(self.rect.y)
        self.color = ai_settings.bullet_color
        self.speed_factor = ai_settings.bullet_speed_factor

    def update(self):
        '''向上移动子弹'''
        # 更新表示子弹位置的小数值
        self.y -= self.speed_factor
        # 更新表示子弹的rect的位置
        self.rect.y = self.y

    def draw_bullet(self):
        '''在频幕上绘制子弹'''
        pygame.draw.rect(self.screen,self.color,self.rect)

在game_functions模块中修改发射子弹的相关判定,以及更新将新的子弹加入编组,将超出屏幕的子弹删除等方法
game_functions.py

import sys
import pygame
from bullet import Bullet

def check_keydown_events(event,ai_settings,screen,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,screen,ship,bullets)

def check_keyup_evets(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(ai_settings,screen,ship,bullets):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # 检测游戏窗口关闭按钮是否被点击
            sys.exit(0) # 退出游戏 不抛出异常退出
        elif event.type == pygame.KEYDOWN: # 按下按钮
            check_keydown_events(event,ai_settings,screen,ship,bullets)
        elif event.type == pygame.KEYUP: # 松开按钮
            check_keyup_evets(event,ship)

def fire_bullet(ai_settings,screen,ship,bullets):
    if len(bullets) < ai_settings.bullet_allowed:
        new_bullet = Bullet(ai_settings,screen,ship) # 创建一颗新子弹
        bullets.add(new_bullet) # 将新子弹存入编组bulllets中

def update_bullets(bullets):
    '''更新子弹位置,并删除超出屏幕上边界的子弹'''
    # 更新子弹位置
    bullets.update()
    # 删除超出屏幕上边界的子弹
    for bullet in bullets:
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)

def update_screen(ai_settings,screen,ship,bullets):
    '''更新屏幕上的图像,并切换到新屏幕'''
    # 使用背景色填充屏幕
    screen.fill(ai_settings.bg_color)
    for bullet in bullets.sprites(): # 重绘所有子弹
        bullet.draw_bullet()
    ship.blitme() # 在背景上绘上飞船
    # 让最近绘制的屏幕可见
    pygame.display.flip() # 重绘屏幕

最后根据以上修改,对主程序进行更新
alien_invasion.py

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group

def run_game(): 
    
    # 初始化游戏并创建一个屏幕对象
    pygame.init() # 初始化背景设置
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height)) #创建名为screen的显示窗口
    pygame.display.set_caption("Alien Invasion") 

    # 创建一艘飞船
    ship = Ship(ai_settings,screen)

    # 创建一个用于存储子弹的编组
    bullets = Group()

    # 开始游戏的主循环
    while True:
        # 监视键盘和鼠标事件
        gf.check_events(ai_settings,screen,ship,bullets)
        # 飞船更新位置(移动)
        ship.update()
        # 子弹更新位置,并删除超出屏幕上边界的子弹
        gf.update_bullets(bullets)
        # 更新屏幕
        gf.update_screen(ai_settings,screen,ship,bullets)

run_game()

总结

from pygame.sprite import Sprite

Sprite类是pygame中所定义的类,通过使用它,可以将游戏中相关的元素进行编组。我们创建的Bullet类就是Sprite类的一个子类,目的在于将所有Bullet对象关联起来,便于之后的操作

self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)

rect(left, top, width, height) -> Rect
pygame中rect对象的定义方式,除了之前所提到的方法get_rect(),还可以通过直接对矩形的描述来定义。同样的,参数left,top表示矩形左边到左边界的距离,上边到上边界的距离,也可以认为是矩形左上角的x,y坐标(实际上,rect.x与rect.y表示的就是矩形左上角的坐标);参数width,height表示矩形的宽度与高度

pygame.draw.rect(self.screen,self.color,self.rect)

draw.rect(surface, color, rect) -> Rect
draw.rect(surface, color, rect, width=0, border_radius=0, border_radius=-1, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1) -> Rect
函数通过确定参数surface,color,rect来将确定的rect填满color画在surface上

bullets = Group()

创建一个存储子弹的编组bullets,本质上是创建一个Group类对象,而Group允许接受一系列Sprite类对象,所以可以接受先前创建的Bullet类(Sprite类子类)的对象,进而将所有的bullet关联起来

bullets.update()

对编组bullets调用方法update()时,相当于对其中每一个Bullet类(Sprite类子类)的对象bullet调用方法update()

bullets.add(new_bullet)

通过方法add()将新创建的Bullet类对象new_bullet加入编组bullets

for bullet in bullets.copy():
	if bullet.rect.bottom <= 0:
		bullets.remove(bullet)

当需要通过循环删除容器中的元素时,我们不应直接从容器中删除,而应该遍历其副本的同时,对容器中元素进行操作

 类似资料: