pygame的重力碰撞问题

时间:2017-08-13 21:45:53

标签: python pygame

在pygame中创建一个平台游戏,并使用向量进行重力和移动。现在我停留在与平台的冲突上,因为平台会撞到平台并几乎完全沉入平台,如下所示:

Player sunk into platform block

(编辑)人们想要更多的代码信息......

主类:

import pygame as pg
import sys

from sprites import *

class Game:

    def __init__(self):
        pg.init()
        pg.mixer.init()
        pg.display.set_caption(TITLE)
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        self.clock = pg.time.Clock()
        self.running = True
        self.load_data()
        self.new_game()

    def load_data(self):
        # Eventually will load data
        pass

    def new_game(self):
        # Creates new instances of all of the sprites
        # groups and re-renders sprites at starting locations
        self.all_sprites = pg.sprite.Group()
        self.platform_sprites = pg.sprite.Group()
        self.player = Player(self, 60, 60)

        # Creates some test platforms
        for x in range(10):
            Platform(self, x, 6)

    def run(self):
        # Basic game loop
        while self.running:
              self.dt = self.clock.tick(FPS) # Get time passed since last        update / Set FPS
            self.events()
            self.render()
            self.update()

    def events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.running = False
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    self.running = False
    # Check for quit event and close window

    def render(self):
        self.screen.fill(WHITE)
        self.all_sprites.draw(self.screen) # Draws all sprites to screen
        pg.display.flip() # updates screen

    def update(self):
        self.all_sprites.update() # calls the update function of all of the sprites

if __name__ == '__main__':
    g = Game()
    while g.running:
        g.run()
    pg.quit()
    sys.exit()

....播放器和平台精灵代码:

import pygame as pg

from constants import *
vec = pg.math.Vector2


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        self.game = game
        super().__init__(self.groups)
        self.image = pg.Surface((40, 70))
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        pg.draw.rect(self.image, BLACK, (0, 0, self.rect.width, self.rect.height), 3)

        self.pos = vec(x, y)
        self.vel = vec(0, 0)
        self.acc = vec(0, 0)

    def move(self):

        self.acc = vec(0, 0)
        keypress = pg.key.get_pressed()
        if keypress[pg.K_a]:
            self.acc.x += -PLAYER_MOVE_SPEED
        if keypress[pg.K_d]:
            self.acc.x += PLAYER_MOVE_SPEED

        self.acc += self.vel * PLAYER_FRICTION
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc
        self.rect.midbottom = self.pos

    def collisions(self, axis):
        if axis == 'y':
            for plat in self.game.platform_sprites:
                if self.acc.y > 0:
                    if pg.Rect.colliderect(self.rect, plat.rect):
                        self.acc.y = 0
                        self.pos.y = plat.rect.top

    def update(self):
        self.move()
        self.collisions('y')



class Platform(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.platform_sprites
        self.game = game
        super().__init__(self.groups)
        self.image = pg.Surface((TILESIZE, TILESIZE))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.x = x * TILESIZE
        self.y = y * TILESIZE

    def update(self):
        self.rect.x = self.x
        self.rect.y = self.y

“常量”文件仅包含定义的屏幕大小,颜色和播放器速度等内容。如果有任何需要,我会加上它。

1 个答案:

答案 0 :(得分:0)

Player.collisions中:

if self.acc.y > 0:
    if pg.Rect.colliderect(self.rect, plat.rect):
        self.acc.y = 0
        self.pos.y = plat.rect.top
  1. 您遇到问题的主要原因是玩家的速度:

    您正在重置垂直加速度(acc.y)和位置(pos.y),但似乎您忘记了垂直速度(vel.y)。 玩家下沉是因为它仍然具有向下的速度,您可以使用self.vel.y = 0对此进行补救。

  2. 另一个更小的问题可能是@LarryMcMuffin正确猜测的,在您的移动/绘图之间存在订购问题:

    您可能正确地更新了Player.pos.y,因此玩家可以完美地站在平台上,但是如果您想绘制角色,还需要更新self.rect.midbottom 处于新位置-您可以执行此操作,但是位于Player.move中,该位置称为之前。您可以重新排列移动/碰撞功能的顺序,但是我的建议是将self.rect.midbottom = self.posPlayer.move移动到Player.update的最后。

最终结果:

def collisions(self, axis):
    if axis == 'y':
        for plat in self.game.platform_sprites:
            if self.acc.y > 0:
                if pg.Rect.colliderect(self.rect, plat.rect):
                    self.acc.y = 0
                    self.vel.y = 0
                    self.pos.y = plat.rect.top

def update(self):
    self.move()
    self.collisions('y')
    self.rect.midbottom = self.pos

我想指出的另一件事,即使它可能与您所描述的问题无关: 使用时间增量

看,您有两个影响角色位置的值:

  • 速度(vel):表示位置随时间变化
  • 加速度(acc):表示速度随时间变化

这里的超时是关键-由于两次move调用之间经过的时间是可变的,因此很重要:随着时间的流逝,速度应该更多/更少的位置。幸运的是,您将在 Game.dt 中保存两个帧/更新之间的时间。将其传递给您的播放器并大致使用它,就像这样:

self.acc += self.vel * PLAYER_FRICTION
self.vel += self.acc * dt
self.pos += (self.vel + 0.5 * self.acc) * dt

它无法完全解决问题,因此两次 dt = 0.5 的调用会产生与一次一次 dt = 1 的调用相同的效果,但是它将“填充”差距”。我认为,如果不以固定间隔更新物理原理,或者诉诸昂贵且复杂的计算(使用 power 函数),就无法实现这一目标。