配套视频教程
本节最终效果:
向上弹跳其实很简单,按下空格触发时,只要把y轴速度给一个向上的速度即可。
调用该方法,会使方块具有向上20px的速度,然后由于重力依然在起作用,所以二者结合,就会形成向上弹跳的效果。
main.py
sprites.py新增jump方法。
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 = -20
上面冲突检测的代码是保证只有站在挡板上才可以起跳,否则可以在空中连跳。
多加一些挡板
settings.py
main.py的new方法修改如下:
一个遗留问题
运行程序,发现一个问题:向上跳时,如果上方有档板,永远不可能跳过档板,只要一接近档板,就自动吸附上去了。
是因为main.py中,一直在检测碰撞,向上跳的过程中,如果头顶有档板,一碰到档板,代码逻辑就强制把方块固定在档板上了(即:认为方块落在档板上了)。改进方法:仅在下降过程中,才做碰撞检测,update方法修改如下:
相比之前,加了一个碰撞检测判断,如果不加这个条件,就会出现以下现象:
其他一些小改动
image.png
完整代码:
settings.py
# game options/settings TITLE = "Jumpy!" WIDTH = 480 HEIGHT = 600 FPS = 60 # Player properties PLAYER_ACC = 0.5 PLAYER_FRICTION = -0.12 PLAYER_GRAV = 0.8 # 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 def new(self): # start a new game 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 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) # *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 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 = -20 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