ターン制ストラテジーゲームを作っているのですが・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sadora3
記事: 175
登録日時: 7年前

ターン制ストラテジーゲームを作っているのですが・・・

#1

投稿記事 by sadora3 » 4年前

ターン制ストラテジーゲームを作っているのですが、行き詰まってしまいました。
プレイヤーをクリックしたら移動可能範囲を表示させたいのですが、どうしても出来ません。
どうすれば上手く出来るのでしょうか?

OS:Window7
コンパイラ:Microsoft Visual Studio 2010
ライブラリ:Dxライブラリ
言語:C

C言語はポインタは出来ませんが、ポインタ以外はしっかり勉強してあります。

コード:

#include"DxLib.h"

#define STAGE_SIZE 13
#define SIZE 32
#define SPACE 0
#define PLAYER 1
#define MOVE 2

int MasuX, MasuY;

int STAGE[STAGE_SIZE + 2][STAGE_SIZE + 2] = {
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

typedef struct{
	int PosX;
	int PosY;
	int Move;
} STATUS;

STATUS Player = {5, 5, 3};

void DrawStage();
void Mouse();
void MoveSearch(int, int, int);

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE);
	SetGraphMode(SIZE * 15, SIZE * 15, 16);
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }

	STAGE[Player.PosY][Player.PosX] = PLAYER;

	while(ProcessLoop() == 0){
		DrawStage();
		Mouse();
		DrawFormatString(0, 0, GetColor(255,255,255), "%d %d", MasuX, MasuY);
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}

void DrawStage(){
	for(int y = 0; y < STAGE_SIZE + 2; y++){
		for(int x = 0; x < STAGE_SIZE + 2; x++){
			switch(STAGE[y][x]){
			case SPACE: DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE); break;
			case PLAYER: DrawCircle(x * SIZE + SIZE / 2, y * SIZE + SIZE / 2, SIZE / 2 - 2, GetColor(0,0,255), TRUE); break;
			case MOVE: DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(50,50,200), TRUE); break;
			}
		}
	}
}

void Mouse(){
	int MouseX, MouseY;
	GetMousePoint(&MouseX, &MouseY);

	MasuX = MouseX / SIZE;
	MasuY = MouseY / SIZE;

	if((GetMouseInput() & MOUSE_INPUT_LEFT) == 1 && STAGE[MasuY][MasuX] == PLAYER){
		MoveSearch(Player.PosX, Player.PosY, Player.Move);
	}
}

void MoveSearch(int PlayerX, int PlayerY, int Move){
	if(STAGE[PlayerY - 1][PlayerX] == 0 && Move > 0){
		STAGE[PlayerY - 1][PlayerX] = MOVE;
		MoveSearch(PlayerX, PlayerY - 1, Move - 1);
	}
	if(STAGE[PlayerY + 1][PlayerX] == 0 && Move > 0){
		STAGE[PlayerY + 1][PlayerX] = MOVE;
		MoveSearch(PlayerX, PlayerY + 1, Move - 1);
	}
	if(STAGE[PlayerY][PlayerX - 1] == 0 && Move > 0){
		STAGE[PlayerY][PlayerX - 1] = MOVE;
		MoveSearch(PlayerX - 1, PlayerY, Move - 1);
	}
	if(STAGE[PlayerY][PlayerX + 1] == 0 && Move > 0){
		STAGE[PlayerY][PlayerX + 1] = MOVE;
		MoveSearch(PlayerX + 1, PlayerY, Move - 1);
	}
}

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: ターン制ストラテジーゲームを作っているのですが・・・

#2

投稿記事 by Tatu » 4年前

左右が欠けるのは移動可能であるとわかった場所をもう一度調べることができないためです。
それをどうにかすれば思った通りに動くと思います。
before.png
before.png (39.27 KiB) 閲覧数: 2575 回
after.png
after.png (38.67 KiB) 閲覧数: 2575 回

sadora3
記事: 175
登録日時: 7年前

Re: ターン制ストラテジーゲームを作っているのですが・・・

#3

投稿記事 by sadora3 » 4年前

出来ました!

コード:

#include"DxLib.h"

#define STAGE_SIZE 13
#define SIZE 32
#define SPACE 0
#define PLAYER 1
#define MOVE 2

