11-实战(飞机大战)

pip3 安装pygame

安装python3后一般即安装了pip3。

# 安装
sudo pip3 install pygame
# 验证安装
python3 -m pygame.examples.aliens
使用pygame创建图形窗口

1.游戏的初始化和退出

方法 说明
pygame.init() 导入并初始化pygame模块,使用其他模块之前,必须先调用init()方法
pygame.quit() 卸载所有pygame模块,在游戏结束之前调用

2.游戏中的坐标系

  • 游戏中,所有可见元素都是用矩形区域来描述位置的
    要描述一个矩形区域有4个元素(x,y)(width,height)
  • pygame专门提供了一个pygame.Rect类用于描述矩形区域
hero_rect = pygame.Rect(100, 500, 120, 125)

3.创建游戏主窗口
pygame专门提供了一个模块pygame.display用于创建、管理游戏窗口。

方法 说明
pygame.display.setup_mode() 初始化游戏显示窗口
pygame.display.update() 刷新屏幕显示内容

set_mode(resolution=(0,0), flags=0, depth=0) -> Surface
# 指定返回的屏幕参数
screen = pygame.display.set_mode(400, 700)

参数:

  • resolution:指定屏幕显示的长度和宽度,默认创建的窗口和屏幕大小一致
  • flags:指定屏幕的附件选项,例如是否全屏
  • depth:表示颜色的位数
绘制图像
  • 1.使用pygame.image.load()加载图像的数据
  • 2.使用游戏屏幕对象,调用blit方法将图像加载到屏幕指定位置
  • 3.调用pygame.display.update()更新整个屏幕的显示
import pygame

# 初始化pygame模块
pygame.init()

# 创建游戏窗口
screen = pygame.display.set_mode((480, 700))

# 绘制背景图片
# 获取背景图片
bg = pygame.image.load("./images/background.png")
# 将图片绘制到屏幕指定位置
screen.blit(bg, (0, 0))

# 绘制英雄的飞机
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (150, 500))

# 渲染
pygame.display.update()

# 退出pygame,删除相应模块
pygame.quit()

while True:
    pass
游戏中的动画实现原理

图像快速移动形成动画效果。
一般在电脑上每秒绘制60次,就能够达到非常连续、高品质的动画效果。
每次绘制的结果被称为帧。

游戏循环

游戏循环:

  • 设置刷新帧率
  • 检测用户交互
  • 更新所有图像位置
  • 更新屏幕显示

游戏循环作用

  • 保证游戏不会直接退出
  • 变换图像位置,动画效果
  • 检测用户交互
游戏时钟

pygame专门提供了一个pygame.time.clock可以非常方便的设置屏幕绘制速度--刷新帧率
使用步骤:

  • 在游戏初始化时创建一个时钟对象
  • 在游戏循环时让时钟对象调用tick(帧率)方法
    tick方法会自动根据上次被调用的时间,自动设置游戏循环中的延时
# 创建时钟对象
clock = pygame.time.Clock()

# 游戏循环-> 意味游戏的正式开始
i = 0
while True:
    clock.tick(1)
    print(i)
    i += 1
    pass
在游戏循环中监听事件

事件event
就是游戏启动后,用户针对游戏所做的操作,例如点击关闭按钮,点击鼠标等。
监听
在游戏循环中,判断用户具体操作
pygame中通过pagame.event.get()可以得到用户当前所做动作的事件列表。

监听退出事件并且退出游戏
event_list = pygame.event.get()
    if len(event_list) > 0:
        for event in event_list:
            # 判断事件类型是否退出事件
            if event.type == pygame.QUIT:

                # 写在所有模块
                pygame.quit()
                # exit() 直接终止当前正在执行的程序
                exit()
精灵和精灵组

为了简化开发步骤,pygame提供了两个类,精灵和精灵组

  • pygame.sprite.Sprite -- 存储图像image和位置rect的对象
  • pygame.sprite.Group
使用常量定义游戏窗口

常量的定义

  • 定义常量和定义变量的语法完全一样,都是使用赋值语句
  • 常量的命名应该所有的字母都大些,单词与单词之间使用下划线连接
# 屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 刷新的帧率
FRAME_PER_SEC = 60
定时器

pygame中可以使用pygame.time.set_timer()创建定时器

set_timer(eventid, milliseconds) -> None
- 第一次参数事件代号需要基于常量pygame.USEREVENT来指定,USEREVENT是一个整数,再增加事件可以使用USEREVENT + 1
- 第二个参数事件触发时间是毫秒
kill方法

kill方法会将精灵从所有精灵组中移除,精灵就会被销毁。

if self.rect.y >= SCREEN_RECT.height:
     # 当敌机飞出屏幕,调用kill()方法从所有组中删除
     # kill方法会将精灵从所有精灵组中移除,精灵就会被销毁
     self.kill()
pygame中捕获按键的两种方式
# elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
# print("向右移动")
# 使用键盘提供的方法获取键盘按键 - 按键元组
keys_pressed = pygame.key.get_pressed()
 # 判断元组中对应的按键索引值
if keys_pressed[pygame.K_RIGHT]:
    print("持续向右移动")
碰撞检测

pygame提供了两个方法用于检测碰撞

pygame.sprite.groupcollide
groupcollide(groupa, groupb, dokilla, dokillb, collided=None): return dict
  • 两个精灵组中所有精灵的碰撞检测
  • 如果将dokill设置为True,则发生碰撞的精灵会被自动移除。
  • collided参数用于计算碰撞的回调函数,如果没有指定,则每个精灵必须有一个rect属性
