本节最终效果:
如果我们希望方块挂了之后,游戏可以重新来过,可以这样做,修改Game类的update方法:
如果方块跌落到屏幕之外,为了让体验更好,整个屏幕上滚,然后将所有方块干掉。如果1个档板都没有了,游戏结束,然后run()本次运行结束,下一轮主循环进来时,new()重新初始化,所有sprite实例重新初始化,满血复活。
for sprite in self.all_sprites: sprite.rect.y -= max(self.player.vel.y, 10)
这里的重点是:
1.update方法每一帧都执行,每个挡板的y值不断减小(相当于屏幕向上滚动)
2.self.player.vel.y的值在重力加速度的作用下不断变大
游戏得分
再来讨论另一个问题:游戏得分。 每跳一级,应该给于玩家一定的奖励(比如:得分),然后在屏幕上显示出来。
先定义一个显示文字的函数:(main.py中)
def draw(self): # Game Loop - draw self.screen.fill(BLACK) self.all_sprites.draw(self.screen) self.draw_text(str(self.score), 22, WHITE, WIDTH / 2, 15) # *after* drawing everything, flip the display pg.display.flip()
self.font_name在初始化时指定:
为了方便调整,可以在settings.py中定义字体名:
image.png
得分值score在new()中初始化:(main.py中)
image.png
跳跃过程中,屏幕会下滚(包括所有档板),如果档板下移到屏幕外,得分+10(注:不能在方块与档板碰撞时+分,不然如果方块跳上一块档板,再跳下来,再跳上去,反复上下跳,可以不断刷得分)
image.png
最后main.py中的draw函数中,实时显示得分:
image.png
sprites.py
image.png
完整代码:
settings.py
# game options/settings TITLE = "Jumpy!" WIDTH = 480 HEIGHT = 600 FPS = 60 FONT_NAME = 'arial' # Player properties PLAYER_ACC = 0.5 PLAYER_FRICTION = -0.12 PLAYER_GRAV = 0.8 PLAYER_JUMP = 20 # Starting platforms PLATFORM_LIST = [(0, HEIGHT - 40, WIDTH, 40), (WIDTH / 2 - 50, HEIGHT * 3 / 4, 100, 20), (125, HEIGHT - 350, 100, 20), (350, 200, 100, 20), (175, 100, 50, 20)] # 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) LIGHTBLUE = (0, 155, 155)
main.py
import pygame as pg import random from settings import * from sprites import * class Game: def __init__(self): # initialize game window, etc pg.init() pg.mixer.init() self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() self.running = True self.font_name = pg.font.match_font(FONT_NAME) def new(self): # start a new game self.score = 0 self.all_sprites = pg.sprite.Group() self.platforms = pg.sprite.Group() self.player = Player(self) self.all_sprites.add(self.player) for plat in PLATFORM_LIST: p = Platform(*plat) self.all_sprites.add(p) self.platforms.add(p) self.run() def run(self): # Game Loop self.playing = True while self.playing: self.clock.tick(FPS) self.events() self.update() self.draw() def update(self): # Game Loop - Update self.all_sprites.update() # check if player hits a platform - only if falling if self.player.vel.y > 0: hits = pg.sprite.spritecollide(self.player, self.platforms, False) if hits: self.player.pos.y = hits[0].rect.top self.player.vel.y = 0 # if player reaches top 1/4 of screen if self.player.rect.top <= HEIGHT / 4: self.player.pos.y += abs(self.player.vel.y) for plat in self.platforms: plat.rect.y += abs(self.player.vel.y) if plat.rect.top >= HEIGHT: plat.kill() self.score += 10 # Die! if self.player.rect.bottom > HEIGHT: for sprite in self.all_sprites: sprite.rect.y -= max(self.player.vel.y, 10) if sprite.rect.bottom < 0: sprite.kill() if len(self.platforms) == 0: self.playing = False # spawn new platforms to keep same average number while len(self.platforms) < 6: width = random.randrange(50, 100) p = Platform(random.randrange(0, WIDTH - width), random.randrange(-75, -30), width, 20) self.platforms.add(p) self.all_sprites.add(p) def events(self): # Game Loop - events for event in pg.event.get(): # check for closing window if event.type == pg.QUIT: if self.playing: self.playing = False self.running = False if event.type == pg.KEYDOWN: if event.key == pg.K_SPACE: self.player.jump() def draw(self): # Game Loop - draw self.screen.fill(BLACK) self.all_sprites.draw(self.screen) self.draw_text(str(self.score), 22, WHITE, WIDTH / 2, 15) # *after* drawing everything, flip the display pg.display.flip() def show_start_screen(self): # game splash/start screen pass def show_go_screen(self): # game over/continue pass def draw_text(self, text, size, color, x, y): font = pg.font.Font(self.font_name, size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() text_rect.midtop = (x, y) self.screen.blit(text_surface, text_rect) g = Game() g.show_start_screen() while g.running: g.new() g.show_go_screen() pg.quit()
sprites.py
# Sprite classes for platform game import pygame as pg from settings import * vec = pg.math.Vector2 class Player(pg.sprite.Sprite): def __init__(self, game): pg.sprite.Sprite.__init__(self) self.game = game self.image = pg.Surface((30, 40)) self.image.fill(YELLOW) self.rect = self.image.get_rect() self.rect.center = (WIDTH / 2, HEIGHT / 2) self.pos = vec(WIDTH / 2, HEIGHT / 2) self.vel = vec(0, 0) self.acc = vec(0, 0) def jump(self): # jump only if standing on a platform self.rect.x += 1 hits = pg.sprite.spritecollide(self, self.game.platforms, False) self.rect.x -= 1 if hits: self.vel.y = -PLAYER_JUMP def update(self): self.acc = vec(0, PLAYER_GRAV) keys = pg.key.get_pressed() if keys[pg.K_LEFT]: self.acc.x = -PLAYER_ACC if keys[pg.K_RIGHT]: self.acc.x = PLAYER_ACC # apply friction self.acc.x += self.vel.x * PLAYER_FRICTION # equations of motion self.vel += self.acc self.pos += self.vel + 0.5 * self.acc # wrap around the sides of the screen if self.pos.x > WIDTH: self.pos.x = 0 if self.pos.x < 0: self.pos.x = WIDTH self.rect.midbottom = self.pos class Platform(pg.sprite.Sprite): def __init__(self, x, y, w, h): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((w, h)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y