int MasuX, MasuY;
int cnt = 0;

int STAGE[STAGE_SIZE + 2][STAGE_SIZE + 2] = {
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

typedef struct{
	int PosX;
	int PosY;
	int Move;
} STATUS;

STATUS Player = {5, 5, 3};

void DrawStage();
void Mouse();
void MoveSearch(int, int, int);

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE);
	SetGraphMode(SIZE * 15, SIZE * 15, 16);
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }

	STAGE[Player.PosY][Player.PosX] = PLAYER;

	while(ProcessLoop() == 0){
		DrawStage();
		Mouse();
		DrawFormatString(0, 0, GetColor(255,255,255), "%d %d", MasuX, MasuY);
		DrawFormatString(0, 20, GetColor(255,255,255), "%d", cnt);
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}

void DrawStage(){
	for(int y = 0; y < STAGE_SIZE + 2; y++){
		for(int x = 0; x < STAGE_SIZE + 2; x++){
			switch(STAGE[y][x]){
			case SPACE:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			case PLAYER:
				DrawCircle(x * SIZE + SIZE / 2, y * SIZE + SIZE / 2, SIZE / 2 - 2, GetColor(0,0,255), TRUE);
				break;
			case MOVE:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(50,50,200), TRUE);
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			}
		}
	}
}

void Mouse(){
	int MouseX, MouseY;
	GetMousePoint(&MouseX, &MouseY);

	MasuX = MouseX / SIZE;
	MasuY = MouseY / SIZE;

	if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0 && STAGE[MasuY][MasuX] == PLAYER && cnt == 0){
		MoveSearch(Player.PosX, Player.PosY, Player.Move);
	}
}

void MoveSearch(int PlayerX, int PlayerY, int Move){
	cnt++;
	if((STAGE[PlayerY - 1][PlayerX] == 0 || STAGE[PlayerY - 1][PlayerX] == MOVE) && Move > 0){
		STAGE[PlayerY - 1][PlayerX] = MOVE;
		MoveSearch(PlayerX, PlayerY - 1, Move - 1);
	}
	if((STAGE[PlayerY + 1][PlayerX] == 0 || STAGE[PlayerY + 1][PlayerX] == MOVE) && Move > 0){
		STAGE[PlayerY + 1][PlayerX] = MOVE;
		MoveSearch(PlayerX, PlayerY + 1, Move - 1);
	}
	if((STAGE[PlayerY][PlayerX - 1] == 0 || STAGE[PlayerY][PlayerX - 1] == MOVE) && Move > 0){
		STAGE[PlayerY][PlayerX - 1] = MOVE;
		MoveSearch(PlayerX - 1, PlayerY, Move - 1);
	}
	if((STAGE[PlayerY][PlayerX + 1] == 0 || STAGE[PlayerY][PlayerX + 1] == MOVE) && Move > 0){
		STAGE[PlayerY][PlayerX + 1] = MOVE;
		MoveSearch(PlayerX + 1, PlayerY, Move - 1);
	}
}
しかし、65回もMoveSearch関数を呼び出してしまっているのですが、これ最小24回で済みますよね。
もう少し呼び出し回数は減らせないものでしょうか?

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: ターン制ストラテジーゲームを作っているのですが・・・

#4

投稿記事 by Tatu » 4年前

戦術SLGの移動アルゴリズム
http://dixq.net/forum/viewtopic.php?f=3&t=9445
というトピックで参考になりそうなサイトが挙げられているので見てはどうでしょうか。
2011年のトピックで挙げられたサイトなので今はもっとよいサイトがあるかもしれませんが。

すでに調べていてかつ移動量が少ない場合は調べない
調べるときに直前と逆の方向には進まないようにする
というような工夫の仕方があるようです。

sadora3
記事: 175
登録日時: 7年前

Re: ターン制ストラテジーゲームを作っているのですが・・・

#5

投稿記事 by sadora3 » 4年前

呼び出し回数を減らす処理はこのように対処しました。

コード:

#include"DxLib.h"

#define STAGE_SIZE 13
#define SIZE 32
#define SPACE 0
#define PLAYER 1
#define MOVE 2

int MasuX, MasuY;
int cnt = 0;

