2013-06-16 4 views
1

나는 Ball 클래스를 생성 한 다음 파이썬 스크립트의 인스턴스를 생성합니다. 공은 벽에서 튀어 나와 나중에 (아직 구현되지 않음) 서로 떨어져 있어야합니다. 볼이 벽에 도달 할 때 볼의 방향을 바꾸는 대신 벽이 볼에 힘 (또는 가속)을 가하는 것에 유의하십시오.파이썬 tkinter 튀는 공 - 에너지가 무한대로갑니다

불행히도, 벽에서 튀어 오르면 볼은 진폭이 커지면서 진동 운동을 시작합니다.

저는 파이썬에 매우 익숙하지만 다양한 자바 스크립트/캔버스 시뮬레이션을 작성했습니다.

이 특수한 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 
+0

while 루프의 j.x + = 및 j.y + = 부분에 * dt가 누락되었습니다.진동 운동은 끝났지 만 입자가 벽을 통과합니다! – user2094585

답변

0

난 당신이 가지고 있던 문제는 당신이 당신의 행동 루프에 시간 간격을 넣어 잊었 믿습니다 : 코드가 작동하지만

while True: 
    for i in range(10): 
     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 
      compute_accelerations(j) 
     for j in list: 
      j.xvel += 0.5 * j.ax * dt 
      j.yvel += 0.5 * j.ay * dt 

는 또한, 내가 생각하는 당신의 Ball 가속 방법 정리 될 수있다 :

# box_width = 400 

def compute_accelerations(self): 
     if self.x < self.rad: 
      self.ax = wallStiffness * (self.rad - self.x) 
     elif self.x > box_width - self.rad: 
       self.ax = wallStiffness * (box_width - self.rad - self.x) 

당신이 selfz 대신 사용되는 것을 볼 수 있습니다 그 다음에. 이것은 파이썬에서 클래스 내부의 메소드를 생성하는 표준 방법입니다. 여기서 selfBall 개체의 현재 인스턴스를 의미합니다. 말이 돼?

j.compute_accelerations() 
0

이 직접 귀하의 질문에 대답하지 않습니다,하지만 당신은 잘못은 Tkinter를 사용 :

는이 같은이 새로 수정 방법을 부를 것이다. 엄지 손가락의 일반적 규칙으로 update을 호출하면 안되며 무한 루프가 없어야하며 after을 한 번만 호출해야합니다. Tkinter는 이미 무한 루프를 실행 중입니다 - mainloop - 그럼 그것을 이용하지 않으시겠습니까? 그렇게함으로써 내가 열거 한 모든 나쁜 습관들을 제거 할 수 있습니다.

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) 

이렇게하면 단일 프레임이 그려지고 10ms 동안 기다린 다음 다른 프레임을 그려 영원히 반복합니다. ,

if we_should_continue: 
     canvas.after(10, draw_frame) 

이 당신의 계획에 비해 우수한 장점 : 당신이 뭔가를 할 것이다 경우 : (we_should_continue=False 예를 들면), 당신은 능력이 애니메이션을 중지하려면, 당신은 플래그 변수를 설정하는 버튼을 만들 수 있습니다 당신의 계획에는 GUI가 완전히 얼어 붙은 작은 10ms 창문이있어서 약간의 말더듬이가 생길 수 있습니다. 더 큰 이점은 단순히 tkinter가 작동하도록 설계된 것입니다.