多次碰撞未测试
Multiple collisions not testing
我有一个 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)
您几乎可以肯定这部分代码存在逻辑错误,它似乎控制了您的布尔 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 行代码,即使 contacts 为空,它也应该可以工作,这也会生成 False
!
我有一个 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)
您几乎可以肯定这部分代码存在逻辑错误,它似乎控制了您的布尔 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 行代码,即使 contacts 为空,它也应该可以工作,这也会生成 False
!