2Dシューティング 操作キャラの向いている方向に弾を飛ばし続けたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
もんの

2Dシューティング 操作キャラの向いている方向に弾を飛ばし続けたい

#1

投稿記事 by もんの » 1年前

Dxライブラリで2Dシューティングをつくろうとしています。言語はC++です。学習歴は10か月程です。
こちらのサイト https://bituse.info/game/shot/ を参考にしています。
現在、操作キャラが向いている方向に弾を発射したいと考えており、キャラが向いている方向ごとに
弾の発射角度を設定しました。この方法だと、例えば右を向いているときに弾を発射すると、弾は右方向へ飛んでいくのですが、弾が画面外に出る前にキャラが左を向くと、弾も左へ来てしまいます。キャラが向いている方向ごとに発射角度を設定したので当たり前ですが、弾の飛んでいく方向がキャラの向いている方向と一致してしまいます。
最終的には、一度弾を発射したらキャラの向いている方向に関係なく、弾が最初の方向に飛び続けていくようにしたいのですが、解決策が思いつきません。助言をいただけると幸いです。


player.h

コード:

 
#include "define.h"

class PLAYER {
private:
	int x = 100, y = 100;
	int gh[12];
	int width = 32, height = 32;
	
	double move = 1.0; //移動係数

	int xcount = 0, ycount = 0; //横方向と縦方向のカウント数。
	
	int ix = 0, iy = 0, result = 0; //添字用変数
	
	bool life = true; //生きているか
    
	double speed = 4, angle; //ショットのスピードと角度
    int aflag[num], bflag; 
	int sx[num], sy[num];
	int sgh, swidth, sheight;
	int mw, mh, sw, sh;
	

private:
	void DRAW();
	void MOVE();
	void SHOT();
public:
	PLAYER();
	void ALL();
};


player.cpp

コード:

 
 #include "DxLib.h"
#include "PLAYER.h"
#include "define.h"
#include <math.h>

PLAYER::PLAYER() {
	LoadDivGraph("キャラ_017.png", 12, 3, 4, 32, 32, gh);
	sgh = LoadGraph("star3.png");
	for (int i = 0; i < num; i++) {
		aflag[i] = 0;
	}
	bflag = 0;
	}