int STAGE[STAGE_SIZE + 2][STAGE_SIZE + 2] = {
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

typedef struct{
	int PosX;
	int PosY;
	int Move;
} STATUS;

STATUS Player = {7, 7, 4};

void DrawStage();
void Mouse();
void MoveSearch(int, int, int);

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE);
	SetGraphMode(SIZE * 15, SIZE * 15, 16);
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }

	STAGE[Player.PosY][Player.PosX] = PLAYER;

	while(ProcessLoop() == 0){
		DrawStage();
		Mouse();
		DrawFormatString(0, 0, GetColor(255,255,255), "%d %d", MasuX, MasuY);
		DrawFormatString(0, 20, GetColor(255,255,255), "%d", cnt);
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}

void DrawStage(){
	for(int y = 0; y < STAGE_SIZE + 2; y++){
		for(int x = 0; x < STAGE_SIZE + 2; x++){
			switch(STAGE[y][x]){
			case SPACE:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			case PLAYER:
				DrawCircle(x * SIZE + SIZE / 2, y * SIZE + SIZE / 2, SIZE / 2 - 2, GetColor(0,0,255), TRUE);
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			case MOVE:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(50,50,200), TRUE);
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			}
		}
	}
}

void Mouse(){
	int MouseX, MouseY;
	GetMousePoint(&MouseX, &MouseY);

	MasuX = MouseX / SIZE;
	MasuY = MouseY / SIZE;

	if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0 && STAGE[MasuY][MasuX] == PLAYER && cnt == 0){
		MoveSearch(Player.PosX, Player.PosY, Player.Move);
	}
}

void MoveSearch(int PlayerX, int PlayerY, int Move){
	cnt++;
	if(STAGE[PlayerY - 1][PlayerX] != MOVE){
		if((STAGE[PlayerY - 1][PlayerX] == 0 || STAGE[PlayerY - 1][PlayerX] == MOVE) && Move > 0){
			STAGE[PlayerY - 1][PlayerX] = MOVE;
			MoveSearch(PlayerX, PlayerY - 1, Move - 1);
		}
	}
	if(STAGE[PlayerY + 1][PlayerX] != MOVE){
		if((STAGE[PlayerY + 1][PlayerX] == 0 || STAGE[PlayerY + 1][PlayerX] == MOVE) && Move > 0){
			STAGE[PlayerY + 1][PlayerX] = MOVE;
			MoveSearch(PlayerX, PlayerY + 1, Move - 1);
		}
	}
	if((STAGE[PlayerY][PlayerX - 1] == 0 || STAGE[PlayerY][PlayerX - 1] == MOVE) && Move > 0){
		STAGE[PlayerY][PlayerX - 1] = MOVE;
		MoveSearch(PlayerX - 1, PlayerY, Move - 1);
	}
	if((STAGE[PlayerY][PlayerX + 1] == 0 || STAGE[PlayerY][PlayerX + 1] == MOVE) && Move > 0){
		STAGE[PlayerY][PlayerX + 1] = MOVE;
		MoveSearch(PlayerX + 1, PlayerY, Move - 1);
	}
}
もうひとつやりたいことがあって、今は1~Player.Moveマス移動出来る様になっていますが、これをPlayer.Moveマスの移動に変えたいです。
例えば、Player.Moveが3だったとすれば、
□□□■□□□
□□■□■□□
□■□□□■□
■□□●□□■
□■□□□■□
□□■□■□□
□□□■□□□
こうしたいです。どうすればいいのでしょうか?

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: ターン制ストラテジーゲームを作っているのですが・・・

#6

投稿記事 by Tatu » 4年前

No:5のコードでプレイヤーの移動力を6とすると
移動できるはずなのに移動できない場所がでました。
move6.png
move6.png (45.22 KiB) 閲覧数: 2331 回
各マスでの移動量を記憶する変数を追加し、
すでに調べていてかつ移動量が多い場所を調べないようにし、
移動量を表示するようにした場合は以下の画像のようになります。
idouryou.png
idouryou.png (49.05 KiB) 閲覧数: 2331 回
3マス先にのみ移動できるようにするには調べ終わった時に
3マス先にある場所だけ移動可能にすればよいのではないでしょうか。

YuO
記事: 941
登録日時: 8年前
住所: 東京都世田谷区

