慣性を導入した移動 †
レースゲームの特色とも言える慣性を実装するための方法を解説します。
レースゲームに特化して解説しますが、アクションやシューティングなどのジャンルにも応用できると思います。
慣性とは力を受けない限り物体の運動状態が(慣性系に対して)変化しない性質です。
現実世界の運動には必ず慣性が働くので、リアリティのあるゲームを作成する上で慣性は非常に重要です。
一般的なレースゲームではアイテムなどの例を除いて
- タイヤと道路間の摩擦力
- アクセルによる力
- ブレーキによる力
- コースや他の車から受ける力
を受けない限り車の速度が変化しないようになっています。
しかしゲームプログラムでこれらの力の計算を厳密に行うのは無駄な場合が多いので、適宜近似した式を用いることをお勧めします。
慣性を導入するにあたって必要な知識をまとめました。より詳しいことは物理のおおまかな話などを参照してください。
- 速度
- 1フレームあたりの位置の移動量。メインループが1回実行されると10ピクセル移動する物体の速度は10[px/f]。
平面上で運動する物体なら、物体の速度は2方向に分解できる。通常レースゲームではX方向とY方向に分解する。
- 加速度
- 1フレームあたりの速度の変化量。メインループが1回実行されると速度が2ピクセル減少する物体の加速度は-2[px/f/f]。
慣性を導入しない場合はstickやgetkeyで取得したプレイヤーの入力をそのまま速度として使えば良かったのですが、
慣性を導入する場合はプレイヤーの入力は加速度に反映させる必要があります。
速度はこの加速度をフレームごとに加算することで決定されます。
摩擦力の計算やアクセル・ブレーキなどの概念を取っ払った、近似的な慣性を実現したサンプルスクリプトです。
ゲームプログラムではこうした近似で充分役に立ちます。
↑キーを押している間だけ加速し、押していない場合は減速します。
速度はlimitf()関数によって上限および下限が決められています。
#constで定義されている数値を変更して色々と試してみてください。
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
79
80
81
82
83
84
85
86
87
88
89
90
91
|
-
|
|
|
|
|
|
|
|
!
-
|
|
|
|
|
|
!
|
#const PI 3.14159
#const AREA_X 320 #const AREA_Y 320 #const GRID_DISTANCE 32 #const GRID_NUM_X 11 #const GRID_NUM_Y 11 #const CAR_SIZE 12 #const ACCELERATION 0.1 #const ANG_SPEED 0.1 #const MAX_SPEED 3.0 #const AWAIT_TIME 16
*init
screen 0, AREA_X, AREA_Y, 0
title "慣性を導入した移動"
carX = 10.0 : carY = 10.0 carT = PI / 4 carSpeed = 0.0 needToDraw = 1
*main
gosub *move gosub *draw await AWAIT_TIME
goto *main
*move
stick key, %111 gosub *moveCar return
*moveCar
carSpeed = limitf(carSpeed + ACCELERATION * ((key & 2) - 1), 0.0, MAX_SPEED)
if carSpeed > 0.0 {
carT += ANG_SPEED * ((key & 1) - (key >> 2 & 1))
carX = limitf(carX + carSpeed * cos(carT), 0, AREA_X)
carY = limitf(carY + carSpeed * sin(carT), 0, AREA_Y)
needToDraw = 1 }
return
*draw
if needToDraw {
redraw 0
color : boxf
gosub *drawGrid
gosub *drawCar
redraw 1
if carSpeed == 0.0 : needToDraw = 0
}
return
*drawGrid
color 0, 0, 255
repeat GRID_NUM_Y
y = cnt * GRID_DISTANCE
repeat GRID_NUM_X
x = cnt * GRID_DISTANCE
line x, AREA_Y, x, 0
line AREA_X, y, 0, y
loop
loop
return
*drawCar
color 255
pos carX, AREA_Y - carY
line carX - cos(carT + 0.2) * CAR_SIZE, AREA_Y - (carY - sin(carT + 0.2) * CAR_SIZE)
line carX - cos(carT - 0.2) * CAR_SIZE, AREA_Y - (carY - sin(carT - 0.2) * CAR_SIZE)
line carX, AREA_Y - carY
return
|