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

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

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

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

Q&A

解決済

1回答

1027閲覧

C言語(ゲーム制作)

saitama0216

総合スコア10

C

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

0グッド

0クリップ

投稿2022/07/24 03:18

編集2022/07/24 06:39

前提

ゲームの制作をしています。
キーボード入力をして、味方のキャラクター(黄色)を、敵キャラクター(赤)と合わないようにゴール(緑)を目指します。

実現したいこと

ゲームの味方キャラクターを上下左右に動かしたいです。
座標移動をさせたいのですが、case文を使おうと思いましたが、うまく行きませんでした。
if文やfor文を使おうと思ったのですが、どのような書けばよいかが分かりません。
具体的には157行目あたりにある NULL と書いてあるところにプログラムを入れる予定です。

発生している問題・エラーメッセージ

156行目のNULLというところにこのように書いていたのですが、エラーが出てしまいました。

エラーメッセージ

該当のソースコード

#include <stdio.h> #include <stdlib.h> #include <time.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> // 表示制御用関数 ( マクロ ) #define clearScreen() printf("\033[2J") #define setPosition(x, y) printf("\033[%d;%dH", (y), (x)) #define setCharColor(n) printf("\033[3%dm", (n)) #define setBackColor(n) printf("\033[4%dm", (n)) #define setAttribute(n) printf("\033[%dm", (n)) #define cursolOn() printf("\033[?25h") #define cursolOff() printf("\033[?25l") // 使用可能な色 #define BLACK 0 #define RED 1 #define GREEN 2 #define YELLOW 3 #define BLUE 4 #define MAGENTA 5 #define CYAN 6 #define WHITE 7 #define DEFAULT 9 // 使用可能な属性 #define NORMAL 0 #define BOLD 1 #define UNDERLINE 4 #define BLINK 5 #define REVERSE 7 #define HIDE 8 // フィールドのサイズ #define WIDTH 10 #define HEIGHT 5 // 敵の数 #define ENEMY_NUM 3 // ブロック構造体 ( プレーヤや壁,道などを表示する際に使用する ) typedef struct Block { int charcolor; // 文字の色 int backcolor; // 背景の色 int attribute; // 表示方法 }Block; // キャラクター構造体 ( プレーヤや敵の情報を保存する際に使用する ) typedef struct Character { Block b; // キャラクターを表示するときに使用する各種情報 int x; // 表示位置 ( x座標 ) int y; // 表示位置 ( y座標 ) }Character; // 関数のプロトタイプ宣言 void moveRight(Character *c); // キャラクタを右に移動させる関数 void moveLeft(Character *c); // キャラクタを左に移動させる関数 void moveUp(Character *c); // キャラクタを上に移動させる関数 void moveDown(Character *c); // キャラクタを下に移動させる関数 void initializeEnemy(Character *c); // 敵の初期化を行う関数 void moveEnemy(Character *c); // 敵をランダムに動かす関数 int check(Character p, Character *e); // ゴールや敵との遭遇をチェックする関数 int checkRange(int x, int y); // 表示可能な範囲 ( map内 ) かどうかをチェックする関数 void printBlock(Block block, int x, int y); // ブロック(キャラクタや壁・道など)を表示する関数 void clearBlock(Character c); // ブロック( キャラクタ )を消す関数 void initialize(void); // ゲームの初期化を行う関数 void reset(void); // 表示に関わる設定内容をリセットする関する void wait(int msec); // 一定時間Waitをかける関数 int kbhit(void); // リアルタイムにキーボード入力を判定する関数 // ゲームマップ ( 0:道,1:壁 ) int map[HEIGHT][WIDTH] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 1, 0, 0, 0, 1}, {1, 0, 1, 0, 0, 0, 1, 0, 0, 1}, {1, 0, 0, 0, 1, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1} }; int main(void) { int w, h, gx, gy; int flag = 0; // ゲームの終了を判定するフラグ char ch; Block wall = {WHITE, BLACK, REVERSE}; // 壁の表示方法を設定 Block path = {BLACK, BLACK, NORMAL}; // 道の表示方法を設定 Block gole = {GREEN, BLACK, REVERSE}; // ゴールの表示方法を設定 Character player = {{YELLOW, YELLOW, REVERSE}, 2, 2}; // プレーヤの表示方法と初期位置を設定 // プレーヤと敵の座標はmap配列のインデックス+1となる Character enemy[ENEMY_NUM]; // 敵の情報を保存する配列 srand(time(NULL)); // ゲームの初期化 initialize(); // 敵を生成 initializeEnemy(enemy); // ゴールの位置を設定 ( ランダムな位置 ) ← ゴール位置に対応するfield配列には2を代入する do { // 有効な座標が見つかるまでランダムに座標を変更 gx = rand() % WIDTH; gy = rand() % HEIGHT; }while(map[gy][gx] != 0); map[gy][gx] = 2; while( 1 ) { ch = ' '; // キーボード入力をチェック if( kbhit() ) ch = getchar(); // 壁・道・ゴールを表示 for( h=0; h<HEIGHT; h++ ) { for( w=0; w<WIDTH; w++ ) { if( map[h][w] == 0 ) printBlock(path, w+1, h+1); // 表示位置はmap配列のインデックス+1となる else if( map[h][w] == 1 ) printBlock(wall, w+1, h+1); // 表示位置はmap配列のインデックス+1となる else if( map[h][w] == 2 ) printBlock(gole, w+1, h+1); // 表示位置はmap配列のインデックス+1となる } } // 入力されたキーに応じてプレーヤを動かす clearBlock(player); switch(ch) { case 'd': // 'd'が押されたら右に動く moveRight(&player); break; case 'a': // 'a'が押されたら左に動く moveLeft(&player); break; case 'w': // 'w'が押されたら上に動く moveUp(&player); break; case 's': // 's'が押されたら下に動く moveDown(&player); break; case 'q': // 'q'が押されたら終了する reset(); return 0; } printBlock(player.b, player.x, player.y); // 敵をランダムに動かす ( 表示も含む ) moveEnemy(enemy); wait(1000); // 単位はミリ秒 // ゴールや敵との遭遇をチェック flag = check(player, enemy); if( flag == 1 ) break; } reset(); return 0; } // キャラクタを右に移動させる関数 ( キャラクタの座標を変更する ) void moveRight(Character *c) switch (*c){case 'd': if (m[*y][*x-1]==0){ m[*y][*x]=0; *x-=1; m[*y][*x]=2; f=1; } // キャラクタを左に移動させる関数 ( キャラクタの座標を変更する ) void moveLeft(Character *c) { NULL; } // キャラクタを上に移動させる関数 ( キャラクタの座標を変更する ) void moveUp(Character *c) { NULL; } // キャラクタを下に移動させる関数 ( キャラクタの座標を変更する ) void moveDown(Character *c) { NULL; } // 敵の初期化を行う関数 void initializeEnemy(Character *c) { int i, x, y; for( i=0; i<ENEMY_NUM; i++ ) { do { // 有効な座標が見つかるまでランダムに座標を設定 x = 1 + rand() % WIDTH; y = 1 + rand() % HEIGHT; }while(map[y-1][x-1] != 0); c[i].b.charcolor = RED; // 敵の色は赤色 c[i].b.backcolor = BLACK; c[i].b.attribute = REVERSE; c[i].x = x; c[i].y = y; } } // 敵をランダムに動かす関数 void moveEnemy(Character *c) { int i, r; for( i=0; i<ENEMY_NUM; i++ ) { r = rand() % 4; clearBlock(c[i]); switch(r) { case 0: moveRight(&c[i]); break; case 1: moveLeft(&c[i]); break; case 2: moveUp(&c[i]); break; case 3: moveDown(&c[i]); break; } printBlock(c[i].b, c[i].x, c[i].y); } } // ゴールや敵との遭遇をチェックする関数 int check(Character player, Character *enemy) { int i; if( map[player.y-1][player.x-1] == 2 ) { // プレーヤとゴールが重なった場合 reset(); setPosition(1, HEIGHT+1); printf("Goalしました!!おめでとう!!\n"); return 1; } else{ for( i=0; i<ENEMY_NUM; i++ ) { if( player.x == enemy[i].x && player.y == enemy[i].y ) { // プレーヤと敵が重なった場合 reset(); setPosition(1, HEIGHT+1); printf("敵に遭遇しました...残念...\n"); return 1; } } } return 0; } // 表示可能な範囲かどうかをチェックする関数 int checkRange(int x, int y) { if( x < 0 || y < 0 || x >= WIDTH+1 || y >= HEIGHT+1 ) return -1; else return 1; } // ブロック(キャラクタや壁・道など)を表示する関数 void printBlock(Block block, int x, int y) { if(checkRange(x, y) == 1) { setPosition(x, y); setCharColor(block.charcolor); setBackColor(block.backcolor); setAttribute(block.attribute); printf(" "); fflush(stdout); } } // ブロック( キャラクタ )を消す関数 void clearBlock(Character c) { if(checkRange(c.x, c.y) == 1) { setPosition(c.x, c.y); setCharColor(BLACK); setBackColor(BLACK); setAttribute(NORMAL); printf(" "); } } // ゲームの初期化を行う関数 void initialize(void) { setBackColor(BLACK); setCharColor(WHITE); setAttribute(NORMAL); clearScreen(); cursolOff(); } // 表示に関わる設定内容をリセットする関する void reset(void) { setBackColor(BLACK); setCharColor(WHITE); setAttribute(NORMAL); setPosition(1, HEIGHT+1); printf("\n"); cursolOn(); } // 一定時間Waitをかける関数 void wait(int msec) { usleep(msec * 1000); } // リアルタイムにキーボード入力を判定する関数 int kbhit(void) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if (ch != EOF) { ungetc(ch, stdin); return 1; } return 0; }

