2017年12月31日日曜日

wxpythonで自由落下をpyodeで実現

 
 
 
をしていたが、「自由落下」でなかったので、pyodeと組み合わせ(スレッド)
自由落下をしてみた。
pyodeの動きにwxpythonの動きをスレッドでリンク。
 
上サイトのコードに著作権があるのか、またこのページでは引用になるのかわからないが
無断で借用させていただいた。
 
vpython と wxpython の各大きさはカット&トライで決定。もともと大きさの単位が
わからないため。
 
vpyton pyode 側コード
E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\ball_bound.py
 
# coding: UTF-8
#ボールの自由落下による 地面とのバウンドから停止まで
#以下のようなコードにすると文法どおりだがやりにくい
#E:\goolgedrive\myprg_main\python_my_prg\ode_prg\ball_bound1.py
#このコードのほうがいいのか

import ode
from visual import *
#以下の変数をグローバル的に使いたくてリストとする
#そうでないといちいちglobalと宣言するハメになる
field = [""]
ball =  [""]
ball_pos = [0]
dt   = [0]
class Field:

 #scene = display(forward=visual.norm((0,1,-4)), center= (0,-1, 0))
 scene = display(width=500, height=600)
 #scene.senter=(0,-1,0)

 #物理世界を作成
 world=ode.World()
 world.setGravity((0, -9.81, 0))
 #自由落下させたいなら worldのコメントアウトのほうを生かし
 # 最後の方の ball.body.addForce((0,-1000,0)) を殺す
 #world.setGravity((0, 0, 0))
 #地平面を作成?
 space=ode.Space()
 #衝突関係
 jointgroup=ode.JointGroup()
 ode_floor=ode.GeomPlane(space,(0,1,0),0)
 #()なかの引数 上の例ではy軸方向に重力が発生
 #多分 spaceの最後の引数が y軸の座標を示す
 ode_floor.setCategoryBits(1)
 ode_floor.setCollideBits(3)
 ode_floor.viz=box(
  pos=(0,-0.03,0),
  width=10,length=10,height=0.06,color=(0.5,0.5,1.0))
 #タイム関係
 #30に変更
 target_fps=30
 #target_fps=30だから1秒間に30回の処理をする
 dt[0]=1.0/target_fps

 def near_callback(self,args,geom1,geom2):
  for c in ode.collide(geom1,geom2):
   #接触ジョイント (Contact joint) 
   #mu 摩擦係数 (摩擦方向1) mu2 摩擦係数 (摩擦方向2)
   #bounce 反発係数
   c.setBounce(0.97)
   c.setMu(50)
   c.setMu2(50)
   j=ode.ContactJoint(self.world,self.jointgroup,c)
   j.attach(geom1.getBody(),geom2.getBody())
 def tick(self):
  #ballはグローバル変数でもないのにupdateができるのが不思議
  ball[0].update()
  time.sleep(0.03)
  self.space.collide((),self.near_callback)
  #self.dtの間隔で世界を動かしていく
  self.world.step(dt[0])
  self.jointgroup.empty()
  return True
class Ball:
 def __init__(self,field):
  self.body=ode.Body(field.world)
  M=ode.Mass()
  M.setSphere(1, 1)
  self.body.setMass(M)
  self.geom=ode.GeomSphere(
    space=field.space,
    radius=0.3
    )
  #このradiusが実際のバウンドを決める
  #多分 sphereの座標が0で radiusが0.3だから
  #posが0.3ぐらいのバウンド点になる
  self.geom.setCategoryBits(1)
  self.geom.setCollideBits(3)
  #上は Boxのジオメトリを作成
  self.geom.setBody(self.body)
  # 剛体にジオメトリをセット
  self.vball=sphere(
   radius=0.3,
   color=color.red)
 def update(self):
  #boxのジオメトリの位置を得る
  pos=self.geom.getPosition()
  # ここに余計な処理を書くとアニメがスムーズでなくなるので
  # こめんとアウトする 
  # #ボールの位置を表示す
  # #round:引数の2 小数点第3位を四捨五入
  # #ljust:文字列を5桁で表示し足らなければ右側を0で埋める
  # #こうするとvpythonでposをラベルで表示したとき、
  # #周りの四角の囲みがぶれなくていい  
  # x_lj = str(round(pos[0],2)).ljust(5,'0')
  # y_lj = str(round(pos[1],2)).ljust(5,'0')
  # z_lj = str(round(pos[2],2)).ljust(5,'0')
  # ball_pos_txt = x_lj + " " +  y_lj + " " + z_lj
  # label(pos=(0,-5,0), text=ball_pos_txt)
  self.vball.pos = pos
  ball_pos[0]    = pos
 
  #print ball_pos[0]
  

