プロジェクトシートK(仮)

技術の吐き溜めなどなど

【6】Siv3Dで、シューティングゲームの自機を実装する

シューティングゲームの要領で、キーボード入力に対して画面上のオブジェクトを動かしてみようと思います。また、自機とオブジェクトとの当たり判定なんかも実装してみます。

今回取り扱う内容はかなり簡単な内容かと思いますので、肩の力を抜いてみて頂ければなーと思います!



自機の実装

まず、自機を実装するために必要な情報を確保します。新たに構造体を定義して作るのが後を見据えると良いのですが、段階を追うためにとりあえずは簡単な単一のものから取り扱います。

自機に必要なものを考えてみると、最低限
・自機の位置
・自機の形

の2つがあれば成り立ちそうです。プレイヤーが操作する自機の情報として、Circle型の変数playerが1つあれば、これら2つの情報がまとめて確保できますね。

続けて、この自機をキーボード操作により動かせるようにしましょう。Siv3Dでは、キー入力の情報などがInput::KeyLeft.pressedという形で簡単に検出することができます。これを使います。

具体的には、「左キーが押されれば左に(画面におけるx軸マイナスの向き)、上キーが押されれば上に(画面におけるy軸マイナスの向き)、右キーが押されれば右に(画面におけるx軸プラスの向き)、下キーが押されれば下に(画面におけるy軸プラスの向き) 自機を移動させる」ことをします。この情報は、大きさを考慮しなければ
Vec2 direction(Input::KeyRight.pressed - Input::KeyLeft.pressed, Input::KeyDown.pressed - Input::KeyUp.pressed);
のように記述することができます。ここで得た情報とplayer.moveBy()関数を用いれば、自機の移動が実装できます。Vector型には大きさをセットできるsetLength()関数が定義されているため、これを用いれば自機の速さの制御も行えます。

あとはこのplayerを描写すればオッケーです!

# include <Siv3D.hpp>

void Main()
{
	Circle player({ 320,400 }, 10);

	while (System::Update())
	{
		Vec2 direction(Input::KeyRight.pressed - Input::KeyLeft.pressed, Input::KeyDown.pressed - Input::KeyUp.pressed);
		if (!direction.isZero()) //キーが入力されていれば
			player.moveBy(direction.setLength(5)); //速さ5でプレイヤーを動かす

		player.draw(Palette::Red);
	}
}

当たり判定の実装

当たり判定を実装するために、図形同士の当たり判定を行う関数intersects()を使います。これは図形1.intersects(図形2)のように使い、図形同士がちょっとでも触れていればTrueが返されます。他にも図形の包含を判定する関数などもあるので、詳細はリファレンスを参照するといいでしょう。
図形の当たり判定 · Siv3D/Reference-JP Wiki · GitHub

今回作成したコード

# include <Siv3D.hpp>
struct MyCircle {
private:
	int radius;
	Vec2 place;
	int color;
public:
	MyCircle(int r, Vec2 p, int c) {
		radius = r; place = p; color = c;
	}
	void setRadius(int r) { radius = r; }
	void setPlace(Vec2 p) { place = p; }
	void setColor(int c) { color = c; }
	int getRadius(void) { return radius; }
	Vec2 getPlace(void) { return place; }
	int getColor(void) { return color; }
	bool deleteCheck(void) { return ((place.x < -20) || (place.x > 660) || (place.y < -20) || (place.y > 500));}
};

void Main()
{
	Array<MyCircle> array;
	int radius = 20;
	int count = 0;
	Circle player({ 320,400 }, 10);
	int hitCount = 0;

	while (System::Update())
	{
		if (count == 0) {
			MyCircle cir(radius, Vec2(340, 20), 100);
			array.push_back(cir);
		}

		//キーボード入力部
		Vec2 direction(Input::KeyRight.pressed - Input::KeyLeft.pressed, Input::KeyDown.pressed - Input::KeyUp.pressed);
		if (!direction.isZero())
			player.moveBy(direction.setLength(5));

		//オブジェクトの描写・セット・当たり判定チェック
		for (auto& object : array) {
			//場所のセット
			object.setPlace(object.getPlace() + Vec2(0, 5));
			//オブジェクトの定義・描写
			Circle cir(object.getPlace(), object.getRadius());
			cir.draw(HSV(object.getColor()));
			//当たり判定チェック 当たったとき、オブジェクトが消えるように仕向ける
			if (player.intersects(cir)) {
				object.setPlace(Vec2(-50,-50));
				hitCount++;
			}
		}

		//オブジェクトの削除
		Erase_if(array, [](MyCircle& c) { return c.deleteCheck(); });

		//プレイヤーの描写
		player.draw(Palette::Red);

		PutText(L"HIT回数:", hitCount).from(80, 10);
		count++;
		count = count % 60;
	}
}

www.youtube.com