【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类,还有几个容纳Sprite的Group类。是否使用 这些类在Pygame中是可选的。这些类是轻量级的,仅仅提供了一个大部分游戏所共同需要的代码的起点。
Sprite类是用作游戏中各种类型对象的基类。还有一个Group基类用来简单的容纳sprites。一个游戏可以创 建新的Group类用来操作它们包含的特殊的Sprite对象。
基本的Sprite类可以把它 包含的Sprite画到Surface上。Group.draw方法需要每个Sprite都有一个Sprite.image属性和一个 Sprite.rect属性。Group.clear方法需要相同的属性,可以用于删除所有的Sprite。还有更高级的 Group:pygame.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 – 把sprite从group里面删除
Sprite.kill – 把srpite从所有group里面删除
Sprite.alive – 判断是否有个Group包含这个sprite
Sprite.groups – 列出所有包含这个Sprite的Group
表示可见的游戏对象的简单基类。它的派生类需要覆盖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 – 把Sprite从group里面删除
Group.has – 判断这个Group是否包含一些Sprites
Group.update – 调用所有包含的Sprite的update方法
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上调用update。Sprite基类有一个可以带任何参数并不作任何事情的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擦掉。目标Surface上Sprite的区域会被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相交
如果给定的Sprite和Group里面的某个Sprite相交,则返回True。是否相交通过比较 Sprite.rect属性来确定。
这个碰撞检测比 pygame.sprite.spritecollide更快,因为它要作的事情少一点。