pygame教程
- 安装pygame
- Game Development 1-1: Getting Started with Pygame
- Game Development 1-2: Working with Sprites
- Game Development 1-3: More About Sprites
- Pygame Shmup Part 1: Player Sprite and Controls
- Pygame Shmup Part 2: Enemy Sprites
- Pygame Shmup Part 3: Collisions (and Bullets!)
- Pygame Shmup Part 4: Adding Graphics
- Pygame Shmup Part 5: Improved Collisions
- Pygame Shmup Part 6: Sprite Animation(精灵动画)
- Pygame Shmup Part 7: Score (and Drawing Text)
- Pygame Shmup Part 8: Sound and Music
安装pygame
坑:如果使用虚拟解释器中的pygame模块,可能会产生没有提示的副作用
Game Development 1-1: Getting Started with Pygame
游戏主体是一个大循环主要分为三个部分:
处理输入(鼠标键盘事件等等),更新游戏(更新位置坐标,速度属性等)和渲染屏幕(更新屏幕上的图像).
绘制图像就像一个板,我们在后面画上我们要画的东西,然后立刻反转板子,东西就呈现出来了.如此循环往复
import pygame
import random
from pygame.locals import *
# 定义初始屏幕大小和游戏帧率
WIDTH = 360
HEIGHT = 480
FPS = 30
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game") # 设置标题
clock = pygame.time.Clock()
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
# 3.渲染绘图
screen.fill(BLACK)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Game Development 1-2: Working with Sprites
精灵就是一个对象,如果绘制每个精灵还要更新的话就会很耗时,因此引入了精灵组
坐标原点在左上角
import pygame
import random
from pygame.locals import *
# 定义初始屏幕大小和游戏帧率
WIDTH = 880
HEIGHT = 600
FPS = 30
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 定义玩家类
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50,50))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.center = (WIDTH/2, HEIGHT/2)
def update(self):
self.rect.x += 5
if self.rect.left > WIDTH:
self.rect.right = 0
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game") # 设置标题
clock = pygame.time.Clock()
# 创建一个装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
all_sprites.update()
# 3.渲染绘图
screen.fill(BLACK)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Game Development 1-3: More About Sprites
开源游戏素材:https://opengameart.org/
搜索Kenny ke
import pygame
import random
import os
from pygame.locals import *
# 定义初始屏幕大小和游戏帧率
WIDTH = 880
HEIGHT = 600
FPS = 30
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 设置assets文件夹(游戏素材)
# E:\xiangyun\代码\AlienBattle\img\sinkar birber.png
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "img")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# 添加路径并把图像转换为透明
self.image = pygame.image.load(os.path.join(img_folder,"sinkar birber.png")).convert_alpha()
# self.image.set_colorkey(BLACK) 把黑色部分转换为透明
self.rect = self.image.get_rect()
self.rect.center = (WIDTH/2, HEIGHT/2)
self.y_speed = 5
def update(self):
self.rect.x += 1
# 使角色看起来上下跳跃
self.rect.y += self.y_speed
if self.rect.bottom > HEIGHT - 200:
self.y_speed = -5
if self.rect.top < 200:
self.y_speed = 5
if self.rect.left > WIDTH:
self.rect.right = 0
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game") # 设置标题
clock = pygame.time.Clock()
# 创建一个装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
all_sprites.update()
# 3.渲染绘图
screen.fill(BLUE)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Pygame Shmup Part 1: Player Sprite and Controls
shoot em up
"""Shump Game"""
import pygame
import random
from pygame.locals import *
# 定义初始屏幕大小和游戏帧率
WIDTH = 480
HEIGHT = 600
# 射击游戏需要高帧率
FPS = 60
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!") # 设置标题
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
def update(self):
# 加入按键控制
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT] or keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_RIGHT] or keystate[pygame.K_d] :
self.speedx = 5
self.rect.x += self.speedx
# 边界约束
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
# 创建一个装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
all_sprites.update()
# 3.渲染绘图
screen.fill(BLACK)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Pygame Shmup Part 2: Enemy Sprites
"""Shump Game"""
import pygame
import random
from pygame.locals import *
# 定义初始屏幕大小和游戏帧率
WIDTH = 480
HEIGHT = 600
# 射击游戏需要高帧率
FPS = 60
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!") # 设置标题
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
def update(self):
# 加入按键控制
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT] or keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_RIGHT] or keystate[pygame.K_d] :
self.speedx = 5
self.rect.x += self.speedx
# 边界约束
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
# 创建敌方类
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 40))
self.image.fill(RED)
self.rect = self.image.get_rect()
# 设置敌方的出生位置,要在屏幕外面,这样才显得不突兀
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
def update(self, *args):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right>WIDTH+25:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
# 创建装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
# 创建敌方精灵组
mobs = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Mob()
all_sprites.add(m)
mobs.add(m)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
all_sprites.update()
# 3.渲染绘图
screen.fill(BLACK)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Pygame Shmup Part 3: Collisions (and Bullets!)
精灵碰撞检测:检查一个精灵和其他精灵组的碰撞,返回值是一个列表,列表中是和这个精灵发生碰撞的精灵组中的精灵…
dokill是个布尔值,如果设置为真,则所有发生碰撞的精灵组精灵将会移除.
collided是遮罩用于碰撞检测,默认矩形
精灵组碰撞:检测两组精灵组的碰撞,返回一个字典,字典的Key是第一组里面发生碰撞的精灵,而value是第二组中碰撞的精灵.
dokill指的是否消除碰撞精灵
# 检查碰撞
# 检查是否子弹击中敌方
dics = pygame.sprite.groupcollide(bullets, mobs, True, True)
for dic in dics:
m = Mob()
all_sprites.add(m)
mobs.add(m)
# if dic:
# print(dic)
hits = pygame.sprite.spritecollide(player, mobs, False)
if hits:
running = False
Pygame Shmup Part 4: Adding Graphics
"""
Shump Game
添加了图片,代替小方块(缩放, 加载, 转换)
"""
import pygame
import random
from os import path
from pygame.locals import *
img_dir = path.join(path.dirname(__file__), "img")
# 定义初始屏幕大小和游戏帧率
WIDTH = 480
HEIGHT = 600
# 射击游戏需要高帧率
FPS = 60
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!") # 设置标题
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(player_img, (50, 38))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
# 定义玩家射击方法
def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
def update(self):
# 加入按键控制
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT] or keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_RIGHT] or keystate[pygame.K_d] :
self.speedx = 5
self.rect.x += self.speedx
# 边界约束
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
# 创建敌方类
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = meteor_img
self.rect = self.image.get_rect()
# 设置敌方的出生位置,要在屏幕外面,这样才显得不突兀
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
def update(self, *args):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right>WIDTH+25:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self, *args):
self.rect.y += self.speedy
# 如果飞出屏幕顶部则销毁
if self.rect.bottom < 0:
self.kill()
# 加载全部游戏图像
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_alpha()
meteor_img = pygame.image.load(path.join(img_dir, "meteorBrown_med1.png")).convert_alpha()
bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert_alpha()
# 创建装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
# 创建敌方精灵组
mobs = pygame.sprite.Group()
# 创建子弹精灵组
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Mob()
all_sprites.add(m)
mobs.add(m)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
# 2.更新update
all_sprites.update()
# 检查碰撞
# 检查是否子弹击中敌方
dics = pygame.sprite.groupcollide(bullets, mobs, True, True)
for dic in dics:
m = Mob()
all_sprites.add(m)
mobs.add(m)
# if dic:
# print(dic)
hits = pygame.sprite.spritecollide(player, mobs, False)
if hits:
running = False
# 3.渲染绘图
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Pygame Shmup Part 5: Improved Collisions
圆形碰撞遮罩更符合,可以设置radius实例属性,并
"""
Shump Game
添加圆形碰撞
"""
import pygame
import random
from os import path
from pygame.locals import *
img_dir = path.join(path.dirname(__file__), "img")
# 定义初始屏幕大小和游戏帧率
WIDTH = 480
HEIGHT = 600
# 射击游戏需要高帧率
FPS = 60
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!") # 设置标题
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(player_img, (50, 38))
self.rect = self.image.get_rect()
# 增加半径属性,可以绘制出⚪来显示范围
self.radius = 20
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
# 定义玩家射击方法
def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
def update(self):
# 加入按键控制
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT] or keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_RIGHT] or keystate[pygame.K_d] :
self.speedx = 5
self.rect.x += self.speedx
# 边界约束
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
# 创建敌方类
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = meteor_img
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * 0.85 / 2)
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
# 设置敌方的出生位置,要在屏幕外面,这样才显得不突兀
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
def update(self, *args):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right>WIDTH+25:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self, *args):
self.rect.y += self.speedy
# 如果飞出屏幕顶部则销毁
if self.rect.bottom < 0:
self.kill()
# 加载全部游戏图像
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_alpha()
meteor_img = pygame.image.load(path.join(img_dir, "meteorBrown_med1.png")).convert_alpha()
bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert_alpha()
# 创建装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
# 创建敌方精灵组
mobs = pygame.sprite.Group()
# 创建子弹精灵组
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Mob()
all_sprites.add(m)
mobs.add(m)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
# 2.更新update
all_sprites.update()
# 检查碰撞
# 检查是否子弹击中敌方
dics = pygame.sprite.groupcollide(bullets, mobs, True, True)
for dic in dics:
m = Mob()
all_sprites.add(m)
mobs.add(m)
# if dic:
# print(dic)
hits = pygame.sprite.spritecollide(player, mobs, False, pygame.sprite.collide_circle)
if hits:
running = False
# 3.渲染绘图
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
Pygame Shmup Part 6: Sprite Animation(精灵动画)
旋转,如果用以下代码,会因为位信息丢失的累加,让图像失真
# 设置精灵旋转度数,速率
self.rot = 0
self.rot_speed = random.randrange(-8, 8)
self.last_update = pygame.time.get_ticks()
def rotate(self):
now = pygame.time.get_ticks()
if now - self.last_update > 50:
self.last_update = now
self.rot = (self.rot + self.rot_speed) % 360
self.image = pygame.transform.rotate(self.image, self.rot) # 这一行会出问题
def update(self, *args):
self.rotate()
self.image = pygame.transform.rotate(self.image, self.rot) # 这一行会出问题
解决办法:
self.image = pygame.transform.rotate(self.image, self.rot) # 这一行会出问题
由于拷贝的是原始图像,将不会因为失真问题而导致程序崩溃
import pygame
import random
from os import path
from pygame.locals import *
img_dir = path.join(path.dirname(__file__), "img")
WIDTH = 360
HEIGHT = 480
FPS = 30
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
class Plane(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.orig = plane_img
self.image = self.orig
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT / 2
self.rot = 0
self.rot_speed = 1
self.last_update = pygame.time.get_ticks()
def update(self, *args):
now = pygame.time.get_ticks()
if now - self.last_update > 50:
self.last_update = now
self.rot = (self.rot + self.rot_speed) % 360
new_img = pygame.transform.rotate(self.orig, self.rot)
old_center = self.rect.center
self.image = new_img
self.rect = self.image.get_rect()
self.rect.center = old_center
# 初始化并创建游戏窗口
pygame.init()
pygame.mixer.init() # 如果需要混音声音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Test Game") # 设置标题
clock = pygame.time.Clock()
# 必须初始化之后才能加载
plane_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert()
# 创建一个装有所有精灵的精灵组
all_sprites = pygame.sprite.Group()
plane = Plane()
all_sprites.add(plane)
# 游戏循环
running = True
while running:
clock.tick(FPS)
# 1.处理输入
for event in pygame.event.get():
# 检查是否关闭窗口事件
if event.type == pygame.QUIT:
running = False
# 2.更新update
all_sprites.update()
# 3.渲染绘图
screen.fill(BLUE)
all_sprites.draw(screen)
# 画完了之后翻转显示
pygame.display.flip()
pygame.quit()
添加列表随机值,让陨石的图像随机出现
Pygame Shmup Part 7: Score (and Drawing Text)
Pygame Shmup Part 8: Sound and Music