【python 第10日】打飞机的小游戏 pygame

安装pygame

  • 首先安装pip,  python -m ensurepip --default-pip  或者下载安装包安装
  • 安装完pip,  安装模块可以python -m pip install Packagename 也可以直接pip install PackageName, 在pycharm里也可以直接下载File | Settings | Project: python-learn | Project Interpreter
  • 验证安装, python -m PackageName
    •   python -m PackageName  就相当于加载,并不执行
    •   python PackageName  直接执行

 本地文件路径选择,提示框

单文件选择

from  tkinter import Tk
from tkinter import messagebox
from tkinter import filedialog

def get_file_path(msg):
root = Tk()
root.withdraw() # 把root隐藏为了防止多一个窗口
# print(root.winfo_screenwidth()) #获取系统屏幕像素
# print(root.winfo_screenheight())
ret = messagebox.showinfo("提示", msg)
if ret :
filepath = filedialog.askopenfile()
return filepath.name
return ""

多文件选择

def get_files_path():
root = Tk()
root.withdraw() #把root隐藏为了防止多一个窗口
ret = messagebox.showinfo("提示", msg)
if ret:
filepath = filedialog.askopenfiles()
file_list = []
for file in filepath:
file_list.append(file.name)
return file_list
return ""

 打飞机的游戏

分为三个文件: 

  • 一个是类文件,包含背景类,飞机类, 英雄类,子弹类 都是精灵
  • 一个是屏幕控制,初始化,加载背景,飞机,英雄,子弹自动出,检测碰撞,英雄发射子弹,事件检测
  • 最后一个是配置文件

有待添加的事情:

  • 背景音乐,爆炸音乐,音乐控制
  • 爆炸效果,加载另外一个图片
  • 设置按键等等
  • 效果优化
  • 多个人play

屏幕控制

import os
import random
import sys

from hitfeiji.conf.setting import BEIJING_SIZE

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import pygame
from lib.plane_class import *
from  conf.setting import *
CREATE_ENEMY = pygame.USEREVENT
CREATE_ZIDAN = pygame.USEREVENT + 1

class PlaneMain:
    def __init__(self):
        #初始化窗口,背景
        # pygame.init()
        self.screen = pygame.display.set_mode(BEIJING_SIZE)
        #设置标题
        pygame.display.set_caption(GAME_TITLE)
        self.clock = pygame.time.Clock()
        self.__create_sprites()
        pygame.time.set_timer(CREATE_ENEMY, SHUAXIN_PINLV)
        pygame.time.set_timer(CREATE_ZIDAN , ZIDAN_PER)
        print("初始化完毕")
    def __event_handle(self):

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                PlaneMain.__game_over()

            if event.type == CREATE_ENEMY:
                tmpfile = random.choice(ENEMY_PATH)
                enemy = Enemy(tmpfile)
                self.enemy_group.add(enemy)
            if event.type == CREATE_ZIDAN:
                self.hero.fire()

            #获取键盘信息
            key_pressed = pygame.key.get_pressed()
            if key_pressed[pygame.K_RIGHT]:
                self.hero.speed = HERO_SPEED
            elif key_pressed[pygame.K_LEFT]:
                self.hero.speed = -HERO_SPEED
            else:
                self.hero.speed = 0

    def __check_collide(self):
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        #不让死,可以注释掉
        if not WUDI:
            res = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
            if res :
                self.__game_over()

    def __create_sprites(self):
        length = len(BEIJING_DEFAULT_PATH)
        BEIJING_DEFAULT_PATH_NEW = BEIJING_DEFAULT_PATH
        if length == 1:
            BEIJING_DEFAULT_PATH_NEW = BEIJING_DEFAULT_PATH*2

        #t添加背景组
        self.bg_group = pygame.sprite.Group()
        for path in BEIJING_DEFAULT_PATH_NEW :
            bg = BackGroud(path)
            self.bg_group.add(bg)
        print("背景图像加载完毕:",self.bg_group.sprites())

        #添加敌人组
        self.enemy_group = pygame.sprite.Group()

        #添加英雄组
        self.hero_group = pygame.sprite.Group()
        self.hero = Hero(FEIJI_DEFAULT_PATH)
        self.hero_group.add(self.hero)

        #设置字体
        self.font = FontClass("傲雪的游戏", FONT_POSITON, FONT_SIZE)
        self.font_group = pygame.sprite.Group(self.font)

    def __update_sprites(self):
        #刷新背景组
        self.bg_group.update()
        self.bg_group.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)

        #字体刷新
        self.font_group.update()
        self.font_group.draw(self.screen)
    @staticmethod
    def __game_over():
        print("游戏结束")
        pygame.quit()
        exit()

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

        while True:

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

