物理のおおまかな話
動くボール †
サッカー、野球にビリヤード、ボーリングやらゲートボールやらいろいろありますが、経験的に
ボールは長い時間動くと止まると思われているでしょう。
ほんとのところはといいますと…。
- ボールに止まろうとする力が働かないかぎりボールは、最初に受けた力や速度を維持しつづける。
- 実際にボールを蹴ってみると壁にぶつかったわけじゃないのに、時間がたつと止まってしまうのは、
空気や地面から摩擦や抵抗としてボールを止めようとするような力が働いているからです。
- ボールが動くのを邪魔するものがなければボールは速度を緩めることも止まることも方向を変えることも
ありません。
(このときボールは等速直線運動をします。←検索時のキーワードにどうぞ。^ ^;)
- 何もしなければボールは1度蹴ると永遠に真っ直ぐ飛びつづけます。
- 逆を言えば、1度蹴ってしまえば後は何もしなくてもいい。というわけです。
とまあ、こんな感じでボールは動いているわけです。
ではこの辺のことを頭に置いといて、下のスクリプトを実行して体験してみてください。
+
| | モジュール
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
|
#module
#deffunc DrwCls int,int,int,int,int,int
mref wt, 0 mref cr, 1 mref cg, 2 mref cb, 3 mref px, 4 mref py, 5
ginfo 1
mref bm, 96+prmy
ginfo_r = bm.40&(1<<8-1)
ginfo_g = bm.40&(1<<16-1)>>8
ginfo_b = bm.40&(1<<24-1)>>16
redraw 1
if wt<1 : wt = 10
await wt
redraw 0
color cr, cg, cb
boxf
color ginfo_r, ginfo_g, ginfo_b
pos px, py
return
#deffunc DrwArrow int,int,int,int
mref sx, 0
mref sy, 1
mref ex, 2
mref ey, 3
line sx,sy, ex,ey
x = sx - ex
y = sy - ey
ax = (x-y)* 10/14 /5+ex
ay = (y+x)* 10/14 /5+ey
line ex,ey, ax,ay
ax = (x+y)* 10/14 /5+ex
ay = (y-x)* 10/14 /5+ey
line ex,ey, ax,ay
return
#deffunc sqrt int
mref x, 0
mref ostat, 64
if x = 0 : ostat = 0 : return
s=x
repeat
last = s: s = x / s + s >> 1 if s >= last: p=cnt: break loop
ostat = last
return
#global
|
|
+
| | 等速直線運動サンプル
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
|
#include "mp001.as"
title "等速直線運動"
px = 100 : py = 100 vx = 0 : vy = 0
*main
DrwCls 5, 255,255,255
color 0,0,0
mes "座標( "+px+", "+py+" )"
mes "速度 v = "+vx
if vx = 0 : mes "スペースキーを押してください。"
gosub *inkey
px = px + vx py = py + vy
boxf px, py, px+10, py+10
color 255,0,0
DrwArrow px+5,py+5, vx*50+px+5, vy*50+py+5
goto *main
stop
*inkey
stick key
if (key&16=16) & (vx=0) : vx=vx+1 if key&128 : end
return
|
|
px :移動物体の x方向の位置
py :移動物体の y方向の位置
vx :移動物体の x方向の速度
vy :移動物体の y方向の速度
と、こんな感じです。このように速度や座標はx方向とy方向に分けて考えます。
理由は表示上の都合と言うのもありますが、ベクトルをキーワードにして数学系サイトなどを検索してみてください。
スペースキーを押すとvxに速度が入り、移動スピードが変化します。
if (key&16=16) & (vx=0) : vx=vx+1 ;速度を与える
この行のvxに代入している値を変えると速度が変わります。
- 一度だけ速度を与えた後は、何も出来ないことを確認してみてください。
- あちこち値を変更してみて遊んでみてください。(おもにvxやvyの値とか)
|
スクリプトをシンプルにするためモジュールを作成してあります。
モジュールで作成した命令は次のとおり。
- DrwCls? : redrawやawaitをまとめたものです。
- DrwCls? wt, cr,cg,cb, px,py
wt : awaitで待機する時間。(ms)
cr,cg,cb : ウィンドウを塗りつぶす色。
px,py : posによる指定座標。
- DrwArrow? : 矢印を描画
- DrwArrow? px1,py1, px2,py2
px1,py1 : 矢印の根元座標
px2,py2 : 矢印の先端座標
- sqrt : 平方根を計算します。
- sqrt p1
statにp1の平方根の値が返されます。
肝心の物理的な計算の部分の解説をします。計算はこれだけです。
; 物理計算
px = px + vx
py = py + vy
え、前の座標に速度を足すと次の瞬間の座標になる??違います。
距離を x [m]、速度を v [m/s]、経過時間を t [s]としたとき、移動後の位置を求める式は
x1 = x0 + v * t
と、こんな感じです。
では、距離を x [ドット]、速度を v [ドット/コマ]、経過時間を t [コマ]とすると、移動後の位置を求める式は
x1 = x0 + v * t
と、やっぱりこんな感じです。
ちなみにドットは画面上の座標、コマはループの回数で1コマは1ループです。
1コマごとに1回計算するのでtは常にt=1[コマ]と考えてokです。
px = px + (vx * 1)
というわけで、スクリプトでは×1を省略しています。
このように省略するには1コマあたりにかかる時間が安定していないといけないわけですが、
DirectXを使用するHSPプラグインではフレームレート(1コマにかかる時間)を一定に維持する命令が用意されています。
またちょっとした(さほど重くない)ゲームなら、1ループあたりの経過時間はほとんど問題になりません。(今回のサンプル
みたいなのがそうですね。)
40行目付近の
if (key&16=16) & (vx=0) : vx=vx+1 ;速度を与える
を消して次のように書き加えてみてください。
if key&256 : vx=vx+1 ;速度をxの正方向に加える
if key&512 : vx=vx-1 ;速度をxの負方向に加える
書き換えたらマウスの左右のボタンを押すと、速度vが変化するのを確認し、
動いている物体の様子をながめてみます。
HSP3では三角関数が標準で利用できますので、全方向に転がるボールを考えてみました。
画面をクリックすると、その方向にボールが転がります。
物理演算などは上で説明されているものと変わりません。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
-
|
!
-
|
|
-
|
!
-
|
|
|
!
|
#module
#deffunc DrwArrow int sx, int sy, int ex, int ey
line sx, sy, ex, ey
x = sx - ex
y = sy - ey
ax = (x - y) / 7 + ex
ay = (y + x) / 7 + ey
line ex, ey, ax, ay
ax = (x + y) / 7 + ex
ay = (y - x) / 7 + ey
line ex, ey, ax, ay
return
#global
#const SPEED 5
#const BALL_SIZE 6
title "等速直線運動"
WINX = ginfo_winx
WINY = ginfo_winy
gosub *resetBall
goto *main
*resetBall moving = 0 px = 100 py = 100
return
*main redraw 0
color 255, 255, 255 : boxf gosub *inkey
gosub *ball
gosub *draw
redraw 1
await 5
goto *main
*inkey stick key
if key & 128 : end
if ((key >> 8) & 1) & (moving == 0) { moving = 1 }
return
*ball if moving { px += vx
py += vy
if (px < 0)|(WINX < px)|(py < 0)|(WINY < py) { gosub *resetBall }
} else { theta = atan(mousey - py, mousex - px) vx = int(cos(theta) * SPEED)
vy = int(sin(theta) * SPEED)
}
return
*draw color 0, 0, 0 : pos 0, 0
mes "座標( " + px + ", " + py + " )"
mes "速度 v = ( " + vx + ", " + vy + " )"
if moving == 0 : mes "画面をクリックしてください。"
circle px - BALL_SIZE, py - BALL_SIZE, px + BALL_SIZE, py + BALL_SIZE
color 255, 0, 0
DrwArrow px, py, vx * 30 + px, vy * 30 + py
return
|