当前位置:网站首页>太空射击第17课: Game Over (結束)
太空射击第17课: Game Over (結束)
2022-07-29 06:02:00 【acktomas】
太空射击第17课: Game Over (結束)
这是我们“Shmup”项目的第14部分。如果您尚未通读前面的部分,请从第 1 部分开始。在本课中,我们将通过添加“游戏结束”屏幕和再次玩游戏的功能来完成游戏。
视频
您可以在此处观看本课程的视频:
游戏结束
现在,当我们的玩家耗尽生命时,程序会突然结束。这不是很友好,所以我们将制作一个“游戏结束”屏幕,并允许玩家根据需要再次玩游戏。
游戏结束的原因是我们的游戏循环由running标志控制(running标志是一个变量,可以是真或假),我们设置running为False玩家死亡时。相反,我们想要跟踪游戏所处的状态(显示游戏结束或正在播放),我们将创建一个名为game_over 的标志,并将其添加到游戏循环的顶部:
# Game loop
game_over = True
running = True
while running:
if game_over:
show_go_screen()
我们稍后会定义show_go_screen(),但我们还需要考虑其他事情。当游戏结束时,我们通过屏幕进入游戏,如果玩家选择再次玩,我们需要重置所有内容 - 分数,流星,玩家的生命值等。现在,我们在游戏循环开始之前设置了这些内容,但现在我们将将它们移动到show_go_screen()之后,以便每当玩家退出该屏幕时,它们就会发生:
# Game loop
game_over = True
running = True
while running:
if game_over:
show_go_screen()
game_over = False
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
bullets = pygame.sprite.Group()
powerups = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
newmob()
score = 0
我们开始设置game_over为False,因为我们要开始一个新的游戏。然后,我们可以改变当玩家耗尽生命时发生的事情:
# if the player died and the explosion has finished playing
if player.lives == 0 and not death_explosion.alive():
game_over = True
游戏结束屏幕
现在我们只需要定义show_go_screen做些什么。由于对于此示例,我们只做一个“屏幕”,因此我们只使用游戏的标题,并放置一些有关如何玩游戏的漂亮说明:
def show_go_screen():
screen.blit(background, background_rect)
draw_text(screen, "SHMUP!", 64, WIDTH / 2, HEIGHT / 4)
draw_text(screen, "Arrow keys move, Space to fire", 22,
WIDTH / 2, HEIGHT / 2)
draw_text(screen, "Press a key to begin", 18, WIDTH / 2, HEIGHT * 3 / 4)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
waiting = False
末尾的 while 循环是我们如何处理“按一个键开始”部分。这有点像一个微型游戏循环,但我们所做的只是检查事件。我们唯一关心的事件是pygame.QUIT ,单击窗口上的 X 时会发生 ,以及按键时发生的事件。你有没有注意到我们没有使用'pygame.KEYDOWN'?
使用KEYUP代替的原因是,当玩家仍然按住一个键时,我们不会启动游戏。他们必须点击并释放才能继续。
这是在屏幕上玩游戏的一种非常简单的方法。还有许多其他方法来处理它,但我们将在后面的教程中讨论这些方法。
结束语
我们有它,你的第一个完整的Pygame游戏!如果你已经坚持了所有这些步骤,那么你就走上了成为一名游戏程序员的道路。
显然,我们可以添加更多内容,例如:
- 难度增加
- 更多道具
- 敌人(反击!)
- 高分制
- 老板级别
您可能还可以想到其他想法。但是,出于本视频的目的,我们将称此游戏完成。在以后的课程中,我们将介绍其他技术,然后您可以返回并将其应用于Shmup。
您可以在此处查看我们所做的其他课程:KidsCanCode 课程和教程
感谢您阅读/观看这些课程!非常感谢您的支持,问题和意见。
此部分的完整代码
# KidsCanCode - Game Development with Pygame video series
# Shmup game - part 14
# Video link: https://www.youtube.com/watch?v=Z2K2Yttvr5g
# Game Over Screen
# Frozen Jam by tgfcoder <https://twitter.com/tgfcoder> licensed under CC-BY-3
# Art from Kenney.nl
import pygame
import random
from os import path
img_dir = path.join(path.dirname(__file__), 'img')
snd_dir = path.join(path.dirname(__file__), 'snd')
WIDTH = 480
HEIGHT = 600
FPS = 60
POWERUP_TIME = 5000
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!")
clock = pygame.time.Clock()
font_name = pygame.font.match_font('arial')
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)
def newmob():
m = Mob()
all_sprites.add(m)
mobs.add(m)
def draw_shield_bar(surf, x, y, pct):
if pct < 0:
pct = 0
BAR_LENGTH = 100
BAR_HEIGHT = 10
fill = (pct / 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):
img_rect = img.get_rect()
img_rect.x = x + 30 * i
img_rect.y = y
surf.blit(img, img_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()
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
self.shield = 100
self.shoot_delay = 250
self.last_shot = pygame.time.get_ticks()
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
self.power = 1
self.power_time = pygame.time.get_ticks()
def update(self):
# timeout for powerups
if self.power >= 2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME:
self.power -= 1
self.power_time = pygame.time.get_ticks()
# unhide if hidden
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
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 = -8
if keystate[pygame.K_RIGHT]:
self.speedx = 8
if keystate[pygame.K_SPACE]:
self.shoot()
self.rect.x += self.speedx
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
def powerup(self):
self.power += 1
self.power_time = pygame.time.get_ticks()
def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
self.last_shot = now
if self.power == 1:
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
shoot_sound.play()
if self.power >= 2:
bullet1 = Bullet(self.rect.left, self.rect.centery)
bullet2 = Bullet(self.rect.right, self.rect.centery)
all_sprites.add(bullet1)
all_sprites.add(bullet2)
bullets.add(bullet1)
bullets.add(bullet2)
shoot_sound.play()
def hide(self):
# hide the player temporarily
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image_orig = random.choice(meteor_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 * .85 / 2)
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.bottom = random.randrange(-80, -20)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
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
new_image = pygame.transform.rotate(self.image_orig, self.rot)
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()
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -100 or self.rect.right > WIDTH + 100:
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.image.set_colorkey(BLACK)
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
# kill if it moves off the top of the screen
if self.rect.bottom < 0:
self.kill()
class Pow(pygame.sprite.Sprite):
def __init__(self, center):
pygame.sprite.Sprite.__init__(self)
self.type = random.choice(['shield', 'gun'])
self.image = powerup_images[self.type]
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.center = center
self.speedy = 5
def update(self):
self.rect.y += self.speedy
# kill if it moves off the top of the screen
if self.rect.top > HEIGHT:
self.kill()
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.last_update = pygame.time.get_ticks()
self.frame_rate = 75
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
def show_go_screen():
screen.blit(background, background_rect)
draw_text(screen, "SHMUP!", 64, WIDTH / 2, HEIGHT / 4)
draw_text(screen, "Arrow keys move, Space to fire", 22,
WIDTH / 2, HEIGHT / 2)
draw_text(screen, "Press a key to begin", 18, WIDTH / 2, HEIGHT * 3 / 4)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
waiting = False
# Load all game graphics
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()
player_mini_img = pygame.transform.scale(player_img, (25, 19))
player_mini_img.set_colorkey(BLACK)
bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert()
meteor_images = []
meteor_list = ['meteorBrown_big1.png', 'meteorBrown_med1.png', 'meteorBrown_med1.png',
'meteorBrown_med3.png', 'meteorBrown_small1.png', 'meteorBrown_small2.png',
'meteorBrown_tiny1.png']
for img in meteor_list:
meteor_images.append(pygame.image.load(path.join(img_dir, img)).convert())
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)
img_lg = pygame.transform.scale(img, (75, 75))
explosion_anim['lg'].append(img_lg)
img_sm = pygame.transform.scale(img, (32, 32))
explosion_anim['sm'].append(img_sm)
filename = 'sonicExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
explosion_anim['player'].append(img)
powerup_images = {
}
powerup_images['shield'] = pygame.image.load(path.join(img_dir, 'shield_gold.png')).convert()
powerup_images['gun'] = pygame.image.load(path.join(img_dir, 'bolt_gold.png')).convert()
# Load all game sounds
shoot_sound = pygame.mixer.Sound(path.join(snd_dir, 'pew.wav'))
shield_sound = pygame.mixer.Sound(path.join(snd_dir, 'pow4.wav'))
power_sound = pygame.mixer.Sound(path.join(snd_dir, 'pow5.wav'))
expl_sounds = []
for snd in ['expl3.wav', 'expl6.wav']:
expl_sounds.append(pygame.mixer.Sound(path.join(snd_dir, snd)))
player_die_sound = pygame.mixer.Sound(path.join(snd_dir, 'rumble1.ogg'))
pygame.mixer.music.load(path.join(snd_dir, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
pygame.mixer.music.set_volume(0.4)
pygame.mixer.music.play(loops=-1)
# Game loop
game_over = True
running = True
while running:
if game_over:
show_go_screen()
game_over = False
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
bullets = pygame.sprite.Group()
powerups = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
newmob()
score = 0
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
# Update
all_sprites.update()
# check to see if a bullet hit a mob
hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
for hit in hits:
score += 50 - hit.radius
random.choice(expl_sounds).play()
expl = Explosion(hit.rect.center, 'lg')
all_sprites.add(expl)
if random.random() > 0.9:
pow = Pow(hit.rect.center)
all_sprites.add(pow)
powerups.add(pow)
newmob()
# check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
player.shield -= hit.radius * 2
expl = Explosion(hit.rect.center, 'sm')
all_sprites.add(expl)
newmob()
if player.shield <= 0:
player_die_sound.play()
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.hide()
player.lives -= 1
player.shield = 100
# check to see if player hit a powerup
hits = pygame.sprite.spritecollide(player, powerups, True)
for hit in hits:
if hit.type == 'shield':
player.shield += random.randrange(10, 30)
shield_sound.play()
if player.shield >= 100:
player.shield = 100
if hit.type == 'gun':
player.powerup()
power_sound.play()
# if the player died and the explosion has finished playing
if player.lives == 0 and not death_explosion.alive():
game_over = True
# Draw / render
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.shield)
draw_lives(screen, WIDTH - 100, 5, player.lives, player_mini_img)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
边栏推荐
- Connecting PHP 7.4 to Oracle configuration on Windows
- vim文本编辑器的一些使用小技巧
- vscode通过remotessh结合xdebug远程调试php解决方案
- 阿里一面,给了几条SQL,问需要执行几次树搜索操作?
- IO stream - file - properties
- Flink实时仓库-DWD层(kafka-关联mysql的lookup join)模板代码
- 王树尧老师运筹学课程笔记 05 线性规划与单纯形法(概念、建模、标准型)
- 数据库持久化+JDBC数据库连接
- IDEA找不到Database解决方法
- ECCV 2022 lightweight model frame Parc net press apple mobilevit code and paper Download
猜你喜欢

城市花样精~侬好!DESIGN#可视化电台即将开播

【flask入门系列】Flask-SQLAlchemy的安装与配置

Teacher wangshuyao's operations research course notes 07 linear programming and simplex method (standard form, base, base solution, base feasible solution, feasible base)

IO stream - file - properties

我的创业邻居们

【论文阅读】TomoAlign: A novel approach to correcting sample motion and 3D CTF in CryoET

线程 - 线程安全 - 线程优化

吴恩达老师机器学习课程笔记 02 单变量线性回归

记 - 踩坑-实时数仓开发 - doris/pg/flink

LDAP brief description and unified authentication description
随机推荐
【技能积累】写邮件时的常用表达
MVFuseNet:Improving End-to-End Object Detection and Motion Forecasting through Multi-View Fusion of
Simulation volume leetcode [ordinary] 172. Zero after factorial
Actual combat! Talk about how to solve the deep paging problem of MySQL
Windows 上 php 7.4 连接 oracle 配置
1172. 餐盘栈 有序列表+栈
没那么简单的单例模式
Teacher Wu Enda machine learning course notes 05 octave tutorial
【C语言刷LeetCode】1054. 距离相等的条形码(M)
SS command details
网上传说软件测试培训真的那么黑心吗?都是骗局?
Unity免费元素特效推荐
mysql查询区分大小写
Overview of database system
Jetpack Compose 中的键盘处理
SDN topology discovery principle
游戏资产的革命
Implementation of DDP cluster distributed training under pytoch multi GPU conditions (brief introduction - from scratch)
王树尧老师运筹学课程笔记 01 导学与绪论
Salesforce中过滤器Filter使用的相对日期