質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

解決済

3回答

1287閲覧

DXLIBを使いシューティングゲームを作っています。連射させたいです。

ashiseidou

総合スコア7

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

0クリップ

投稿2023/05/15 12:13

実現したいこと

DXLIBにてシューティングゲームを作っているが…連射させたい。

前提

初心者でDXLIBにてシューティングゲームをつくっているのですが、初歩的な質問になると思います。

C++で組んでいます。キャラクターから上の方向に連射させるための処理を書いていますが。連射しません。zボタンを押して連射させたいと
思っているのですが、zボタンを押している間に画像がプレイヤーの上に表示されて、zボタンを離すと消える処理になってしまいます。因みに画像は固定されたままで動きません。

ソースコード(処理部のみ)

void image::DrawBulletsImage() { static int fireCount = 0; const int fireRate = 30; SHOT shot; shot.visible = false; shot.g_handle = imgB; if (CheckHitKey(KEY_INPUT_Z)==1 && fireCount % fireRate==0) { shot.visible = true; shot.x = sizeX; shot.y = sizeY; } if (shot.visible) shot.y -= 20; if (shot.y < -10)shot.visible = false; if (shot.visible)DrawGraph(shot.x, shot.y, shot.g_handle, TRUE); }
別にヘッダーファイルにtypedefしている。 typedef struct SHOT//弾の構造体、視覚、x、y及び高さ、幅の一つ一つの情報体 { bool visible; int x; int y; int g_handle; int width, height; };
C++

試したこと・説明

typedefでSHOTの構造体を作り呼び出しでSHOT shotを宣言している。shotはそれぞれvisibleは見えるかどうか、x,yは座標、g_handleは
グラフィックを表示させる。widthやheightは書いていますが使ってません。それぞれ画像の幅と高さを表しています。
shot[]のようにして配列を入れたりしてforループをかけたりしましたが、うまくいきませんでした。
下記のサイトを参考にしたりしました。
https://dixq.net/s/

補足情報(FW/ツールのバージョンなど)

visualstudio2022

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

おそらく,SHOT 型の変数というのは,ある単一の弾の状態情報を保持するために,少なくとも発射から消滅までの間,生存し続ける想定の物であろうと見受けます.

が,現コードでは SHOT shot;image::DrawBulletsImage() メソッド内のローカル変数になっており,
このメソッドを実施するたびにローカル変数 shot は新規に生成され,
shot.visible = false; 等が実施され,
メソッドを抜ける際には解体されてしまうわけです.

よって,現在の実装形態では所望の処理を達成できないように見受けます.
少なくとも SHOT 型変数の扱い方(どこで作ったり捨てたり保持したりするのか,というあたりの話)を考え直す必要があるでしょう.


…というわけで,おそらく,「オブジェクト(変数)の生存期間」といったような話を学ぶ必要があると見えます.
「どこかに int a; として変数を定義したならば,この a というのはいつまで使えるのか(生存しているのか)」みたいなルールの話ですから,
クラスとか構造体とかを書き始めるよりも遥かに前の段階で知っておくべき基礎的な事柄です.

まずは C++ 言語自体の基礎の話を小一時間くらい(?) 学ぶのが近道でしょう.
いきなりどこぞの「ゲームをつくる」的な話を見ても,振り回されるだけですよ.

投稿2023/05/16 01:16

編集2023/05/16 01:32
fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2023/05/16 01:36

「連射」の前に,まずは「単発」の実現を目指すべきでしょう.
ashiseidou

2023/05/16 02:03

