日期:2018/7/23
由於我們之前做的動畫,都是在按在 F5 後自動開始執行,如果我們想要在動畫中新增按鈕,讓使用者可以自己控制動畫,應該要怎麼做呢?我們希望按鈕的功能有:
- Run:按下時開始執行動畫
- Reset:按下時還原成起始狀態
- Stop:按下時停止執行程式
我們使用最簡單的動畫〈等速度直線運動〉的程式碼來改寫,成果如下:
有按鈕的等速度直線運動畫面截圖
按下 Run 按鈕後
用滑桿改變速度,使木塊向左移動
按下 Reset 按鈕後
VPython進階教學: 按鈕
"""
VPython進階教學: 按鈕
日期: 2018/7/23
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 0.1 # 木塊邊長
L = 1 # 地板長度
v = 0.03 # 木塊速度
t = 0 # 時間
dt = 0.01 # 時間間隔
re = False # 重置狀態
running = False # 物體運動狀態
end = False # 程式是否結束
"""
2. 函式設定
"""
# 建立動畫視窗, 建立按鈕時才不會另外開啟一個黑底、無物件的動畫視窗
scene = canvas(title="1D Motion\n\n", width=800, height=400, x=0, y=0,
center=vec(0, 0.1, 0), background=vec(0, 0.6, 0.6))
# 初始畫面設定
def setup():
global floor, cube, gd, gd2, xt, vt
floor = box(pos=vec(0, 0, 0), size=vec(L, 0.1*size, 0.5*L), color=color.blue)
cube = box(pos=vec(-0.5*L + 0.5*size, 0.55*size, 0), size=vec(size, size, size),
color=color.red, v=vec(v, 0, 0))
gd = graph(title="<i>x</i>-<i>t</i> plot", width=600, height=450, x=0, y=400,
xtitle="<i>t</i> (s)", ytitle="<i>x</i> (m)")
gd2 = graph(title="<i>v</i>-<i>t</i> plot", width=600, height=450, x=0, y=850,
xtitle="<i>t</i> (s)", ytitle="<i>v</i> (m/s)")
xt = gcurve(graph=gd, color=color.red)
vt = gcurve(graph=gd2, color=color.red)
# 執行按鈕
def run(b1):
global running
running = not running
b1 = button(text="Run", pos=scene.title_anchor, bind=run)
# 物體運動
def motion(t, dt):
global running
while(cube.pos.x <= L*0.5 - size*0.5):
rate(1000)
cube.pos += cube.v*dt
xt.plot(pos=(t, cube.pos.x))
vt.plot(pos=(t, cube.v.x))
t += dt
print("t = ", t)
running = False
# 重置按鈕
def reset(b2):
global re
re = not re
b2 = button(text="Reset", pos=scene.title_anchor, bind=reset)
# 重置用, 初始化
def init():
global re, running
cube.pos = vec(-L*0.5 + size*0.5, size*0.55, 0)
cube.v = vec(v, 0, 0)
t = 0
xt.delete()
vt.delete()
re = False
running = False
# 停止按鈕
def stop(b3):
global end
end = not end
b3 = button(text="Stop", pos=scene.title_anchor, bind=stop)
"""
3. 主程式
"""
setup()
while not end:
if running:
print("Run")
motion(t, dt)
if re:
print("Reset")
init()
print("Stop")
參數設定
除了一些物件的資料之外,另外設定了重置狀態re、物體運動狀態running、程式是否結束end等3個變數,預設值皆為False。
畫面及函式設定
- 先用以下的程式碼新增動畫視窗scene,這是為了在新增按鈕時不會另外開啟一個新的動畫視窗。
scene = canvas(title="1D Motion\n\n", width=800, height=400, x=0, y=0, center=vec(0, 0.1, 0), background=vec(0, 0.6, 0.6))
- 自訂函式setup(),執行此函式時產生木塊、地板、繪圖視窗。
- 設定執行按鈕b1,分為2個部分:
def run(b1): global running running = not running b1 = button(text="Run", pos=scene.title_anchor, bind=run)
- 自訂函式run(b1),函式內定義了全域變數running,當b1被按下時,將running的狀態反過來,若原為False則改為True,若原為True則改為False。
- 用button產生按鈕b1,其中text為按鈕上顯示的文字,pos為按鈕位置,在此設定為scene的標題位置(scene.title_anchot),bind則是用來將這個按鈕物件連結到自訂函式run。
- 自訂函式motion(t, dt),執行此函式時,木塊會開始向右移動,直到木塊抵達地板右側邊緣為止,木塊停止後再將running的狀態設為False,避免動畫繼續執行,形成無窮迴圈。
- 設定重置按鈕b2,分為3個部分:
def reset(b2): global re re = not re b2 = button(text="Reset", pos=scene.title_anchor, bind=reset) def init(): global re, running cube.pos = vec(-L*0.5 + size*0.5, size*0.55, 0) cube.v = vec(v, 0, 0) t = 0 xt.delete() vt.delete() re = False running = False
- 自訂函式reset(b2),函式內定義了全域變數re,當b2被按下時,將re的狀態反過來,若原為False則改為True,若原為True則改為False。
- 用button產生按鈕b2。
- 自訂函式init(),執行此函式時,木塊會回到初位置,清除x-t圖、v-t圖中的資料。
- 設定停止按鈕b3,分為2個部分:
def stop(b3): global end end = not end b3 = button(text="Stop", pos=scene.title_anchor, bind=stop)
- 自訂函式stop(b3),函式內定義了全域變數end,當b3被按下時,將end的狀態反過來,若原為False則改為True,若原為True則改為False。
- 用button產生按鈕b3。
主程式
由於我們將大部分的內容及效果寫在自訂函式中,所以主程式非常短,只有以下幾行
setup()
while not end:
if running:
print("Run")
motion(t, dt)
if re:
print("Reset")
init()
print("Stop")
- 先呼叫自訂函式setup(),產生需要的物件。
- 進入while迴圈,若end的值為False,則迴圈持續執行;若end的值為True,則結束迴圈並輸出訊息Stop。
- 如果running的值為True,輸出訊息Run、呼叫自訂函式motion(t, dt)。
- 如果re的值為True,輸出訊息Reset、呼叫自訂函式init()。
如果執行此程式並依序按下Run、Reset、Run、Stop,應該會在Python Shell看到以下的訊息:
Run
t = 30.00000000000189
Reset
Run
t = 30.00000000000189
Stop
執行效果
我們可以用滑桿控制木塊的速度使木塊來回移動,當木塊抵達地板邊緣時,木塊會停止移動,但是時間仍會繼續增加,這是和第1版程式最大的差異。
用滑桿控制木塊來回移動的x-t圖
結語
用VPython製作一個有操作界面的動畫,雖然也能做出不錯的效果,但是我們需要花較多的時間寫程式,用來處理物理模型的時間相對上較少,所以我們只簡單地做了這個動畫,之後的課程還是以處理物理模型為主。如果對於VPython的按鈕、拉桿……等元件的用法有興趣,請參考GlowScript網站上的範例自行改寫。
參考資料
- VPython官方說明書Widgets: http://www.glowscript.org/docs/VPythonDocs/controls.html
- GlowScript網站範例Buttons Sliders Menus: http://www.glowscript.org/#/user/GlowScriptDemos/folder/Examples/program/ButtonsSlidersMenus-VPython
HackMD 版本連結:https://hackmd.io/@yizhewang/H1Uyq-Q4m
沒有留言:
張貼留言