Re: ターン制ストラテジーゲームを作っているのですが・・・

#7

投稿記事 by YuO » 4年前

その地点までの移動コストを記録していかないと,回り込まないと移動できないような場合に対処できなくなったり,移動可能な距離が短く算出されたりしますね。
see) http://dixq.net/forum/viewtopic.php?f=3&t=12639

sadora3 さんが書きました:今は1~Player.Moveマス移動出来る様になっていますが、これをPlayer.Moveマスの移動に変えたいです。
地形の移動コストが常に1でPlayer.Moveが3の時に,「上左下」と動いて左隣のマスに移動は許可するのでしょうか。
同様に,Player.Moveが4の時に「上左左下」と動いて,2つ左のマスへの移動は許可するのでしょうか (左隣に障害物がある場合に検索されるルート)。
# どちらも,一度上に移動した後,以前に移動した方向と逆方向である下に移動するという点で違いはありません。

許可しないのであれば,回り込み不可のため,2点間を結ぶ経路があるか否かだけの問題になります。
距離がPlayer.Moveの点を列挙して (全部でPlayer.Move * 4箇所),各点に対して障害物のない経路が存在するかを確認する,というアルゴリズムになるかと思います。
# 地形の移動コストに1と移動不可以外が存在する場合は,条件の再定義が必要なので除外。

許可するのであれば,一度訪れた点 (初期位置含む) を再度訪れることができるかでも話が変わります。
再訪を許可する場合は,「戻る」ルートも気にせず調べていって末端が移動可能な場所になります。
移動コストが1固定ならば格子状(Player.Moveが偶数ならば初期位置を含み,奇数ならば含まない) になります。
再訪を許可しない場合は,探索時に訪れた点を記録しながら探索していき,再訪しないように移動していってやはり末端が移動可能な場所になります。
こちらは,格子の上に結果が乗ることは再訪を許可する場合と同じですが,きれいな格子になるとは限りません。

どちらにしても,途中で止まれるものとは若干(または大幅に)アルゴリズムを変更する必要が出て来ます。

sadora3
記事: 175
登録日時: 7年前

Re: ターン制ストラテジーゲームを作っているのですが・・・

#8

投稿記事 by sadora3 » 4年前

>>Tatuさん
まさか移動力が6の場合に不具合が出るとは思ってもいませんでした。ご指摘ありがとうございます。
それと途中に障害物があったら正しく探索できませんでした。
以上の2つの理由から、No.3のコードに戻しました。
移動量を変数に代入する方法は途中に障害物があったら無理そうです・・・。

>>YuOさん
申し訳ありませんが、言っていることがよく分かりません・・・。移動コストとはなんでしょう?
ですが、途中に障害物があれば正しく探索出来ないのはなんとか分かりました。
>>「地形の移動コストが常に1でPlayer.Moveが3の時に,「上左下」と動いて左隣のマスに移動は許可するのでしょうか。」
これはつまり、1マス左に移動するという意味でしょうか?それなら許可しません。Tatuさんが張ってくれた、[idouryou.png]という画像の1の部分にのみ移動を許可したいです。

ちなみにどうしてMove.Playerの値だけ離れたマスに移動可能範囲を表示させたいのかと言うと、実は移動したいわけではなく、弓兵の攻撃可能範囲として実装したいからです。攻撃範囲は4(1~3は攻撃できない)にしようかと思っています。
やはり探索の途中に障害物があると、むずかしすぎて自分の頭ではアルゴリズムが思いつきません。
どうすればいいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: ターン制ストラテジーゲームを作っているのですが・・・

#9

投稿記事 by softya(ソフト屋) » 4年前

プログラミングの中でもゲームは難しい部類に入りますが、その中でもストラテジーゲームは上級レベルの難易度に分類されます。
なので難しいことを考えるのがストラテジーゲーム作成だと思ってもらったほうが良いと思います。

> やはり探索の途中に障害物があると、むずかしすぎて自分の頭ではアルゴリズムが思いつきません。

紙などに書いてシミュレートしてみると良いかもしれません。
その難しいことを考えるのがストラテジーゲーム作成の醍醐味ですので、そこを難しいで排除してしまうと更に難しい部分で行き詰まってしまうかもしれません。