pygame.sprite.spritecollide
spritecollide(sprite, group, dokill, collided=None):Sprite_list
  • 判断某个精灵和指定精灵组中的精灵的碰撞
  • 如果将dokill设置为True,则指定精灵组中发生碰撞的精灵会自动移除
  • collided参数用于计算碰撞的回调函数,如果没有指定,则每个精灵必须有一个rect属性
  • 返回精灵组中跟精灵发生碰撞的精灵列表

附代码

import pygame
from plane_sprites import *


class PlaneGame(object):
    """飞机大战主游戏"""

    def __init__(self):
        print("游戏初始化")

        # 1. 创建游戏的窗口
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 2. 创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 3. 调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
        # 4. 设定定时器事件 - 创建敌机
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        # 5. 创建字典定时器
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)

    def __create_sprites(self):

        # 创建背景精灵和精灵组
        bg1 = Background()
        bg2 = Background(True)

        self.back_ground = pygame.sprite.Group(bg1, bg2)

        # 创建敌机的精灵组
        self.enemy_group = pygame.sprite.Group()

        # 创建英雄的精灵和精灵组
        self.hero = Hero()
        self.hero_group = pygame.sprite.Group(self.hero)

    def start_game(self):
        print("游戏开始...")

        while True:
            # 1. 设置刷新帧率
            self.clock.tick(FRAME_PER_SEC)
            # 2. 事件监听
            self.__event_handler()
            # 3. 碰撞检测
            self.__check_collide()
            # 4. 更新/绘制精灵组
            self.__update_sprites()
            # 5. 更新显示
            pygame.display.update()

    def __event_handler(self):
        for event in pygame.event.get():

            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                PlaneGame.__game_over()
            elif event.type == CREATE_ENEMY_EVENT:
                # 创建敌机精灵
                enemy = Enemy()

                # 将敌机精灵添加到敌机精灵组
                self.enemy_group.add(enemy)
            elif event.type == HERO_FIRE_EVENT:
                self.hero.fire()
            # elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            #     print("向右移动")
            # 使用键盘提供的方法获取键盘按键 - 按键元组
            keys_pressed = pygame.key.get_pressed()
            # 判断元组中对应的按键索引值
            if keys_pressed[pygame.K_RIGHT]:
                self.hero.speed = 2
            elif keys_pressed[pygame.K_LEFT]:
                self.hero.speed = -2
            else:
                self.hero.speed = 0

    def __check_collide(self):
        # 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        # 敌机摧毁英雄飞机
        enemys = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
        # 判断列表是否有内容,如果有内容,则英雄飞机牺牲
        if len(enemys) > 0:
            # 英雄牺牲
            self.hero.kill()

            # 游戏结束
            PlaneGame.__game_over()


    def __update_sprites(self):
        self.back_ground.update()
        self.back_ground.draw(self.screen)

        self.enemy_group.update()
        self.enemy_group.draw(self.screen)

        self.hero_group.update()
        self.hero_group.draw(self.screen)

        self.hero.bullets.update()
        self.hero.bullets.draw(self.screen)

    @staticmethod
    def __game_over():
        print("游戏结束")

        pygame.quit()
        exit()


if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()

    # 启动游戏
    game.start_game()

import random
import pygame

# 屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 刷新的帧率
FRAME_PER_SEC = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1


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):

        # 在屏幕的垂直方向上移动
        self.rect.y += self.speed


class Background(GameSprite):
    """游戏背景精灵"""

    def __init__(self, is_alt=False):
        # 调用父类方法实现精灵的创建
        super().__init__("./images/background.png")
        # 判断是否交替图片,如果是,需要设置初始位置
        if is_alt:
            self.rect.y = -self.rect.height

    def update(self):
        # 1. 调用父类的方法实现
        super().update()

        # 2. 判断是否移除屏幕,如果移除屏幕,将图像设置到屏幕的上方
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y -= self.rect.height


class Enemy(GameSprite):
    """敌机精灵"""
    def __init__(self):
        # 调用父类方法创建敌机精灵
        super().__init__("./images/enemy1.png")
        # 指定敌机的初始随机速度
        self.speed = random.randint(1, 3)
        # 指定敌机的随机位置
        self.rect.bottom = 0
        max_x = SCREEN_RECT.width - self.rect.width
        self.rect.x = random.randint(0, max_x)

    def update(self):
        # 调用父类方法
        super().update()
        # 判断敌机是否飞离屏幕,并且从精灵组中删除
        if self.rect.y >= SCREEN_RECT.height:
            # 当敌机飞出屏幕,调用kill()方法从所有组中删除
            # kill方法会将精灵从所有精灵组中移除,精灵就会被销毁
            self.kill()

    def __del__(self):
        print("敌机挂了")


class Hero(GameSprite):
    """英雄精灵"""
    def __init__(self):
        # 调用父类方法,设置image & speed
        super().__init__("./images/me1.png", 0)

        # 英雄初始位置设置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120

        # 创建子弹的精灵组
        self.bullets = pygame.sprite.Group()

    def update(self):
        # 英雄水平方向移动
        self.rect.x += self.speed

        # 控制英雄不能离开屏幕
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.right > SCREEN_RECT.width:
            self.rect.right = SCREEN_RECT.width

    def fire(self):
        print("发射子弹了")

        for i in (0, 1, 2):
            # 创建子弹精灵
            bullet = Bullet()

            # 设置子弹精灵的位置
            bullet.rect.bottom = self.rect.y - 20 * i
            bullet.rect.centerx = self.rect.centerx

            # 将精灵添加到精灵组
            self.bullets.add(bullet)


class Bullet(GameSprite):
    """子弹精灵"""
    def __init__(self):
        # 调用父类方法
        super().__init__("./images/bullet1.png", -2)

    def update(self):
        # 调用父类方法,让子弹沿垂直方向飞行
        super().update()

        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()

    def __del__(self):
        print("子弹被销毁了")

你可能感兴趣的:(11-实战(飞机大战))