java中两个物体相撞触发,在碰撞中将能量从一个物体转移到另一个物体(在pymunk / chipmunk中)...

这个问题是关于pymunk的,但我知道那里有更多的Chimpunk用户;所以如果你的答案涉及C / Chipmunk代码,那没关系 . 虽然我不知道如何编写C代码,但我通常可以弄清楚如果我读了别人的话会发生什么 .

The Setup

我正在模拟一个自上而下的滑动对象游戏(想想冰壶或沙狐球) . 我已经对代码的相关部分(在问题的最后)做了一个最小的例子,但它的核心是:

创建了两个相同的物理对象(遵循卷曲术语,我称之为'stones')

它们的位置具有相同的x值但是y值不同(一个在另一个上方的直线上) .

使用apply_impulse(现在,虽然尝试了其他方法),下面的石头直接在另一块石头上

What I'm hoping to achieve

当石头碰撞时,下部的石头会突然停止(或者可能会稍微反弹一下 - 我还没有将这些细节冒出来),而其全部或大部分能量都会转移到上部石头上,这样就会开始向上移动 .

What I'm getting instead

当石头碰撞时,下部石头不会停止,并开始将上部石头向上推 . 就像下半部分的质量比上部更大,但它们的功能相同,所以它们应该是相同的 .

我上传了一个.gif文件来说明这个,如果它有帮助:http://imgur.com/a/FF6Xq

它的帧速率低于实际运行脚本时的帧速率,但它仍然说明了正在发生的事情 .

What I've tried

阅读pygame文档,尝试识别可能相关的所有正文和形状属性,我尝试以各种组合调整以下所有内容:

body.mass

shape.friction

shape.elasticity

'ground friction'(在自上而下场景中模拟地面摩擦的枢轴约束的max_force)

'power',下方的石头被发射(其中一个参数传递给apply_impulse)

使用apply_force而不是apply_impulse

调整任何/所有这些都会使石头的行为发生显着和预期的变化,但没有一个改变了一块石头在碰撞时推动另一块石头的根本问题 .

我已经阅读了有关使用pymunk.CollisionHandler()的信息,但尚未尝试使用它 . 从文档中,我感觉这主要是为了为碰撞添加额外的效果,而不是为了首先修改碰撞中发生的事情的基本物理 . 但我可能误解了,并对任何建议持开放态度 .

我看了几个pymunk演示 . 最值得注意的是,一个名为newtons_cradle.py的演示展示了我想要的行为 . 这是一个模拟其中一个五个球连续悬挂的小工具;当使用者在末端背部拉一个球时,它击中该排的其余部分并且能量被传递到另一侧的球 . newtons_crade.py只与我的代码有两个主要区别:

它's '侧视图'(因此,重力大于0)

而不是使用apply_impulse或apply_force,只使用重力将球推向其他球(受约束约束) .

遗憾的是,在我的自上而下设置中使用重力不是一个选项 . 所以问题可能是我使用apply_impulse / apply_force,但是我看不出有什么方法可以修改它们的使用方式(我已经尝试了各种功率和质量组合,以及调整约束的设置) .

甚至指出我正确的方向 - 即我可能会读到的其他一些建议,我可能尝试修改的其他内容 - 将不胜感激 . 我不能成为第一个在pymunk / chipmunk中尝试这个的人,但我找不到一个例子 . 至少不在花栗鼠方面;如果C / Chipmunk中有一个很好的例子我可以研究,那也是有用的 .

谢谢大家的时间 .

Minimal Example Code

没有必要研究代码来理解这个问题,但是我已经在这里发布它以防它有用 . 虽然被剥离以显示代码的核心,但它是一个完整的脚本并且可以运行 . 它在Python 3中 .

#!/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())

再次感谢大家的时间 .

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值