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

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

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

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

Q&A

解決済

1回答

868閲覧

シューティングにおける弾の移動と自機の移動の実現

tomo1040

総合スコア1

C

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

0グッド

0クリップ

投稿2022/07/09 21:05

C言語とncursesを用いてシューティングゲームを作りたいのですが入力された方向への自機の移動と発射した弾の移動を同時に行う方法がわかりません。
自機の移動と弾の発射そのものは可能なのですが発射された弾が画面上部で消滅するまでの間自機の操作ができなくなります。GameMainのWhile文内でShootBulletが実行されると弾が消滅するまで操作不可となるいわゆる逐次処理になってしまっていることが原因であることは理解しています。そこでMoveBullet関数が呼び出される度に弾を1マスだけ移動させることも考えましたが(いろいろ試しているとごちゃごちゃしてしまったので下のソースコードはそれらの修正を試す前の状態のものです)、そうすると今度はgetchが邪魔をして先に弾を上手く移動させられなくなります。どなたか改善方法がわかる方がいましたらアドバイスしてもらえると助かります。
まだまだ未完成のものなので不自然な点も多いと思いますが下に記述しているものが自力で途中まで作成したソースコードです。

<ソースコード>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <locale.h>
#include <ncurses.h>
#include <windows.h>

struct Player{
int x;
int y;
int hp;
};

struct Enemy{
int x;
int y;
int hp;
};

void PrintPlayer(int x, int y){
struct Player player;
char *you = "△";
player.x = x;
player.y = y;
mvprintw(y, x, "%s", you);
refresh();
}

void CreateEnemy(int x, int y, int type){
struct Enemy enemy;
char *target = "▼";
enemy.x = x;
enemy.y = y;
if(type == 1){
enemy.hp = 5;
}else if(type == 2){
enemy.hp = 50;
}
mvprintw(y, x, "%s", target);
refresh();
}

void MoveBullet(int x, int y, char *bullet){
while(y != 2){
mvprintw(y, x, " ");
y--;
mvprintw(y, x, "%s", bullet);
refresh();
Sleep(100);
}
mvprintw(y, x, " ");
}

void ShootBullet(int x, int y){
char *bullet ="◎";
mvprintw(y, x, "%s", bullet);
refresh();
MoveBullet(x, y, bullet);
}

void GameMain(int x, int y1, int y2, int wideL, int wideR){
int input;

keypad(stdscr, TRUE); noecho(); PrintPlayer(x, y1); CreateEnemy(58, y2, 1); input = getch(); while(input != 'q'){ if(input == KEY_RIGHT && x != wideR - 3){ x++; }else if(input == KEY_LEFT && x != wideL + 1){ x--; }else if(input == KEY_UP){ ShootBullet(x, y1 - 1); } PrintPlayer(x, y1); input = getch(); }

}

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

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

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

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

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

tomo1040

2022/07/10 00:05

構造体を用いて書き直してみましたが、依然としてキー入力がない限り弾の移動が起こりません。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <locale.h> #include <ncurses.h> #include <windows.h> struct Player{ int x; int y; int hp; }; struct Enemy{ int x; int y; int hp; }; struct Bullet{ int x; int y; int flag; }; void PrintPlayer(int x, int y){ struct Player player; char *you = "△"; player.x = x; player.y = y; mvprintw(y, x, "%s", you); refresh(); } void CreateEnemy(int x, int y, int type){ struct Enemy enemy; char *target = "▼"; enemy.x = x; enemy.y = y; if(type == 1){ enemy.hp = 5; }else if(type == 2){ enemy.hp = 50; } mvprintw(y, x, "%s", target); refresh(); } struct Bullet MoveBullet(struct Bullet bullet){ if(bullet.y != 2){ mvprintw(bullet.y, bullet.x, " "); bullet.y--; mvprintw(bullet.y, bullet.x, "◎"); refresh(); Sleep(50); }else{ mvprintw(bullet.y, bullet.x, " "); bullet.flag = 0; } return bullet; } struct Bullet ShootBullet(int x, int y){ struct Bullet bullet; bullet.x = x; bullet.y = y; bullet.flag = 1; mvprintw(bullet.y, bullet.x, "◎"); refresh(); return bullet; } void GameMain(int x, int y1, int y2, int wideL, int wideR){ int input; struct Bullet bullet; keypad(stdscr, TRUE); noecho(); PrintPlayer(x, y1); CreateEnemy(58, y2, 1); input = getch(); while(input != 'q'){ if(input == KEY_RIGHT && x != wideR - 3){ x++; }else if(input == KEY_LEFT && x != wideL + 1){ x--; }else if(input == KEY_UP){ bullet = ShootBullet(x, y1 - 1); } PrintPlayer(x, y1); if(bullet.flag == 1){ bullet = MoveBullet(bullet); } input = getch(); } }
guest

回答1

0

ベストアンサー

ひとまずは弾もPlayerやEnemy同様に構造体で管理するようにしてください。

今の構造のまま無理やり進めてもいずれ2発目や相手の弾の話になったときに結局詰まります。

弾の構造体には状態を表すint型の変数でも持たせておき、
発射されて画面内にいる状態のときにGameMain関数のwhileループ内で毎度Printするようにしましょう。
弾の移動もPlayerの移動のためにキー入力に応じてwhile内でxを増減させているように弾の構造体のyをループ内で減らしていく形にしましょう。
弾の構造体のyが0になったら状態を表す変数を書き換えてPrintしないようにします。

またPlayer構造体ですが、PrintPlayerで表示するところでPlayer構造体のx,yを代入しても意味がないので、
キー入力に応じてwhile内でxを増減させているところでPlayer構造体のxを変化させ、
PrintPlayerはPlayer構造体の値を基にして表示する形にしましょう。

投稿2022/07/09 21:50

RiaFeed

総合スコア2701

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

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

tomo1040

2022/07/09 22:10

やはりキー入力があった時にしか弾の移動はできないのでしょうか。whileループ内でその都度プリントすることも試しましたが、それでもキー入力のたびに弾が停止してしまうので不自然になってしまいます。弾を発射して以降はキーの入力がなくとも自動で弾が画面上部へ移動していくような自機の移動とは独立した処理にしたいのですが、getchを使っている以上難しいでしょうか。
RiaFeed

2022/07/09 22:33

そもそもgetchで入力があるまで止まってる状態ってことですかね? cbreakでバッファを無効にしてnodelayかtimeout(0)でノンブロッキングモードにしてください。
tomo1040

2022/07/09 23:14

そうです。弾が1マス移動してまた入力の繰り返しになります。 すみません、知識がまだまだ浅いのもあってそれらの関数について調べてみてもよくわからなくて…具体的にどのようにすればよいのでしょうか。
RiaFeed

2022/07/10 01:16

どのようにもなにもnoecho();してるところ辺りでcbreak(); と timeout(0);を呼び出すだけですけど…
tomo1040

2022/07/10 01:51

ありがとうございます。無事動きました。ノンブロッキングについては調べてみて何となく理解できたのですが、バッファを無効にする理由は何なのでしょうか。
RiaFeed

2022/07/10 14:55 編集

C言語の一般的な入出力は既定ではバッファに貯めて後でまとめて入出力するようになってて ゲームなんかですぐ入力したキーを知りたい状況でバッファが有効だとバッファに貯めちゃってキー入力が取れない
tomo1040

2022/07/11 00:21

なるほど!お忙しい中何度も質問に答えていただきありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問