本文博主将讲述python开发“太空大战”小游戏的过程
一、对即将开发的小游戏初认识
注:初认识的目的是,让开发者脑中有个你即将开发的游戏的大概轮廓和游戏功能
1、先给大家介绍一下游戏的玩法和界面说明
当你刚开始运行代码时,出现如图界面问你是否开始游戏
按下“回车”确认开始后,出现如下待机界面,(注:该待机界面不会超过10秒)
游戏开始后,玩法和界面说明
注:按“空格”键是发射子弹,键盘的“左右”键用来控制飞机左右躲避陨石撞击(注:您一共有三架飞机,若是三架飞机都被撞毁,则游戏结束)
二、对整个工程的解释:
整个工程相对来说还是挺简单的,在你的工程下创建一个文件夹命名为“game”用来存放整个项目,“assets”是存放游戏所需的图片资源,“sounds”是存放游戏所需的音频资源,“shooter.py”文件是实现游戏的python代码,以下是“shooter.py”文件的代码,“assets”和“sounds”文件夹,我会打包给你们(点击这里获取
),直接放到你创建的game目录下即可;
注:本人博客所有内容完全免费,请放心下载
三、开始写python代码,写完代码运行即可开始游戏
代码我做了比较详细的说明,希望你能看懂
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
# 导入模块
import pygame
from os import path
import random
# 图片资源路径
img_dir = path.join(path.dirname(__file__), 'assets')
# 音频资源路径
sound_folder = path.join(path.dirname(__file__), 'sounds')
# 游戏界面的宽度
WIDTH = 480
# 游戏界面的高度
HEIGHT = 600
# 游戏中生命条长度
BAR_LENGTH = 100
# 游戏中生命条高度
BAR_HEIGHT = 10
# 游戏中的字体
font_name = pygame.font.match_font('楷体', 16)
# 帧数
FPS = 60
# 游戏中的常用颜色 RGB
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# 游戏初始化 .是调用的意思
# 如何进入源码查看Ctrl+鼠标左键
pygame.init()
# 游戏音频初始化操作
pygame.mixer.init()
# 初始化游戏显示窗口 数组 列表 (1,2,3,4)元组
# [1,2,3,4]列表
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 设置游戏标题
pygame.display.set_caption("太空 射击")
# 时钟
clock = pygame.time.Clock()
# 游戏运行背景图片
background = pygame.image.load(path.join(img_dir, 'starfield.png')).convert()
# 游戏运行背景图片的矩形
background_rect = background.get_rect()
# 飞机图片
player_img = pygame.image.load(path.join(img_dir, 'playerShip1_orange.png')).convert()
# 子弹图片
bullet_img = pygame.image.load(path.join(img_dir, 'laserRed16.png')).convert()
# 一个个资源获取 添加到陨石图片列表中
# 利用循环将资源获取添加
# 陨石图片列表
metor_images = []
# 陨石图片名称列表
metor_list = [
'meteorBrown_big1.png',
'meteorBrown_big2.png',
'meteorBrown_med1.png',
'meteorBrown_med3.png',
'meteorBrown_small1.png',
'meteorBrown_small2.png',
'meteorBrown_tiny1.png',
]
# 向陨石图片列表添加图片
for image in metor_list:
metor_images.append(pygame.image.load(path.join(img_dir, image)).convert())
# 字典
# ni---》你 key(键值)————》value(内容)
# 爆炸图片动画
explosion_anim = {}
explosion_anim ['lg'] = []
explosion_anim ['sm'] = []
explosion_anim ['player'] = []
# 循环添加图片到列表中
for i in range(9):
# 获取文件名
fileName = 'regularExplosion0{}.png'.format(i)
# 根据文件名获取图片
img = pygame.image.load(path.join(img_dir, fileName)).convert()
img.set_colorkey(BLACK)
# 将爆炸图片缩放(75,75) 大的陨石爆炸效果
img_lg = pygame.transform.scale(img, (75, 75))
# 将缩放后的图片添加到lg列表中
explosion_anim['lg'].append(img_lg)
# 将爆炸图片缩放(32,32)小的陨石爆炸效果
img_sm = pygame.transform.scale(img, (32, 32))
# 将缩放后的图片添加到sm列表中
explosion_anim['sm'].append(img_sm)
# 飞机爆炸
# 获取文件名
fileName = 'regularExplosion0{}.png'.format(i)
# 根据文件名获取图片
img = pygame.image.load(path.join(img_dir, fileName)).convert()
img.set_colorkey(BLACK)
# 将获得的图片添加到player列表中
explosion_anim['player'].append(img)
# 小飞机图片
# 缩放小飞机图片
player_mini_img = pygame.transform.scale(player_img, (25, 19))
player_mini_img.set_colorkey(BLACK)
# 奖励图片
powerup_images = {}
powerup_images['shield'] = pygame.image.load(path.join(img_dir, 'bolt_gold.png')).convert()
powerup_images['dun'] = pygame.image.load(path.join(img_dir, 'shield_gold.png')).convert()
# 导弹图片
missile_img = pygame.image.load(path.join(img_dir, 'missile.png')).convert_alpha()
# 陨石爆炸音频列表
expl_sounds = []
for sound in ['expl3.wav', 'expl6.wav']:
expl_sounds.append(pygame.mixer.Sound(path.join(sound_folder, sound)))
# 飞机爆炸音效
player_die_sound = pygame.mixer.Sound(path.join(sound_folder, 'rumble1.ogg'))
# 音效资源获取
shooting_sound = pygame.mixer.Sound(path.join(sound_folder, 'pew.wav'))
# 导弹发射音效资源获取
missile_sound = pygame.mixer.Sound(path.join(sound_folder, 'rocket.ogg'))
# 主菜单函数 得分函数名称(参数.......):
def main_menu():
global screen
# 获取游戏主菜单背景音乐资源
menu_song = pygame.mixer.music.load(path.join(sound_folder, 'menu.ogg'))
# 无限时的播放
pygame.mixer.music.play(-1)
# 获取游戏主菜单背景图片
background_menu = pygame.image.load(path.join(img_dir, 'main.png')).convert()
# 缩放背景图片
background_menu = pygame.transform.scale(background_menu, (WIDTH, HEIGHT), screen)
# 将缩放后的图片设置到主菜单上
screen.blit(background_menu, (0, 0))
# 刷新屏幕(部分刷新屏幕)
pygame.display.update()
# 提示 使用不可控制次数循环
while True:
# 键盘的监听
ev = pygame.event.poll()
# 如果是按键按下事件
if ev.type == pygame.KEYDOWN:
# 如果用户按下了回车键
if ev.key == pygame.K_RETURN:
break
elif ev.key == pygame.K_q:
# 退出游戏
pygame.quit()
quit()
# 如果是鼠标点击关闭按钮
elif ev.type == pygame.QUIT:
# 退出游戏
pygame.quit()
quit()
# 绘制提示文字
else:
draw_text(screen, "Press [ENTER] to Begin", 30, WIDTH/2, HEIGHT/2)
draw_text(screen, "or [Q] to Quit", 30, WIDTH/2, (HEIGHT/2)+40)
# 刷新屏幕
pygame.display.update()
# 游戏的准备界面
# 获取游戏准备的音频资源
ready = pygame.mixer.Sound(path.join(sound_folder, 'getready.ogg'))
# 仅播放一次
ready.play()
# 将游戏屏幕填充为黑色
screen.fill(BLACK)
draw_text(screen, "GET READY!", 80, WIDTH/2, HEIGHT/2)
# 刷新屏幕
pygame.display.update()
# 绘制字体的函数
def draw_text(surf, text, size, x, y):
# 字体
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE)
# 获得字的矩形形状
text_rect = text_surface.get_rect()
# 设置矩形的顶点坐标
text_rect.midtop = (x, y)
# 将矩形(字)绘制到屏幕中
surf.blit(text_surface, text_rect)
# 飞机类
class Player(pygame.sprite.Sprite):
# 构造函数
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# 缩放飞机图片
self.image = pygame.transform.scale(player_img, (50, 38))
# 设置飞机图片不透明
self.image.set_colorkey(BLACK)
# 获得飞机图片的矩形
self.rect = self.image.get_rect()
# 设置矩形的 x方向中心点
self.rect.centerx = WIDTH/2
# 设置矩形的底部坐标 y
self.rect.bottom = HEIGHT - 10
# 飞机的X方向移动速度
self.speedx = 0
# 飞机最后一次发射完成时间 pygame.time.get_ticks() 获得当前的系统时间
self.last_shoot = pygame.time.get_ticks()
# 子弹发射时间间隔
self.shoot_delay = 100
# 子弹的初始火力值
self.power = 1
# 子弹的火力时间
self.power_time = pygame.time.get_ticks()
# 飞机的生命值
self.sheild = 100
# 飞机的生命
self.lives = 3
# 半径
self.radius = 20
# 飞机的隐身状态
self.hidden = False
# 飞机的隐身时间
self.hide_timer = pygame.time.get_ticks()
# 飞机的更新函数
def update(self):
# 消弱飞机的火力
if self.power >=2 and pygame.time.get_ticks() - self.power_time > 5000:
self.power -=1
self.power_time = pygame.time.get_ticks()
# 恢复飞机 取消隐身
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 2000:
self.hidden = False
self.rect.centerx = WIDTH /2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
keystate = pygame.key.get_pressed()
# 如果按键按下的是左键
if keystate[pygame.K_LEFT]:
self.speedx = -5
# 如果按建按下的是右键
if keystate[pygame.K_RIGHT]:
self.speedx = 5
# 空格按键监听
if keystate[pygame.K_SPACE]:
self.shoot()
# 越界检测 飞机左边x坐标是3 -5 =-2 =0
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > WIDTH:
self.rect.right = WIDTH
# 让飞机加上 速度
# 15 + 5 =20
# self.rect.x + self.speedx = self.rect.x
self.rect.x += self.speedx
# 飞机的射击函数
def shoot(self):
# 当前时间
now = pygame.time.get_ticks()
# 判断 当前时间 = 最后一次发射时间 > 子弹发射时间间隔
if now - self.last_shoot > self.shoot_delay:
# 发射子弹
# 将最后一次发射子弹时间更改为当前时间
self.last_shoot = now
# 判断火力值
if self.power == 1:
# 生产(穿建)一颗子弹
bullet = Bullet(self.rect.centerx, self.rect.top)
# 将子弹添加到精灵组合中
all_sprites.add(bullet)
# 将子弹添加到子弹的精灵组合中
bullets.add(bullet)
# 播放射击音效
shooting_sound.play()
if self.power == 2:
bullet1 = Bullet(self.rect.left, self.rect.top)
bullet2 = Bullet(self.rect.right, self.rect.top)
all_sprites.add(bullet1)
all_sprites.add(bullet2)
bullets.add(bullet1)
bullets.add(bullet2)
shooting_sound.play()
# 火力值大于等于3的情况
if self.power >= 3:
bullet1 = Bullet(self.rect.left, self.rect.top)
bullet2 = Bullet(self.rect.right, self.rect.top)
# 导弹
missile1 = Missile(self.rect.centerx, self.rect.top)
all_sprites.add(bullet1)
all_sprites.add(bullet2)
all_sprites.add(missile1)
bullets.add(bullet1)
bullets.add(bullet2)
bullets.add(missile1)
shooting_sound.play()
missile_sound.play()
# 飞机的隐身函数
def hide(self):
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200)
# 飞机的火力增加函数
def powerup(self):
self.power += 1
self.power_time = pygame.time.get_ticks()
# 子弹类
class Bullet(pygame.sprite.Sprite):
# 构造函数
# 飞机在发射子弹的时候,由飞机当前位置计算子弹出现的x,y坐标
def __init__(self, x, y):
# 执行父类的构造函数
pygame.sprite.Sprite.__init__(self)
# 图片
self.image = bullet_img
self.image.set_colorkey(BLACK)
# 矩形
self.rect = self.image.get_rect()
# 底部边y坐标
self.rect.bottom = y
# 中心点x坐标
self.rect.centerx = x
# 子弹的移动速度
self.speedy = -10
# 子弹的更新函数
def update(self):
self.rect.y +=self.speedy
if self.rect.y <= 0-self.rect.top:
self.kill()
# 陨石类
class Mob(pygame.sprite.Sprite):
# 构造函数
def __init__(self):
# 执行父类的构造函数
pygame.sprite.Sprite.__init__(self)
# 陨石图片 随机从列表中选择一个
self.image_orig = random.choice(metor_images)
# 设置陨石图片不透明
self.image_orig.set_colorkey(BLACK)
# 复制陨石的图片
self.image = self.image_orig.copy()
# 陨石图片的矩形
self.rect = self.image.get_rect()
# 陨石的半径
self.radius = int(self.rect.width * .90 / 2)
# 陨石的x坐标 x随机值 范围: 0 ~ 屏幕宽度-陨石本身的宽度
self.rect.x = random.randrange(0, WIDTH - self.rect.width)
# 陨石的y坐标 y随机值 范围: -150 ~ -100
self.rect.y = random.randrange(-150, -100)
# 陨石的x方向移动速度 陨石可以左右运动
self.speedx = random.randrange(-3, 3)
# 陨石的y方向移动速度 陨石只允许向下 不允许向上
self.speedy = random.randrange(5, 20)
# 陨石的旋转角度
self.rotation = 0
# 陨石旋转时的角度变化速度
self.rotation_speed = random.randrange(-8, 8)
# 陨石最后一次更新时间
self.last_update = pygame.time.get_ticks()
# 陨石的旋转函数
def rotate(self):
# 获得当前时间
time_now = pygame.time.get_ticks()
if time_now - self.last_update > 50:
# 旋转陨石
self.last_update = time_now
# 旋转角度设定
self.rotation = (self.rotation + self.rotation_speed) % 360
# 通过旋转后得到的新图片
new_image = pygame.transform.rotate(self.image_orig, self.rotation)
# 找到矩形的中心点
old_center = self.rect.center
# 将原有的图片替换为新图片
self.image = new_image
# 获得图片的矩形
self.rect = self.image.get_rect()
# 设定矩形的中心点
self.rect.center = old_center
# 陨石的更新函数
def update(self):
# 执行陨石的旋转函数
self.rotate()
# 陨石的x方向更新
self.rect.x += self.speedx
# 陨石的y方向更新
self.rect.y += self.speedy
# 将越界额陨石 重新生成
if(self.rect.top > HEIGHT + 10) or (self.rect.left < -25) or (self.rect.left > WIDTH + 20):
# 重新生成陨石(为陨石重新设定坐标)
self.rect.x = random.randrange(0, WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
# 爆炸类
class Explosion(pygame.sprite.Sprite):
# 构造函数
def __init__(self, center, size):
# 执行父类的构造函数
pygame.sprite.Sprite.__init__(self)
# 爆炸范围大小
self.size = size
# 爆炸图片
self.image = explosion_anim[self.size][0]
# 爆炸图片矩形
self.rect = self.image.get_rect()
# 设置爆炸矩形的中心点
self.rect.center = center
# 动画开始时间
self.frame = 0
# 动画间隔时间
self.frame_rate = 75
# 最后一次刷新的时间
self.last_update = pygame.time.get_ticks()
# 爆炸类更新函数
def update(self):
# 获取当前时间
now = pygame.time.get_ticks()
if now - self.last_update > self.frame_rate:
# 将最后一次时间设置成当前时间
self.last_update = now
self.frame += 1
# 如果拿的图片是最后一张
if self.frame == len(explosion_anim[self.size]):
# 杀掉爆炸
self.kill()
else:
center = self.rect.center
self.image = explosion_anim[self.size][self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
# 奖励类
class Pow(pygame.sprite.Sprite):
def __init__(self, center):
pygame.sprite.Sprite.__init__(self)
self.type = random.choice(['shield', 'dun'])
# 图片
self.image = powerup_images[self.type]
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.center = center
# 移动速度
self.speedy = 2
def update(self):
self.rect.y += self.speedy
# 将出屏幕的奖励kill掉
if self.rect.top > HEIGHT:
self.kill()
# 导弹类
class Missile(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = missile_img
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
# 生成陨石函数
def newmob():
# 创建陨石对象
mob_element = Mob()
# 将陨石添加到精灵组合中
all_sprites.add(mob_element)
# 将陨石添加到陨石精灵组合中
mobs.add(mob_element)
# 游戏运行
# 游戏运行状态
# 布尔值 False True
running = True
# 主菜单显示状态
menu_display = True
# 绘制飞机生命条的函数
def draw_shield_bar(surf, x, y, shield):
# 在第一次执行这个函数的时候 取血量的最大值
shield = max(shield, 0)
# 填充长度
fill = (shield / 100) * BAR_LENGTH
# 生命条外界边框
outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
# 生命条填充矩形(内部代表生命值)
fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT)
# 绘制两个矩形
pygame.draw.rect(surf, GREEN, fill_rect)
pygame.draw.rect(surf, WHITE, outline_rect, 2)
# 绘制小飞机函数
def draw_lives(surf, x, y, lives, img):
for i in range(lives):
image_rect = img.get_rect()
image_rect.x = x + 30 * i
image_rect.y = y
surf.blit(img, image_rect)
# 不可控的循环
while running:
# 缩进 标准python下的缩进是四个空格
# 条件语句
if menu_display:
# 显示主菜单 定义函数
main_menu()
# pygame延迟操作
pygame.time.wait(3000)
# 停止播放主菜单背景音乐
pygame.mixer.music.stop()
# 获得游戏运行背景音乐
pygame.mixer.music.load(path.join(sound_folder, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
# 播放游戏背景音乐
pygame.mixer.music.play(-1)
# 将主菜单显示状态切换为False
menu_display = False
# 创建精灵组合
all_sprites = pygame.sprite.Group()
# 创建飞机对象
player = Player()
# 将飞机对象添加到精灵组合中
all_sprites.add(player)
# 陨石的精灵组合
mobs = pygame.sprite.Group()
for i in range(8):
# 新建陨石
newmob()
# 子弹的精灵组合
bullets = pygame.sprite.Group()
# 奖励的精灵组合
powerups = pygame.sprite.Group()
# 初始分数
score = 0
clock.tick(FPS)
# 循环获取用户事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# 利用精灵组合执行精灵的变化函数
all_sprites.update()
# 子弹与陨石的碰撞 pygame提供的精灵组合与精灵组合之间的碰撞检测函数
hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
for hit in hits:
# 添加分数
score += 50 - hit.radius
# 播放爆炸音效
random.choice(expl_sounds).play()
# 产生爆炸效果
exp1 = Explosion(hit.rect.center, 'lg')
# 将爆炸效果添加到精灵组合中
all_sprites.add(exp1)
# 随机产生相应奖励
if random.random() > 0.9:
pow = Pow(hit.rect.center)
all_sprites.add(pow)
powerups.add(pow)
# 产生新的陨石
newmob()
# 飞机与陨石的碰撞
hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
# 飞机减少生命值
player.sheild -= hit.radius * 2
# 产生爆炸效果 陨石
expl = Explosion(hit.rect.center, 'sm')
all_sprites.add(expl)
# 产生新的陨石
newmob()
# 判断飞机的生命值是否小于等于0
if player.sheild <= 0:
# 播放飞机去世音效
player_die_sound.play()
# 飞机爆炸效果
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
# 飞机隐身效果
player.hide()
# 飞机的生命-1
player.lives -= 1
# 重新设置飞机的生命值100
player.sheild = 100
# 飞机与奖励的碰撞
hits = pygame.sprite.spritecollide(player, powerups, True)
for hit in hits:
# 火力值奖励
if hit.type == 'shield':
player.powerup()
# 生命值(盾)奖励
if hit.type == 'dun':
player.sheild += random.randrange(10, 30)
if player.sheild >= 100:
player.sheild = 100
# 判断飞机的生命是否为0 同时 飞机爆炸动画结束
if player.lives == 0 and not death_explosion.alive():
# 设置游戏状态为False
running = False
# 刷新屏幕
# 将游戏屏幕填充为黑色
screen.fill(BLACK)
# 设置游戏运行背景图片
screen.blit(background, background_rect)
# 绘制精灵到屏幕中
all_sprites.draw(screen)
# 绘制分数
draw_text(screen, str(score), 18, WIDTH/2, 10)
# 绘制生命条
draw_shield_bar(screen, 5, 5, player.sheild)
# 绘制小飞机
draw_lives(screen, WIDTH-100, 5, player.lives, player_mini_img)
pygame.display.flip()