所以我当时在做一个pygame平台游戏,却陷入了一件事情。我找不到找到使平台基础坚实的方法。玩家可以降落在它的顶部,但是当它试图穿过底部时,它会弹跳回去。我试过了,但是没用:
hits = pg.sprite.spritecollide(player, platforms, False) if hits: if player.pos.y == hits[0].rect.top: player.vel.y = 10 else: player.pos.y = hits[0].rect.top + 1 player.vel.y = 0
有人为我提供解决方案吗?这是完整的程序。
这是一个简短的平台游戏示例。机芯尤其重要。您必须首先沿x轴移动,检查播放器是否与墙壁碰撞,然后在发生碰撞时将其移回墙壁。然后,对y轴执行相同的操作。如果您不将机芯分为这两个部分,那么如果您同时按下多个机芯键,则玩家将跳到墙的侧面,顶部或底部。
import pygame as pg pg.init() WINDOW_WIDTH, WINDOW_HEIGHT = 800, 600 screen = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) GRAY = pg.Color('gray24') GRAVITY = 800 class Player(pg.sprite.Sprite): def __init__(self, pos, blocks): super().__init__() self.image = pg.Surface((30, 50)) self.image.fill(pg.Color(0, 110, 170)) self.rect = self.image.get_rect(topleft=pos) self.vel = pg.math.Vector2(0, 0) self.pos = pg.math.Vector2(pos) self.blocks = blocks self.on_ground = False def update(self, dt): # Move along x-axis. self.pos.x += self.vel.x * dt self.rect.x = self.pos.x collisions = pg.sprite.spritecollide(self, self.blocks, False) for block in collisions: # Horizontal collision occurred. if self.vel.x > 0: # Moving right. self.rect.right = block.rect.left # Reset the rect pos. elif self.vel.x < 0: # Moving left. self.rect.left = block.rect.right # Reset the rect pos. self.pos.x = self.rect.x # Update the actual x-position. # Move along y-axis. self.pos.y += self.vel.y * dt # +1 to check if we're on a platform each frame. self.rect.y = self.pos.y + 1 # Prevent air jumping when falling. if self.vel.y > 0: self.on_ground = False collisions = pg.sprite.spritecollide(self, self.blocks, False) for block in collisions: # Vertical collision occurred. if self.vel.y > 0: # Moving down. self.rect.bottom = block.rect.top # Reset the rect pos. self.vel.y = 0 # Stop falling. self.on_ground = True elif self.vel.y < 0: # Moving up. self.rect.top = block.rect.bottom # Reset the rect pos. self.vel.y = 0 # Stop jumping. self.pos.y = self.rect.y # Update the actual y-position. # Stop the player at screen bottom. if self.rect.bottom >= WINDOW_HEIGHT: self.vel.y = 0 self.rect.bottom = WINDOW_HEIGHT self.pos.y = self.rect.y self.on_ground = True else: self.vel.y += GRAVITY * dt # Gravity class Block(pg.sprite.Sprite): def __init__(self, rect): super().__init__() self.image = pg.Surface(rect.size) self.image.fill(pg.Color('paleturquoise2')) self.rect = rect def main(): clock = pg.time.Clock() done = False dt = 0 all_sprites = pg.sprite.Group() blocks = pg.sprite.Group() player = Player((300, 100), blocks) all_sprites.add(player) rects = ((300, 200, 30, 70), (100, 350, 270, 30), (500, 450, 30, 170), (400, 570, 270, 30), (500, 150, 70, 170), (535, 310, 270, 70)) for rect in rects: # Create the walls/platforms. block = Block(pg.Rect(rect)) all_sprites.add(block) blocks.add(block) while not done: for event in pg.event.get(): if event.type == pg.QUIT: done = True elif event.type == pg.KEYDOWN: if event.key == pg.K_a: player.vel.x = -220 elif event.key == pg.K_d: player.vel.x = 220 elif event.key == pg.K_w: # Jump if player.on_ground: player.vel.y = -470 player.pos.y -= 20 player.on_ground = False elif event.type == pg.KEYUP: if event.key == pg.K_a and player.vel.x < 0: player.vel.x = 0 elif event.key == pg.K_d and player.vel.x > 0: player.vel.x = 0 all_sprites.update(dt) screen.fill(GRAY) all_sprites.draw(screen) pg.display.flip() dt = clock.tick(60) / 1000 if __name__ == '__main__': main() pg.quit()
这是您在注释中发布的代码的有效版本(仅对于垂直碰撞,还需要添加水平碰撞)。因此,当玩家跳跃并与平台碰撞时,您必须将设置player.rect.top为platform.rect.bottom并更改vel.y。
player.rect.top
platform.rect.bottom
vel.y
import pygame as pg from pygame.math import Vector2 as vec pg.init() WIDTH, HEIGHT = 800, 600 YELLOW = pg.Color('yellow') GREEN = pg.Color('green') BLACK = pg.Color('gray11') screen = pg.display.set_mode((WIDTH,HEIGHT)) clock = pg.time.Clock() FPS = 60 PLAYER_FRICTION = .95 PLAYER_ACC = .2 class Player(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((30, 40)) self.image.fill(YELLOW) self.rect = self.image.get_rect(center=(WIDTH/2, HEIGHT-30)) self.pos = vec(WIDTH/2, HEIGHT/2) self.vel = vec(0,0) self.acc = vec(0,0) def jump(self): self.rect.y += 1 hits = pg.sprite.spritecollide(self, platforms, False) self.rect.y -= 1 if hits: self.vel.y = -13 def update(self): self.acc = vec(0, 0.5) keys = pg.key.get_pressed() if keys[pg.K_a]: self.acc.x = -PLAYER_ACC if keys[pg.K_d]: self.acc.x = PLAYER_ACC # apply friction self.vel.x *= PLAYER_FRICTION self.vel += self.acc self.pos += self.vel # 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(topleft=(x, y)) all_sprites = pg.sprite.Group() platforms = pg.sprite.Group() player = Player() all_sprites.add(player) # spawns and adds platforms to group p1 = Platform(0, HEIGHT - 40, WIDTH, 40) p2 = Platform(WIDTH / 2 - 50, HEIGHT - 300, 100, 20) p3 = Platform(WIDTH / 2 - 100, HEIGHT - 150, 200, 20) all_sprites.add(p1, p2, p3) platforms.add(p1, p2, p3) running = True while running: clock.tick(FPS) for event in pg.event.get(): if event.type == pg.QUIT: running = False if event.type == pg.KEYDOWN: if event.key == pg.K_SPACE: player.jump() all_sprites.update() # Check if we hit a wall/platform. hits = pg.sprite.spritecollide(player, platforms, False) for platform in hits: # Iterate over the collided platforms. if player.vel.y > 0: # We're falling. player.rect.bottom = platform.rect.top player.vel.y = 0 elif player.vel.y < 0: # We're jumping. player.rect.top = platform.rect.bottom player.vel.y = 3 player.pos.y = player.rect.bottom #Draw / render screen.fill(BLACK) all_sprites.draw(screen) pg.display.flip() pg.quit()
顺便说一句,在跳跃方法,你必须改变self.rect.y不self.rect.x。
self.rect.y
self.rect.x