这个问题是关于pymunk的,但是我知道有更多的Chimpunk用户在那里;所以如果你的答案涉及到C/Chimpunk代码,没关系。虽然我不知道如何编写C代码,但如果我读了别人的代码,我通常可以弄清楚发生了什么
设置
我在模拟一个自上而下的滑动物体游戏(比如冰壶或洗牌板)。 我对代码的相关部分做了一个最小的示例(在问题的末尾),但它的核心是:
我希望实现的目标
当两块石头碰撞时,下一块石头会突然停止(或者可能会反弹一点——我还没有完全考虑这个细节),而它的全部或大部分能量都会转移到上面的石头上,而上面的石头会开始向上移动。在
我得到的是什么
当石头碰撞时,下一块石头并没有停止,而是开始把上面的石头推到屏幕上。 好像下层的质量比上层的大,但它们的功能是一样的,所以它们应该是相同的。在
我已经上传了一个.gif到imgur,它说明了这一点,如果有帮助的话: http://imgur.com/a/FF6Xq
它的帧速率比实际运行脚本时要低,但它仍然说明了发生了什么。在
我尝试过的
在阅读pygame文档时,为了确定所有可能相关的body和shape属性,我尝试以各种组合调整以下所有属性:
调整所有这些都会使石头的行为发生明显的和预期的变化,但没有改变一块石头在碰撞时推动另一块石头的根本问题。在
我读过关于使用pymunk.CollisionHandler(),但尚未尝试使用它。从文档中,我得到的感觉是,这主要是为了增加碰撞的附加效果,而不是为了首先修改碰撞时发生的基本物理现象。但我可能误解了,我愿意接受任何建议。在
我看过几个pymunk的演示。最值得注意的是一个叫做牛顿的演示_摇篮.py表现出我想要的行为。这是一个模拟的装置,有五个球悬浮在一排;当用户把一端的一个球向后拉时,它会击中另一端的球,能量就会转移到另一边的球上。 牛顿_crade.py与我的代码只有两个主要区别:
遗憾的是,在我自上而下的设置中,使用重力不是一个选项。 所以问题可能是我使用了apply_impulse/apply_force,但我看不出任何方法来修改这些方法的使用方式(我已经尝试过各种力量和质量的组合,以及调整约束的设置)。在
即使是给我指出正确的方向——也就是说,对于我可能读到的其他东西,还有什么我可以尝试修改的建议——都会非常感激。我不可能是第一个在俾木/花栗鼠尝试这个的人我还没有找到一个例子。至少在pymunk方面没有;如果在C/chimpmunk中有一个很好的例子,那也很有用。在
谢谢大家抽出时间。在
最小示例代码
没有必要研究代码来理解这个问题,但我把它贴在这里,以防有用。虽然将其剥离出来只是为了显示代码的核心,但它是一个完整的脚本,可以运行。它在Python3中。在
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util
def add_and_tether_stone(space,sx,sy):
"""Creates a stone and its corresponding shape, and tethers it with constraints that simulate ground friction and govern spin."""
#body
mass = stone_mass
radius = stone_radius
moment = pymunk.moment_for_circle(mass, 0, radius)
body = pymunk.Body(mass, moment)
body.position = sx,sy
#shape
shape = pymunk.Circle(body, radius)
shape.friction = stone_friction
shape.elisticity = stone_elisticity
space.add(body, shape)
#constraints
fpiv = pymunk.constraint.PivotJoint(space.static_body,body,(0.0,0.0),(0.0,0.0))
fpiv.max_force = ground_friction
fpiv.max_bias = 0.0
fmot = pymunk.constraint.SimpleMotor(space.static_body,body,0)
fmot.max_force = 5000000 #arbitry 'very high' value clamps down on the high rotation imparted by apply_impulse or apply_force
space.add(fpiv)
space.add(fmot)
return body,shape,fpiv,fmot
def launch_stone(body,power):
"""Launches a stone in the manner of a player taking a shot."""
body.apply_impulse_at_world_point((0,power),(0,0)) #force(x,y),offset(x,y)
def main():
global ground_friction,stone_mass,stone_radius,stone_friction,stone_elisticity
running = True
#PyGame setup
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
sheet = pygame.Surface((500,500))
sheetcolor = (0,0,0)
sheet.fill(sheetcolor)
sheet = sheet.convert()
sheetblit = (0,0)
screen.blit(sheet,sheetblit)
#PyMunk setup
space = pymunk.Space() #space.damping defaults to 1.0, and space.gravity defaults to (0.0, 0.0).
draw_options = pymunk.pygame_util.DrawOptions(sheet) #used only for the pygame_util debug draw mode
#Constants to Tweak
stone_mass = 1.4
stone_radius = 20
power = 340 #in a full implementation, this would vary with player input
ground_friction = 4.5
stone_friction = 2.0
stone_elisticity = 1.0
#Setup for the minimal example: add two stones and launch one at the other.
stone_a = add_and_tether_stone(space,40,260)
stone_b = add_and_tether_stone(space,40,21)
launch_stone(stone_b[0],power)
while running:
for event in pygame.event.get(): #listen for controls (all the controls except 'esc' have been removed for the minimal example)
if event.type == KEYDOWN and event.key == K_ESCAPE:
running = False
#Draw, update physics, and advance
sheet.fill(sheetcolor)
space.debug_draw(draw_options) #from pymunk.pygame-util (handy!)
screen.blit(sheet,sheetblit)
space.step(1/50.0)
pygame.display.flip()
clock.tick(50)
if __name__ == '__main__':
sys.exit(main())
再次感谢大家抽出时间。在
也许我在你的代码中漏掉了一些东西(我这里只有命令行python,所以我不能运行你的脚本),但是我不能重现你的问题。在
下面是我尝试过的一个简短代码,它似乎可以按您的需要工作:
这将在我的屏幕上打印出来(因此b1停止,所有运动都转移到b2):
^{pr2}$相关问题 更多 >
编程相关推荐