2

Ball クラスを作成し、そのインスタンスを作成する Python スクリプトを作成しました。ボールは壁で跳ね返り、後で (まだ実装されていません) 互いに跳ね返ります。ボールが壁に到達したときにボールの方向を逆にするのではなく、壁がボールに力 (または加速度) を加えることに注意してください。

残念ながら、壁で跳ね返った後、ボールは振動運動に入り、振幅がどんどん大きくなります。

私は Python を初めて使用しますが、以前にさまざまな javascript/canvas シミュレーションを作成したことがあります。

この特定の python スクリプトは、Verlet 統合を使用して位置と速度を計算します。私はこれに基づいてスクリプトを作成しています:

http://physics.weber.edu/schroeder/software/demos/MolecularDynamics.html

ボールが壁に跳ね返って「安定」するようにコードを変更する方法を誰か提案できますか? ありがとうございました

from Tkinter import *
import random
window = Tk()
canvas = Canvas(window, width = 400, height = 300)
canvas.pack()
wallStiffness=0.05
dt=0.02


class Ball:

    def __init__(self):
        self.x=0
        self.y=0
        self.xvel=random.random()*2-1
        self.yvel=random.random()*2-1
        self.ax=0
        self.ay=0
        self.rad=20



def computeAccelerations(z):

        if z.x<z.rad:
             z.ax=wallStiffness*(z.rad-z.x)
        else: 
            if z.x>400-z.rad:
                z.ax=wallStiffness*(400-z.rad-z.x) 
        #only have horizontal bounces so far, and no bounces between balls yet


list=[]

for i in range(100):    #0 to 99, make 100 balls
    myball=Ball()
    list.append(myball)

#script to place in a crystal to begin with

current_x=30
current_y=0

for j in list:

        j.x=current_x
        current_x+=30
        j.y=current_y

        if current_x+30>370:
            current_x=30
            current_y+=30            

        j.ball=canvas.create_oval(j.x,j.y,j.x+j.rad,j.y+j.rad,fill="blue")



while True:

    for i in range(10):     #10 steps per frame
        for j in list:
            j.x+=j.xvel*dt+0.5*j.ax*dt*dt
            j.y+=j.yvel*dt+0.5*j.ay*dt*dt
            j.xvel+=0.5*j.ax*dt
            j.yvel+=0.5*j.ay*dt
            computeAccelerations(j)
        for j in list:
            j.xvel+=0.5*j.ax*dt
            j.yvel+=0.5*j.ay*dt

    canvas.after(10)    #duration of frame in ms
    for z in list:
        canvas.move(z.ball,z.xvel, z.yvel)
        canvas.update()

window.mainloop()   #keeps the window open
4

2 に答える 2

1

これはあなたの質問に直接答えるものではありませんが、Tkinter を間違って使用しています。一般的な経験則として、 を呼び出すupdateべきではなく、無限ループを発生afterさせたり、単一の引数で呼び出したりするべきではありません。Tkinter ではすでに無限ループが実行されています -- mainloop-- では、それを利用してみませんか? そうすることで、私が挙げた 3 つの悪い習慣をすべて排除することができます。

ループの本体を削除しwhile Trueて、関数に入れる必要があります。次に、その関数自体が一定の間隔で再度呼び出されるように調整します。例えば:

def draw_frame():
    for i in range(10):
        for j in list:
            ...
    for z in list:
        canvas.move(z.ball,z.xvel, z.yvel)

    canvas.after(10, draw_frame)

これは単一のフレームを描画し、10 ミリ秒待ってから別のフレームを描画し、永遠に繰り返します。アニメーションを停止する機能が必要な場合は、フラグ変数 (例: ) を設定するボタンを作成できます。we_should_continue=Falseこの場合、次のようにします。

    if we_should_continue:
        canvas.after(10, draw_frame)

これがスキームに勝る利点は、GUI が完全にフリーズする 10 ミリ秒の小さなウィンドウがスキームにあり、非常にわずかなスタッタリングが発生する可能性があることです。より大きな利点は、これが tkinter が動作するように設計されていることです。

于 2013-06-17T16:26:26.077 に答える