7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【GameMaker:Studio2】ホーミングミサイルの作り方 (GML)

Posted at

はじめに

今回はアクションゲームやシューティングゲームなどでよく使う、ホーミングミサイルの実装方法を解説します。

使用する関数

ホーミングミサイルを実装するにあたって、以下の関数を使うと簡単に実装できます。

  • instance_nearest(): 一番近いオブジェクトを取得する →一番近い敵を追尾するため
  • angle_difference(): 2つの角度の差を求める →ホーミングは旋回軌道により追尾を行う
  • point_direction(): 2点間のなす角度を求める →目標に命中する角度を求める
  • point_distance(): 2点間のなす距離を求める →一定距離内に達したら追尾を開始する

使用する素材

使用する素材はこちらにアップロードしているので、あらかじめダウンロードしておきます。
http://www.syun777.sakura.ne.jp/tmp/gms2/gms2_horming.zip

プロジェクトの作成

今回は GML を使用するので、GameMakerLanguage のプロジェクトを作成します
001.png

プロジェクトの設定

歯車アイコンをクリックして、Game Options を開きます。
Game frames per second の値を 60 にして、フレームレートを 60 にします。
002.png

プレイヤーの作成

オブジェクトを作成し、名前を objPlayer とし、スプライト作成します。
003.png

スプライトの名前を sprPlayer とします。
Import ボタンを押して、素材画像 player_strip2.png をインポートします。
004.png

アニメーションフレーム( Frames Per Second )を 3 とします。
005.png

今回はスプライトの原点が中央であると都合が良いので、原点を Middle Centre に変更します。
007.png

プレイヤーの配置

objPlayer をルームに配置します。 room0 を開きます。
Room Editor > Properties > Room Settings から Width800Height480 に変更します。
006.png

ルームサイズを変更したら、objPlayer をルームの左側に配置します。
008.png

実行して、objPlayerが表示されるのを確認します。

プレイヤーの移動処理

objPlayer を開いて、移動処理を作成します。
Add Event > Step > Step でStepイベントを作成します。
009.png

コードは以下のように記述します。

objPlayer>Stepイベント
// マウス座標との差を求める
var dy = mouse_y - y;

// 差の10分の1を足しこむ.
y += dy * 0.1;

このコードは現在の座標とマウス座標との差を求め、その差の10分の1をじわじわ足しこむ処理となります。
実行してみて動作を確認します。マウスの位置にプレイヤーが追従する動きをするようになりました。

ただ、プレイヤーが画面外に出て行ってしまうので、それを防ぐコードを追加します。

objPlayer>Stepイベント
// マウス座標との差を求める
var dy = mouse_y - y;

// 差の10分の1を足しこむ.
y += dy * 0.1;

// 画面外に出ないようにする
y = median(32, y, room_height-32);

median関数を使うことで、yの値が 32〜room_height-32 の範囲に収まるようにしました。
実行して、プレイヤーが画面外に出ないことを確認します。

ミサイルの実装

ホーミングミサイルを実装します。
オブジェクトを作成して、名前を objShot とします。
010.png

スプライトを作成し、名前を sprShot にして、Import ボタンを押して、人参の画像 carrot.png をインポートします。
011.png

人参のスプライトの原点を中央にするため、Middle Centre に変更します
012.png

objShot のイベントを追加します。
Add Event > Other > Outside Room を選択して、Outside Room イベントを追加します。
013.png

コードは以下のように記述します。

objShot>OutsideRoomイベント
instance_destroy();

ルーム外に出たら破棄処理を行います。

さらに、Add Event > Destroy で破棄イベントを追加します。
014.png

コードは以下のように記述して、破棄されたらエフェクトを発生させるようにします。

objShot>Destroyイベント
effect_create_above(ef_explosion, x, y, 1, c_white);

プレイヤーからミサイルを発射する

objPlayer を開いて、Stepイベントのコードを以下のように修正します。

objPlayer>Stepイベント
// マウス座標との差を求める
var dy = mouse_y - y;

// 差の10分の1を足しこむ.
y += dy * 0.1;

// 画面外に出ないようにする
y = median(32, y, room_height-32);

// ※※※※※※※※※※※
// ここから追加
// ※※※※※※※※※※※
if(mouse_check_button_pressed(mb_left)) {
	// 左クリックでミサイルを発射
	var inst = instance_create_depth(x, y, 0, objShot);
	with(inst) {
		// 0度方向に5の速度で発射
		motion_add(0, 5);
	}
}

マウスの左クリックで右側に向かって発射するようにしました。
では、実行して人参ミサイルが発射できることを確認します。
015.png

敵オブジェクトを作成

新しくオブジェクトを追加して、名前を objEnemy とします。
016.png

