#plane_sprites.py
# 模块导入顺序
import random # 官方标准模块
import pygame # 第三方模块
# 应用程序模块
# 定义一个屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 600) # 不用担心,到时候可以通过Rect类中的size方法获取到矩形窗口大小的元组
# 刷新的帧率
FRAME_PER_SECOND = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT # pygame提供了一个用户事件常量
#英雄发射子弹事件
HERO_FIRE_EVENT=pygame.USEREVENT+1
# 需要继承一下pygame中的精灵类
class GameSprite(pygame.sprite.Sprite):
"""飞机大战的游戏精灵"""
def __init__(self, image_name, speed=1):
# 调用父类的初始化方法,必须在这里调用,我们要求扩展式继承而不是覆盖式
# 要求不同对象的init方法也要有重合部分,就是继承的super()父类的部分
super().__init__() # 这里每个对象有相同的操作
# 定义对象的属性,这里每个对象属性不同
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect() # image的图像大小
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):
super().update()
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:
# print("飞出屏幕,需要从精灵组删除")
self.kill() # kill方法可以将精灵从所有精灵组中移出,自动销毁,以正常调用__del__()方法
def __del__(self): # 销毁敌机
pass
# print("敌机挂在了 %s" % self.rect)
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):
pass
class Hero(GameSprite):
def __init__(self):
super().__init__("./images/me1.png",0)# 第二个参数是飞机的速度,我们实现飞机在screen中水平移动
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
#rect提供了一个矩形对象right属性,right属性的本质等于精灵的位置加上width
elif self.rect.right>SCREEN_RECT.right:
self.rect.right=SCREEN_RECT.right
def fire(self):
for i in (0,1,2):
# 1.创建子弹精灵
bullet=Bullet()
# 2.设置精灵位置
bullet.rect.bottom=self.rect.y- i*20
bullet.rect.centerx=self.rect.centerx
# 3.将精灵添加到精灵组
self.bullets.add(bullet)
#plane_main.py
import pygame.examples.sprite_texture
from plane_sprites import *
# 使用import方式导入模块在使用模块中的工具时必须使用 模块. 的方式访问
# 使用from 模块 import * 的方式导入模块在使用的时候就无需写 模块. ,直接调用相应对象即可
class PlaneGame(object):
"""飞机大战主游戏"""
def __init__(self):
print("游戏初始化")
# 1.创建游戏窗口,用到类似C语言中的宏定义常量
self.screen = pygame.display.set_mode(SCREEN_RECT.size) # 从SCREEN_RECT这个矩形对象中取出描述窗口大小的元组
# 2.创建游戏时钟
self.clock = pygame.time.Clock()
# 3.调用私有方法
self.__create_sprites() # 创建精灵和精灵组
# 4.设置定时器事件--创建敌机
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)# 第二个参数以毫秒为单位
pygame.time.set_timer(HERO_FIRE_EVENT,500)# 每隔0.5秒发射一颗子弹
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
# bg2.rect.y=-bg2.rect.height# bg2的初始位置,由于已经封装在Background类初始化方法中,故可以不写
self.back_group = 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_SECOND)
# 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:
print("敌机出场")
# 创建敌机精灵
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]:
#print("向右移动")
self.hero.speed=3
elif keys_pressed[pygame.K_LEFT]:
self.hero.speed=-3
else:
self.hero.speed=0
def __check_collide(self):
# 子弹摧毁敌机
pygame.sprite.groupcollide(self.hero.bullets,self.enemy_group,True,True)
# 敌机撞毁英雄
enemies=pygame.sprite.spritecollide(self.hero,self.enemy_group,True)
# 判断enemise列表是否有内容,如果有就做英雄牺牲的动作
if len(enemies)>0:
self.hero.kill()
PlaneGame.__game_over()
def __update_sprites(self):
self.back_group.update()
self.back_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)
@staticmethod # 静态方法 1.添加修饰符 2.无需任何参数(self也不需要)
def __game_over():
print("游戏结束")
pygame.quit()
exit()
def main():
# pygame.init()
# 创建游戏对象
game = PlaneGame()
game.start_game() # 启动游戏
if __name__ == '__main__':
main()
"""以下为入门举例代码
pygame.init()
# 使用pygame.Rect类描述一个矩形对象,rect就是矩形的意思
# 这个矩形对象pygame.Rect(x,y,width,height)
hero_rect=pygame.Rect(150,300,102,126)# 102,126是英雄飞机图像的参数,英雄飞机的初始位置
# print("英雄的原点 %d %d"% (hero_rect.x,hero_rect.y))
# print("英雄的尺寸 %d %d"%(hero_rect.width,hero_rect.height))
# print("%d %d"%hero_rect.size)#使用Rect类中的size属性可以返回英雄的宽度和高度
# 1.创建游戏窗口480*700
# 使用pygame模块中的display模块中的set_mode()方法
screen=pygame.display.set_mode((480,600))
# 2.绘制图像初始位置
# 绘制背景图像
# 1>加载图像数据,设置background
bg=pygame.image.load("./images/background.png")
# 2>屏幕对象screen调用blit方法在窗口(0,0)处绘制图像
screen.blit(bg,(0,0))
# 3>update更新屏幕显示,如果不调用update方法则不能绘制背景图像
#pygame.display.update()#可以在screen对象调用完所有blit方法后统一调用一次
# 绘制英雄飞机(和上面一样,三步曲,其中第三步可以在screen对象调用完所有blit方法后统一调用一次)
hero=pygame.image.load("./images/me1.png")
screen.blit(hero,(200,500))
# 可以在screen对象调用完所有blit方法后统一调用一次,可以提高游戏流畅度
pygame.display.update()# 把screen对象的绘制结果一次性的绘制到屏幕上
# 3.创建时钟对象
clock=pygame.time.Clock()
# i=0# 用于测试游戏循环帧率
# 创建敌机的精灵
enemy=GameSprite("./images/enemy1.png")
enemy1=GameSprite("./images/enemy1.png",2)# 2是敌机的速度
# 创建敌机的精灵组
enemy_group=pygame.sprite.Group(enemy,enemy1)
# 游戏循环
while True:
# 60fps(60 frame per second)
clock.tick(60)
# 捕获事件
# event_list = pygame.event.get()#get()方法的返回值是一个列表
# if len(event_list)>0:# 只有当有事件时才输出
# print(event_list)
#事件监听
for event in pygame.event.get():
if event.type==pygame.QUIT:
# print("退出游戏")
pygame.quit()# 在这里卸载pygame
exit()#直接终止程序
# 修改飞机位置
hero_rect.y-=1
# 判断飞机的位置,如果y<=0,则修改y的值,让飞机实现在框内循环
if hero_rect.y<=-126:# 当飞机完全越过上界时才重新定位到最下方
hero_rect.y=600
# 调用blit方法绘制图像
# 我们不希望在循环的时候留下飞机的残影
# 我们的解决方案是在移动之前重新绘制背景图像
screen.blit(bg,(0,0))# 解决方案核心代码
screen.blit(hero,hero_rect)# 参数一:图像特性;参数二:位置特性
# 让精灵组调用两个方法update draw
enemy_group.update()# 让组中所有精灵更新位置
enemy_group.draw(screen)# 在screen上绘制所有的精灵
pygame.display.update()
#用于测试游戏循环帧率
# i+=1
# print(i)
#用于测试游戏循环帧率
# pygame.quit() #在事件监听中退出pygame
"""
![](https://i-blog.csdnimg.cn/blog_migrate/92b0f52a175b8cc009da0d5743b8c956.png)
![](https://i-blog.csdnimg.cn/blog_migrate/93b59bd5a628c0df5548e562e5d5c1b7.png)
//linux
![](https://i-blog.csdnimg.cn/blog_migrate/21be3428a646f786530f208bc1e0ff27.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ef25642b36d8b3dc2ef675c1014c9bc2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/14cdd64768275ccf1567ed04a3631de3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bf72358cdc3e136e1b79e646193c43c8.png)
//矩阵
![](https://i-blog.csdnimg.cn/blog_migrate/67481280dfc790dcdfdaffe4391baf64.png)
Pygame.Rect 类
![](https://i-blog.csdnimg.cn/blog_migrate/1e070d5bff1cff3a4956c1a59a15aea2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fb77360dc63fe37dc4df1d216413b1e7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f3b7e2cc14580bd39198882e8c97c6bb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/da313e6d12bc1cc1e2e0bcdf1dc42d65.png)
![](https://i-blog.csdnimg.cn/blog_migrate/928f19f92a9052e7a254f54e5dab5185.png)
![](https://i-blog.csdnimg.cn/blog_migrate/515a8a19c208855ba70e91711e0aac38.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b6591f3c720f0ec4bd2d1aff081fd3b9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e992365472589e306a0e67e14a03c159.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6ce3403f7f91a5baa1f84e0c5d4e7e44.png)
![](https://i-blog.csdnimg.cn/blog_migrate/63eedc0221cf5817d5bdc076067f9ebf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/738ead0474d1d95c1cdfe34c9124428a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4621d3647f66221fe1223e00a9b2fe51.png)
![](https://i-blog.csdnimg.cn/blog_migrate/be2886e34cb60170bfe9d98eb72766e5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/753827c7ce056e0dff5bfb0c8970f3de.png)
//精灵类继承自pygame的精灵类,而不是继承自object的类,我们需要先扩展重写super()一下父类的__init__()方法
//用于代替blit、update方法进行绘制和更新
![](https://i-blog.csdnimg.cn/blog_migrate/7d16ad4966ff01cbe6d47199fd1f3bda.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3ae6f1ca2ecb45e2835ab45a93c671db.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7c6072a57d669231b6774920b64e9014.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6222306d123ae1d4b9f3f4bb7dfda3a9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6c9ab077394ed3c3e5262fc975f0894e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ca5ba7f465277ec984bad6b21f412b10.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fc93832117b2bab86dc937dcceba4179.png)
![](https://i-blog.csdnimg.cn/blog_migrate/693777986331ac722c825402fccec59d.png)
//背景图片的动态实现的原理:
![](https://i-blog.csdnimg.cn/blog_migrate/40ab9a9569b9e898a6c095820629196f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d2b3393e226d5ba568350480c7fdfc82.png)
![](https://i-blog.csdnimg.cn/blog_migrate/24722c2711ca62a8dc36e7ce2841d3ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5f14b5b9fe77565d76eab3974a0d9f84.png)
![](https://i-blog.csdnimg.cn/blog_migrate/42de32d7390aa91c1580eaa7a494e60c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7d51c0a636f4e3d53ee4973b3f28c79d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1e73e1122866f8019baf13ac7065f677.png)
改进:
背景图像的设置封装在初始化方法内部
初始位置的设置封装在初始化方法内部
采用is_alt参数来确定到底是哪一个对象
False表示第一张图像,位置与屏幕重合
True表示另一张图像,位置在屏幕正上方
![](https://i-blog.csdnimg.cn/blog_migrate/97c6afe1c770174ea1e5e50992671f1b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e55e081d26110dc58c4ae1c2dc87adba.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fd1b2a495fad1b4f0e2427399fd90288.png)
![](https://i-blog.csdnimg.cn/blog_migrate/37b6093f16056aa046d6c09720e14bd2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0c2a17afb9a5107d6564ba656653f735.png)
![](https://i-blog.csdnimg.cn/blog_migrate/472e92255c1c1e7143d011eef25be019.png)
//import的顺序
![](https://i-blog.csdnimg.cn/blog_migrate/c0e32915361ab3d539e2db844a070639.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ec9649272e2c3455ed4f3dabcc9897de.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a445afcbc45f3bdbfcd8675b3d9ad525.png)
![](https://i-blog.csdnimg.cn/blog_migrate/027f8d299ece6953c37ce9088f9f92d0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/53307fa4cebea2759652e8aa743ea0ed.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6f9bffe01412a07bd8d31303f5482c03.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1693ab2fb872b7b035a44f5a993f78e0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7cff11609481e6e03824274ea2fba6b9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ac59eebe5247c714605712a23de85ffc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a39d69a7ef0db4e74edcd510f3a3f20e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b269bbb52c5803b2a7052436dfac499d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bc38b6218b3abf3c5cddaba1252334f7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d4b3e380b502d9817c0fdb1859d18313.png)
![](https://i-blog.csdnimg.cn/blog_migrate/def7eaecbf7d91b52cdcd9b5050d61e8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5d046d1dea998228827f9fad3611c518.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ed1f2044eced3e390ad99fb018c98b0f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/24c225241ed4efb6c617bda73f60768b.png)
链接:https://pan.baidu.com/s/1c2aMz1kjHMtmnlsgDC7pKw?pwd=5kxc
提取码:5kxc
--图片素材