ヒントとしては、4射程の範囲の攻撃範囲から3射程の攻撃範囲を取り除けば、そういうことは出来ると思います。
あるいは、射程を範囲の配列に書き残せば4だけ選択表示すれば良いことなります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

taketoshi
記事: 221
登録日時: 9年前
住所: 日本国

Re: ターン制ストラテジーゲームを作っているのですが・・・

#10

投稿記事 by taketoshi » 4年前

SRPGを作っているので何かの参考になるかもしれません。
私は移動関数を改造して、弓兵や魔法使いの攻撃可能範囲を求めました。

http://dixq.net/forum/blog.php?u=288&b=4163

お互い頑張りましょう。

sadora3
記事: 175
登録日時: 7年前

Re: ターン制ストラテジーゲームを作っているのですが・・・

#11

投稿記事 by sadora3 » 4年前

ソフト屋さんの「4射程の範囲の攻撃範囲から3射程の攻撃範囲を取り除けば」というので出来ました!

コード:

#include"DxLib.h"

#define STAGE_SIZE 13
#define SIZE 32
#define SPACE 0
#define PLAYER 1
#define ATK 2

int MasuX, MasuY;
int cnt = 0;

int STAGE[STAGE_SIZE + 2][STAGE_SIZE + 2] = {
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

typedef struct{
	int PosX;
	int PosY;
} STATUS;

STATUS Player = {7, 7};

void DrawStage();
void Mouse();
void AtkSearch(int, int, int);
void AtkClear(int, int, int);

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE);
	SetGraphMode(SIZE * 15, SIZE * 15, 16);
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }

	STAGE[Player.PosY][Player.PosX] = PLAYER;

	while(ProcessLoop() == 0){
		DrawStage();
		Mouse();
		DrawFormatString(0, 0, GetColor(255,255,255), "%d %d", MasuX, MasuY);
		DrawFormatString(0, 20, GetColor(255,255,255), "%d", cnt);
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}

void DrawStage(){
	for(int y = 0; y < STAGE_SIZE + 2; y++){
		for(int x = 0; x < STAGE_SIZE + 2; x++){
			switch(STAGE[y][x]){
			case SPACE:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			case PLAYER:
				DrawCircle(x * SIZE + SIZE / 2, y * SIZE + SIZE / 2, SIZE / 2 - 2, GetColor(0,0,255), TRUE);
				break;
			case ATK:
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(200,50,50), TRUE);
				DrawBox(x * SIZE, y * SIZE, x * SIZE + SIZE, y * SIZE + SIZE, GetColor(255,255,255), FALSE);
				break;
			}
		}
	}
}

void Mouse(){
	int MouseX, MouseY;
	GetMousePoint(&MouseX, &MouseY);

	MasuX = MouseX / SIZE;
	MasuY = MouseY / SIZE;

	if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0 && STAGE[MasuY][MasuX] == PLAYER && cnt == 0){
		AtkSearch(Player.PosX, Player.PosY, 4);
		AtkClear(Player.PosX, Player.PosY, 2);
	}
}

void AtkSearch(int PlayerX, int PlayerY, int AtkRange){
	cnt++;
	if(STAGE[PlayerY - 1][PlayerX] != -1 && AtkRange > 0){
		if(STAGE[PlayerY - 1][PlayerX] == 0 && AtkRange == 1){
			STAGE[PlayerY - 1][PlayerX] = ATK;
		}
		AtkSearch(PlayerX, PlayerY - 1, AtkRange - 1);
	}
	if(STAGE[PlayerY + 1][PlayerX] != -1 && AtkRange > 0){
		if(STAGE[PlayerY + 1][PlayerX] == 0 && AtkRange == 1){
			STAGE[PlayerY + 1][PlayerX] = ATK;
		}
		AtkSearch(PlayerX, PlayerY + 1, AtkRange - 1);
	}
	if(STAGE[PlayerY][PlayerX - 1] != -1 && AtkRange > 0){
		if(STAGE[PlayerY][PlayerX - 1] == 0 && AtkRange == 1){
			STAGE[PlayerY][PlayerX - 1] = ATK;
		}
		AtkSearch(PlayerX - 1, PlayerY, AtkRange - 1);
	}
	if(STAGE[PlayerY][PlayerX + 1] != -1 && AtkRange > 0){
		if(STAGE[PlayerY][PlayerX + 1] == 0 && AtkRange == 1){
			STAGE[PlayerY][PlayerX + 1] = ATK;
		}
		AtkSearch(PlayerX + 1, PlayerY, AtkRange - 1);
	}
}

