---
# System prepended metadata

title: 水平抛射
tags: [VPython]

---

# 水平抛射

> 作者：王一哲
> 日期：2018/3/20

<br />

將一個小球由高度 h 處以水平初速 v0 抛出，小球受到重力作用向下加速，小球撞到地板時反彈，共有以下3種不同的狀況：

1. 只考慮重力的作用，小球與地板間為彈性碰撞。　（[GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/5-1projectile)）
2. 只考慮重力的作用，小球撞地板的恢復係數為 e。　（[GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/5-2projectilee)）
3. 同時考慮重力及空氣阻力 f = -bv。　（[GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/5-3projectileair)）

成果如下：

<img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/DDdhuwo.png">
<div style="text-align:center">只考慮重力的作用，小球與地板間為彈性碰撞</div>
<br />

<img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/TQErQza.png">
<div style="text-align:center">只考慮重力的作用，小球撞地板的恢復係數為 e = 0.9</div>
<br />

<img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/tEPx24o.png">
<div style="text-align:center">只考慮重力的作用，小球撞地板的恢復係數為 e = 0.8</div>
<br />

<img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/gwXbVAA.png">
<div style="text-align:center">同時考慮重力及空氣阻力 f = -bv， b = 0.1</div>
<br />

## 程式 5-1：水平抛射 （[取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/05.%E6%B0%B4%E5%B9%B3%E6%8A%9B%E5%B0%84/5-1_projectile.py)）

```python=
"""
 VPython教學: 5-1.水平抛射
 Ver. 1: 2018/2/19
 Ver. 2: 2019/9/6
 作者: 王一哲
"""
from vpython import *

"""
 1. 參數設定, 設定變數及初始值
"""
size = 1     # 小球半徑
v0 = 5       # 小球水平初速
h = 15       # 小球離地高度
L = 50       # 地板長度
g = 9.8      # 重力加速度 9.8 m/s^2
i = 0        # 小球撞地板次數
t = 0        # 時間
dt = 0.001   # 時間間隔

"""
 2. 畫面設定
"""
scene = canvas(title="Projectile", width=800, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal)
ball = sphere(pos=vec(-L/2, h, 0), radius=size, texture=textures.wood, make_trail=True, v=vec(v0, 0, 0), a=vec(0, -g, 0))

"""
 3. 物體運動部分, 小球觸地時反彈
"""
while ball.pos.x < L/2:
    rate(1000)
    ball.v += ball.a*dt
    ball.pos += ball.v*dt

    if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
        i += 1
        print(i, t, ball.pos.x + L/2)
        ball.v.y = -ball.v.y

    t += dt
```
<br />

### 參數設定

在此定義的變數有 size、v0、h、L、g、i、t、dt，用途都已經寫在該行的註解中。
<br />

### 畫面設定