def main():
 field[0] = Field()
 ball[0]=Ball(field[0])
 ball[0].body.setPosition((0,10,0))
 Field#ball[0].body.addForce((0,-1000,0))
 while True:
  field[0].tick()

 #最後の数行 main()にまとめて 
 #if __name__ == '__main__':
 #    main() 
 # などとしたいけれど 変数にglobalをいくつも
 #いれないと だめなようだ。

if __name__ =="__main__":
 main()

wxpython 側コード ほとんど拝借
E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\anime_ball_down_simple.
py
# coding: UTF-8
# 元コード Panelをつかっていたが動作しないため
# 以下のように改変した
import wx
import ball_bound
ball_pos_txt = ["","",""]
class myPanel(wx.Panel):
 def __init__(self, parent):
  wx.Panel.__init__(self, parent, size=(500,600))
  #self.panel = wx.Panel(self, size=(300,600))
  self.SetBackgroundColour('WHITE')
  self.InitBuffer()
  self.Bind(wx.EVT_PAINT, self.OnPaint)
  self.createTimer()
  self.counter = 0
  self.ball = Ball(10)

 def InitBuffer(self):
  size = self.GetClientSize()
  self.buffer = wx.EmptyBitmap(max(1, size.width), max(1, size.height))
  dc = wx.BufferedDC(None, self.buffer)
  dc.SetBackground(wx.Brush( self.GetBackgroundColour()))
  dc.Clear()
  dc.SetBrush(wx.Brush(wx.Colour(0,255,0)))
  dc.DrawRectangle(0,300, 500, 5)
 def createTimer(self):
  t = ball_bound.dt[0] * 1000
  self.timer = wx.Timer(self)
  self.timer.Start(t)
  self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)
 def onTimer(self, event):
  self.InitBuffer()
  dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
  #dc.Clear()
  dc.BeginDrawing()
  dc.SetPen(wx.Pen("black", 3, wx.SOLID))
  self.ball.Fall(dc)
  str = ball_pos_txt[0] + "  " + ball_pos_txt[1] + "  " + ball_pos_txt[2]
  dc.DrawText(str , 100,500)
  #dc.DrawText(ball_pos_txt[0], 20,20)
  dc.EndDrawing()
 def OnPaint(self, event):
  dc = wx.BufferedPaintDC(self, self.buffer)
class Ball:
 def __init__(self, R):
  self.r = R
  self.v = 0
  self.x = 0
  self.y = 0
  self.z = 0
  #vpythonは(0,0)がウィンドウセンターにあるので調整する
  self.x0 = 500/2
  self.y0 =  600/2
  self.z0 = 0
 def Fall(self, dc):
  #wxpythonのyは下に行くほど数値が高くなる
  #vpytonは逆
  self.x =  self.x0 + ball_bound.ball_pos[0][0]
  self.y =  self.y0 + -ball_bound.ball_pos[0][1]*30
  self.z =  self.z0 + ball_bound.ball_pos[0][2]
  x_lj = str(round(self.x,2)).ljust(7,'0')
  y_lj = str(round(self.y,2)).ljust(7,'0')
  z_lj = str(round(self.z,2)).ljust(7,'0')
  ball_pos_txt[0] = x_lj
  ball_pos_txt[1] = y_lj
  ball_pos_txt[2] = z_lj

  #self.v += 0.5
  #self.y += self.v / 2
  #if self.y > 600:
  # self.y = 0
  # self.v = 0
  dc.SetPen(wx.Pen(wx.Colour(255,165,0)))
  #領域をブラシを使って赤で塗りつぶす
  dc.SetBrush(wx.Brush(wx.Colour(255,0,0)))
  dc.DrawCircle(self.x, self.y, self.r)
class MainFrame(wx.Frame):
 def __init__(self, parent, title):
  wx.Frame.__init__(self, parent, -1, title)
  myPanel(self)
  #MainFrameをmyPanelの大きさにあわせる
  self.Fit()
def main():
 app = wx.PySimpleApp()
 frame = MainFrame(None, "Free Fall")
 frame.Show(True)
 app.MainLoop()
if __name__ =="__main__":
 main()
 
メインコード スレッド
E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\anime_ball_down_ode.py
# coding: UTF-8
# ball_bound.pyとanime_ball_down_simple.py
# をスレッドする
import anime_ball_down_simple
import ball_bound
import threading
#import printmy
#今まで何気なくimportしてきたが、モジュールに実行できる
#文、命令があるとimportされた側のファイルを実行すると
# モジュール側の命令文なども、実行されてしまう。
# たとえ モジュール.命令文 の形をとらなくても。
class ThreadWx(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)
 def run(self):
  anime_ball_down_simple.main()

class ThreadOde(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)
 def run(self):
  ball_bound.main()

if __name__ == '__main__':
 t1 = ThreadWx()
 t2 = ThreadOde()
 t1.start()
 t2.start()
 t1.join()
 t2.join()
 print "end"
 

0 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ページ

Featured Posts