#pragma once #include<DxLib.h> #include<math.h> #include"LoadImages.h" #include<iostream> #include<list> using namespace std; #define M_PI 3.14159265358979 #define Max_Shot 2000 int image; int enemyimage; int imgbk; int imgB; int sizeX = 20; int sizeY = 50; int blsizeX; int blsizeY; int bksizeX = 30; int bksizeY = 50; int ensizeX = 20; int ensizeY = 20; typedef struct SHOT//弾の構造体、視覚、x、y及び高さ、幅の一つ一つの情報体 { bool visible; int x; int y; int g_handle; int width, height; }; SHOT shot; void image::LoadImageCharacter() { image = LoadGraph("E:\\Aseprite\\hakureireimu_0001_7.png"); enemyimage = LoadGraph("E:\\Aseprite\\hakureireimu_0001_7.png"); imgbk = LoadGraph("E:\\Aseprite\\back-002.png"); imgB = LoadGraph("E:\\Aseprite\\chara0001.png"); } void image::backgroundImage() { DrawGraph(bksizeX, bksizeY, imgbk, TRUE); } void image::DrawImageCharacter() { //キー入力初期化 int key[256]; char tmpkey[256]; GetHitKeyStateAll(tmpkey); for (int i = 0; i < 256; i++) { if (tmpkey[i] != 0) { key[i] ++; } else { key[i] = 0; } } //描画 DrawGraph(sizeX, sizeY, image, TRUE); //操作 if (key[KEY_INPUT_W]!=0) { sizeY--; if (sizeY < 0) { sizeY = 0; } } else if (key[KEY_INPUT_S]!=0) { sizeY++; if (sizeY > 200) { sizeY = 200; } } else if (key[KEY_INPUT_D]!=0) { sizeX++; if (sizeX > 150) { sizeX = 150; } } else if (key[KEY_INPUT_A]!=0) { sizeX--; if (sizeX < 0) { sizeX = 0; } } } void image::enemycharacterImage3() { DrawGraph(ensizeX, ensizeY, enemyimage, TRUE); ensizeY+=10; } void image::enemycharacterImage4() { static int startTime = 0; // 停止開始時刻を記録する変数(初期値は0) DrawGraph(ensizeX, ensizeY, enemyimage, TRUE); if (ensizeY < 150) { ensizeY += 10; } else { // 150に達した時の処理 if (startTime == 0) { // 停止開始時刻が未記録の場合は、現在時刻を記録する startTime = GetNowCount(); } else { // 停止開始時刻が記録されている場合は、一定時間が経過したら動かす int currentTime = GetNowCount(); if (currentTime - startTime >= 5000) { // 1000ミリ秒(1秒)待つ ensizeY += sin(M_PI * (100) / 150) * 2.5f; ensizeX += sin(M_PI * 200 / 150) * 2.5f; } } } } void image::DrawBulletsImage() { //キー入力初期化 static int fireCount = 0; const int fireRate = 30; shot.visible = false; shot.g_handle = imgB; if (CheckHitKey(KEY_INPUT_Z)==1 && fireCount % fireRate==0) { shot.visible = true; shot.x = sizeX; shot.y = sizeY; } if (shot.visible) shot.y -= 20; if (shot.y < -10)shot.visible = false; if (shot.visible)DrawGraph(shot.x, shot.y, shot.g_handle, TRUE); } void image::MoveBullet() { } のようにSHOTをimage::DrawBulletsImage()から外へ定義してみましたが、変わりませんでした。 そうですね。単発を実現すべきだと思いました。しかし連射させたいです。
fana

2023/05/16 04:44 編集

唐突にコメント欄にて怒涛のコードを示すのはやめてください. ご覧のように非常に見難いです. --- 確かに本回答はオブジェクトの寿命に焦点を当てた話ですが,あなたのコードのそれ以外の事柄が須らく「妥当」であると言っているわけではありません. (処理自体もダメ,という点に関しては一応ヒントは示しているつもりですが) あなたはいろんな箇所に処理を書いていて,あなたが見ている動作とはそれらの総合的な結果であるわけですから, オブジェクトの定義場所を変え「さえすれば,それで解決するとは限らない」というのは言うまでもないことと思います. オブジェクトに対する処理自体がダメな状態のままならば,当然「思うような動作」には至らないでしょう. いつ/何を すべきなのか/すべきでないのか といった事柄をしっかりとご自身で考え,決定し,その通りに動作するコードを実装することです.
fana

2023/05/16 02:27

「ボタンを押したら→何かが飛んでいく」という内容の実現が現時点の課題であるならば, それだけを実装するプログラムを作ってみることをお勧めします. すなわち,まずは 他の一切合切の要素の影響が無い/余計な関連性等を考えたり面倒みたりする必要のない世界において,課題の部分のみに関する試行錯誤を行い, そこで「連射」までが実現できたならば → その結果を本番のプログラムに取り込む という.
ashiseidou

2023/05/16 05:57

ご迷惑をおかけし申し訳ありませんでした。
guest

0

ベストアンサー

質問者の提示コードの状態と無関係な内容の話(且つ,DXLIBというので実現できるかどうかも私は知らない)ですが…

本当に常に上方向に等速で飛んでいくだけの物であれば,

  1. ゲーム画面と同じサイズの画像バッファを用意し,
  2. 弾を発射すべきときには,単にそのバッファ上に弾の画像を(発射位置の座標に)描画し,
  3. メインループ内で毎回この画像バッファ全体の内容を上方向にずらす