試したこと

case文で書こうとしましたが、うまくいきませんでした。

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

Cloud Shellで作っています。

ここにより詳細な情報を記載してください。

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

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

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

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

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

saitama0216

2022/07/24 03:49

教えてくださってありがとうございます。
y_waiwai

2022/07/24 03:50

どういう問題があって、それをどうしたいんでしょう。 長々と書いてますが、質問の体をなしてませんよ
hoshi-takanori

2022/07/24 04:02

穴埋め課題を代わりにやってくれってこと?
saitama0216

2022/07/24 04:04

キーボードからw(上)をおしたとき、上の座標が壁か道かを判断し、壁ならい移動せずにそのままの場所、道なら進むというプログラムを作りたいのですが、どうやって壁か道かを判断するのかに困っています。
dodox86

2022/07/24 05:58

> どうやって壁か道かを判断するのかに 指定の方向が壁か道なのかはmap[][]の値が0か1かで分かりますよね。 ここまでコードが書けていてそれができないと言うのはちょっと妙に思います。穴埋め課題っぽいですが、まず、全体を理解できていますか?
saitama0216

2022/07/24 06:40

大まかにどのような挙動をすればよいかは分かります。細かい所になってくると、分からない部分の方が多いかもしれません。
episteme

2022/07/24 11:00

