【问题标题】:Multiple collisions not testing [closed]多次碰撞未测试[关闭]
【发布时间】:2021-09-12 03:11:02
【问题描述】:

我有一个 box2d pygame 平台示例。您可以移动玩家并生成平台。除非玩家与关卡中的所有平台发生碰撞,否则我无法对玩家执行跳跃动作。这不是预期的行为,当您触摸一个平台而不是所有其他平台时,您希望能够跳跃。我正在使用 for 循环来循环播放玩家的所有碰撞,并根据需要设置 can_jump。

main.py

import pygame
from draw import Draw
from Box2D import (b2World,b2Vec2)

from box import Box

from player import Player

def Run():
    PPM = 20
    TARGET_FPS = 60
    TIME_STEP = 1.0 / TARGET_FPS

    SCREEN_WIDTH,SCREEN_HEIGHT = 640,480
    CAPTION = ""

    BGCOLOR = ((255,255,255))

    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(CAPTION)
    clock = pygame.time.Clock()

    world = b2World(gravity=(0, 30), doSleep=True)

    closed = False

    global player, hold_left, hold_right, can_jump, speed, deceleration
    player = Player(world,200,200,PPM)
    speed = 20
    deceleration = 0.95
    hold_left = False
    hold_right = False
    can_jump = False

    while not closed:

        def left():
            player.body.ApplyForce(b2Vec2(-1*speed*speed,0),point=player.body.worldCenter,wake=True)
        def right():
            player.body.ApplyForce(b2Vec2(speed*speed,0),point=player.body.worldCenter,wake=True)
        if hold_left:
            left()
        elif hold_right:
            right()

        if len(player.body.contacts) == 0:
            can_jump = False
        else:
            for contact in player.body.contacts:
                contact = contact.contact
                print(contact)
                if contact.manifold.localPoint == b2Vec2(0,1):
                    can_jump=True
                elif contact.manifold.localPoint != b2Vec2(0,1):
                    can_jump=False

        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                closed = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_d:
                    hold_right = True
                elif event.key == pygame.K_a:
                    hold_left = True
                elif event.key == pygame.K_SPACE:
                    if can_jump:
                        player.body.linearVelocity.y = 0
                        player.body.ApplyLinearImpulse(b2Vec2(0,-150),point=player.body.worldCenter,wake=True)
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_d:
                    hold_right = False
                elif event.key == pygame.K_a:
                    hold_left = False

        click = pygame.mouse.get_pressed()  
        if click[0] == 1:
            x,y = pygame.mouse.get_pos()
            Box(world, x, y, PPM)

        player.body.linearVelocity.x *= deceleration

        screen.fill(BGCOLOR)

        Draw(screen,world.bodies,PPM)

        world.Step(TIME_STEP, 10, 10)
        pygame.display.flip()
        clock.tick(TARGET_FPS)

    pygame.quit()

if __name__ == '__main__':
    Run()

player.py

from Box2D import (b2FixtureDef, b2PolygonShape)

class Player:
    def __init__(self, world, x, y, PPM):
        self.x = x / PPM
        self.y = y / PPM
        self.w = 1
        self.h = 1
        self.gh = 0.1

        self.world = world
        self.body = self.world.CreateDynamicBody(
            position=(self.x, self.y),
            fixtures=b2FixtureDef(
                shape=b2PolygonShape(box=(self.w, self.h)), density=2.0, friction = 0.1))
        self.body.fixedRotation = True

box.py

from Box2D import (b2FixtureDef, b2PolygonShape)

class Box:
    def __init__(self, world, x, y, PPM):
        self.x = x / PPM
        self.y = y / PPM
        self.w = 10
        self.h = 1

        self.world = world
        self.body = self.world.CreateStaticBody(
            position=(self.x, self.y),
            fixtures=b2FixtureDef(
                shape=b2PolygonShape(box=(self.w, self.h)), density=2.0, friction = 0.1))

draw.py

import pygame
from Box2D import b2PolygonShape

def Poly(screen,body,fixture,PPM):
    shape = fixture.shape
    vertices = [(body.transform * v) * PPM for v in shape.vertices]
    pygame.draw.polygon(screen, (0, 255, 187), vertices)
    pygame.draw.polygon(screen, (0,0,0), vertices,2)

def Draw(screen,bodies,PPM):
    for body in bodies:
        for fixture in body.fixtures:
            if isinstance(fixture.shape, b2PolygonShape):
                Poly(screen,body,fixture,PPM)

【问题讨论】:

  • 听起来您可能需要学习如何使用调试器来单步调试您的代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。延伸阅读:How to debug small programs
  • 我将使用调试器。

标签: python pygame game-physics collision


【解决方案1】:

您几乎可以肯定在这部分代码中存在逻辑错误,这似乎控制了您的布尔 can_jump 变量:

else:
    for contact in player.body.contacts:
        contact = contact.contact
        print(contact)
        if contact.manifold.localPoint == b2Vec2(0,1):
            can_jump=True
        elif contact.manifold.localPoint != b2Vec2(0,1):
            can_jump=False

一个错误,一个清理,和几个提示......

首先报错:

您正在循环访问联系人。当你跳出这个循环,是什么决定了can_jump的T/F值?

Ans:只有数据容器中的最后一个联系人会影响 can_jump 的值。这有意义吗?

提示:

您在此处测试 T/F 条件,正确的方法是进行测试一次,然后让它确定结果。现在您正在测试“如果为真”,然后测试“如果为假”。这是多余的并且容易出错。所以这样的东西更好:

if contact.blah.blah == b2vec():
    can_jump = True
else:
    can_jump = False

更正:

现在,这并不能解决您的问题。 (这和你的代码一样长......哈哈)。您可能想要做的是检查“所有”或“任何”联​​系人以确定条件,具体取决于您的游戏逻辑。您可以像现在一样使用循环来执行此操作,并且,如果遇到“失败”条件,请设置变量,然后跳出循环等。 或者你可以巧妙地查看 Python 的 any()all() 内置命令。

例如...(您可以将此处的逻辑测试替换为您自己的,但这显示了结构)

contacts = {2, 5, 7}

can_jump = any(contact > 3 for contact in contacts)
print(can_jump)  # True

can_jump = all(contact > 3 for contact in contacts)
print(can_jump)  # False

因此,您可以正确地重新编写循环逻辑,也可以将其全部替换为 1-liner,即使联系人为空也应该可以工作,这也会生成 False

【讨论】:

    猜你喜欢
    • 2014-01-26
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2013-01-16
    • 2015-05-01
    • 1970-01-01
    相关资源
    最近更新 更多