void PLAYER::MOVE() {
	
	if (key[KEY_INPUT_LEFT] == 1 || key[KEY_INPUT_RIGHT] == 1) {

		if (key[KEY_INPUT_UP] == 1 || key[KEY_INPUT_DOWN] == 1) {
			//移動係数を0.7に設定
			move = 0.7;
		}
		else {
			//斜めじゃなければ1.0に設定
			move = 1.0;
		}
	}
	else if (key[KEY_INPUT_UP] == 1 || key[KEY_INPUT_DOWN] == 1) {
		move = 1.0;
	}

	if (key[KEY_INPUT_LEFT] == 1) {
		x -= 4 * move;
	}

	if (key[KEY_INPUT_RIGHT] == 1) {
		x += 4 * move;
	}

	if (key[KEY_INPUT_UP] == 1) {
		y -= 4 * move;
	}

	if (key[KEY_INPUT_DOWN] == 1) {
		y += 4 * move;
	}

	if (x < MARGIN) x = MARGIN;
	
    if (x > 625) x = 625;
	
	if (y < MARGIN) y = MARGIN;
	
    if (y > 458) y = 458;
	
	//左キーが押されてて、かつxcountが0以上なら0にしてから1引く。
	//それ以外は1引く
	if (key[KEY_INPUT_LEFT] == 1) {
		if (xcount > 0)
			xcount = 0;
		--xcount;
		angle = -PI; //左
	}
	//右キーが押されてて、かつxcountが0以下なら0にしてから1足す。
	//それ以外は1引く
	if (key[KEY_INPUT_RIGHT] == 1) {
		if (xcount < 0)
			xcount = 0;
		++xcount;
		angle = 2 * PI;//右
	}
	//上キーが押されてて、かつycountが0以上なら0にしてから1引く。
	//それ以外は1引く
	if (key[KEY_INPUT_UP] == 1) {
		if (ycount > 0)
			ycount = 0;
		--ycount;
		angle = -(PI / 2); //上
	}
	//下キーが押されてて、かつycountが0以下なら0にしてから1足す。
	//それ以外は1足す
	if (key[KEY_INPUT_DOWN] == 1) {
		if (ycount < 0)
			ycount = 0;
		++ycount;
		angle = PI / 2; //下
	}


	//カウント数から添字を求める。
	ix = abs(xcount) % 30 / 10;
	iy = abs(ycount) % 30 / 10;

	//xカウントがプラスなら右向きなので3行目の先頭添字番号を足す。
	if (xcount > 0) {
		ix += 6;
		result = ix;
	}
	else if (xcount < 0) {
		//マイナスなら左向きなので、2行目の先頭添字番号を足す。
		ix += 3;
		result = ix;
	}

	//yカウントがプラスなら下向きなので、1行目の先頭添字番号を足す。
	if (ycount > 0) {
		iy += 0;
		result = iy;
	}
	else if (ycount < 0) {
		//1行目の先頭添字番号は0なので何もする必要なし。
		iy += 9;
		result = iy;
	}

	//斜め移動の場合は横顔を優先
	if (move == 0.7)
		result = ix;

	if (life) {
		DrawGraph(x - width / 2, y - height / 2, gh[result], TRUE);
	}

	//押されてなければカウントをゼロにする
	if (key[KEY_INPUT_LEFT] != 1 && key[KEY_INPUT_RIGHT] != 1) {
		xcount = 0;
	}
	if (key[KEY_INPUT_UP] != 1 && key[KEY_INPUT_DOWN] != 1) {
		ycount = 0;
	}

    }

	

	void PLAYER::SHOT() {


		// スペースキーを押した場合は処理を分岐
		if (CheckHitKey(KEY_INPUT_SPACE))
		{
			// 前フレームでショットボタンを押したかが保存されている変数が0だったら弾を発射
			if (bflag == 0)
			{
				// 画面上にでていない弾があるか、弾の数だけ繰り返して調べる
				for (int i = 0; i < num; i++)
				{
					// 弾iが画面上にでていない場合はその弾を画面に出す
					if (aflag[i] == 0)
					{
						int mw = 32, mh = 32, sw, sh;
						//弾の画像のサイズを得る
						GetGraphSize(sgh, &sw, &sh);
						// 弾iの位置をセット、位置は主人公の中心にする
						sx[i] = (mw - sw) / 2 + x;
						sy[i] = (mh - sh) / 2 + y;
						// 弾iは現時点を持って存在するので、存在状態を保持する変数に1を代入する
						aflag[i] = 1;
						
						// 一つ弾を出したので弾を出すループから抜ける
						break;
					}
                }
			}
			// 前フレームでショットボタンを押されていたかを保存する変数に1(おされてた)を代入
			bflag = 1;
		}
		else {
			// ショットボタンが押されていなかった場合は
// 前フレームでショットボタンが押されてたかを保存する変数に0(おされてない)を代入
			bflag = 0;
		}
}

	
	void PLAYER::DRAW() {
		DrawGraph(x - width / 2, y - width / 2, gh[result], TRUE);

		// 弾の数だけ弾を動かす処理を繰り返す
		for (int i = 0; i < num; i++) {
			//自機の弾iの移動ルーチン(存在状態を保持している変数の内容が1(存在)の場合のみ行う)
			if (aflag[i] == 1) {
				sx[i] += cos(angle) * speed;
				sy[i] += sin(angle) * speed;
					
                // 画面外に出てしまった場合は存在状態を保持している変数に0(存在しない)を代入する
				if (sy[i] < -150 || sy[i] > 450) {
					aflag[i] = 0;
				}
				else if (sx[i] < -150 || sx[i] > 450) {
					aflag[i] = 0;
				}
				// 画面に弾iを描画する
				DrawRotaGraph(sx[i] + 132, sy[i] + 130, 0.1, 0.0, sgh, TRUE);
			}
		}
			}
	

	void PLAYER::ALL() {
	MOVE();
	SHOT();
        DRAW();
	}
 


