Python学习记录-pygame实战

飞机大战

0 pygame入门

初始化和退出:pygame.init() | 导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法
                         pygame.quit() | 卸载所有 pygame 模块,在游戏结束之前调用
坐标系:坐标原点在左上角,x 轴正方向水平向右;y 轴正方向垂直向下
元素:以矩形区域来描述位置。类 pygame.Rect 用于描述 矩形区域
窗口:pygame.display模块用于创建、管理游戏窗口,
注意:必须使用变量记录 set_mode 方法的返回结果,因为后续所有的图像绘制都基于这个返回结果
           pygame.display.set_mode() | 初始化游戏显示窗口,指定宽、高、颜色深度等
           pygame.display.update() | 刷新屏幕内容显示
游戏循环:为了使游戏程序启动后,不会立即退出,通常会在游戏程序中增加一个 游戏循环,即无限循环:while True: pass
                  保证游戏 不会直接退出、变化图像位置(造成动画效果)、检测用户交互(按键、鼠标等)
游戏图形:用 pygame.image.load() 加载图像的数据:bg = pygame.image.load("./images/background.png")
                  用 游戏屏幕 对象,调用 blit 方法 将图像绘制到指定位置:screen.blit(bg, (0, 0))
                  调用 pygame.display.update() 方法更新整个屏幕的显示:pygame.display.update()
帧 Frame:类 pygame.time.Clock 可以设置刷新帧率,

clock = pygame.time.Clock() 
i = 0
while True:
    clock.tick(60)
    print(i)
    i += 1

简单动画:初始化定义一个 pygame.Rect 的变量记录图像初始位置;在游戏循环中每次让变量的坐标移动;
                  每一次调用 update() 方法之前,需要把所有的游戏图像都重新绘制一遍;应最先重新绘制背景图像;
监听事件:事件event,就是游戏启动后,用户针对游戏所做的操作,如按键、鼠标等。
                   通过pygame.event.get() 可以获得用户当前所做动作的事件列表

while True:
    clock.tick(60)
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
        print("退出游戏...")
        pygame.quit()     
        exit()

游戏精灵:显示图像的对象 叫做精灵 Sprite,有两个重要属性:"image"要显示的图像和"rect "图像要显示在屏幕的位置
       注意:pygame.sprite.Sprite 没有提供 image 和 rect 两个属性;需要程序员从 pygame.sprite.Sprite 派生子类
                 并在子类的初始化方法中设置 image 和 rect 属性

class GameSprite(pygame.sprite.Sprite):
    """游戏精灵基类"""
    def __init__(self, image_name, speed=1):
        super().__init__()                           # 调用父类的初始化方法;如果一个类的父类 
                                                     # 不是 object,在重写初始化方法时,要先 
                                                     # super() 父类的 __init__ 方法   
        self.image = pygame.image.load(image_name)   # 加载图像     
        self.rect = self.image.get_rect()            # 设置尺寸,image 的 get_rect() 方法
                                                     # 可以返回图像宽,高
        self.speed = speed                           # 记录速度
    def update(self, *args):                         # 默认在垂直方向移动
        self.rect.top += self.speed

精灵组:一个精灵组可以包含多个精灵对象;可以自动调用组内每一个精灵的update() 方法;
              可以将组内每一个精灵 的 image 绘制在 rect 位置

enemy1 = GameSprite("./images/enemy1.png")        #创建敌机精灵1
enemy2 = GameSprite("./images/enemy1.png", 2)     #创建敌机精灵2
enemy2.rect.x = 200 
enemy_group = pygame.sprite.Group(enemy1, enemy2) #创建敌机精灵组
while True:
    。。。。。。
    enemy_group.update()        #更新精灵组中所有精灵的位置
    enemy_group.draw(screen)    #更新位置后重新绘制在窗口中
    。。。。。。
    pygame.display.update()     #绘制后更新显示

1 游戏主程序

import pygame
from plane_sprites import *
CREATE_ENEMY_EVENT = pygame.USEREVENT       # 敌机出现事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1      # 发射子弹事件