みたいなことをするのが,ある意味最も手っ取り早い(作る物次第ではそんな方法を採用しちゃって良いみたいな)可能性が無くもないです.
とにかく弾を発射したい際には上記2.をやるだけなので,「連射」の実現に悩まされることもないでしょうし.

(あと,この画像バッファを簡素な当たり判定処理に用いることができる可能性もある.)

投稿2023/05/18 07:45

編集2023/05/18 07:46
fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2023/05/18 07:52

言うまでもないだろうけど,この画像バッファを背景(弾以外の領域)を透過する形で描画すれば「弾の描画処理」になる.
ashiseidou

2023/05/19 04:51

申し訳ないですが。自分で解決しました。 答えてくださった皆様ご迷惑をお掛けしました。 ありがとうございます。
fana

2023/05/19 06:25 編集

> 自分で解決しました そういう場合には「ご自身の解決方法を回答として書き,それをベストアンサーとして選択する」ということになっています. そうでなくとも,この回答の内容があなたの解決方法と異なるならば,これをベストアンサーに選択する意味はありません. 既存回答から選ぶにしても,他の回答の方が,質問コードの問題点に言及している(解決に貢献している)分だけ妥当でしょう. ※あと,「迷惑がどうの」とか過剰に言わなくても大丈夫だと思います.(相手が明らかに憤怒しているのでもなければ)
guest

0

shotのx,y座標がつねにsizeX,sizeYから変わらないので動きません。
縦方向に動かしたければshot.y+=sizeYにすればとりあえず動くと思います。

ただし、初めてzが押されたときのみ初期化をしないと無限にy方向に加算されるので一度画面外に行くと二度と戻って来なくなります。

スコープの問題みたいですね。
shotを毎回作り直しているのでsizeY-20で固定されているようです。
shotは関数の外側で管理して有効期限を伸ばすさないといけないです。
具体的にはshotのポインタを関数の外側に置いてzが初めて押されたならnewして、弾が画面外に行ったらdeleteするような処理で実現できると思います。

投稿2023/05/16 01:12

編集2023/05/16 03:14
vann_2921

総合スコア190

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2023/05/16 01:18

座標を変更しようとしているらしき記述としては > shot.y -= 20; という記述が既に存在していますよ.
fana

2023/05/16 04:43

> スコープ とは,「識別子(変数名とか)が通用する範囲」なので,違う気がします.
vann_2921

2023/05/16 15:27

すみません。スコープと有効期限の違いは私にはわかりません。
vann_2921

2023/05/16 15:30

たしかにローカルでポインタを宣言してnewしてもdeleteするまでの有効期限は確保できますね。でもインスタンスとしての有効期限の話なのであまり変わらない気もします。やはり私にはわかりません。
fana

2023/05/17 03:13

「スコープ」というのは, int x; とかしたときに,x という名前でこの変数にアクセスできる(コード上の)範囲のことです. コードのどこであれば x という名前でこの変数を示すことができ,どこではできないのか,という言語のルールであり,xの生存期間とは別の話です. 例えば int main(){ int x; f(); return 0; } //f()は何らかの関数 とかいう場合,xのスコープは main関数の中です. すなわち,「関数 f() の内部からは x という名称でこの main関数内のローカル変数にアクセスできません」っていうような話. なので, > スコープの問題 と述べると「ある場所から,ある変数に,変数名でアクセスできないこと」を問題視している意味合いになると思います.
fana

2023/05/17 03:25 編集

ざっくり言えば(?),「スコープの問題」を抱えているコードに対して起きることとは, コンパイルエラー(その名前が何なのかわからん,と言われる)とか, 「同名の変数があったときにどっちを示すことになるのか」という点をプログラマが誤解していて,結果として想定外の動きになっちゃうとか,そんな話かと. --- ※「newして…」みたいな方法論について何か言っているのではなくて,単純に「そこ,言葉がちがくない?」っていうだけです.
vann_2921

2023/05/18 02:54

承知しました。
vann_2921

2023/05/18 03:20 編集

でもローカル変数はスコープ切れたらその生存期間も終わる仕様ではないですかね? スコープを解決しないと仮にローカルでポインタ変数を宣言してそこにnewして実体の生存期間を延ばしたところでポインタのデリファレンスができなくなるのでやはりスコープの問題かと思いました。
fana

2023/05/18 07:33

強硬な言葉狩り(?)みたいなことをしたいわけではないので,これらのコメントによって回答の意味する内容をより明確にできたとすれば,それでいいかな,と思います. (質問者も話に入ってこないみたいですし)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問