define.h

コード:

 
 #include <windows.h>

extern char key[256];
extern int g_count;

#define MARGIN 20

#define SCROLL_SPEED 2

#define num 20

#define s_num 50

#define PI 3.14159265358979323846
	

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 2Dシューティング 操作キャラの向いている方向に弾を飛ばし続けたい

#2

投稿記事 by みけCAT » 1年前

1. 存在状態や座標と同様に、それぞれの弾が飛ぶ角度を表す配列を追加する
2. 弾の発射時、その弾が飛ぶ角度を操作キャラの角度に設定する
3. 弾の移動時、操作キャラの角度ではなくその弾が飛ぶ角度を参照するようにする

ようにするといいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

もんの

Re: 2Dシューティング 操作キャラの向いている方向に弾を飛ばし続けたい

#3

投稿記事 by もんの » 1年前

助言していただいたとおり、弾の座標決定時に新たに用意した配列に弾の角度を代入しておき、
発射時にはそちらの配列の方を参照したことで弾とキャラの動きが独立するようになりました。
返信していただきありがとうございました。

コード:

#include "DxLib.h"
#include "PLAYER.h"
#include "define.h"
#include <math.h>

PLAYER::PLAYER() {
	LoadDivGraph("キャラ_017.png", 12, 3, 4, 32, 32, gh);
	sgh = LoadGraph("star3.png");
	for (int i = 0; i < num; i++) {
		aflag[i] = 0;
		}
	bflag = 0;
	}


