经过前面九篇文章的编写,「跳跳兔」游戏基本已经被编写出来了,本节在此基础上进一步完善它,并添加上云彩背景。python
添加云彩背景的大体步骤以下。git
一步步来编写,首先是建立云彩类,代码以下。github
# sprites.py
class Cloud(pg.sprite.Sprite):
def __init__(self, game):
self._layer = CLOUD_LAYER
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = random.choice(self.game.cloud_images)
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
# 随机出现位置
scale = random.randrange(50, 101) / 100
self.image = pg.transform.scale(self.image, (int(self.rect.width * scale),
int(self.rect.height * scale)))
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-500, -50)
def update(self):
# 云朵大于2倍高度,就被消除
if self.rect.top > HEIGHT * 2:
self.kill()
复制代码
代码内容与此前内容很是相似,再也不详细分析。算法
但你仔细观察,你会发现,Cloud类的__init__()方法中建立了 self._layer,并经过以下形式将其加入到相应的groups中。app
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
复制代码
这是一个优化点,后文再讨论。dom
构建了Cloud类后,接着要作的就是载入图片、随机生成以及同步移动了,轻车熟路。ide
# main.py/Game
def load_data(self): # 加载数据
# ... 省略无关代码
# 加载云彩图片
self.cloud_images = []
for i in range(1, 4):
self.cloud_images.append(pg.image.load(os.path.join(img_dir, 'cloud{}.png'.format(i))).convert())
def new(self):
self.score = 0
# ... 省略无关代码
# 建立云彩
for i in range(8):
c = Cloud(self)
c.rect.y += 500
self.run()
def update(self):
# 玩家到达游戏框 1/4 处时(注意,游戏框,头部为0,底部为游戏框长度,到到游戏框的1/4处,表示已经到达了顶部一部分了)
if self.player.rect.top <= HEIGHT / 4:
# 玩家位置移动(往下移动)
self.player.pos.y += max(abs(self.player.vel.y), 2)
# 随机生成新云朵
if random.randrange(100) < 10:
Cloud(self)
# 云彩同步移动
for cloud in self.clouds:
cloud.rect.y += max(abs(self.player.vel.y / 2), 2)
# 敌人位置同步往下移动
for mob in self.mobs:
mob.rect.y += max(abs(self.player.vel.y), 2)
# 平台在游戏框外时,将其注销,避免资源浪费
for plat in self.platforms:
# 平台移动位置(往下移动,移动的距离与玩家相同,这样玩家才能依旧站立在本来的平台上)
plat.rect.y += max(abs(self.player.vel.y), 2)
if plat.rect.top >= HEIGHT:
plat.kill()
# 分数增长 - 平台销毁,分数相加
self.score += 10
复制代码
woo~,搞定,若是有疑惑,能够拉下github代码对照着看。学习
云彩类添加完了,接着来进行一些优化。优化
首先,对碰撞检测的优化,若是你仔细观察,你会发现,玩家对象与敌人对象的本体尚未接触到,就触发了碰撞检测,游戏就结束了,形成这种现象的缘由是,玩家也好、敌人也好,游戏中的任何元素都是一个对应大小的长方形,碰撞检测默认形式就是对这两个方块进行检测,此时两个元素自己可能没有接触,但对应的方块接触到了,因此触发了碰撞检测。spa
为了不这种状况,能够利用pygame的蒙版机制mask,为Player、Mob都建立相应的蒙版,具体作法以下。
# sprites.py
class Player(pg.sprite.Sprite):
def animate(self):
# ... 省略无关代码
self.mask = pg.mask.from_surface(self.image) # 建立蒙版
class Mob(pg.sprite.Sprite):
def update(self):
# ... 省略无关代码
self.rect = self.image.get_rect()
self.mask = pg.mask.from_surface(self.image) # 建立蒙版
self.rect.center = center
# ... 省略无关代码
复制代码
检测时,加上pygame.sprite.collide_mask回调则可
def update(self):
# ... 省略无关代码
# 碰撞检测 - 若是碰撞到了敌人,游戏结束
mob_hits = pg.sprite.spritecollide(self.player, self.mobs, False, pg.sprite.collide_mask)
if mob_hits:
self.playing = False
复制代码
此外还有个须要优化的问题,就是元素图层关系,增长云彩对象后,图层关系的问题显得明显,云彩做为背景却会遮挡玩家对象、敌人对象、平台对象等,这是不合理的,不一样元素应该在不一样图层,从而合理的显示出来。
首先定义好不一样元素要出现的图层。
# settings.py
# 不一样元素在不一样层
PLAYER_LAYER = 2 # 玩家
PLATFORM_LAYER = 1 # 平台
POW_LAYER = 1 # 道具
MOB_LAYER = 2 # 敌人
CLOUD_LAYER = 0 # 云
复制代码
而后为不一样的元素对象都添加上设置图层的逻辑
#Sprite.py
class Player(pg.sprite.Sprite):
def __init__(self, game):
self._layer = PLAYER_LAYER # 对应的图层
self.groups = game.all_sprites # 所在的组
pg.sprite.Sprite.__init__(self, self.groups) # 添加、实例化
# ... 省略无关代码
class Platform(pg.sprite.Sprite):
def __init__(self, game, x, y):
self._layer = PLATFORM_LAYER # 对应的图层
self.groups = game.all_sprites, game.platforms # 所在的组
pg.sprite.Sprite.__init__(self, self.groups) # 添加、实例化
# ... 省略无关代码
class Pow(pg.sprite.Sprite):
def __init__(self, game, plat):
self._layer = POW_LAYER
self.groups = game.all_sprites, game.powerups
pg.sprite.Sprite.__init__(self, self.groups)
# ... 省略无关代码
class Mob(pg.sprite.Sprite):
def __init__(self, game):
self._layer = MOB_LAYER
self.groups = game.all_sprites, game.mobs
pg.sprite.Sprite.__init__(self, self.groups)
# ... 省略无关代码
class Cloud(pg.sprite.Sprite):
def __init__(self, game):
self._layer = CLOUD_LAYER
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
# ... 省略无关代码
复制代码
优化后,再修改一个Game类的new()方法,使用pygame.sprite.LayeredUpdates()来实例化all_sprites对象。
LayeredUpdates(分层更新)是一个精灵组,它能够处理图层并顺序绘制元素。
# main.py
class Game:
def new(self):
self.score = 0
# self.all_sprites = pg.sprite.Group()
# 层次添加,避免元素重叠显示(如背景云遮挡住平台与玩家)
self.all_sprites = pg.sprite.LayeredUpdates()
self.platforms = pg.sprite.Group()
self.powerups = pg.sprite.Group() # 急速飞跃道具
self.mobs = pg.sprite.Group() # 敌人对象
self.clouds = pg.sprite.Group() # 云彩对象
self.player = Player(self)
self.all_sprites.add(self.player)
for plat in PLATFORM_LIST:
p = Platform(self, *plat)
# self.all_sprites.add(p)
# self.platforms.add(p)
self.mob_timer = 0
# 游戏的背景音乐
pg.mixer.music.load(os.path.join(self.snd_dir, 'Happy Tune.ogg'))
# 建立云彩
for i in range(8):
c = Cloud(self)
c.rect.y += 500
self.run()
复制代码
最终效果以下。
「跳跳兔」至此开发完啦,Pygame系列的文章也暂时告一段落啦。
「跳跳兔」代码github:github.com/ayuLiao/jum…
Pygame还有不少有趣的功能在「跳跳兔」游戏中并无体现出来。
正如本系列第一篇文章所说,这些文章只是学习笔记,此外还有下面两个游戏的学习笔记,一个是打飞机、一个是RPG打僵尸游戏。
若是你们感兴趣,记得告诉我,我才有动力继续分享,后面按我的计划应该会以漫画形式分享算法、计算机基础方面的东西,但愿喜欢。
最后,再次声明一下,学习内容来自:kidscancode.org/,游戏并非自主原创的…
若是文章对你有所帮助,请点「在看」给做者一点鼓励,叩谢豪恩。