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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

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

Q&A

解決済

3回答

557閲覧

2Dゲームにおける左向きに攻撃する処理の方法

maguro2020

総合スコア34

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

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

0グッド

0クリップ

投稿2022/03/20 04:33

概要
現在、右向きに進んでいく2Dのスクロール系のゲームを作成しております。
ゲームの主人公(コード内におけるheroという名前です)が左向きに攻撃する処理は描けているのですが、右向きに攻撃をする処理をうまく描くことができず、質問をさせていただきました。
以下は対象のコードです。
コード

C/C++

1void DrawBall(int key) { 2 // 発射処理 3 // 右向き 4 if (IsBKeyTrigger(key) == TRUE && g_stagedata.hero.turn == FALSE) { 5 // 空きを探す 6 int i; 7 for (i = 0; i < MAX_BALL; i++) { 8 if (g_stagedata.balls[i].living == FALSE) break; 9 } 10 if (i < MAX_BALL) { 11 g_stagedata.balls[i].living = TRUE; 12 g_stagedata.balls[i].x = g_stagedata.hero.x + IMG_CHIPSIZE; 13 g_stagedata.balls[i].y = g_stagedata.hero.y; 14 } 15 // 左向き 16 }else if (IsBKeyTrigger(key) == TRUE && g_stagedata.hero.turn == TRUE) { 17 // 空きを探す 18 int i; 19 for (i = 0; i < MAX_BALL; i++) { 20 if (g_stagedata.balls[i].living == FALSE) break; 21 } 22 if (i < MAX_BALL) { 23 g_stagedata.balls[i].living = TRUE; 24 g_stagedata.balls[i].x = g_stagedata.hero.x - IMG_CHIPSIZE; 25 g_stagedata.balls[i].y = g_stagedata.hero.y; 26 } 27 } 28 // ボールの描画と移動 29 float mv = 350.0f * g_frametime; // 移動量計算 30 for (int i = 0; i < MAX_BALL; i++) { 31 if (g_stagedata.balls[i].living == FALSE) continue; 32 g_stagedata.balls[i].x += mv; 33 34 // マップ当たり判定 35 AtariInfo atari = CheckBlock(g_stagedata.balls[i].x, g_stagedata.balls[i].y, 36 g_stagedata.balls[i].x); 37 if (atari.DR == TRUE || atari.UR == TRUE) g_stagedata.balls[i].living = FALSE; 38 // 画面外に出ても消滅 39 if (g_stagedata.balls[i].x > g_stagedata.scrollx + 1000) { 40 g_stagedata.balls[i].living = FALSE; 41 } 42 43 DrawGraph((int)(g_stagedata.balls[i].x - g_stagedata.scrollx), 44 (int)g_stagedata.balls[i].y, 45 g_imghandles.ball, TRUE); 46 } 47 if (g_stagedata.hero.turn == TRUE) { 48 for (int i = 0; i < MAX_BALL; i++) { 49 if (g_stagedata.balls[i].living == FALSE) continue; 50 g_stagedata.balls[i].x -= mv; 51 52 // マップ当たり判定 53 AtariInfo atari = CheckBlock(g_stagedata.balls[i].x, g_stagedata.balls[i].y, 54 g_stagedata.balls[i].x); 55 if (atari.DR == TRUE || atari.UR == TRUE) g_stagedata.balls[i].living = FALSE; 56 // 画面外に出ても消滅 57 if (g_stagedata.balls[i].x > g_stagedata.scrollx - 1000) { 58 g_stagedata.balls[i].living = FALSE; 59 } 60 61 DrawGraph((int)(g_stagedata.balls[i].x - g_stagedata.scrollx), 62 (int)g_stagedata.balls[i].y, 63 g_imghandles.ball, TRUE); 64 } 65 } 66} 67 68// キートリガー処理 69BOOL IsBKeyTrigger(int key) { 70 if (key & PAD_INPUT_B) { 71 if (g_stagedata.g_bkey_prev == FALSE) { 72 g_stagedata.g_bkey_prev = TRUE; 73 return TRUE; 74 } 75 } 76 else { 77 g_stagedata.g_bkey_prev = FALSE; 78 } 79 return FALSE; 80}

発生している問題
右向き(g_stagedata.hero.turn==FALSE)に攻撃(ボール)を飛ばすことはできているのですが、左(g_stagedata.hero.turn==TRUE)を向いたときに左にボールを飛ばすことができません。また、右向きでボールを飛ばした後に、左を向いた場合、右向きに飛ばしたボールが消えてしまう現象も発生しております。

解決するために考えている方法
現在、自分の考えている解決方法として蛇足的ではありますが、void DrawBall()関数内の処理を左向きと右向きで完全に分けて記述する方法で、解決できるのではないかと考えております。
もし、上記のコードの処理において、左向きに攻撃する(ボールを飛ばす)かつ、一度右向きに飛ばしたボールを消させない方法がわかる方がいらっしゃいましたら、アドバイスをいただけると幸いです。

補足
主人公=hero
攻撃=ball(ボール)
向き=turn(FALSE:右向き、TRUE=左向き)

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

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

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

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

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

guest

回答3

0

右と左で計算式の一部値の符号しか変わらないので、それを返す関数を一つ作るだけで、左右別の条件を作る必要が無くなります。
また、ボールの移動方向は「発射時の hero の turn 」のみで決まるのは大前提ですが、turn は mv の符号にしか影響しませんので、最初から mv を balls に作っておいて発射時に mv / -mv を入れてしまえば、移動時に向きを見る必要も無くなります。
(ついでに mv の計算も発射時に毎回する必要は無さそうに思います。→ 発射ボタンによっては早い/遅いボールを撃てる?)
(さらについでに、 "DrawBall" という名前の関数で "移動" から "発射処理" まで行うのは変な気がします。)

※コンパイルも何も出来ないので切り貼りしたイメージコードです。コンパイルエラーその他が発生する可能性があります。

c?

1//turn==TRUE(左向き) なら -v, そうで無いなら v を返す 2int GetTurnedValue(BOOL turn, int v) { 3 return turn == TRUE ? -v : v; 4} 5 6void DrawBall(int key) { 7 // 発射処理 8 if (IsBKeyTrigger(key) == TRUE) { 9 for (int i = 0; i < MAX_BALL; i++) { 10 if (g_stagedata.balls[i].living == FALSE) { // 空き 11 g_stagedata.balls[i].living = TRUE; 12 g_stagedata.balls[i].x = g_stagedata.hero.x + GetTurnedValue(g_stagedata.hero.turn, IMG_CHIPSIZE); 13 g_stagedata.balls[i].y = g_stagedata.hero.y; 14 15 float mv = 350.0f * g_frametime; // 移動量計算 16 g_stagedata.balls[i].mv = GetTurnedValue(g_stagedata.hero.turn, mv); //構造体? に mv メンバ追加 17 break; 18 } 19 } 20 } 21 22 // ボールの移動・描画 23 for (int i = 0; i < MAX_BALL; i++) { 24 if (g_stagedata.balls[i].living == FALSE) continue; 25 26 g_stagedata.balls[i].x += g_stagedata.balls[i].mv; 27 28 // 画面外に出たら消滅 29 if (g_stagedata.balls[i].x > g_stagedata.scrollx + 1000 || 30 g_stagedata.balls[i].x < g_stagedata.scrollx - 1000) { 31 g_stagedata.balls[i].living = FALSE; 32 continue; 33 } else { 34 // マップ当たり判定 35 AtariInfo atari = CheckBlock(g_stagedata.balls[i].x, g_stagedata.balls[i].y, g_stagedata.balls[i].x); 36 if (atari.DR == TRUE || atari.UR == TRUE) { 37 g_stagedata.balls[i].living = FALSE; 38 continue; 39 } 40 } 41 42 DrawGraph((int)(g_stagedata.balls[i].x - g_stagedata.scrollx), (int)g_stagedata.balls[i].y, g_imghandles.ball, TRUE); 43 } 44} 45 46// キートリガー処理 47BOOL IsBKeyTrigger(int key) { 48 if (key & PAD_INPUT_B) { 49 if (g_stagedata.g_bkey_prev == FALSE) { 50 g_stagedata.g_bkey_prev = TRUE; 51 return TRUE; 52 } 53 } else { 54 g_stagedata.g_bkey_prev = FALSE; 55 } 56 return FALSE; 57}

投稿2022/03/20 18:59

編集2022/03/20 19:11
jimbe

総合スコア12632

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

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

maguro2020

2022/03/21 01:13

ご回答いただきありがとうございます。 確かに、DrawBall関数内で"移動"と"発射処理"を同時に行うのは違和感がありました。 jimbeさんのコードも参考にしながら、自分のコードを改良したいと思います。 改めてご回答してくださり、ありがとうございました。
guest

0

まず、下記のif文の範囲が意図とあっていないと思います。

C++

1 // ボールの描画と移動 2 float mv = 350.0f * g_frametime; // 移動量計算 3 for (int i = 0; i < MAX_BALL; i++) { 4 : 5 } 6 if (g_stagedata.hero.turn == TRUE) { //←ここ 7 for (int i = 0; i < MAX_BALL; i++) { 8 : 9 } 10 }

そして、プレイヤーの左右の向きで、ボールの動きを制御しようとしていますが、プレイヤーの向きとボールの動きが無関係だと思うので、ロジック的におかしいです。g_stagedata.ballsの構造体に向きのメンバ変数(turn)を持たせてそれでボールの動きを制御すべきです。

ifでの分岐では全体に右向きと左向きで似たようなコードが出現するので、ボールのメンバ変数(turn)でコードをまとめるとよいかと思います。

投稿2022/03/20 06:13

Serbonis

総合スコア581

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

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

maguro2020

2022/03/20 07:08

ご回答いただきありがとうございます。 現在、ボールの向きと主人公の向きが同時に動いてしまう(ボールを投げた後に向きを変えた場合、ボールの向きも変わる現象です)、別の問題が発生していたため、とても助かります。もう少し自分でもボールの発射方法について、変更を加えてみたいと思います。
guest

0

自己解決

自己解決しました。
ありがとうございました。

投稿2022/03/20 05:56

maguro2020

総合スコア34

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

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

fiveHundred

2022/03/20 06:43

具体的な解決手順が書かれていないので、低評価します。
jimbe

2022/03/20 07:16 編集

[4-2. どのように解決したのかを伝えましょう] https://teratail.com/help/question-tips#questionTips42 >あなたがどのように解決したかを書き残しておくことで、あなたの質問は貴重なコンテンツ資産となります。 >いつか他の誰かがあなたと同じ問題に陥った時、そのコンテンツにたどり着いたらすぐに解決できるように情報を残しておいてあげてください
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問