pygame中奇怪的矢量运动

Posted

技术标签:

【中文标题】pygame中奇怪的矢量运动【英文标题】:Weird vector movement in pygame 【发布时间】:2022-01-24 01:56:31 【问题描述】:

由于某种原因,我的精灵的移动仅在按 A 时沿对角线向上和向左移动,在按 D 时沿对角线向下和向右移动,并且 W/S 只是不起作用,尽管给定了正确的向量以向任何方向移动。这是处理输入的地方:

class Operator:
    PLAYER = 'player'
    COMPUTER = 'computer'

    def __init__(self, type, AI=None):
        self.type = type
        self.AI = AI

    def handle(self, entity):
        keys = pygame.key.get_pressed()
        direction = Vector(0, 0)

        if self.type == Operator.PLAYER:
            if keys[pygame.K_w]:
                direction += Vector(0, -1)

            if keys[pygame.K_s]:
                direction += Vector(0, 1)

            if keys[pygame.K_a]:
                direction += Vector(-1, 0)

            if keys[pygame.K_d]:
                direction += Vector(1, 0)

        if direction:
            entity.move(direction)

        return bool(direction)

这里是相关的精灵代码:

class Sprite(pygame.sprite.Sprite):
    @property
    def x(self):
        return self._x_coordinate

    @x.setter
    def x(self, value):
        self._x_coordinate = self.rect.centerx = wrap(value,
                                                      WIDTH,
                                                      -self.width)

    @property
    def y(self):
        return self._y_coordinate

    @x.setter
    def y(self, value):
        self._y_coordinate = self.rect.centery = wrap(value,
                                                      HEIGHT,
                                                      -self.height)

    @property
    def position(self):
        return Vector(self.x, self.y)

    @position.setter
    def position(self, value: Vector):
        self.x, self.y = value

    @property
    def width(self):
        return self.rect.width

    @property
    def height(self):
        return self.rect.height

    def set_surface(self, surface):
        self.image = surface

class Entity(Sprite):
    @property
    def colliding(self):
        return pygame.sprite.spritecollide(self,
                                           sprites(self),
                                           False)

    @property
    def velocity(self):
        return self.internal_velocity + self.external_velocity

    @property
    def angle(self):
        return self.velocity.as_polar()[1]

    def __init__(self, size, position, operator=None, image=None, color='#FF4C4C'):
        super().__init__()

        if image:
            image = pygame.image.load(image)

        self.image = pygame.Surface(image.get_size() if image else size)
        self.rect = self.image.get_rect()

        self.position = position
        self.operator = operator
        self.internal_velocity = Vector(0, 0)
        self.external_velocity = Vector(0, 0)

        if not image:
            self.image.fill(color)
        else:
            self.image.blit(image, ORIGIN)

    def draw(self, surface):
        if camera.on_screen(self):
            surface.blit(self.image,
                         (self.x - self.width / 2, self.y - self.height / 2))

        if debugging:
            offset = Vector()
            offset.from_polar((20, self.angle))

            pygame.draw.line(surface,
                             '#54CE0E',
                             self.position,
                             self.position + offset,
                             1)

    def update(self):
        if self.operator and not self.operator.handle(self):
            self.internal_velocity *= FRICTION
            self.external_velocity *= FRICTION

        self.position += self.velocity

        if self.internal_velocity.x and 0.2 > self.internal_velocity.x > -0.2:
            self.internal_velocity.x = floor(self.internal_velocity.x)

        if self.internal_velocity.y and 0.2 > self.internal_velocity.y > -0.2:
            self.internal_velocity.y = floor(self.internal_velocity.y)

    def move(self, vector: Vector):
        self.internal_velocity += vector

        if self.internal_velocity.length() > MOVE_SPEED:
            self.internal_velocity.scale_to_length(MOVE_SPEED)

    def set_operator(self, operator):
        self.operator = operator

def wrap(number, maximum, minimum=0):
    return (number - minimum) % (maximum - minimum + 1) + minimum

def floor(number):
    if number > 0:
        return math.floor(number)
    elif not number:
        return 0
    else:
        return math.floor(abs(number)) * -1

我可以提供整个程序,但它有 350 多行,如果需要,请告诉我。

【问题讨论】:

Yeaaaaaaaah hmmmmm 可能不提供整个代码。你提供的已经很长了。我怀疑你不会发现很多人有兴趣浏览你的代码并为你调试它。你能尝试用更小的代码重现这个问题吗?请参阅minimal reproducible example 获取建议。 请修剪您的代码,以便更容易找到您的问题。请按照以下指南创建minimal reproducible example。 【参考方案1】:

Entiry.update 函数中似乎发生了一些奇怪的事情。

 if self.operator and not self.operator.handle(self):
      self.internal_velocity *= FRICTION
      self.external_velocity *= FRICTION

首先 self.operator 不是布尔值。其次,如果 x 和 y 值都非零,self.operator.handle 返回 true。这意味着仅在实体不移动时才应用摩擦,这没有任何意义。但是考虑到整个 if 语句的摩擦总是被应用,因为 self.operator 总是有一个值。但这一切只会改变规模而不是方向。

真正的问题似乎是错字,同样在更新功能中。我不知道这里发生了什么,但我很确定这是问题所在,因为如果这些评估为真,你的 self.internal_velocity 向量就会改变方向。如果你的向量施加了摩擦力,因此它的值在 -1 和 1 之间,它将下降到 0。假设你的 FRICTION 常数小于 1。这就是我假设它不起作用的原因。

if self.internal_velocity.x and 0.2 > self.internal_velocity.x > -0.2:

if self.internal_velocity.y and 0.2 > self.internal_velocity.y > -0.2:

【讨论】:

以上是关于pygame中奇怪的矢量运动的主要内容,如果未能解决你的问题,请参考以下文章

Pygame 生涩的玩家运动

UIImageView 中奇怪的对齐行为

zsh 中奇怪的“工作”行为

列表理解中奇怪的 lambda 行为

Oracle中奇怪的SQL执行结果[关闭]

倒计时项目中奇怪的 setInterval 问题