如何使用 Pymunk 将一个物体保持在另一个物体之上
How to keep one body on top of another using Pymunk
我有一个圆圈,上面有一个框:
圆圈是一个简单的马达。我希望盒子直接位于圆圈上方。我尝试过不同的约束,但我的大部分尝试都会导致盒子翻到一边。
我最成功的尝试是将盒子的 body.moment 设置为 pymunk.inf,并将盒子固定到圆上。这已经很接近了,但是当我希望它直接越过圆心时,盒子仍然会左右移动。我可以在那里手动设置它,但似乎我应该能够在某种约束下这样做。
有什么想法吗?下面是一些使用 Pymunk 和 Arcade 库的示例代码。
import arcade
import pymunk
import math
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
BOX_SIZE = 45
class MyApplication(arcade.Window):
""" Main application class. """
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.DARK_SLATE_GRAY)
# -- Pymunk space
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# Create the floor
body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.floor = pymunk.Segment(body, [0, 10], [SCREEN_WIDTH, 10], 0.0)
self.floor.friction = 10
self.space.add(self.floor)
# Create the circle
player_x = 300
player_y = 300
mass = 2
radius = 25
inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))
circle_body = pymunk.Body(mass, inertia)
circle_body.position = pymunk.Vec2d(player_x, player_y)
self.circle_shape = pymunk.Circle(circle_body, radius, pymunk.Vec2d(0, 0))
self.circle_shape.friction = 1
self.space.add(circle_body, self.circle_shape)
# Create the box
size = BOX_SIZE
mass = 5
moment = pymunk.moment_for_box(mass, (size, size))
moment = pymunk.inf
body = pymunk.Body(mass, moment)
body.position = pymunk.Vec2d(player_x, player_y + 49)
self.box_shape = pymunk.Poly.create_box(body, (size, size))
self.box_shape.friction = 0.3
self.space.add(body, self.box_shape)
# Create a joint between them
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body)
self.space.add(constraint)
# Make the circle rotate
constraint = pymunk.constraint.SimpleMotor(self.circle_shape.body, self.box_shape.body, -3)
self.space.add(constraint)
def on_draw(self):
"""
Render the screen.
"""
arcade.start_render()
# Draw circle
arcade.draw_circle_outline(self.circle_shape.body.position[0],
self.circle_shape.body.position[1],
self.circle_shape.radius,
arcade.color.WHITE,
2)
# Draw box
arcade.draw_rectangle_outline(self.box_shape.body.position[0],
self.box_shape.body.position[1],
BOX_SIZE,
BOX_SIZE,
arcade.color.WHITE, 2,
tilt_angle=math.degrees(self.box_shape.body.angle))
# Draw floor
pv1 = self.floor.body.position + self.floor.a.rotated(self.floor.body.angle)
pv2 = self.floor.body.position + self.floor.b.rotated(self.floor.body.angle)
arcade.draw_line(pv1.x, pv1.y, pv2.x, pv2.y, arcade.color.WHITE, 2)
def animate(self, delta_time):
# Update physics
self.space.step(1 / 80.0)
window = MyApplication(SCREEN_WIDTH, SCREEN_HEIGHT)
arcade.run()
您可以使用两个销接头而不是一个,在盒子上展开锚点。在现实生活中如何使它稳定 :)
# Create a joint between them
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body, (-20,0))
self.space.add(constraint)
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body, (20,0))
self.space.add(constraint)
如果它不够好,您可以尝试使用较低的 error_bias
约束值进行试验,但我不确定它有多大帮助。如果你需要它是像素完美的,我不认为关节可以做到,它们总是会有一些小错误。所以在那种情况下,我认为你必须通过在相同的 x 值上绘制上下精灵来伪造它。
我有一个圆圈,上面有一个框:
圆圈是一个简单的马达。我希望盒子直接位于圆圈上方。我尝试过不同的约束,但我的大部分尝试都会导致盒子翻到一边。
我最成功的尝试是将盒子的 body.moment 设置为 pymunk.inf,并将盒子固定到圆上。这已经很接近了,但是当我希望它直接越过圆心时,盒子仍然会左右移动。我可以在那里手动设置它,但似乎我应该能够在某种约束下这样做。
有什么想法吗?下面是一些使用 Pymunk 和 Arcade 库的示例代码。
import arcade
import pymunk
import math
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
BOX_SIZE = 45
class MyApplication(arcade.Window):
""" Main application class. """
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.DARK_SLATE_GRAY)
# -- Pymunk space
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# Create the floor
body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.floor = pymunk.Segment(body, [0, 10], [SCREEN_WIDTH, 10], 0.0)
self.floor.friction = 10
self.space.add(self.floor)
# Create the circle
player_x = 300
player_y = 300
mass = 2
radius = 25
inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))
circle_body = pymunk.Body(mass, inertia)
circle_body.position = pymunk.Vec2d(player_x, player_y)
self.circle_shape = pymunk.Circle(circle_body, radius, pymunk.Vec2d(0, 0))
self.circle_shape.friction = 1
self.space.add(circle_body, self.circle_shape)
# Create the box
size = BOX_SIZE
mass = 5
moment = pymunk.moment_for_box(mass, (size, size))
moment = pymunk.inf
body = pymunk.Body(mass, moment)
body.position = pymunk.Vec2d(player_x, player_y + 49)
self.box_shape = pymunk.Poly.create_box(body, (size, size))
self.box_shape.friction = 0.3
self.space.add(body, self.box_shape)
# Create a joint between them
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body)
self.space.add(constraint)
# Make the circle rotate
constraint = pymunk.constraint.SimpleMotor(self.circle_shape.body, self.box_shape.body, -3)
self.space.add(constraint)
def on_draw(self):
"""
Render the screen.
"""
arcade.start_render()
# Draw circle
arcade.draw_circle_outline(self.circle_shape.body.position[0],
self.circle_shape.body.position[1],
self.circle_shape.radius,
arcade.color.WHITE,
2)
# Draw box
arcade.draw_rectangle_outline(self.box_shape.body.position[0],
self.box_shape.body.position[1],
BOX_SIZE,
BOX_SIZE,
arcade.color.WHITE, 2,
tilt_angle=math.degrees(self.box_shape.body.angle))
# Draw floor
pv1 = self.floor.body.position + self.floor.a.rotated(self.floor.body.angle)
pv2 = self.floor.body.position + self.floor.b.rotated(self.floor.body.angle)
arcade.draw_line(pv1.x, pv1.y, pv2.x, pv2.y, arcade.color.WHITE, 2)
def animate(self, delta_time):
# Update physics
self.space.step(1 / 80.0)
window = MyApplication(SCREEN_WIDTH, SCREEN_HEIGHT)
arcade.run()
您可以使用两个销接头而不是一个,在盒子上展开锚点。在现实生活中如何使它稳定 :)
# Create a joint between them
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body, (-20,0))
self.space.add(constraint)
constraint = pymunk.constraint.PinJoint(self.box_shape.body, self.circle_shape.body, (20,0))
self.space.add(constraint)
如果它不够好,您可以尝试使用较低的 error_bias
约束值进行试验,但我不确定它有多大帮助。如果你需要它是像素完美的,我不认为关节可以做到,它们总是会有一些小错误。所以在那种情况下,我认为你必须通过在相同的 x 值上绘制上下精灵来伪造它。