- 文件目录
-
constant.py:存放一些常量(速度,尺寸。。)的文件
-
game_sprite:设计精灵的文件
-
game_maneger.py:管理游戏进行的文件
contant.py
import pygame
import random
import os
# 定义游戏帧率
GAME_FRAME = 60
# 定义游戏窗口的大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 600)
# 定义间距
MARGIN = 20
# 自定义创建敌方陨石的事件
EVENT_CREATE_STONE = pygame.USEREVENT
EVENT_CREATE_PLANE = pygame.USEREVENT + 1
# 定义所有陨石的文件名
# , 'meteorBrown_small1.png', 'meteorBrown_small2.png'
STONE_LIST = ['meteorBrown_big1.png', 'meteorBrown_big2.png', 'meteorBrown_med1.png', 'meteorBrown_med3.png']
# 图片所在的文件夹路径
IMAGE_FOLDER = os.path.join(os.path.dirname(__file__), 'img')
# 准备爆炸精灵字典
exp_animation = {'regular': [],'sonic': []}
for i in range(9):
# 加载regular动画
file_name_re = f'regularExplosion0{i}.png'
exp_1 = pygame.image.load(os.path.join(IMAGE_FOLDER, file_name_re))
exp_animation['regular'].append(exp_1)
# 加载sonic动画
file_name_so = f'sonicExplosion0{i}.png'
exp_2 = pygame.image.load(os.path.join(IMAGE_FOLDER, file_name_so))
exp_animation['sonic'].append(exp_2)
game_sprite.py
from constant import *
# 精灵的分析:
# 玩家飞机 玩家飞机的子弹 敌方飞机 敌方飞机的子弹 背景 爆炸效果
# 继承关系
class GameSprite(pygame.sprite.Sprite):
"""游戏精灵的基类"""
def __init__(self, img_src, speed=1):
# 调用父类的初始化方法
super().__init__()
# 通过路径(图片)加载精灵
self.image = pygame.image.load(img_src)
# 获取image的大小
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
"""更新精灵的方法(自动被调用的)"""
super().update()
# 默认所有精灵都是向下移动
self.rect.y += self.speed
class Background(GameSprite):
def __init__(self, isFirst=True):
super().__init__(img_src='./img/bg.png')
if not isFirst:
# 如果你不是第一张图片
# 此时设置第二张背景图的位置
self.rect.y = -self.rect.height
def update(self):
super().update()
# 判断当背景移动到windwow外的时候,改变移出屏幕的那张背景的位置
if self.rect.y > SCREEN_RECT.height:
self.rect.y = -self.rect.height
#玩家精灵类
class Player(GameSprite):
def __init__(self):
super().__init__(img_src='./img/player.png')
# 是否存活
self.islive = True
# 改变加载的图像的尺寸
self.image = pygame.transform.scale(self.image, (50, 38))
# 获取精灵的大小
self.rect = self.image.get_rect()
# 给飞机设置初始位置
# 设置飞机水平居中
self.rect.centerx = SCREEN_RECT.width * .5
self.rect.bottom = SCREEN_RECT.height - MARGIN
# 给玩家飞机定义初始的水平速度
self.speedx = 0
self.speedy = 0
# 定义子弹精灵组
self.bullet_group = pygame.sprite.Group()
def update(self):
# 初始化水平速度
self.speedx = 0
self.speedy = 0
# 获取用户的按键情况
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speedx = -4
if keystate[pygame.K_RIGHT]:
self.speedx = 4
if keystate[pygame.K_UP]:
self.speedy = -4
if keystate[pygame.K_DOWN]:
self.speedy = 4
# 改变自身x
self.rect.x += self.speedx
self.rect.y += self.speedy
# 如何设置飞机的边界(确保飞机飞不出屏幕外)
# 左边
if self.rect.x < 0:
self.rect.x = 0
# 右边
if self.rect.x > SCREEN_RECT.width - self.rect.width:
self.rect.right = SCREEN_RECT.right
# 上边
if self.rect.y < 0:
self.rect.top = 0
# 下边
if self.rect.y > SCREEN_RECT.height - self.rect.height:
self.rect.bottom = SCREEN_RECT.bottom
def fire(self):
# 创建子弹
b = Bullet()
# 初始化子弹的位置
b.rect.bottom = self.rect.y - MARGIN
b.rect.centerx = self.rect.centerx
# 将子弹加入到子弹精灵组
self.bullet_group.add(b)
#子弹精灵类
class Bullet(GameSprite):
def __init__(self):
super().__init__(img_src='./img/bullet.png', speed=-5)
def update(self):
super().update()
# 如果子弹飞出屏幕外,处理掉这个精灵
if self.rect.bottom < 0:
self.kill()
#敌人精灵类
class Enemy(GameSprite):
def __init__(self, stone_name):
print(stone_name)
super().__init__(img_src=f'./img/{stone_name}')
# 设置石头的随机速度
self.speedy = random.randint(2, 3)
self.speedx = random.randint(-1, 2)
# 设置石头的初始位置
self.rect.bottom = -10
self.rect.x = random.randint(0, SCREEN_RECT.width - self.rect.width)
def update(self):
super().update()
# 叠加随机x速度
self.rect.x += self.speedx
self.rect.y += self.speedy
# 判断陨石飞出边界
if self.rect.y >= SCREEN_RECT.height or \
self.rect.left < -2 * MARGIN or \
self.rect.right > SCREEN_RECT.width + 2 * MARGIN:
self.kill()
def __del__(self):
print("陨石被销毁了------------------>")
#精灵爆炸类
class Explosion(pygame.sprite.Sprite):
def __init__(self, pos, anim_key):
super().__init__()
self.key = anim_key
# 展示第一张
self.image = exp_animation[self.key][0]
self.rect = self.image.get_rect()
# 给第一张图像初始化位置
self.rect.center = pos
# 索引
self.index = 0
self.frame_rate = 2
self.last_time = pygame.time.get_ticks()
def update(self):
# 1. 获取当前帧的时间
now_time = pygame.time.get_ticks()
if now_time - self.last_time > self.frame_rate:
# 记录上一帧的时间
self.last_time = now_time
# 控制索引递增
self.index += 1
if self.index == len(exp_animation[self.key]):
self.kill()
else:
# 如果能来到这里,就开始切换下一张图片
# 记录位置
cur_pos = self.rect.center
# 取出图像
self.image = exp_animation[self.key][self.index]
self.rect = self.image.get_rect()
self.rect.center = cur_pos
game_manager.py
from game_sprite import *
class GameManager:
def __init__(self):
"""游戏初始化阶段"""
pygame.init()
# 1. 设置游戏的窗口
self.window = pygame.display.set_mode(SCREEN_RECT.size)
# 2. 创建精灵
self.create_sprite()
# 3. 设置循环条件
self.isRunning = True
# 4. 设置游戏帧率
# 4.1 创建时钟对象
self.clock = pygame.time.Clock()
self.clock.tick(GAME_FRAME)
# 5. 设置定时器事件
pygame.time.set_timer(EVENT_CREATE_STONE, 1000)
def create_sprite(self):
"""创建游戏精灵"""
# 1. 创建背景精灵类对象
self.b1 = Background()
self.b2 = Background(isFirst=False)
# 2. 创建背景精灵组
self.bg_group = pygame.sprite.Group(self.b1, self.b2)
# 3. 创建玩家精灵
self.player = Player()
self.player_group = pygame.sprite.Group(self.player)
# 4. 创建陨石精灵组
self.stone_group = pygame.sprite.Group()
# 5. 创建爆炸精灵组
self.exp_group = pygame.sprite.Group()
def update_sprites(self):
"""更新精灵"""
# 更新精灵组
self.bg_group.update()
self.bg_group.draw(self.window)
# 更新玩家精灵组
self.player_group.update()
self.player_group.draw(self.window)
# 更新子弹精灵组
self.player.bullet_group.update()
self.player.bullet_group.draw(self.window)
# 更新陨石精灵组
self.stone_group.update()
self.stone_group.draw(self.window)
# 更新爆炸精灵组
self.exp_group.update()
self.exp_group.draw(self.window)
def event_handle(self):
"""事件监听"""
for event in pygame.event.get():
# print(event)
if event.type == pygame.QUIT:
self.isRunning = False
self.game_over()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# 让玩家飞机开火
self.player.fire()
elif event.type == EVENT_CREATE_STONE:
for _ in range(3):
# 获取随机索引
random_index = random.randint(0, len(STONE_LIST) - 1)
# 利用随机出来的索引去列表中取出对应的文件名
file_name = STONE_LIST[random_index]
# 创建陨石
enemy = Enemy(stone_name=file_name)
# 将陨石加入到陨石精灵组中
self.stone_group.add(enemy)
def collide(self):
"""碰撞检测"""
# 检测玩家的子弹精灵组和敌人精灵组之间的碰撞
# groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
hit = pygame.sprite.groupcollide(self.player.bullet_group, self.stone_group, True, True)
for h in hit:
pos = h.rect.center
# 生成爆炸精灵
exp = Explosion(pos, 'regular')
# 爆炸精灵加入到精灵组中
self.exp_group.add(exp)
# 玩家和敌人之间的碰撞检测
# spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
# hit = pygame.sprite.spritecollide(self.player, self.stone_group, True)
# if(self.player.islive):
# # -生命
# self.player.islive = False
# else:
# self.player.kill()
# self.isRunning = False
def gaming(self):
"""游戏阶段"""
while self.isRunning:
# 更新精灵组(绘制)
self.update_sprites()
# 事件监听
self.event_handle()
# 检测碰撞
self.collide()
# 刷新屏幕
pygame.display.update()
self.game_over()
def game_over(self):
"""游戏结束"""
pygame.quit()
if __name__ == "__main__":
GameManager().gaming()