>細かい所になってくると、分からない部分の方が多いかもしれません。 それを訊いておくれよ。
dodox86

2022/07/25 01:14

[2022/07/24 15:39]の質問編集「プログラムソースの追加」を読んで: 正直、C言語のプログラムとしてもコードの意図としてもメチャクチャです。何となく書いても要望通り動くわけないです。まずC言語の基本を修めてから課題にあたりましょう。コード付きの回答をいただいても恐らく理解できないし、よくあるケースで「よくわからないけど動くコードだからOK」で終わります。(課題消化だけが目的ならそれでいいのでしょうけど) 現状のコードでも分からない部分の方が多いとのことで、そこが理解できないと自分で実際にコードを書くのは不可能です。お説教を求めている訳ではないでしょうから、この辺で。 [推奨していない質問] https://teratail.com/help/avoid-asking
fana

2022/07/25 03:54

> case文で書こうとしましたが、うまくいきませんでした。 一体何をどう考えた結果,「caseを用いる」という話に行き着いたのか? …っていうことを明確に述べねば,読み手にはその意図をくみ取ることはできない. 「うまくいきませんでした」って言うからには,「あれがこうなってこうだから,これでうまくいくハズ」みたいな話があなたの中にはあるハズ. 筋道立てて説明することを試みよ.
guest

回答1

0

自己解決

