Redpoll's 60
 Home / 3Dプログラミング入門 / 第2章 $§$2-10
第2章 2D空間におけるオブジェクトの運動
$§$2-1 オブジェクトの初期状態$§$2-17 衝突判定 5
$§$2-2 行列による変換の詳細 1$§$2-18 初期状態における頂点情報の取得について
$§$2-3 行列による変換の詳細 2$§$2-19 衝突判定 6 (軸平行な長方形同士の衝突)
$§$2-4 自転と公転$§$2-20 衝突判定 7 (円盤 vs 長方形)
$§$2-5 一体化したオブジェクトの運動 1$§$2-21 衝突判定 8 (回転した長方形同士の衝突)
$§$2-6 一体化したオブジェクトの運動 2$§$2-22 衝突判定 9 (「倉庫番」プログラムの作成)
$§$2-7 一体化したオブジェクトの運動 3$§$2-23 衝突判定 10 (円盤 vs 三角形)
$§$2-8 指定方向へのオブジェクトの移動 1$§$2-24 衝突判定 11 (直線 vs 長方形、円盤、直線)
$§$2-9 指定方向へのオブジェクトの移動 2$§$2-25 円と直線による補間曲線 1
$§$2-10 指定方向へのオブジェクトの移動 3$§$2-26 円と直線による補間曲線 2
$§$2-11 指定方向へのオブジェクトの移動 4 (連射プログラムの実装)$§$2-27 その他の重要事項 1 (UnityのTransformクラスによる記述 ; カメラ移動の基本)
$§$2-12 指定方向へのオブジェクトの移動 5$§$2-28 その他の重要事項 2 (画面に表示されるXY平面の範囲 ; ミニマップの実装)
$§$2-13 衝突判定 1 (点 vs 円盤、長方形 ; ローカル座標からワールド座標への変換 2D)$§$2-29 その他の重要事項 3 (スクリーン座標からワールド座標への変換 2D; スクリーンショットの撮影範囲)
$§$2-14 衝突判定 2$§$2-30 課題 1
$§$2-15 衝突判定 3$§$2-31 課題 2
$§$2-16 衝突判定 4

$§$2-10 指定方向へのオブジェクトの移動 3


本節では、2D形状のヘリコプターを使用して今までに学習してきた内容についての復習を行う。本節におけるプログラムはすべて、その内容については今までに学習したものとほとんど同じである。したがって、プログラムに関しての解説は必要最小限に留める。

使用するオブジェクトは以下の2つである。

図1 Body 初期状態
図2 Rotor 初期状態


# Code1
まずは、2つのオブジェクトを一体化するだけのプログラムである。
Rotorを Bodyにアタッチする (親子関係は Bodyが親で、Rotorが子である)。

[Code1]  (実行結果 図3)
THMatrix3x3 localRotor = TH2DMath.GetTranslation3x3(c_attachPos_Rotor);
THMatrix3x3 localBody = THMatrix3x3.identity;

THMatrix3x3 worldRotor = localBody * localRotor;
THMatrix3x3 worldBody  = localBody;

Rotor.SetMatrix(worldRotor);
Body.SetMatrix(worldBody);

1行目の c_attachPos_Rotor は Rotorのアタッチポジションを表す Vector2型の定数である。

図3 Code1 実行結果
図4 Code2 実行結果

# Code2
続いて、Rotorがアタッチポジションにおいて回転を行うプログラムを作成する。

[Code2]  (実行結果 図4)
i_degRotor += 12;
THMatrix3x3 rotRotor = TH2DMath.GetRotation3x3(i_degRotor);
THMatrix3x3 traRotor = TH2DMath.GetTranslation3x3(c_attachPos_Rotor);
THMatrix3x3 localRotor = traRotor * rotRotor;

THMatrix3x3 localBody = THMatrix3x3.identity;

THMatrix3x3 worldRotor = localBody * localRotor;
THMatrix3x3 worldBody = localBody;

Rotor.SetMatrix(worldRotor);
Body.SetMatrix(worldBody);

1行目の i_degRotor は Rotorの回転角度を表すインスタンス変数であり(int型)、毎フレーム $12$ずつ増加するので Rotorはアタッチポジションにおいて毎フレーム $12$°ずつ回転する (30FPSの設定なので1秒間で1回転である。上図4)。

# Code3
次に、Bodyと Rotorの一体化した運動として、全体の向きを変えるプログラムを作成する。向きの変更はキー操作によって行うが、使用するキーは2-8節や2-9節と同じである。

H  :  Bodyの向きを反時計周りに回転 (回転は $1^\circ$ ずつ)。
L  :  Bodyの向きを時計周りに回転。

(「Bodyの向き」とは、図1の初期状態ではy軸プラス方向であり、Bodyの先端の方向のことである)

まずは、Bodyだけが回転するプログラムである。
[Beta3]  (実行結果 図5)
if (Input.GetKey(KeyCode.H))
{
    i_degBody += 1;
}
else if (Input.GetKey(KeyCode.L))
{
    i_degBody -= 1;
}

THMatrix3x3 R = TH2DMath.GetRotation3x3(i_degBody);
Body.SetMatrix(R);

使用されている変数 i_degBody は、Bodyの回転角度を表すインスタンス変数である。Hキー、Lキーが押されるごとに(あるいは押され続けている間に) その値が$1$ずつ増減する。このプログラムは毎フレーム Bodyに対して、初期状態の向きであるy軸プラス方向から角度i_degBodyの回転を実行するだけのプログラムである。