1. 這次在 sphere 及 box 物件當中沒有設定[顏色 (color)](https://www.glowscript.org/#/user/yizhe/folder/Public/program/colors)，反而設定了[材質 (texture)](https://www.glowscript.org/#/user/yizhe/folder/Public/program/textures)，語法為
    ```python
    texture = textures.[材質名稱]
    ```
    VPython 7 目前支援的材質有下列12種。 

<iframe src="https://www.glowscript.org/#/user/yizhe/folder/Public/program/textures" width="810" height="700"></iframe>
<div style="text-align:center">VPython 7 支援的材質</div>
<br />

<iframe src="https://www.glowscript.org/#/user/yizhe/folder/Public/program/colors" width="810" height="700"></iframe>
<div style="text-align:center">VPython 7 支援的顏色</div>
<br />

也可以使用網路上的圖片自訂材質，只要將圖片網址加在 texture 之後並用引號包起來即可，以[木星圖片為例](https://glowscript.org/#/user/yizhe/folder/Public/program/jupiter)
```python
jupiter = sphere(pos=vec(0, 0, 0), radius=1, 
                 texture="https://upload.wikimedia.org/wikipedia/commons/c/c1/Jupiter_New_Horizons.jpg")
```
<br />
<div style="text-align:center">
<iframe src="https://glowscript.org/#/user/yizhe/folder/Public/program/jupiter" width="650" height="650"></iframe></div>
<div style="text-align:center">使用網路圖片自訂材質（木星圖片來源 <a href="https://upload.wikimedia.org/wikipedia/commons/c/c1/Jupiter_New_Horizons.jpg" target="_blank">https://upload.wikimedia.org/wikipedia/commons/c/c1/Jupiter_New_Horizons.jpg</a>）</div>
<br />

<div style="text-align:center">
<iframe src="https://glowscript.org/#/user/yizhe/folder/Public/program/earth" width="650" height="650"></iframe></div>
<div style="text-align:center">內建的地球材質</div>
<br />


2. 用 sphere 產生小球 ball 時可以同時設定初速度及加速度，也可以之後再用以下的方式設定。

    ```python
    ball.v = vec(v0, 0, 0)
    ball.a = vec(0, -g, 0)
    ```
<br />

### 物體運動

1. 在 while 迴圈中設定的條件為
    ```python
    ball.pos.x < L/2
    ```
    所以動畫會一直執行直到小球到達地板的右側邊緣為止。

2. 當小球撞到地板時，將撞擊次數 i 加 1，印出撞擊次數 i、經過時間 t、水平射程 ball.pos.x + L/2，並將小球的 y 方向速度反向，因此要加上以下的程式碼
    ```python
    if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
        i += 1
        print(i, t, ball.pos.x + L/2)
        ball.v.y = -ball.v.y
    ```
<br />

## 程式 5-2：水平抛射，恢復係數e （[取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/05.%E6%B0%B4%E5%B9%B3%E6%8A%9B%E5%B0%84/5-2_projectile_e.py)）

```python=
"""
 VPython教學: 5-2.水平抛射, 恢復係數e
 Ver. 1: 2018/2/19
 Ver. 2: 2019/9/6
 作者: 王一哲
"""
from vpython import *

"""
 1. 參數設定, 設定變數及初始值
"""
size = 1     # 小球半徑
v0 = 5       # 小球水平初速
e = 0.8      # 恢復係數
h = 15       # 小球離地高度
L = 50       # 地板長度
g = 9.8      # 重力加速度 9.8 m/s^2
i = 0        # 小球撞地板次數
t = 0        # 時間
dt = 0.001   # 時間間隔

"""
 2. 畫面設定
"""
scene = canvas(title="Projectile", width=800, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal)
ball = sphere(pos=vec(-L/2, h, 0), radius=size, texture=textures.wood, make_trail=True, v=vec(v0, 0, 0), a=vec(0, -g, 0))

"""
 3. 物體運動部分, 小球觸地時反彈
"""
while ball.pos.x < L/2:
    rate(1000)
    ball.v += ball.a*dt
    ball.pos += ball.v*dt

    if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
        i += 1
        print(i, t, ball.pos.x + L/2)
        ball.v.y = -ball.v.y*e

    t += dt
```
<br />

程式 5-2 與 5-1 幾乎一模一樣，只有增加恢復係數 e，並在小球撞擊地板時改為

```python
if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
    i += 1
    print(i, t, ball.pos.x + L/2)
    ball.v.y = -ball.v.y*e
```
<br />

## 程式 5-3：水平抛射，考慮重力及空氣阻力 f = -bv （[取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/05.%E6%B0%B4%E5%B9%B3%E6%8A%9B%E5%B0%84/5-3_projectile_air.py)）

```python=
"""
 VPython教學: 5-3.水平抛射, 恢復係數e, 空氣阻力 f = -bv
 Ver. 1: 2018/2/19
 Ver. 2: 2019/9/6
 作者: 王一哲
"""
from vpython import *

"""
 1. 參數設定, 設定變數及初始值
"""
size = 1     # 小球半徑
v0 = 5       # 小球水平初速
e = 1        # 恢復係數
m = 1        # 小球質量
h = 15       # 小球離地高度
L = 50       # 地板長度
g = 9.8      # 重力加速度 9.8 m/s^2
b = 0.1      # 空氣阻力 f = -bv
i = 0        # 小球撞地板次數
t = 0        # 時間
dt = 0.001   # 時間間隔

"""
 2. 畫面設定
"""
scene = canvas(title="Projectile", width=800, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal)
ball = sphere(pos=vec(-L/2, h, 0), radius=size, texture=textures.wood, make_trail=True, v=vec(v0, 0, 0), a=vec(0, -g, 0))

"""
 3. 物體運動部分, 小球觸地時反彈
"""
while ball.pos.x < L/2 and i < 20:
    rate(1000)
    f = -b*ball.v
    ball.a = vec(0, -g, 0) + f/m
    ball.v += ball.a*dt
    ball.pos += ball.v*dt

    if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
        i += 1
        print(i, t, ball.pos.x + L/2)
        ball.v.y = -ball.v.y*e

    t += dt
```
<br />

程式 5-3 與 5-2 幾乎一模一樣，不同之處在於：

1. 增加了空氣阻力的係數 b。
2. while 迴圈當中增加
    ```python
        f = -b*ball.v
        ball.a = vec(0, -g, 0) + f/m
    ```
    計算當時的空氣阻力及小球的加速度。

3. 為了避免小球受到的阻力太大，小球沒辦法到達地板的右側邊緣，因此在 while 迴圈的條件當中增加了 i < 20，當小球撞擊地板20次時停止動畫。
<br />

## 結語

程式 5-1 是為了寫出 5-2 及 5-3 的前置作業，先寫出最簡單程式再慢慢把條件加上去。在程式 5-1 中，可以試著將 h 改成不同的值，看看小球撞擊地板所需時間與高二物理中學到的理論計算是否相符。在程式 5-2 中，可以試著將 e 改成不同的值，觀察每次撞擊後反彈的高度飛行時間。在程式 5-3 中，可以試著將 b 改成不同的值，觀察小球運動的軌跡有何不同之後。
<br />

## VPython官方說明書
1. **canvas**: http://www.glowscript.org/docs/VPythonDocs/canvas.html
2. **box**: http://www.glowscript.org/docs/VPythonDocs/box.html
3. **sphere**: http://www.glowscript.org/docs/VPythonDocs/sphere.html
4. **texture**: http://www.glowscript.org/docs/VPythonDocs/textures.html

---

###### tags: `VPython`