if __name__ == '__main__':
    pygame.init()
    p = PlaneMain()
    p.start_game()

类文件

import os
import random
import sys
import pygame

from hitfeiji.conf.setting import ENEMY_SIZE

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from  conf.setting import *
from lib.functions import *

class FontClass(pygame.sprite.Sprite):
        def __init__(self, string, positon, size):
            super().__init__()
            print(self.__dict__)
            myfont = pygame.font.Font(FONT_PATH, size)
            self.image = myfont.render(string, True, FONT_COLOR)
            self.rect = self.image.get_rect()
            self.rect.x = positon[0]
            self.rect.y = positon[1]


class GameSprites(pygame.sprite.Sprite):
    def __init__(self, filename, size, speed = 1, ):
        super().__init__()
        self.image = pygame.image.load(filename).convert_alpha()
        self.new_image = pygame.transform.smoothscale(self.image, size)
        self.image = self.new_image               #还是需要的否则图像不会变化
        self.rect = self.new_image.get_rect()
        self.speed = speed

    def update(self, *args):
        self.rect.y += self.speed

class BackGroud(GameSprites):
    number = 0
    def __init__(self, filename, speed = 1):
        super().__init__(filename, BEIJING_SIZE, speed)
        self.rect.y = -BackGroud.number * BEIJING_SIZE[1]
        BackGroud.number += 1

    def update(self, *args):
        self.rect.y = self.rect.y + self.speed
        if self.rect.y > BEIJING_SIZE[1]:
            self.rect.y = - (BackGroud.number - 1)* BEIJING_SIZE[1]

class Enemy(GameSprites):
    def __init__(self, filename ):
        self.speed = random.randint(1, 4)
        super().__init__(filename, ENEMY_SIZE, self.speed)
        self.rect.x = random.randint(0, BEIJING_SIZE[0]-ENEMY_SIZE[0])
        self.rect.bottom = 0

    def update(self):
        super().update()
        if self.rect.y > BEIJING_SIZE[1]:
            self.kill()

class Hero(GameSprites):
    def __init__(self, filename):
        super().__init__(filename, FEIJI_SIZE, 0)
        self.rect.centerx = int(BEIJING_SIZE[1]/2)
        self.rect.y = BEIJING_SIZE[1] - FEIJI_SIZE[1]
        self.bullets = pygame.sprite.Group()

    def update(self, *args):
        self.rect.x += self.speed
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.x > BEIJING_SIZE[0]:
            self.rect.x = BEIJING_SIZE[0] - FEIJI_SIZE[0]
    def fire(self):

        for i in range(1,2):
            bullet = Bullet(ZIDAN_DEFAULT_PATH)
            bullet.rect.bottom = self.rect.y -20*i
            bullet.rect.centerx = self.rect.centerx
            self.bullets.add(bullet)

class Bullet(GameSprites):
    def __init__(self, filename):
        super().__init__(filename, ZIDAN_SIZE, ZIDAN_SPEED)
        self.rect.x =  1
    def update(self):
        self.rect.y = self.rect.y + ZIDAN_SPEED
        if self.rect.bottom < 0:
            self.kill()

if __name__ == '__main__':
    pass

 


第七章 Pygame.sprite

这个模块包含几个游戏中使用的简单类。最主要的是Sprite类,还有几个容纳SpriteGroup类。是否使用 这些类在Pygame中是可选的。这些类是轻量级的,仅仅提供了一个大部分游戏所共同需要的代码的起点。