では、Bodyと Rotorが一体となって向きを変えるプログラムを以下に示す。ただし、Rotorはアタッチポジションにおいて回転をしている。
[Code3]  (実行結果 図6)
if (Input.GetKey(KeyCode.H))
{
    i_degBody += 1;
}
else if (Input.GetKey(KeyCode.L))
{
    i_degBody -= 1;
}

i_degRotor += 12;
THMatrix3x3 rotRotor = TH2DMath.GetRotation3x3(i_degRotor);
THMatrix3x3 traRotor = TH2DMath.GetTranslation3x3(c_attachPos_Rotor);
THMatrix3x3 localRotor = traRotor * rotRotor;

THMatrix3x3 localBody = TH2DMath.GetRotation3x3(i_degBody);

THMatrix3x3 worldRotor = localBody * localRotor;
THMatrix3x3 worldBody  = localBody;

Rotor.SetMatrix(worldRotor);
Body.SetMatrix(worldBody);

Beta3、Code3の実行結果を以下に示す。

図5 Beta3 実行結果
図6 Code3 実行結果

# Code4
今までのプログラムではオブジェクトの位置は最初の位置である原点から動かなかったが、ここでは キー操作により Bodyと Rotorが一体となって平行移動を行うプログラムを作成する。

まずは、キーを1回押すごとに Bodyの向きに一定距離だけ進むプログラムを作成する。使用するキーは以下のとおり。
H  :  Bodyの向きを反時計周りに回転 (回転は $1^\circ$ ずつ)。
L  :  Bodyの向きを時計周りに回転。
S  :  Bodyの向きに一定距離だけ移動 (移動させるためにキーを1回1回押す必要がある)。

[Beta4]  (実行結果 図7)
if (Input.GetKey(KeyCode.H))
{
    i_degBody += 1;
}
else if (Input.GetKey(KeyCode.L))
{
    i_degBody -= 1;
}

// localRotor
i_degRotor += 12;
THMatrix3x3 rotRotor = TH2DMath.GetRotation3x3(i_degRotor);
THMatrix3x3 traRotor = TH2DMath.GetTranslation3x3(c_attachPos_Rotor);
THMatrix3x3 localRotor = traRotor * rotRotor;

// localBody
THMatrix3x3 rotBody = TH2DMath.GetRotation3x3(i_degBody);
Vector2 direBody = rotBody * new Vector3(0, 1, 1);

Vector2 curP = Body.GetPosition();
Vector2 newP = (Input.GetKeyDown(KeyCode.S)) ? (curP + 1.0f * direBody) : curP;  
THMatrix3x3 traBody = TH2DMath.GetTranslation3x3(newP);
THMatrix3x3 localBody = traBody * rotBody;

// world matrix
THMatrix3x3 worldRotor = localBody * localRotor;
THMatrix3x3 worldBody  = localBody;

Rotor.SetMatrix(worldRotor);
Body.SetMatrix(worldBody);

図7 Beta4 実行結果
18行目の変数 direBody は、2-9節の後半で使われた同名の変数と役割は同じである。すなわち、オブジェクトBodyの進行方向を単位ベクトルとして保持するローカル変数で、プログラム実行中 常に Bodyの向きと一致する。
実行結果(図7)に見られるように、Sキーを押すごとに Bodyの向いている方向へ一定距離だけ進んでいく (21行目で使われているSキー処理用のメソッドは Input.GetKeyDown(..) なので長押しには対応しない)。

では最後に、キーを1回1回押すことによる移動ではなく、1回キーを押すと再度押されるまでの間 ずっと動き続けるプログラムを作成する。
使用するキーは先程と同じであるが、Sキーに関しては内容が異なる。具体的には、次のように変更する。

S  :  オブジェクトの移動/停止用スイッチ。静止中に押すと、Bodyの向いている方向へ(direBodyの方向へ)一定速度で移動を開始する。再度キーを押すまでこの移動は続く。

[Code4]  (実行結果 図8)
if (Input.GetKey(KeyCode.H))
{
    i_degBody += 1;
}
else if (Input.GetKey(KeyCode.L))
{
    i_degBody -= 1;
}

if (Input.GetKeyDown(KeyCode.S))   // 移動/停止
{
    i_MOVE = !i_MOVE;
}

// localRotor
i_degRotor += 12;
THMatrix3x3 rotRotor = TH2DMath.GetRotation3x3(i_degRotor);
THMatrix3x3 traRotor = TH2DMath.GetTranslation3x3(c_attachPos_Rotor);
THMatrix3x3 localRotor = traRotor * rotRotor;

// localBody    
THMatrix3x3 rotBody = TH2DMath.GetRotation3x3(i_degBody);
Vector2 direBody = rotBody * new Vector3(0, 1, 1);

Vector2 curP = Body.GetPosition();
Vector2 newP = (i_MOVE) ? (curP + 0.075f * direBody) : curP;
THMatrix3x3 traBody = TH2DMath.GetTranslation3x3(newP);
THMatrix3x3 localBody = traBody * rotBody;

// world matrix
THMatrix3x3 worldRotor = localBody * localRotor;
THMatrix3x3 worldBody  = localBody;

Rotor.SetMatrix(worldRotor);
Body.SetMatrix(worldBody);

図8 Code4 実行結果
プログラムの内容自体は2-9節Code7のキー操作による戦車の移動プログラムとほとんど同じである。使用している子オブジェクトの名前や動作に違いがあるだけで、親オブジェクト Bodyの運動に関してはこのプログラムと2-9節Code7とで記述内容に本質的な違いはない。
実行結果(図8)に見られるように、停止中に1度Sキーを押せば Bodyの向いている方向に(連続的な)移動が始まり、移動中にHやLキーを押し続けることで進行方向が変化していく。












© 2020-2024 Redpoll's 60 (All rights reserved)