コード#include <stdio.h> #include <stdlib.h> #include <time.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> // 表示制御用関数 ( マクロ ) #define clearScreen() printf("\033[2J") #define setPosition(x, y) printf("\033[%d;%dH", (y), (x)) #define setCharColor(n) printf("\033[3%dm", (n)) #define setBackColor(n) printf("\033[4%dm", (n)) #define setAttribute(n) printf("\033[%dm", (n)) #define cursolOn() printf("\033[?25h") #define cursolOff() printf("\033[?25l") // 使用可能な色 #define BLACK 0 #define RED 1 #define GREEN 2 #define YELLOW 3 #define BLUE 4 #define MAGENTA 5 #define CYAN 6 #define WHITE 7 #define DEFAULT 9 // 使用可能な属性 #define NORMAL 0 #define BOLD 1 #define UNDERLINE 4 #define BLINK 5 #define REVERSE 7 #define HIDE 8 // フィールドのサイズ #define WIDTH 10 #define HEIGHT 5 // 敵の数 #define ENEMY_NUM 3 // ブロック構造体 ( プレーヤや壁,道などを表示する際に使用する ) typedef struct Block { int charcolor; // 文字の色 int backcolor; // 背景の色 int attribute; // 表示方法 }Block; // キャラクター構造体 ( プレーヤや敵の情報を保存する際に使用する ) typedef struct Character { Block b; // キャラクターを表示するときに使用する各種情報 int x; // 表示位置 ( x座標 ) int y; // 表示位置 ( y座標 ) }Character; // 関数のプロトタイプ宣言 void moveRight(Character *c); // キャラクタを右に移動させる関数 void moveLeft(Character *c); // キャラクタを左に移動させる関数 void moveUp(Character *c); // キャラクタを上に移動させる関数 void moveDown(Character *c); // キャラクタを下に移動させる関数 void initializeEnemy(Character *c); // 敵の初期化を行う関数 void moveEnemy(Character *c); // 敵をランダムに動かす関数 int check(Character p, Character *e); // ゴールや敵との遭遇をチェックする関数 int checkRange(int x, int y); // 表示可能な範囲 ( map内 ) かどうかをチェックする関数 void printBlock(Block block, int x, int y); // ブロック(キャラクタや壁・道など)を表示する関数 void clearBlock(Character c); // ブロック( キャラクタ )を消す関数 void initialize(void); // ゲームの初期化を行う関数 void reset(void); // 表示に関わる設定内容をリセットする関する void wait(int msec); // 一定時間Waitをかける関数 int kbhit(void); // リアルタイムにキーボード入力を判定する関数 // ゲームマップ ( 0:道,1:壁 ) int map[HEIGHT][WIDTH] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 1, 0, 0, 0, 1}, {1, 0, 1, 0, 0, 0, 1, 0, 0, 1}, {1, 0, 0, 0, 1, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1} }; int main(void) { int w, h, gx, gy; int flag = 0; // ゲームの終了を判定するフラグ char ch; Block wall = {WHITE, BLACK, REVERSE}; // 壁の表示方法を設定 Block path = {BLACK, BLACK, NORMAL}; // 道の表示方法を設定 Block gole = {GREEN, BLACK, REVERSE}; // ゴールの表示方法を設定 Character player = {{YELLOW, YELLOW, REVERSE}, 2, 2}; // プレーヤの表示方法と初期位置を設定 // プレーヤと敵の座標はmap配列のインデックス+1となる Character enemy[ENEMY_NUM]; // 敵の情報を保存する配列 srand(time(NULL)); // ゲームの初期化 initialize(); // 敵を生成 initializeEnemy(enemy); // ゴールの位置を設定 ( ランダムな位置 ) ← ゴール位置に対応するfield配列には2を代入する do { // 有効な座標が見つかるまでランダムに座標を変更 gx = rand() % WIDTH; gy = rand() % HEIGHT; }while(map[gy][gx] != 0); map[gy][gx] = 2; while( 1 ) { ch = ' '; // キーボード入力をチェック if( kbhit() ) ch = getchar(); // 壁・道・ゴールを表示 for( h=0; h<HEIGHT; h++ ) { for( w=0; w<WIDTH; w++ ) { if( map[h][w] == 0 ) printBlock(path, w+1, h+1); // 表示位置はmap配列のインデックス+1となる else if( map[h][w] == 1 ) printBlock(wall, w+1, h+1); // 表示位置はmap配列のインデックス+1となる else if( map[h][w] == 2 ) printBlock(gole, w+1, h+1); // 表示位置はmap配列のインデックス+1となる } } // 入力されたキーに応じてプレーヤを動かす clearBlock(player); switch(ch) { case 'd': // 'd'が押されたら右に動く moveRight(&player); break; case 'a': // 'a'が押されたら左に動く moveLeft(&player); break; case 'w': // 'w'が押されたら上に動く moveUp(&player); break; case 's': // 's'が押されたら下に動く moveDown(&player); break; case 'q': // 'q'が押されたら終了する reset(); return 0; } printBlock(player.b, player.x, player.y); // 敵をランダムに動かす ( 表示も含む ) moveEnemy(enemy); wait(1000); // 単位はミリ秒 // ゴールや敵との遭遇をチェック flag = check(player, enemy); if( flag == 1 ) break; } reset(); return 0; } // キャラクタを右に移動させる関数 ( キャラクタの座標を変更する ) void moveRight(Character *c) { if (map[c->y][c->x+1]!=1){ c -> x++; } } // キャラクタを左に移動させる関数 ( キャラクタの座標を変更する ) void moveLeft(Character *c) { if (map[c->y][c->x-1]!=1){ c -> x--; } } // キャラクタを上に移動させる関数 ( キャラクタの座標を変更する ) void moveUp(Character *c) { if (map[c->y-1][c->x]!=1){ c -> y--; } } // キャラクタを下に移動させる関数 ( キャラクタの座標を変更する ) void moveDown(Character *c) { if (map[c->y+1][c->x]!=1){ c -> y++; } } // 敵の初期化を行う関数 void initializeEnemy(Character *c) { int i, x, y; for( i=0; i<ENEMY_NUM; i++ ) { do { // 有効な座標が見つかるまでランダムに座標を設定 x = 1 + rand() % WIDTH; y = 1 + rand() % HEIGHT; }while(map[y-1][x-1] != 0); c[i].b.charcolor = RED; // 敵の色は赤色 c[i].b.backcolor = BLACK; c[i].b.attribute = REVERSE; c[i].x = x; c[i].y = y; } } // 敵をランダムに動かす関数 void moveEnemy(Character *c) { int i, r; for( i=0; i<ENEMY_NUM; i++ ) { r = rand() % 4; clearBlock(c[i]); switch(r) { case 0: moveRight(&c[i]); break; case 1: moveLeft(&c[i]); break; case 2: moveUp(&c[i]); break; case 3: moveDown(&c[i]); break; } printBlock(c[i].b, c[i].x, c[i].y); } } // ゴールや敵との遭遇をチェックする関数 int check(Character player, Character *enemy) { int i; if( map[player.y-1][player.x-1] == 2 ) { // プレーヤとゴールが重なった場合 reset(); setPosition(1, HEIGHT+1); printf("Goalしました!!おめでとう!!\n"); return 1; } else{ for( i=0; i<ENEMY_NUM; i++ ) { if( player.x == enemy[i].x && player.y == enemy[i].y ) { // プレーヤと敵が重なった場合 reset(); setPosition(1, HEIGHT+1); printf("敵に遭遇しました...残念...\n"); return 1; } } } return 0; } // 表示可能な範囲かどうかをチェックする関数 int checkRange(int x, int y) { if( x < 0 || y < 0 || x >= WIDTH+1 || y >= HEIGHT+1 ) return -1; else return 1; } // ブロック(キャラクタや壁・道など)を表示する関数 void printBlock(Block block, int x, int y) { if(checkRange(x, y) == 1) { setPosition(x, y); setCharColor(block.charcolor); setBackColor(block.backcolor); setAttribute(block.attribute); printf(" "); fflush(stdout); } } // ブロック( キャラクタ )を消す関数 void clearBlock(Character c) { if(checkRange(c.x, c.y) == 1) { setPosition(c.x, c.y); setCharColor(BLACK); setBackColor(BLACK); setAttribute(NORMAL); printf(" "); } } // ゲームの初期化を行う関数 void initialize(void) { setBackColor(BLACK); setCharColor(WHITE); setAttribute(NORMAL); clearScreen(); cursolOff(); } // 表示に関わる設定内容をリセットする関する void reset(void) { setBackColor(BLACK); setCharColor(WHITE); setAttribute(NORMAL); setPosition(1, HEIGHT+1); printf("\n"); cursolOn(); } // 一定時間Waitをかける関数 void wait(int msec) { usleep(msec * 1000); } // リアルタイムにキーボード入力を判定する関数 int kbhit(void) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if (ch != EOF) { ungetc(ch, stdin); return 1; } return 0; }

投稿2022/07/25 10:41

saitama0216

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問