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

技術の吐き溜めなどなど

【9】Siv3D 敵HPゲージを実装する

敵HPのゲージを実装してみます。今までの記事と比べると明らかにコードも内容も薄いですが、リアルとの兼ね合いで許してください…orz


今までは、敵のHPを数値によって表示させていました。このままでも良いのかもしれませんが、敵の弾を避けつつ文字を確認するなど玄人でもないと無理ですので、一般人の周辺視野でも確認できる程度にはわかりやすく表示させましょう。(そもそもHP表示の無いシューティングゲームの方が多いと感じますが、ゲージがあった方が個人的には好みです)

また、ついでに自機数なんかの表示形式も変えてみます。


コード

# include <Siv3D.hpp>
struct MyCircle {
private:
	int radius;
	Vec2 place;
	int color;
	Vec2 velocity = Vec2(0, 0);
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; }
	void setVelocity(Vec2 v) { velocity = v; }
	int getRadius() const { return radius; }
	Vec2 getPlace() const { return place; }
	int getColor() const { return color; }
	bool isVisible() const { return InRange(place.x,-10.0,650.0) && InRange(place.y,-10.0,490.0);}
	Vec2 getVelocity() const { return velocity; }
};

struct Player {
private:
	Vec2 place;
	int radius;
	int hp = 3;
	int shotFlg = 2;
public:
	Player(int r, Vec2 p) {
		radius = r; place = p;
	}
	void setRadius(int r) { radius = r; }
	void setPlace(Vec2 p) {
		place += p; 
		place.x = Clamp(place.x, 10.0, 630.0);
		place.y = Clamp(place.y, 10.0, 470.0);
	}
	void hit() { --hp; if (hp == 0) { place = Vec2(1000, 1000); } }
	int getRadius() const{ return radius; }
	Vec2 getPlace() const{ return place; }
	int getHP() const{ return hp; }
	bool shot() {
		++shotFlg;
		if (shotFlg == 3) {
			shotFlg = 0;
			return true;
		}
		return false;
	}
};

struct Enemy {
private:
	Vec2 place;
	int radius;
	int hp = 300;
	int dir = 0;
public:
	Enemy(int r, Vec2 p) {
		radius = r; place = p;
	}
	void setRadius(int r) { radius = r; }
	void setPlace(void) {
			place.x += dir;
		if(place.x < 40 || place.x > 580) {
			dir = -dir;
		}
	}
	void hit(void) {
		--hp;
		if (hp == 200) { dir = 2; }
		if (hp == 100) { dir = dir * 3; }
		if (hp == 0) { place = Vec2(2000, 2000); } 
	}
	int getRadius(void) const { return radius; }
	Vec2 getPlace(void) const { return place; }
	int getHP(void) const { return hp; }
};

void Main()
{
	Array<MyCircle> array;
	Array<Vec2> shots;
	int radius = 10;
	int count = 0;
	Vec2 spawn(340, 60);
	int speed = 5;

	Player player(20, Vec2(320,400));
	Enemy enemy(40, spawn);

	const Rect frame(10, 10, 620, 460); //枠
	const Texture texture(L"Example/texture.png"); //背景テクスチャ
	const Texture star(L"Example/star.png"); //球テクスチャ
	const Texture chara(L"Example/Enemy.png"); //敵テクスチャ

	while (System::Update())
	{
		//背景の表示
		texture.draw(10, 10);

		//敵の表示
		enemy.setPlace();
		Circle ene(enemy.getPlace(), 100); //敵の当たり判定用
		chara.draw(enemy.getPlace() + Vec2(-50,-60));

		//球の発生
		MyCircle cir(radius, enemy.getPlace(), 100);
		cir.setVelocity(Vec2(-cos(count/Pi),sin(count/Pi)).setLength(speed));
		array.push_back(cir);

		//プレイヤー処理
		const Triangle playerView(player.getPlace(), player.getRadius());
		if (player.getHP() != 0) {
			//キーボード入力部
			Vec2 direction(Input::KeyRight.pressed - Input::KeyLeft.pressed, Input::KeyDown.pressed - Input::KeyUp.pressed);
			if (!direction.isZero())
				player.setPlace(direction.setLength(5));

			//Sキーでショット
			if (Input::KeyS.pressed) {
				if (player.shot()) {
					shots.push_back(player.getPlace());
				}
			}
			//プレイヤー描写
			playerView.draw(Palette::Red);
		}

		//自分が出したショットの処理
		for (auto& shot : shots) {
			Circle c(shot,4);
			c.draw(Palette::Gray);
			if (c.intersects(ene)) { 
				enemy.hit(); 
				shot = Vec2(-1000, -1000);
			}
			shot += Vec2(0, -10);
		}
		Erase_if(shots, [](const Vec2& s) { return s.y < -10.0; });

		//オブジェクトの描写・セット・当たり判定チェック
		for (auto& object : array) {
			//場所のセット
			object.setPlace(object.getVelocity());
			//オブジェクトの定義・描写
			Circle c(object.getPlace(), object.getRadius());
			c.draw(HSV(object.getColor()));
			star.draw(object.getPlace()-Vec2(30,30)); //テクスチャ表示
			//当たり判定チェック
			if (playerView.intersects(c)) {
				object.setPlace(Vec2(1000,1000));
				player.hit();
			}
		}

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

		//自機数の表示
		int hp = player.getHP();
		for (auto i = 0; i < hp; ++i) {
			PutText(L"★").from(15 + i*20, 12);
		}

		//敵HPゲージ表示
		Rect(410, 18, 200, 10).draw(Palette::Gray);
		Rect(410, 18, enemy.getHP() * 200 / 300, 10).draw(Palette::Red);

		count++;
		count = count % 180;

		//枠の表示
		frame.drawFrame(2, 0, Palette::Yellow);
		frame.drawFrame(0, 10, Palette::Black);
	}
}

f:id:konkea:20161210001233p:plain
右上に敵HPゲージが追加されている

更新部

今回更新した部分はここです。

//自機数の表示
int hp = player.getHP();
for (auto i = 0; i < hp; ++i) {
	PutText(L"★").from(15 + i*20, 12);
}

//敵HPゲージ表示
Rect(410, 18, 200, 10).draw(Palette::Gray);
Rect(410, 18, enemy.getHP() * 200 / 300, 10).draw(Palette::Red);


短っ!と感じるかもしれませんが、これで敵HPおよび自機数表示ができます。弾幕にゲージが隠れないように、弾幕描写した後にゲージを描写しましょう。Enemy構造体によって敵HPの参照が簡単に行えるため、その値に合わせてゲージ(四角形Rect)を描写するだけでオッケーです!


さて、各種構造体を用いた描写をMainに詰め込んでいるわけですが、管理のしやすさを考えると構造体内で描写をした方が圧倒的に便利に思えますね。その場合、当たり判定をどのように行えばよいのか不安ではありますが…いろいろと模索してみようと思います。


かなり短めですが今回はここまでとします。次回は全面的なコード整理か、シーン遷移、もしくはエフェクトでも実装してみようかなと思います!