スプライトを追加して、名前を sprEnemy とし、Import ボタンを押して、素材画像 nasu.png をインポートします。
017.png

そして、原点を中央 (MiddleCentre) に変更しておきます。
018.png

objEnemy のイベントを追加します。
Add Event > Step > Step を選び、Stepイベントを追加します。
019.png

Stepイベントには以下のように記述します。

objEnemy>Stepイベント
// 下に動かす
vspeed = 2;
// 画面外に出たら反対側から出現させる
move_wrap(true, true, 0);

ホーミングで命中させる対象を動かすだけなので、下に動かして画面外に出たら反対側に移動するだけのコードです。

では敵を配置します。room0を開いて、objEnemy を配置します。
020.png

それぞれの敵が、おおよそ均等に配置されていれば問題ありません。
では実行して、敵が上から下に移動するのを確認します。

ミサイルと敵との当たり判定を実装

objEnemy を開いて Add Event > Collision > objShot を作成し、人参ミサイルとの衝突イベントを作成します。
021.png

コリジョンイベントのコードは以下のように記述します。

objEnemy>Collisionイベント
with(other) {
	// ミサイルを消す
	instance_destroy();
}

衝突したミサイルを消すだけのコードです。
では実行して、敵にミサイルを当てると消滅することを確認します。
022.png

ホーミングの軌道を作成する

ようやくホーミングの軌道の実装です。
objShot を開いて、Add Event > Step > Step でStepイベントを作成します。
025.png

objShot>Stepイベント
// ①一番近い敵を探す
var inst = instance_nearest(x, y, objEnemy);
if(inst == noone) {
	// 見つからなかったので何もしない
	return;
}

// ②目標に対する角度を計算する
var to_dir = point_direction(x, y, inst.x, inst.y);

// ③現在の角度と目標への角度の差を求める
var diff = angle_difference(image_angle, to_dir);
if(diff > 0) {
	// ④-a. プラスは時計回り
	image_angle -= 1;
}
else {
	// ④-b. マイナスは反時計回り
	image_angle += 1;
}

// ⑤回転値を移動角度にも反映する
direction = image_angle;

コードを詳しく解説すると、①のところで一番近い敵を探し、
②でそれに対する角度を計算します。
023.png

③で現在向いている角度から目標への角度差を求めます。
024.png

そして、計算した角度差を元に旋回処理を行っているのが④と⑤となります。
angle_difference() で得られる数値の符合が逆のような気がしますが、そういうものとして反転して扱います。

では実行してみると、発射したミサイルが敵に追尾します。
026.png

一定の範囲内に入ったら追尾するようにする

objShot を開いて、Stepイベントを修正します。

objShot>Stepイベント
// ①一番近い敵を探す
var inst = instance_nearest(x, y, objEnemy);
if(inst == noone) {
	// 見つからなかったので何もしない
	return;
}

// ※ここを追加
var to_dist = point_distance(x, y, inst.x, inst.y);
if(to_dist > 100) {
	// 100px以内に入らないと追尾しない
	return;
}
// ※ここまで追加

// ②目標に対する角度を計算する
var to_dir = point_direction(x, y, inst.x, inst.y);

// ③現在の角度と目標への角度の差を求める
var diff = angle_difference(image_angle, to_dir);
if(diff > 0) {
	// ④-a. プラスは時計回り
	image_angle -= 3; // ※旋回速度を修正
}
else {
	// ④-b. マイナスは反時計回り
	image_angle += 3; // ※旋回速度を修正
}

// ⑤回転値を移動角度にも反映する
direction = image_angle;

※の部分が修正箇所です。
②の角度計算の前に距離を計算し、半径100px以内に入らないと追尾しないようにしています。
また、④の旋回速度の部分を少し大きくしています。

実行すると、基本的にまっすぐ飛びますが、敵の近くに行くと旋回して追尾するようになります。
距離制限のホーミングは、あまり使い道はないように思えるかもしれませんが、敵が発射するホーミングミサイルでこのような追尾条件を入れておくと、回避しやすくなって面白さが増す可能性があります。

あと、追尾範囲が見た目でわかりにくいので追尾する範囲を描画するようにしてみます。
objShot を開いて、 Add Event > Draw > Draw GUI イベントを追加し、以下のコードを追加します。

objShot>DrawGUIイベント
draw_circle(x, y, 100-32, true);

追尾範囲は半径100pxなのですが、ナスの半径が32pxなので、100-32となっています。

では実行して追尾範囲が表示されるのを確認します。
027.png

最後に

ここで作ったホーミングは、一番近い敵を追尾するようにしていますが、例えばロックオンした敵のみを追尾するなど、ゲームシステムによって柔軟に作り変えても良いと思います。

以上、ホーミングの作り方でした。

7
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?