void AtkClear(int PlayerX, int PlayerY, int AtkRange){
	cnt++;
	if(STAGE[PlayerY - 1][PlayerX] != -1 && AtkRange > 0){
		if(STAGE[PlayerY - 1][PlayerX] == ATK && AtkRange == 1){
			STAGE[PlayerY - 1][PlayerX] = 0;
		}
		AtkClear(PlayerX, PlayerY - 1, AtkRange - 1);
	}
	if(STAGE[PlayerY + 1][PlayerX] != -1 && AtkRange > 0){
		if(STAGE[PlayerY + 1][PlayerX] == ATK && AtkRange == 1){
			STAGE[PlayerY + 1][PlayerX] = 0;
		}
		AtkClear(PlayerX, PlayerY + 1, AtkRange - 1);
	}
	if(STAGE[PlayerY][PlayerX - 1] != -1 && AtkRange > 0){
		if(STAGE[PlayerY][PlayerX - 1] == ATK && AtkRange == 1){
			STAGE[PlayerY][PlayerX - 1] = 0;
		}
		AtkClear(PlayerX - 1, PlayerY, AtkRange - 1);
	}
	if(STAGE[PlayerY][PlayerX + 1] != -1 && AtkRange > 0){
		if(STAGE[PlayerY][PlayerX + 1] == ATK && AtkRange == 1){
			STAGE[PlayerY][PlayerX + 1] = 0;
		}
		AtkClear(PlayerX + 1, PlayerY, AtkRange - 1);
	}
}
>>ソフト屋さん
ヒント助かりました。ありがとうございます。出来れば関数一つで済ませたかったのですが、私の力量では無理でした。
一つ質問があるのですが、ストラテジーゲームはそんなに難しいのでしょうか?
私はサイドビューのアクションの方が難しいと思っていたのですが。あとワールドルールのテトリスとか。
ストラテジーゲームの難しいところはどこでしょう?AIでしょうか?

>>taketoshiさん
リンク先を拝見しましたが、凄い数字の羅列があって、ビックリしました。
日記見ましたが、凄い規模のを作ろうとしているんですね。
頑張りましょう!

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: ターン制ストラテジーゲームを作っているのですが・・・

#12

投稿記事 by softya(ソフト屋) » 4年前

> ストラテジーゲームの難しいところはどこでしょう?AIでしょうか?

今に関係ある部分としては、移動など経路探索、攻撃時の障害物処理、そして生産(配置?)・移動・攻撃を司るAIですね。
ストーリーが絡んで来るとややこしさ倍増です。
あとデータの多さもプログラムやバランス調整の規模を大きくするので難易度をアップします。

ちなみにYuOさんの言う移動コストとは、沼地なら移動範囲減少とか移動範囲が地形に左右される処理です。
移動のコスト(物事を達成するのに必要な物理量)が1ではない地形が出てくるか?ということですね。

すでに紹介されている過去ログの「戦術SLGの移動アルゴリズム」でも質問者さんがやることの多さに目を回しているんですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 7年前

Re: ターン制ストラテジーゲームを作っているのですが・・・

#13

投稿記事 by sadora3 » 4年前

>>ソフト屋さん
なるほどです。
コードの量が凄いことになりそうですが、頑張ろうと思います。

私を助けて下さった回答者の皆さん本当にありがとうございました。
問題は無事解決しました。
また何か問題が出てきたときは、また回答よろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: ターン制ストラテジーゲームを作っているのですが・・・

#14

投稿記事 by softya(ソフト屋) » 4年前

一定のコード量を超えると、ちゃんとしたプログラム設計がないと破綻すると言って良いと思います。このプログラム設計が難易度が高いのです。
また、ちゃんと設計されていないと致命的なバグが生まれ、ちゃんと設計されていないゆえに自分も他人もバグを追うことさえ困難になります。
つまり開発中級から上級者の設計成熟度・デバッグ能力が要求されるのでストラテジーゲームは難しいとされるのです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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