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("子弹被销毁了")

问题:mac运行pygame一片空白
解决方案:升级pygame

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352