Sprite类是用作游戏中各种类型对象的基类。还有一个Group基类用来简单的容纳sprites。一个游戏可以创 建新的Group类用来操作它们包含的特殊的Sprite对象。

基本的Sprite类可以把它 包含的Sprite画到Surface上。Group.draw方法需要每个Sprite都有一个Sprite.image属性和一个 Sprite.rect属性。Group.clear方法需要相同的属性,可以用于删除所有的Sprite。还有更高级的 Grouppygame.sprite.RenderUpdates可以跟踪图像脏的部 分(需要更新的部分),pygame.sprite.OrderedUpdates可以以叠加顺序 画Sprites

最后,这个模块还包含几个碰撞检测函数。这些函数帮助我们找到 多个Group里面的Sprite有哪些是相交的。要找到碰撞,Sprite必须有一个rect属性。

Sprite类不是线程安全 的。使用多线程时必须自己锁定它们。

pygame.sprite.Sprite

pygame.sprite.Sprite(*groups): return Sprite

    Sprite.update - 控制sprite的行为

    Sprite.add - sprite添加到group

    Sprite.remove - spritegroup里面删除

    Sprite.kill - srpite从所有group里面删除

    Sprite.alive - 判断是否有个Group包含这个sprite

Sprite.groups - 列出所有包含这个SpriteGroup

表示可见的游戏对象的简单基类。它的派生类需要覆盖Sprite.update方法,并给Sprite.image和 Sprite.rect属性赋值。初始化函数可以带任意个Group对象作为它们的成员。

当从Sprite派生时,记得在把Sprite添加到组中之前一定要调用基类的初始化函数。

Sprite.update

Sprite.update(*args)

控制sprite行为的方法,这个函数的默认实现什么都不做。

Sprite.add

Sprite.add(*groups): return None

sprite添加到 group里面,参数可以给定任意多个Group对 象。Sprite会被添加到不包含它的Group里面去。

Sprite.remove

Sprite.remove(*groups): return None

sprite从 groups里面删除,可以指定任意多个Group作为参 数。Sprite会从包含它的group里面删除。

Sprite.kill

Sprite.kill(): return None

Sprite从所有的 group里面删除,Sprite会从所有包含它的 Group里面删除。这个函数不会改变Sprite本身的任何状态。这个函数用了以后还可以继续使用这个Sprite对象,包括把它添加到Group里 面。

Sprite.alive

Sprite.alive(): return bool

判断是否有某个Group 包含这个Sprite,如果这个Sprite属于某个组或者多个组,这个函数返回True

Sprite.groups

Sprite.groups(): return group_list

列出包含这个Sprite 的所有Group

pygame.sprite.Group

pygame.sprite.Group(*sprites): return Group

    Group.sprites - 列出这个Group包含的所有Sprites

    Group.copy - 复制这个group

    Group.add - Sprite添加到这个group

    Group.remove - Spritegroup里面删除

    Group.has - 判断这个Group是否包含一些Sprites

    Group.update - 调用所有包含的Spriteupdate方法

    Group.draw - Sprite图像画到Surface

    Group.clear - 用背景覆盖掉Sprite

Group.empty - 删除Group包含的所有Sprite

包含多个Sprite的容 器类,Sprite对象的简单容器。这个类 可以派生出包含更多特殊功能的类。构造函数可以带任意多个Sprite作为添加到Group里面的对象。Group支持下列标准的Python操作:

          in      判断一个Sprite是否在里面

          len     获取包含的Sprite的个数

          bool    判断这个Group是否包含了Sprite(或者是空的)

          iter    迭代包含的所有的Sprite

Group包含的Sprite没有 排序,所以画Sprites或者迭代它们是没有一个确定的顺序的。

Group.sprites

Group.sprites(): return sprite_list

列出这个Group包含 的Sprites

返回这个Group包含的所有 Sprites的列表。你可以从这个group获得一个迭代子,但是你不能够迭代一个Group的同时并修改它。

Group.copy

Group.copy(): return Group

复制Group,创建一个新的Group,包含和原 来的group完全相同的Sprites

Group.add

Group.add(*sprites): return None