void PLAYER::MOVE() {
	
	if (key[KEY_INPUT_LEFT] == 1 || key[KEY_INPUT_RIGHT] == 1) {

		if (key[KEY_INPUT_UP] == 1 || key[KEY_INPUT_DOWN] == 1) {
			//移動係数を0.7に設定
			move = 0.7;
		}
		else {
			//斜めじゃなければ1.0に設定
			move = 1.0;
		}
	}
	else if (key[KEY_INPUT_UP] == 1 || key[KEY_INPUT_DOWN] == 1) {
		move = 1.0;
	}

	if (key[KEY_INPUT_LEFT] == 1) {
		x -= 4 * move;
	}

	if (key[KEY_INPUT_RIGHT] == 1) {
		x += 4 * move;
	}

	if (key[KEY_INPUT_UP] == 1) {
		y -= 4 * move;
	}

	if (key[KEY_INPUT_DOWN] == 1) {
		y += 4 * move;
	}

	if (x < MARGIN) x = MARGIN;
	
    if (x > 625) x = 625;
	
	if (y < MARGIN) y = MARGIN;
	
    if (y > 458) y = 458;
	
	//左キーが押されてて、かつxcountが0以上なら0にしてから1引く。
	//それ以外は1引く
	if (key[KEY_INPUT_LEFT] == 1) {
		if (xcount > 0)
			xcount = 0;
		--xcount;
		angle = -PI; //左
	}
	//右キーが押されてて、かつxcountが0以下なら0にしてから1足す。
	//それ以外は1引く
	if (key[KEY_INPUT_RIGHT] == 1) {
		if (xcount < 0)
			xcount = 0;
		++xcount;
		angle = 2 * PI;//右
	}
	//上キーが押されてて、かつycountが0以上なら0にしてから1引く。
	//それ以外は1引く
	if (key[KEY_INPUT_UP] == 1) {
		if (ycount > 0)
			ycount = 0;
		--ycount;
		angle = -(PI / 2); //上
	}
	//下キーが押されてて、かつycountが0以下なら0にしてから1足す。
	//それ以外は1足す
	if (key[KEY_INPUT_DOWN] == 1) {
		if (ycount < 0)
			ycount = 0;
		++ycount;
		angle = PI / 2; //下
	}


	//カウント数から添字を求める。
	ix = abs(xcount) % 30 / 10;
	iy = abs(ycount) % 30 / 10;

	//xカウントがプラスなら右向きなので3行目の先頭添字番号を足す。
	if (xcount > 0) {
		ix += 6;
		result = ix;
	}
	else if (xcount < 0) {
		//マイナスなら左向きなので、2行目の先頭添字番号を足す。
		ix += 3;
		result = ix;
	}

	//yカウントがプラスなら下向きなので、1行目の先頭添字番号を足す。
	if (ycount > 0) {
		iy += 0;
		result = iy;
	}
	else if (ycount < 0) {
		//1行目の先頭添字番号は0なので何もする必要なし。
		iy += 9;
		result = iy;
	}

	//斜め移動の場合は横顔を優先
	if (move == 0.7)
		result = ix;

	if (life) {
		DrawGraph(x - width / 2, y - height / 2, gh[result], TRUE);
	}

	//押されてなければカウントをゼロにする
	if (key[KEY_INPUT_LEFT] != 1 && key[KEY_INPUT_RIGHT] != 1) {
		xcount = 0;
	}
	if (key[KEY_INPUT_UP] != 1 && key[KEY_INPUT_DOWN] != 1) {
		ycount = 0;
	}

    }

	

	void PLAYER::SHOT() {


		// スペースキーを押した場合は処理を分岐
		if (CheckHitKey(KEY_INPUT_SPACE))
		{
			// 前フレームでショットボタンを押したかが保存されている変数が0だったら弾を発射
			if (bflag == 0)
			{
				// 画面上にでていない弾があるか、弾の数だけ繰り返して調べる
				for (int i = 0; i < num; i++)
				{
					// 弾iが画面上にでていない場合はその弾を画面に出す
					if (aflag[i] == 0)
					{
						int mw = 32, mh = 32, sw, sh;
						//弾の画像のサイズを得る
						GetGraphSize(sgh, &sw, &sh);
						// 弾iの位置をセット、位置は主人公の中心にする
						sx[i] = (mw - sw) / 2 + x;
						sy[i] = (mh - sh) / 2 + y;
						// 弾iは現時点を持って存在するので、存在状態を保持する変数に1を代入する
						aflag[i] = 1;
						shangle[i] = angle;
						// 一つ弾を出したので弾を出すループから抜ける
						break;
					}
                }
			}
			// 前フレームでショットボタンを押されていたかを保存する変数に1(おされてた)を代入
			bflag = 1;
		}
		else {
			// ショットボタンが押されていなかった場合は
// 前フレームでショットボタンが押されてたかを保存する変数に0(おされてない)を代入
			bflag = 0;
		}
}

	
	void PLAYER::DRAW() {
		DrawGraph(x - width / 2, y - width / 2, gh[result], TRUE);

		// 弾の数だけ弾を動かす処理を繰り返す
		for (int i = 0; i < num; i++) {
			//自機の弾iの移動ルーチン(存在状態を保持している変数の内容が1(存在)の場合のみ行う)
			if (aflag[i] == 1) {
				sx[i] += cos(shangle[i]) * speed;
				sy[i] += sin(shangle[i]) * speed;
					
                // 画面外に出てしまった場合は存在状態を保持している変数に0(存在しない)を代入する
				if (sy[i] < -150 || sy[i] > 450) {
					aflag[i] = 0;
				}
				else if (sx[i] < -150 || sx[i] > 450) {
					aflag[i] = 0;
				}
				// 画面に弾iを描画する
				DrawRotaGraph(sx[i] + 132, sy[i] + 130, 0.1, 0.0, sgh, TRUE);
			}
		}
			}
	

	
	void PLAYER::ALL() {
	MOVE();
	SHOT();
    DRAW();
	}

返信

“C言語何でも質問掲示板” へ戻る