class PlaneGame(object):
    """飞机大战游戏类"""
    def __init__(self):                                        # 0. 初始化
        pygame.init()                                          # 1. pygame 初始化
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)# 2. 创建游戏屏幕        
        self.clock = pygame.time.Clock()                       # 3. 创建游戏时钟        
        self.__create_sprites()                                # 4. 创建精灵组 
        PlaneGame.__create_user_events()                       # 5. 创建用户事件

    def __create_sprites(self):
        """创建精灵组"""
        bg1 = Background()                                     # 背景组
        bg2 = Background(True)
        self.back_group = pygame.sprite.Group(bg1, bg2)

        enemy = Enemy()                                        # 敌机组
        self.enemy_group = pygame.sprite.Group(enemy)
       
        self.hero = Hero()                                     # 英雄组
        self.hero_group = pygame.sprite.Group(self.hero)

    @staticmethod
    def __create_user_events():
        """创建用户事件"""        
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1 * 1000)    # 每秒添加一架敌机      
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)            # 每秒发射两次子弹

    def start_game(self):
        """开始游戏"""
        while True:            
            self.clock.tick(60)            # 1. 设置刷新帧率         
            self.__event_handler()         # 2. 事件监听           
            self.__update_sprites()        # 3. 更新精灵组           
            self.__check_collide()         # 4. 碰撞检测          
            pygame.display.update()        # 5. 更新屏幕显示

    def __event_handler(self):
        """事件监听"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                print("退出游戏...")
                pygame.quit()
                exit()
            elif event.type == CREATE_ENEMY_EVENT:             
                self.enemy_group.add(Enemy())                    # 创建敌机,并且添加到敌机组              
                # enemy_count = len(self.enemy_group.sprites())  # 测试敌机精灵数量
                # print("敌机精灵数量 %d" % enemy_count)
            elif event.type == HERO_FIRE_EVENT:                
                self.hero.fire()                                 # 英雄发射子弹
        
        keys_pressed = pygame.key.get_pressed()                  # 通过 pygame.key 获取用户按键
        dir = keys_pressed[pygame.K_RIGHT] - keys_pressed[pygame.K_LEFT]        
        self.hero.speed = dir * 2                                # 根据移动方向设置英雄的速度

    def __update_sprites(self):
        """更新精灵组"""
        for group in [self.back_group, self.enemy_group,self.hero_group, self.hero.bullets]:
            group.update()
            group.draw(self.screen)

    def __check_collide(self):
        """碰撞检测"""
        # 1. 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        # 2. 英雄被撞毁
        collide_list = pygame.sprite.spritecollide(self.hero, self.enemy_group, False)
        if len(collide_list) > 0:
            self.hero.is_alive = False
            print("英雄牺牲...")
            pygame.quit()
            exit()

if __name__ == '__main__':
    # 1. 创建游戏对象
    game = PlaneGame()
    # 2. 开始游戏
    game.start_game()

2 游戏对象,plane_sprites.py

import random
import pygame
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)            # 游戏屏幕大小

class GameSprite(pygame.sprite.Sprite):
    """游戏精灵基类"""
    def __init__(self, image_name, speed=1):
        super().__init__()                           # 调用父类的初始化方法     
        self.image = pygame.image.load(image_name)   # 加载图像     
        self.rect = self.image.get_rect()            # 设置尺寸 
        self.speed = speed                           # 记录速度

    def update(self, *args):                         # 默认在垂直方向移动
        self.rect.top += self.speed

class Background(GameSprite):
    """背景精灵"""
    def __init__(self, is_alt=False):
        image_name = "./images/background.png"
        super().__init__(image_name)
        if is_alt:                                   # 判断是否交替图片,如果是,将图片设置到屏幕顶部
            self.rect.bottom = 0

    def update(self, *args):      
        super().update(args)                       # 调用父类方法            
        if self.rect.top >= SCREEN_RECT.height:    # 判断是否超出屏幕
            self.rect.bottom = 0

class Enemy(GameSprite):
    """敌机精灵"""
    def __init__(self):
        image_name = "./images/enemy1.png"
        super().__init__(image_name)
        width = SCREEN_RECT.width - self.rect.width   # 随机敌机出现位置
        self.rect.left = random.randint(0, width)
        self.rect.bottom = 0
        self.speed = random.randint(1, 3)             # 随机速度

    def update(self, *args):
        super().update(args)   
        if self.rect.top >= SCREEN_RECT.height:    # 判断敌机是否移出屏幕            
            self.kill()                            # 将精灵从所有组中删除

class Hero(GameSprite):
    """英雄精灵"""
    def __init__(self):
        image_name = "./images/me1.png"
        super().__init__(image_name, 0)     
        self.rect.centerx = SCREEN_RECT.centerx    # 设置初始位置
        self.rect.bottom = SCREEN_RECT.bottom - 120        
        self.bullets = pygame.sprite.Group()       # 创建子弹组

    def update(self, *args):
        self.rect.left += self.speed            # 飞机水平移动      
        if self.rect.left < 0:                  # 超出屏幕检测
            self.rect.left = 0
        if self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right

    def fire(self):
        # bullet_count = len(self.bullets.sprites())
        # print("子弹数量 %d" % bullet_count)
        for i in range(0, 3):      
            bullet = Bullet()                              # 创建子弹精灵          
            bullet.rect.bottom = self.rect.top - i * 20    # 设置子弹位置
            bullet.rect.centerx = self.rect.centerx           
            self.bullets.add(bullet)                       # 将子弹添加到精灵组

class Bullet(GameSprite):
    """子弹精灵"""
    def __init__(self):
        image_name = "./images/bullet1.png"
        super().__init__(image_name, -2)

    def update(self, *args):
        super().update(args)
        if self.rect.bottom < 0:        # 判断是否超出屏幕
            self.kill()

猜你喜欢

转载自blog.csdn.net/muerjie5669/article/details/81560283
今日推荐