この質問はpymunkに関するものですが、Chimpunkユーザーがもっとたくさんいることを私は知っています。したがって、回答にC / Chipmunkコードが含まれている場合は、問題ありません。Cコードの書き方はわかりませんが、他の人のコードを読んだら、何が起こっているのか理解できます。
セットアップ
トップダウンのスライディングオブジェクトゲームをシミュレートしています(カーリングやシャッフルボードを考えてください)。コードの関連部分の最小限の例を(質問の最後に)作成しましたが、その中心は次のとおりです。
私が達成したいこと
石が衝突すると、下の石は突然停止するはずです(または、少し跳ね返る可能性があります-私はまだその詳細を発汗していません)が、そのエネルギーのすべてまたは大部分は上の石に転送されます。画面を上に移動し始めます。
代わりに私が得ているもの
石が衝突しても、下の石は止まらず、上の石を画面上に押し始めます。下部が上部よりも質量が大きいように見えますが、同じ機能で作成されているため、同じである必要があります。
役立つ場合は、これを説明する.gifをimgurにアップロードしました:http://imgur.com/a/FF6Xq
実際にスクリプトを実行するときよりもフレームレートは低くなりますが、それでも何が起こっているかを示しています。
私が試したこと
pygameのドキュメントを読んで、関連する可能性のあるすべてのボディとシェイプのプロパティを特定するために、次のすべてをさまざまな組み合わせで調整してみました。
これらのいずれか/すべてを微調整すると、石の動作に目立って予想される変化が生じましたが、衝突時に一方の石が他方を押すという根本的な問題は変わりませんでした。
pymunk.CollisionHandler()の使用について読みましたが、まだ使用していません。ドキュメントから、これは主に衝突に追加の効果を追加することを目的としており、最初に衝突で発生することの基本的な物理学を変更することを目的としていないことがわかります。しかし、私は誤解している可能性があり、どんな提案にもオープンです。
私はいくつかのpymunkデモを見てきました。最も注目すべきは、newtons_cradle.pyというデモが私が望む動作を示していることです。これは、5つのボールが連続して吊り下げられているガジェットの1つのシミュレーションです。ユーザーが端の1つのボールを後ろに引くと、そのボールは列の残りの部分に当たり、エネルギーは反対側のボールに伝達されます。newtons_crade.pyには、私のコードとの大きな違いが2つだけあります。
残念ながら、重力を使用することは私のトップダウン設定のオプションではありません。したがって、問題はapply_impulse / apply_forceの使用にある可能性がありますが、これらの使用方法を変更する方法がわかりません(パワーと質量のさまざまな組み合わせを試し、制約の設定を調整しました)。
私を正しい方向に向けることさえ-すなわち、私が他に何を読むかもしれないか、私が修正しようとするかもしれない他のことについてのいくつかのアドバイス-は大いにありがたいです。私はピムンク/シマリスでこれを試す最初の人になることはできませんが、例を見つけることができませんでした。少なくともピムンク側ではありません。私が勉強できるC / Chipmunkの良い例があれば、それも役に立ちます。
いつもありがとうございました。
最小限のサンプルコード
質問を理解するためにコードを調べる必要はありませんが、役立つ場合に備えてここに投稿しました。コードの核心を示すために削除されていますが、これは完全なスクリプトであり、実行できます。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しかないため、スクリプトを実行できません)、問題を再現することはできません。
これが私が試した短いコードで、あなたが望むように動作するようです:
import pymunk
s = pymunk.Space()
b1 = pymunk.Body(1,10)
b1.position = 0,0
b2 = pymunk.Body(1,10)
b2.position = 0,10
c1 = pymunk.Circle(b1, 1)
c1.elasticity = 1.0
c2 = pymunk.Circle(b2, 1)
c2.elasticity = 1.0
j1 = pymunk.constraint.PivotJoint(s.static_body, b1, (0,0),(0,0))
j1.max_force = 4.5
j1.max_bias = 0
j2 = pymunk.constraint.PivotJoint(s.static_body, b2, (0,0),(0,0))
j2.max_force = 4.5
j2.max_bias = 0
j3 = pymunk.constraint.SimpleMotor(s.static_body,b1,0)
j3.max_force = 5000000
j4 = pymunk.constraint.SimpleMotor(s.static_body,b2,0)
j4.max_force = 5000000
s.add(b1,b2,c1,c2,j1,j2,j3,j4)
b1.apply_impulse_at_world_point((0,30),(0,0))
for x in range(25):
s.step(0.02)
print(b1.position, b2.position)
これは私の画面にこれを印刷します(したがって、b1が停止し、すべての動きがb2に転送されます):
Vec2d(0.0, 0.6) Vec2d(0.0, 10.0)
Vec2d(0.0, 1.1982) Vec2d(0.0, 10.0)
Vec2d(0.0, 1.7946) Vec2d(0.0, 10.0)
Vec2d(0.0, 2.3891999999999998) Vec2d(0.0, 10.0)
Vec2d(0.0, 2.9819999999999998) Vec2d(0.0, 10.0)
Vec2d(0.0, 3.573) Vec2d(0.0, 10.0)
Vec2d(0.0, 4.1622) Vec2d(0.0, 10.0)
Vec2d(0.0, 4.7496) Vec2d(0.0, 10.0)
Vec2d(0.0, 5.3352) Vec2d(0.0, 10.0)
Vec2d(0.0, 5.9190000000000005) Vec2d(0.0, 10.0)
Vec2d(0.0, 6.501) Vec2d(0.0, 10.0)
Vec2d(0.0, 7.081200000000001) Vec2d(0.0, 10.0)
Vec2d(0.0, 7.659600000000001) Vec2d(0.0, 10.0)
Vec2d(0.0, 8.2362) Vec2d(0.0, 10.0)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 10.584682725252637)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 11.159477451815137)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 11.732472178377638)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 12.303666904940137)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 12.873061631502637)
Vec2d(0.0, 8.228112001309862) Vec2d(0.0, 13.440656358065137)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加