Sprites添加到这个Group里面,添加任意多个Sprite到这个 Group中。这个函数只会添加Group里面原来没有的Sprite进来。

Group.remove

Group.remove(*sprites): return None

group中删除 Sprites,删除任意多个 Sprites。这个操作只对Group里面存在的Sprite进行。

Group.has

Group.has(*sprites): return None

判断这个Group是否包含一些Sprites,如果Group包含所有给定的 Sprites,则函数返回True

Group.update

Group.update(*args): return None

在包含的Sprites上调用update,在包含的所有Sprites上调用updateSprite基类有一个可以带任何参数并不作任何事情的update 函数。传给Group.update的参数对每一个Sprite对象。

Group.draw

Group.draw(Surface): return None

Sprite图像复制 到Surface

把包含的Sprites画到 Surface上去。这个函数用到Sprite.image作为源Surface,并且用到Sprite.rect作为位置。

Group.clear

Group.clear(Surface_dest, background): return None

用背景来覆盖 Sprites

Group.draw所画的 Sprites擦掉。目标SurfaceSprite的区域会被backgroup上的所填充。

background通常是一个Surface图像,具有和目标Surface同样的大小。它也可以是回调函数,带两个 参数:目标Surface和清除的区域。background回调函数在一次clear的过程中会被调用多次。

这是一个回调函数的例子,把Sprites清除为红色:

    def clear_callback(surf, rect):

        color = 255, 0, 0

        surf.fill(color, rect) 

Group.empty

Group.empty(): return None

去除这个Group包含的所有 Sprites

pygame.sprite.RenderUpdates

pygame.sprite.RenderUpdates(*sprites): return RenderUpdates

RenderUpdates.draw - 块复制Sprite图像,并跟踪改变的区域

它包含一个扩展的draw函数,能够跟踪屏幕上改变的区域。

RenderUpdates.draw

RenderUpdates.draw(surface): return Rect_list

把所有的Sprite画到 surface上,和Group.draw一样。这个函数返回一组矩形,表示屏幕上被改变的区域。返回的改变区域也包括之前被Group.clear影响 的区域。

返回的Rect列表应该传给 pygame.display.update函数。这有助于提高软件显示模式下的游戏性能。这种更新的方法只在背景不会动的时候有效。

pygame.sprite.OrderedUpdates

pygame.sprite.OrderedUpdates(*spites): return OrderedUpdates

它按照 Sprite添加的顺序,画图的RenderUpdates类。这使得从Group里添加和删除Sprites操作比普通的Group慢一点。

pygame.sprite.GroupSingle

pygame.sprite.GroupSingle(sprite=None): return GroupSingle

GroupSingle仅 包含一个Sprite。当一个新的Sprite添加进去,老的就被删除了。

pygame.sprite.spritecollide

pygame.sprite.spritecollide(sprite, group, dokill): return Sprite_list

在一个Group里面找和另一个Sprite相交的Sprites

是否相交通过比较Sprite.rect属性来确定。dokill参数是一个布尔型的。如果设置成True,则所有相交的Sprite会从Group里面删除。

pygame.sprite.groupcollide

pygame.sprite.groupcollide(group1, group2, dokill1, dokill2): return Sprite_dict

找到两个Group里面所有相交的Sprites

这个函数会找到两个group里面 所有相交的Sprites。是否相交通过比较Sprite.rect属性来确定。

group1里面的每一个Sprite会被添加到返回的字典里面,每一项的值是group2中相交的Sprites的列 表。

两个dokill参数,哪一个是True,则对应的 Group里面相交的Sprites会被删除。

pygame.sprite.spritecollideany

pygame.sprite.spritecollideany(sprite, group): return bool

简单的测试一个Sprite是否和Group里面的任意一个 Sprite相交

如果给定的SpriteGroup里面的某个Sprite相交,则返回True。是否相交通过比较 Sprite.rect属性来确定。

这个碰撞检测比 pygame.sprite.spritecollide更快,因为它要作的事情少一点。

posted @ 2019-01-13 00:55  周sir搞人工  阅读(485)  评论(0编辑  收藏  举报