int box[4][7][2]の役割。

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

int box[4][7][2]の役割。

#1

投稿記事 by Ouxiy » 4年前

以下の全体のコードの中でint box[4][7][2]は何を表しているのでしょうか。
また、どんな役割があるのでしょうか。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}
int idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};
int box[4][7][2], teki[5][5][2];

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs)
{
	SetGraphMode(780, 680, 32);        // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box();//これによりint box()を呼び出して初期かしたbox[4][7][2], teki[5][5][2]を呼び出した。
	//int boxColor = GetColor(160, 64, 64);//ステージの色
	int nx = 2, ny = 2;  // tekiのxとyでの初期位置
	int px = teki[ny][nx][0], py = teki[ny][nx][1];  // tekiのx、y、zでの初期位置
	int move = 0;  // 移動状態
	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, gh);  //画像読み込み
	int playerphoto = gh[5];

	while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得
		
			// カーソルキーの右が押されている
			if (1)
				if (idou[ny + 0][nx + 1] == 0) {//移動しようとする先が空いていれば
				//移動可能

					nx = nx + 1; //移動
					playerphoto = gh[6];
					move = 1;
				}
			if (Key[KEY_INPUT_LEFT] == 1)
				if (idou[ny + 0][nx - 1] == 0) { //移動しようとする先が空いていれば
				//移動可能
					
					nx = nx - 1; //移動
					playerphoto = gh[4];
					move = 1;
				}
		

		ClearDrawScreen();  // 裏画面をクリア
		if (move > 0 && ++move == 30) {
			move = 0; playerphoto = gh[5];  // 移動終了
		}
		DrawGraph(teki[ny][nx][0], teki[ny][nx][1], playerphoto, FALSE);//tekiの画像が描画される最初の位置
		ScreenFlip();  // 裏画面を表画面に反映

	}
		

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
	
}

かずま

Re: int box[4][7][2]の役割。

#2

投稿記事 by かずま » 4年前

Ouxiy さんが書きました:
4年前
以下の全体のコードの中でint box[4][7][2]は何を表しているのでしょうか。
また、どんな役割があるのでしょうか。
元のプログラムにあった
int boxColor = GetColor(160, 64, 64); を削除し、
ClearDrawScreen(); の後の次のコードを削除したのはなぜですか?

コード:

		for (int i = 0; i < 4; i++)
			DrawLine(box[i][0][0], box[i][0][1],
				box[i][6][0], box[i][6][1], boxColor);
		for (int j = 0; j < 7; j++)
			DrawLine(box[0][j][0], box[0][j][1],
				box[3][j][0], box[3][j][1], boxColor);
これが何か分かっていれば、int box[4][7][2]; の意味は自明のはずです。
DrawLine が何か分からないのですか?
分からないから削除したのですか?

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#3

投稿記事 by Ouxiy » 4年前

理解できないから消したわけではありません。一旦ステージを消したかったため消しただけです。
あの、再度聞いてしまって申し訳ないのですが、

コード:

 teki[5][5][2]の[2]はteki[ny][nx][0], py = teki[ny][nx][1]
と分解出来て表せますが、この[2]は何を表しているのでしょうか。ステージを立体的に見せるためのZ軸のようなものだとばかり考えていましたが、そうではないようで、正しい答えが知りたいです。
どうかよろしくお願いいたします。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#4

投稿記事 by Ouxiy » 4年前

コード:

void init_box()
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}
において、boxの配列とtekiの配列の初期化のためのプログラムだとわかっています。
どのような役割かと言えばidou配列は一定で値の置き換えはないですが、tekiをそのidouの配列の上で置く必要があるため、boxの配列とtekiの配列が必要と理解しています。
ですが、なぜそう書けたのか、boxの配列とtekiの配列の初期化のプログラムで理解できないことがあります。

どのようにしてtekiの位置を動かすための初期値の配列に25や66は何のためにありますか。

質問として、どういうカズマさんの考えを基にフローチャートを作り

コード:

for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
を作ったのか。なぜこのように作ったのか作った手順が知りたいです。

box配列の

コード:

for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;

に関してもフロチャートや作る過程の手順が知りたいです。
それにより、よりboxの配列とtekiの配列の役割の意味が深まると思います。
どうかお願いいたします。真剣に勉強したいです。

かずま

Re: int box[4][7][2]の役割。

#5

投稿記事 by かずま » 4年前

box と teki の値を見ましたか?
見ましたか? この質問には絶対に答えてください。

Visual Studio を使って、デバッグしているのだったら、
init_box() 実行後にブレークポインタで止めて、簡単に見ることができます。

int box[4][7][2] は

コード:

 (182,237) (255,237) (328,237) (400,237) (472,237) (545,237) (618,237)
 (157,286) (238,286) (319,286) (400,286) (481,286) (562,286) (643,286)
 (130,340) (220,340) (310,340) (400,340) (490,340) (580,340) (670,340)
 (100,400) (200,400) (300,400) (400,400) (500,400) (600,400) (700,400)
int teki[5][5][2] は

コード:

 (  0,  0) (  0,  0) (  0,  0) (  0,  0) (  0,  0)
 (  0,  0) (185,195) (262,195) (339,195) (  0,  0)
 (  0,  0) (163,247) (249,247) (334,247) (  0,  0)
 (  0,  0) (140,304) (235,304) (330,304) (  0,  0)
 (  0,  0) (  0,  0) (  0,  0) (  0,  0) (  0,  0)
WinMain の最初で、SetGraphMode(780, 680, 32); を実行しているから、
画面サイズは 780 x 680 です。
box と teki は、この画面の中に描画するステージの位置や敵の位置です。

[4][7] や [5][5] の意味は分かりますよね。
[2] はその位置の x座標と y座標の 2つです。
だから、DrawLine や DrawGraph で使っているのです。

ステージは、3 x 6 のマスですよね。
したがって、横線 3本、縦線 7本を書かないといけません。

1つのマスを 100 x 100 だとすると、

コード:

 (100,220) (200,220) (300,220) (400,220) (500,220) (600,220) (700,220)
 (100,280) (200,280) (300,280) (400,280) (500,280) (600,280) (700,280)
 (100,340) (200,340) (300,340) (400,340) (500,340) (600,340) (700,340)
 (100,400) (200,400) (300,400) (400,400) (500,400) (600,400) (700,400)
これは、2D の場合です。
3D だと、斜めから見ますから、縦の長さが小さくなります。
1つのマスを 100 x 60 にしてみましょう。
一番下を基準にしたので、上の 3つの位置の y座標が 60ずつ小さくなります。

奥に行くほど、横の長さも小さくなります。
一番下のマスを長方形ではなく、上底90、下底100、高さ60 の台形にします。
ひとマス上に行くと横幅(width)が 90% になるようにするわけです。
ひとマス上の台形は高さ(height)も 90% にします。
これが w = w * 9 / 10, h = h * 9 / 10; の意味です。
box[ i][j][0] = w + 400, box[ i][j][1] = h - 200;
の 400 と -200 は、(400,400) を基準にしたからです。
-200 は h の初期値を 600 にしたからです。

敵はマスの真ん中に立ちますよね。
一つのマスの左上と右下の中点の座標になります。

コード:

			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
足して 2で割って中点です。[0], [1] は x座標と y座標。
その中点で DrawGraph すると、画像が中点に立ちません。
画像のサイズは、LoadDivGraph で分かるように 49 x 66。
左に 25、上に 66 ずらすことによって、画像はマスの真ん中に立ちます。

フローチャートなんか書いていません。
正方形や台形や三角形の図を書いて考えました。

かずま

Re: int box[4][7][2]の役割。

#6

投稿記事 by かずま » 4年前

訂正です。

1つのマスを 100 x 100 だとすると、

コード:

 (100,100) (200,100) (300,100) (400,100) (500,100) (600,100) (700,100)
 (100,200) (200,200) (300,200) (400,200) (500,200) (600,200) (700,200)
 (100,300) (200,300) (300,300) (400,300) (500,300) (600,300) (700,300)
 (100,400) (200,400) (300,400) (400,400) (500,400) (600,400) (700,400)
これは、2D の場合です。
3D だと、斜めから見ますから、縦の長さが小さくなります。
1つのマスを 100 x 60 にしてみましょう。
一番下を基準にしたので、上の 3つの位置の y座標が 60ずつ小さくなります。

コード:

 (100,220) (200,220) (300,220) (400,220) (500,220) (600,220) (700,220)
 (100,280) (200,280) (300,280) (400,280) (500,280) (600,280) (700,280)
 (100,340) (200,340) (300,340) (400,340) (500,340) (600,340) (700,340)
 (100,400) (200,400) (300,400) (400,400) (500,400) (600,400) (700,400)

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#7

投稿記事 by Ouxiy » 4年前

box と teki の値を見ましたか?
見ましたか? この質問には絶対に答えてください。
見ていませんでした。

ですが、初期化のプログラムの作り方、原理への理解は深まりました。どうもありがとうございます。
本当にどうもありがとうございます。

ただ、私の理解が正しいか質問したいこと一つ、と疑問一つがございます。他の方にも質問してみたのですが、まだしっくりこないことがありカズマさんの解説が聞きたいです。どうかよろしくお願いいたします。

質問したいことは以下のことです。
配列idouは移動可能かどうかを判断するための配列です。
そしてint nx = 2, ny = 2;(座標(2、2)は空のマスで実際の画面上に描画するための座標を表しているわけではなく、あくまで「idouのnx = 2, ny = 2は空のマスだよ(idouの空マスの座標が(2、2)なだけで、画面上のどこの座標なのかはまだ決まっていないため配列tekiの座標とその座標を使うための初期化設定が必要)」と伝えているだけで、キャラを描画するための実際の座標(247,249)はまだ定義と初期化もされていないため、空のマスの座標(2、2)が実際の画面のどこの座標かはわからない、なので、後は表現するための座標を設定するだけ)とint px = teki[ny][nx][0], py = teki[ny][nx][1]; よりidouの配列の座標(2,2)(空のマス)に画面上のどこに表現するかのためのtekiの座標(247,249)が必要になります。

teki[ny][nx][0], py = teki[ny][nx][1]を空のマスidouの配列の座標(2,2)に付け加えるために、teki[ny][nx][0], py = teki[ny][nx][1]を初期化する必要もあり以下のプログラムを書きました。

コード:

for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			teki[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			teki[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
長くなり申し訳ありません。私の理解が正しいか確認して頂きたく、書かせて頂きました。

もう一つ疑問なのは、移動可能かどうかを確認するさいにidou配列が必要なのかなと思ってしまったことがあります。というもの、以下のように実際の座標を書いた際に

コード:

// 描画する座標の配列
	int teki[5][5][2] = {
		{{0}}, // どうせここには来ない
		{{0, 0}, {60,  60}, {100,  60}, {140,  60}, {0, 0}},
		{{0, 0}, {50, 100}, {100, 100}, {150, 100}, {0, 0}},
		{{0, 0}, {40, 160}, {100, 160}, {160, 160}, {0, 0}},
		{{0}} // どうせここには来ない
	};
において、{0}と{0, 0}の部分(は壁)には行かないようにプログラムを書けば、idou配列を書かなくても良いのではないか、int teki[5][5][2]だけではないのか?という疑問が生まれました。

以上の確認の質問一つと疑問の質問一つと計二つの質問ですが、どうかよろしくお願いいたします。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#8

投稿記事 by Ouxiy » 4年前

もう一つ疑問があります。なぜidou[5][5]は一つだけでいいのでしょうか。

コード:

idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};

自分用と敵用で二つ必要なのではないかと疑問が生まれました。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: int box[4][7][2]の役割。

#9

投稿記事 by みけCAT » 4年前

かずまさんの解説についての確認への回答はかずまさんに任せます。
Ouxiy さんが書きました:
4年前
もう一つ疑問なのは、移動可能かどうかを確認するさいにidou配列が必要なのかなと思ってしまったことがあります。というもの、以下のように実際の座標を書いた際に

コード:

// 描画する座標の配列
	int teki[5][5][2] = {
		{{0}}, // どうせここには来ない
		{{0, 0}, {60,  60}, {100,  60}, {140,  60}, {0, 0}},
		{{0, 0}, {50, 100}, {100, 100}, {150, 100}, {0, 0}},
		{{0, 0}, {40, 160}, {100, 160}, {160, 160}, {0, 0}},
		{{0}} // どうせここには来ない
	};
において、{0}と{0, 0}の部分(は壁)には行かないようにプログラムを書けば、idou配列を書かなくても良いのではないか、int teki[5][5][2]だけではないのか?という疑問が生まれました。
やりたいことによります。

現状の仕様であれば、「描画する座標が定義されている」と「移動可能」が同値なので、
Ouxiyさんのいう通りidou配列は不要です。

たとえば障害物や穴のような「描画する座標が定義されているけど移動不可」なマスが出てくる場合、
idou配列、もしくはその他何らかの移動可能かを管理する仕組みが必要になるでしょう。
Ouxiy さんが書きました:
4年前
もう一つ疑問があります。なぜidou[5][5]は一つだけでいいのでしょうか。

コード:

idou[5][5] = {
	{ 1, 1, 1, 1, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 0, 0, 0, 1 },
	{ 1, 1, 1, 1, 1 },
};

自分用と敵用で二つ必要なのではないかと疑問が生まれました。
現状の(少なくともここに投稿されている)仕様では、
「自分」と「敵」のどちらか1方しか画面上に登場しないため、
idou[5][5]も一つでいいでしょう。

「自分」と「敵」の両方が画面上に登場する場合、やりたいことによります。

「自分」も「敵」も同じ一つのマップ(例えば3x3のマス)上を動くのであれば、
idou[5][5]はその一つのマップに対応する一つだけにするべきです。

ロックマンエクゼのように「自分」と「敵」が動くマップ(の範囲)が違うのであれば、
それぞれのマップに対応するようにidou[5][5]のような配列を複数用意するか、
配列は一つのままで要素数を増やすのが自然でしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#10

投稿記事 by Ouxiy » 4年前

みけCATさん、どうもありがとうございます。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#11

投稿記事 by Ouxiy » 4年前

box と teki の値を見ましたか?
見ましたか? この質問には絶対に答えてください。

Visual Studio を使って、デバッグしているのだったら、
init_box() 実行後にブレークポインタで止めて、簡単に見ることができます。
visual studio 2019を使って座標を見ようとデバックしています。どうか座標を見るまでの詳しい過程のやり方を教えて頂けないでしょうか。
どうかお願いいたします。

かずま

Re: int box[4][7][2]の役割。

#12

投稿記事 by かずま » 4年前

すみません。
ブレークポインタではなく、ブレークポイントです。
ステージは、3 x 6 のマスですよね。
したがって、横線 3本、縦線 7本を書かないといけません。
横線 4本の間違いでした。
敵はマスの真ん中に立ちますよね。
一つのマスの左上と右下の中点の座標になります。
本当は、マスの四隅の点の座標を足して 4 で割るべきなんでしょうが、
簡略化して、2点の座標でごまかしています。

charall.png の 12個の画像は何かと何度も尋ねているのに
なぜ、回答してくれないんでしょうか?

回答者の質問には答えようとせず、
自分の質問ばかりを繰り返す人に教えたくはありませんが、
「visual studio c++ デバッグ」で検索してみてください。
デバックではなく、デバッグ(debug)です。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#13

投稿記事 by Ouxiy » 4年前

ちゃんと答えられずすいません。ごめんなさい。
charall.png の 12個の画像は何かと何度も尋ねているのに
なぜ、回答してくれないんでしょうか?
こちらのサイトこのサイトですのキャラクターを使わせて頂いています。
この画像のキャラクターを12個の画像にしました。

自分でもブレークポイントで座標を確認しようと試みたのですが、うまくいかず、検索しましたが似たようなことをする人がいなかったため今でもわからずにいます。
ブレークポイントを設定した後、どこを見れば画面上の座標がわかるのかわかりません。

かずま

Re: int box[4][7][2]の役割。

#14

投稿記事 by かずま » 4年前

Ouxiy さんが書きました:
4年前
自分でもブレークポイントで座標を確認しようと試みたのですが、うまくいかず、検索しましたが似たようなことをする人がいなかったため今でもわからずにいます。
ブレークポイントを設定した後、どこを見れば画面上の座標がわかるのかわかりません。
「visual studio c++ デバッグ」で検索したら、
クイック スタート: Visual Studio デバッガーを使用して C++ でデバッグする
チュートリアル:Visual Studio を使用した C++ のデバッグについて理解する
が出ませんか?

そこにブレークポイントの設定や、ステップ実行について説明がありませんか?
Visual Studio を提供しているマイクロソフトのドキュメントですよ。
機械翻訳のせいで、とても読みにくい日本語ですが、図もあるし、ちゃんと
読めばわかるはずです。

新規プロジェクトを作る必要はありません。
既に Dxライブラリを使ってゲームを作るプロジェクトを開いているのですから。

WinMain の最初の SetGraphMode(780, 680, 32); の行の左端をクリックすると
赤丸が付きます。これがブレークポイントです。
ツールバーの緑色の右三角か、F5キーか、メニューのデバッグのデバッグの開始
で、デバッガーがスタートし、ブレークポイントで止まります。
ツールバーの下向き矢印(ステップイン)か、F11キーでステップ実行が始まります。
どんどん進んで、DxLib_Init() を実行すると、ウインドウが開くでしょう。
init_box(); を実行すると、init_box() に制御が移り、どんどん進めると、
右側の「自動」や「ローカル」のペインに変数の値が表示されます。
box や teki はグローバル変数ですから、「ウォッチ1」に、box や teki を
書き込むと、その変数の値を見ることができます。

検索したページが読めないのですか?
「似たようなことをする人」を見つけないといけないのですか?
不思議で仕方ありません。

charall.png ですが、次のコメントと一致しません。

コード:

	int gh[12];  //グラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可
gh[0]~gh[11] のすべての画像について、それが何か、
どのタイミングでどれを使うつもりなのか詳しく説明してください。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#15

投稿記事 by Ouxiy » 4年前

gh[0]~gh[11] のすべての画像について、それが何か、
どのタイミングでどれを使うつもりなのか詳しく説明してください。
えと、静止中は右向きのgh[5]、移動するときの一瞬はgh[6]となり、再び右向きのgh[5]になります。

ブレークポイントに関してありがとうございます。

かずま

Re: int box[4][7][2]の役割。

#16

投稿記事 by かずま » 4年前

Ouxiy さんが書きました:
4年前
ブレークポイントに関してありがとうございます。
検索したページは、読まなかったのですか?
実際に、ブレークポイントを使って、ステップ実行し、
変数の値をみることができるようになったのですか?
Ouxiy さんが書きました:
4年前
えと、静止中は右向きのgh[5]、移動するときの一瞬はgh[6]となり、再び右向きのgh[5]になります。
一瞬とは何フレーム表示するつもりですか?
1フレームじゃ、人間の目には見えませんよ。
gh[4] とか gh[8] って使っていませんでしたか?
プログラム中のコメントは訂正しないんですか?

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#17

投稿記事 by Ouxiy » 4年前

返信どうもありがとうございます。
検索したページは、読まなかったのですか?
実際に、ブレークポイントを使って、ステップ実行し、
変数の値をみることができるようになったのですか?
やってみたのですが、私がポンコツなせいで出来なかっただけです。
もう一度よく読んで実行してみます。
一瞬とは何フレーム表示するつもりですか?
1フレームじゃ、人間の目には見えませんよ。
gh[4] とか gh[8] って使っていませんでしたか?
プログラム中のコメントは訂正しないんですか?
すいません、ありました。
++playerMove > 20と書いたので、20フレームほどです。ですが、5フレームでも良いかもしれません。
以下は全体のコードです。

コード:

#include "DxLib.h"

int Key[256];

int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}

int box[4][7][2];        // 盤上のマス
int enemyGPos[5][5][2];  // 敵の描画座標
int playerGPos[5][5][2]; // 俺の描画座標

void init_box() {
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			box[i][j][0] = w + 400, box[i][j][1] = h - 200;//int box[4][7][2];の初期化のためのプログラム
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++) {
			enemyGPos[i][j][0] = (box[i - 1][j + 2][0] + box[i][j + 3][0]) / 2 - 25;//ステージを作るための線を利用して中心点をbox[4][7][2]を利用してenemyGPos[5][5][2]; playerGPos[5][5][2]の9マスの座標を求める
			enemyGPos[i][j][1] = (box[i - 1][j + 2][1] + box[i][j + 3][1]) / 2 - 66;
			playerGPos[i][j][0] = (box[i - 1][j - 1][0] + box[i][j][0]) / 2 - 25;
			playerGPos[i][j][1] = (box[i - 1][j - 1][1] + box[i][j][1]) / 2 - 66;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) {
	SetGraphMode(780, 680, 32);         // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_box(); // box, enemy, player の初期化

	int enemyX = 2, enemyY = 2;  // 敵の位置
	int playerX = 2, playerY = 2;  // 俺の位置

	int enemyMove = 0;   // 敵の移動状態
	int playerMove = 0;  // 俺の移動状態

	int enemyGHandle[12];   // 敵のグラフィックハンドル格納用配列
	int playerGHandle[12];  // 俺のグラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可

	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);

	// 背景の画像を読み込む
	int imgBack = LoadGraph("red.bmp");
	int enemyImage = enemyGHandle[11];
	int playerImage = playerGHandle[11];

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {

		// 背景の画像を描画
		DrawGraph(182, 237, imgBack, false);
		gpUpdateKey();  // キーの入力状態を取得

		{ // 敵の移動
			if (GetNowCount() >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
				nextMoveTime += MOVE_INTERVAL; // 次回移動処理をする時刻
				if (stopCount > 0) {
					// 停止中のとき
					stopCount--; // 止まっている残り時間(回数)を減らす
				}
				else {
					// 普通の状態のとき
					if (GetRand(99) < 10) { // たまに(10%の確率で)
						stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
					}
					else {
						// 9マス上のいずれかのパネルに移動させる
						int cy = enemyY, cx = enemyX;
						do {
							enemyY = GetRand(2) + 1;
							enemyX = GetRand(2) + 1;
						} while (enemyX == cx && enemyY == cy); // 移動先が今いるパネルなら、移動先を選びなおす
						enemyImage = enemyGHandle[8];
						enemyMove = 1;
					}
				}
			}

			if (enemyMove > 0 && ++enemyMove > 20) {
				enemyMove = 0;
				enemyImage = enemyGHandle[11];
			}
		}

		{ // 俺の移動

			if (Key[KEY_INPUT_RIGHT] == 1)
				if (playerX < 3) {
					playerMove = 1;
					playerX = playerX + 1; //移動
					playerImage = playerGHandle[5];
				}

			if (Key[KEY_INPUT_LEFT] == 1)
				if (playerX > 1) {
					playerMove = 1;
					playerX = playerX - 1; //移動
					playerImage = playerGHandle[5];
				}

			if (Key[KEY_INPUT_UP] == 1)
				if (playerY > 1) {
					playerMove = 1;
					playerY = playerY - 1; //移動
					playerImage = playerGHandle[2];
				}

			if (Key[KEY_INPUT_DOWN] == 1)
				if (playerY < 3) {
					playerMove = 1;
					playerY = playerY + 1; //移動
					playerImage = playerGHandle[8];
				}

			if (playerMove > 0 && ++playerMove > 20) {
				playerMove = 0;
				playerImage = playerGHandle[5];      // 右を向く
			}
		}

		ClearDrawScreen();  // 裏画面をクリア

		int boxColor = GetColor(160, 64, 64);//int box[4][7][2];の描画のためのプログラム。
		for (int i = 0; i < 4; i++)
			DrawLine(box[i][0][0], box[i][0][1],
				box[i][6][0], box[i][6][1], boxColor);
		for (int j = 0; j < 7; j++)
			DrawLine(box[0][j][0], box[0][j][1],
				box[3][j][0], box[3][j][1], boxColor);

		DrawGraph(enemyGPos[enemyY][enemyX][0], enemyGPos[enemyY][enemyX][1], enemyImage, true);// 敵キャラの描画
		DrawGraph(playerGPos[playerY][playerX][0], playerGPos[playerY][playerX][1], playerImage, true);// 俺キャラの描画
		ScreenFlip();  // 裏画面を表画面に反映

	}

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 

}

かずま

Re: int box[4][7][2]の役割。

#18

投稿記事 by かずま » 4年前

Ouxiy さんが書きました:
4年前

コード:

	int enemyGHandle[12];   // 敵のグラフィックハンドル格納用配列
	int playerGHandle[12];  // 俺のグラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可

	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);
まだ、コメントに嘘がありますね。使っているのは、11, 5, 2, 8 なのに。
左に行くとき右向きのままなのも変です。

enemy と player で同じ charall.png を使うんだったら
グラフィックハンドルの配列は一つでよいでしょう。
まあ、これはあとで別の画像を用意するつもりなのかもしれませんが。

DrawGraph(182, 237, imgBack, false); の位置が変です。
ClearDrawScreen(); の後に置かないと表示されませんよね。
表示させてみると、表示位置がおかしいことも分かるでしょう。

DrawLine は引数をもう一つ増やすことができて、それは線の太さです。
デフォルトは 1 なので、10ぐらいにするとよいのではないでしょうか?

というよりも、背景を表示するのなら、そこにステージを描いておけば、
DrawLine を使う必要もありません。

charall.png は透過PNGファイルなので、DrawGraph の最後の引数を
true に変更したのは正解でしょう。

あと、box という名前ですが、これはあまりいい名前ではありません。
最初、マスは「枠」という意味で frame にしようかと思ったのですが、
frame は動画のコマとして既に使っているのでダメです。「四角」ということ
で square も考えましたが、box でいいやと思ってそれにしてしまいました。
ステージが適当と分かったので、stage に変えたほうが良いでしょう。

charall.png の中の一つの画像は 49 x 66 ですが、足の位置が浮いているので
enemyGPos や playerGPos を計算するときの -66 は -55 などにしたほうが
良いのでは?

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#19

投稿記事 by Ouxiy » 4年前

enemy と player で同じ charall.png を使うんだったら
グラフィックハンドルの配列は一つでよいでしょう。
まあ、これはあとで別の画像を用意するつもりなのかもしれませんが。
はい!自分と敵で異なる画像を使う予定です。
DrawLine は引数をもう一つ増やすことができて、それは線の太さです。
デフォルトは 1 なので、10ぐらいにするとよいのではないでしょうか?
リファレンスをみて取り組んでみます。
というよりも、背景を表示するのなら、そこにステージを描いておけば、
DrawLine を使う必要もありません。
最初はステージの画像を作って重ねようかと思ったのですが、意外にもドットのステージ作りが難しく、そして、DrawLineを使ってのステージに丁度収まるように書くのが難しいため断念気味な部分です。
あと、box という名前ですが、これはあまりいい名前ではありません。
最初、マスは「枠」という意味で frame にしようかと思ったのですが、
frame は動画のコマとして既に使っているのでダメです。「四角」ということ
で square も考えましたが、box でいいやと思ってそれにしてしまいました。
ステージが適当と分かったので、stage に変えたほうが良いでしょう。
はい!そうさせて頂きました。ありがとうございます。
charall.png の中の一つの画像は 49 x 66 ですが、足の位置が浮いているので
enemyGPos や playerGPos を計算するときの -66 は -55 などにしたほうが
良いのでは?
確かに少し上に行き過ぎたので下げます。

今攻撃判定のプログラムを作っていまして、以下のプログラムを作りました。
入力キーTで自分と同じ行にいる相手をロックオンして、入力キーAで敵座標―1のマスに瞬間移動します。
ただ、敵陣と味方の陣と固定してしまったため敵陣にはロックオンしても瞬間移動して敵陣に入れずにいます。
自分でもポインタを使って解決できないかと考えたのですが、やはり範囲自体を編集しなければ解決できないでしょうか。何かいい案があれば教えてほしいです。

コード:

//当たり判定のプログラム//
		//自分がplayerX、playerYの座標にいる状態でKを押したらマークする
		if (playerY == enemyY && Key[KEY_INPUT_T] == 1) {//X座標がお互いにどんな条件であれY座標が一致すればいいのでこれでいい。
			enemyImage = enemyGHandle[5];
			if (Key[KEY_INPUT_A] == 1){  //アタックのA
				playerX = enemyX - 1;//enemyXの前に来るためX座標的に-1されたX座標に自分が来るためplayerX=とX座標の値を代入した
				playerImage = playerGHandle[9];//踏み込む際の画像を提示
			}

		}
以下は全体のプログラムです。

コード:

#include "DxLib.h"

int Key[256];

int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;//キーのフレームの習得
	return 0;
}

int stage[4][7][2];        // 盤上のマス
int enemyGPos[5][5][2];  // 敵の描画座標
int playerGPos[5][5][2]; // 俺の描画座標

void init_stage() {
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			stage[i][j][0] = w + 400, stage[i][j][1] = h - 200;//int box[4][7][2];の初期化のためのプログラム
			w = w * 9 / 10, h = h * 9 / 10;//ステージを作るためのboxのプログラム。
		}
	}
	for (int i = 1; i <= 3; i++)// ステージをつくるboxのプログラムを「利用」してplayerX = 2, playerY = 2などの配列の座標を画面上の座標に変換してくれる(初期化と定義の)プログラム。
		for (int j = 1; j <= 3; j++) {//こいつがあることで関数DrawGraphの引数にplayerGPos[playerY][playerX][0]やplayerGPos[playerY][playerX][1]などの[ ][ ][ ]が使える。
			enemyGPos[i][j][0] = (stage[i - 1][j + 2][0] + stage[i][j + 3][0]) / 2 - 25;//ざっくり言えば、ステージを作るための線を利用して中心点をbox[4][7][2]を利用してenemyGPos[5][5][2]; playerGPos[5][5][2]の9マスの座標を求める。詳しくは上に書いた通り。
			enemyGPos[i][j][1] = (stage[i - 1][j + 2][1] + stage[i][j + 3][1]) / 2 - 55;
			playerGPos[i][j][0] = (stage[i - 1][j - 1][0] + stage[i][j][0]) / 2 - 25;
			playerGPos[i][j][1] = (stage[i - 1][j - 1][1] + stage[i][j][1]) / 2 - 55;
		}
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) {
	SetGraphMode(780, 680, 32);         // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_stage(); // box, enemy, player の初期化

	int enemyX = 2, enemyY = 2;  // 敵の位置
	int playerX = 2, playerY = 2;  // 俺の位置

	int enemyMove = 0;   // 敵の移動状態
	int playerMove = 0;  // 俺の移動状態

	int enemyGHandle[12];   // 敵のグラフィックハンドル格納用配列
	int playerGHandle[12];  // 俺のグラフィックハンドル格納用配列
			// 5:正面、7:右向き、2:左向き、4:上向き、3:下向き、9:移動不可

	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);

	// 背景の画像を読み込む
	//int imgBack = LoadGraph("red.bmp");
	int enemyImage = enemyGHandle[11];
	int playerImage = playerGHandle[5];

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {

		// 背景の画像を描画
		//DrawGraph(182, 237, imgBack, false);
		gpUpdateKey();  // キーの入力状態を取得

		{ // 敵の移動
			if (GetNowCount() >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
				nextMoveTime += MOVE_INTERVAL; // 次回移動処理をする時刻
				if (stopCount > 0) {
					// 停止中のとき
					stopCount--; // 止まっている残り時間(回数)を減らす
				}
				else {
					// 普通の状態のとき
					if (GetRand(99) < 10) { // たまに(10%の確率で)
						stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
					}
					else {
						// 9マス上のいずれかのパネルに移動させる
						int cy = enemyY, cx = enemyX;
						do {
							enemyY = GetRand(2) + 1;
							enemyX = GetRand(2) + 1;
						} while (enemyX == cx && enemyY == cy); // 移動先が今いるパネルなら、移動先を選びなおす
						enemyImage = enemyGHandle[10];
						enemyMove = 1;
					}
				}
			}

			if (enemyMove > 0 && ++enemyMove > 20) {
				enemyMove = 0;
				enemyImage = enemyGHandle[11];
			}
		}

		{ // 俺の移動

			if (Key[KEY_INPUT_RIGHT] == 1)//keyフレームを最初で取得しているがこのプログラムの=1のおかげで一回押すごとに1だけ進むようにできた。
				if (playerX < 3) {
					playerMove = 1;
					playerX = playerX + 1; //移動
					playerImage = playerGHandle[5];
				}

			if (Key[KEY_INPUT_LEFT] == 1)
				if (playerX > 1) {
					playerMove = 1;
					playerX = playerX - 1; //移動
					playerImage = playerGHandle[5];
				}

			if (Key[KEY_INPUT_UP] == 1)
				if (playerY > 1) {
					playerMove = 1;
					playerY = playerY - 1; //移動
					playerImage = playerGHandle[2];
				}

			if (Key[KEY_INPUT_DOWN] == 1)
				if (playerY < 3) {
					playerMove = 1;
					playerY = playerY + 1; //移動
					playerImage = playerGHandle[8];
				}

			if (playerMove > 0 && ++playerMove > 20) {
				playerMove = 0;
				playerImage = playerGHandle[5];      // 右を向く
			}
		}

		//当たり判定のプログラム//
		//自分がplayerX、playerYの座標にいる状態でKを押したらマークする
		if (playerY == enemyY && Key[KEY_INPUT_T] == 1) {//X座標がお互いにどんな条件であれY座標が一致すればいいのでこれでいい。
			enemyImage = enemyGHandle[5];
			if (Key[KEY_INPUT_A] == 1){  //アタックのA
				playerX = enemyX - 1;//enemyXの前に来るためX座標的に-1されたX座標に自分が来るためplayerX=とX座標の値を代入した
				playerImage = playerGHandle[9];//踏み込む際の画像を提示
			}

		}



		ClearDrawScreen();  // 裏画面をクリア

		int boxColor = GetColor(160, 64, 64);//int box[4][7][2];の描画のためのプログラム。
		for (int i = 0; i < 4; i++)
			DrawLine(stage[i][0][0], stage[i][0][1],
				stage[i][6][0], stage[i][6][1], boxColor);
		for (int j = 0; j < 7; j++)
			DrawLine(stage[0][j][0], stage[0][j][1],
				stage[3][j][0], stage[3][j][1], boxColor);

		DrawGraph(enemyGPos[enemyY][enemyX][0], enemyGPos[enemyY][enemyX][1], enemyImage, true);// 敵キャラの描画
		DrawGraph(playerGPos[playerY][playerX][0], playerGPos[playerY][playerX][1], playerImage, true);// 俺キャラの描画
		ScreenFlip();  // 裏画面を表画面に反映

	}

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 

}

かずま

Re: int box[4][7][2]の役割。

#20

投稿記事 by かずま » 4年前

ロックしたら、プレイヤーも敵も動かなくなるのですか?
ロックが解除されるのは、いつですか?
アタックしたら解除されるのですか?
それとも、ある一定時間経ったら解除されるのですか?

何も分からないので、とりあえず、Z を押すと、
ロックが解除されるようにしてみました。

コード:

#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;
	return 0;
}

int stage[4][7][2];  // 盤上のマスの格子点の座標
int pos[3][6][2];    // キャラ描画座標

void init_stage()  // stage と pos を初期化する
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			stage[i][j][0] = w + 400, stage[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 6; j++) {
			pos[i][j][0] = (stage[i][j][0] + stage[i+1][j+1][0]) / 2 - 25;
			pos[i][j][1] = (stage[i][j][1] + stage[i+1][j+1][1]) / 2 - 55;
		}
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	SetGraphMode(780, 680, 32);         // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_stage(); // stage, pos の初期化

	int enemyX = 4,  enemyY = 1;   // 敵の位置
	int playerX = 1, playerY = 1;  // 俺の位置

	int enemyMove = 0;   // 敵の移動状態
	int playerMove = 0;  // 俺の移動状態

	int lock = 0;  // ロック状態

	int enemyGHandle[12];   // 敵のグラフィックハンドル格納用配列
	int playerGHandle[12];  // 俺のグラフィックハンドル格納用配列
			// 0-2:後ろ向き、3-5:右向き、6-8:前向き、9-11:左向き
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);
	int enemyImage = enemyGHandle[11];    // 敵 左向き
	int playerImage = playerGHandle[5];   // 俺 右向き

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得

		if (lock) {
			if (Key[KEY_INPUT_A] == 1) {  // アタック
				playerX = enemyX - 1;
				playerMove = 1; playerImage = playerGHandle[4];
				enemyMove = 1; enemyImage = enemyGHandle[10];
			}
			if (Key[KEY_INPUT_Z] == 1) {  // ロック解除
				lock = 0;
			}
		}
		else {
			// 敵の移動
			int t = GetNowCount();
			if (t >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
				nextMoveTime = t + MOVE_INTERVAL; // 次回移動処理をする時刻
				if (stopCount > 0) { // 停止中のとき
					stopCount--; // 止まっている残り時間(回数)を減らす
				}
				else { // 普通の状態のとき
					if (GetRand(99) < 10) { // たまに(10%の確率で)
						stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
					}
					else { // 9マス上のいずれかのパネルに移動させる
						int cy = enemyY, cx = enemyX;
						do {
							enemyY = GetRand(2);
							enemyX = GetRand(2) + 3;
						} while (enemyX == cx && enemyY == cy ||
							enemyX == playerX && enemyY == playerY);
						enemyImage = enemyGHandle[10];
						enemyMove = 1;
					}
				}
			}

			// 俺の移動
			if (Key[KEY_INPUT_RIGHT] == 1 && playerX < 2) {
				playerMove = 1; playerX++; playerImage = playerGHandle[4];
			}
			if (Key[KEY_INPUT_LEFT] == 1 && playerX > 0) {
				playerMove = 1; playerX--; playerImage = playerGHandle[9];
			}
			if (Key[KEY_INPUT_UP] == 1 && playerY > 0) {
				playerMove = 1; playerY--; playerImage = playerGHandle[2];
			}
			if (Key[KEY_INPUT_DOWN] == 1 && playerY < 2) {
				playerMove = 1; playerY++; playerImage = playerGHandle[8];
			}
			if (Key[KEY_INPUT_T] == 1 && playerY == enemyY) {  // ロック
				playerMove = 0; playerImage = playerGHandle[5];
				enemyMove = 0; enemyImage = enemyGHandle[11];
				stopCount = 0;
				lock = 1;
			}
		}
		if (enemyMove > 0 && ++enemyMove > 20) {
			enemyMove = 0; enemyImage = enemyGHandle[11];
		}
		if (playerMove > 0 && ++playerMove > 20) {
			playerMove = 0; playerImage = playerGHandle[5];
		}

		ClearDrawScreen();  // 裏画面をクリア

		// ステージの描画
		int stageColor = GetColor(160, 64, 64);
		for (int i = 0; i < 4; i++)
			DrawLine(stage[i][0][0], stage[i][0][1],
				stage[i][6][0], stage[i][6][1], stageColor, 5);
		for (int j = 0; j < 7; j++)
			DrawLine(stage[0][j][0], stage[0][j][1],
				stage[3][j][0], stage[3][j][1], stageColor, 5);

		DrawGraph(pos[enemyY][enemyX][0], pos[enemyY][enemyX][1],
			enemyImage, true);   // 敵キャラの描画
		DrawGraph(pos[playerY][playerX][0], pos[playerY][playerX][1],
			playerImage, true);  // 俺キャラの描画

		if (lock) DrawFormatString(100, 200, GetColor(255,255,255), "LOCK");
		ScreenFlip();  // 裏画面を表画面に反映
	}

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
}

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#21

投稿記事 by Ouxiy » 4年前

カズマさん、いつもいつもありがとうございます。
説明の仕方が下手ですいません。こちらの動画攻撃方法の5:16のようにロックオンして相手のマスに移動して攻撃するようにしたいです。

プログラムは参考にさせて頂きます。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#22

投稿記事 by Ouxiy » 4年前

出来ればロックオンした後、敵が他の列や同じ列であれ動いたらロックが解除されるように作りたいです。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#23

投稿記事 by Ouxiy » 4年前

コード:

while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得

		if (lock) {
			if (Key[KEY_INPUT_A] == 1) {  // アタック
				playerX = enemyX - 1;
				playerMove = 1; playerImage = playerGHandle[4];
				enemyMove = 1; enemyImage = enemyGHandle[10];
			}
			if (Key[KEY_INPUT_Z] == 1) {  // ロック解除
				lock = 0;
			}
		}
		else {
			// 敵の移動
			int t = GetNowCount();
			if (t >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
				nextMoveTime = t + MOVE_INTERVAL; // 次回移動処理をする時刻
				if (stopCount > 0) { // 停止中のとき
					stopCount--; // 止まっている残り時間(回数)を減らす
				}
				else { // 普通の状態のとき
					if (GetRand(99) < 10) { // たまに(10%の確率で)
						stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
					}
					else { // 9マス上のいずれかのパネルに移動させる
						int cy = enemyY, cx = enemyX;
						do {
							enemyY = GetRand(2);
							enemyX = GetRand(2) + 3;
						} while (enemyX == cx && enemyY == cy ||
							enemyX == playerX && enemyY == playerY);
						enemyImage = enemyGHandle[10];
						enemyMove = 1;
					}
				}
			}

			// 俺の移動
			if (Key[KEY_INPUT_RIGHT] == 1 && playerX < 2) {
				playerMove = 1; playerX++; playerImage = playerGHandle[4];
			}
			if (Key[KEY_INPUT_LEFT] == 1 && playerX > 0) {
				playerMove = 1; playerX--; playerImage = playerGHandle[9];
			}
			if (Key[KEY_INPUT_UP] == 1 && playerY > 0) {
				playerMove = 1; playerY--; playerImage = playerGHandle[2];
			}
			if (Key[KEY_INPUT_DOWN] == 1 && playerY < 2) {
				playerMove = 1; playerY++; playerImage = playerGHandle[8];
			}
			if (Key[KEY_INPUT_T] == 1 && playerY == enemyY) {  // ロック
				playerMove = 0; playerImage = playerGHandle[5];
				enemyMove = 0; enemyImage = enemyGHandle[11];
				stopCount = 0;
				lock = 1;
			}
		}
		
の部分に関して、自分なりに書いたのですが、if (Key[KEY_INPUT_R] == 1 && playerY==enemyY) {}の中にif文でif (Key[KEY_INPUT_A] == 1)を書いたのになぜ反映されないのでしょうか。

コード:

// 俺の移動
		if (Key[KEY_INPUT_RIGHT] == 1 && playerX < 2) {
			playerMove = 1; playerX++; playerImage = playerGHandle[4];
		}
		if (Key[KEY_INPUT_LEFT] == 1 && playerX > 0) {
			playerMove = 1; playerX--; playerImage = playerGHandle[9];
		}
		if (Key[KEY_INPUT_UP] == 1 && playerY > 0) {
			playerMove = 1; playerY--; playerImage = playerGHandle[2];
		}
		if (Key[KEY_INPUT_DOWN] == 1 && playerY < 2) {
			playerMove = 1; playerY++; playerImage = playerGHandle[8];
		}

		if (Key[KEY_INPUT_R] == 1 && playerY==enemyY) {
			enemyImage = enemyGHandle[6];
			if (Key[KEY_INPUT_A] == 1) {  // アタック
				playerX = enemyX - 1;
				playerX = playerX;
				playerMove = 1; playerImage = playerGHandle[4];
				enemyMove = 1; enemyImage = enemyGHandle[10];
			}

		}
以下は全体のプログラムです。

コード:

#include "DxLib.h"

int Key[256];

int gpUpdateKey()
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++)
		(tmpKey[i] == 0) ? (Key[i] = 0) : Key[i]++;
	return 0;
}

int stage[4][7][2];  // 盤上のマスの格子点の座標
int pos[3][6][2];    // キャラ描画座標

void init_stage()  // stage と pos を初期化する
{
	for (int j = 0; j < 7; j++) {
		int w = (j - 3) * 100, h = 600;
		for (int i = 4; --i >= 0; ) {
			stage[i][j][0] = w + 400, stage[i][j][1] = h - 200;
			w = w * 9 / 10, h = h * 9 / 10;
		}
	}
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 6; j++) {
			pos[i][j][0] = (stage[i][j][0] + stage[i + 1][j + 1][0]) / 2 - 25;
			pos[i][j][1] = (stage[i][j][1] + stage[i + 1][j + 1][1]) / 2 - 55;
		}
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	SetGraphMode(780, 680, 32);         // ウィンドウの大きさを指定
	ChangeWindowMode(TRUE);             // 全画面ではなくウインドウを使用
	if (DxLib_Init() == -1) return -1;  // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);      // 裏画面を使用する設定

	init_stage(); // stage, pos の初期化

	int enemyX = 4, enemyY = 1;   // 敵の位置
	int playerX = 1, playerY = 1;  // 俺の位置

	int enemyMove = 0;   // 敵の移動状態
	int playerMove = 0;  // 俺の移動状態

	int lock = 0;  // ロック状態

	int enemyGHandle[12];   // 敵のグラフィックハンドル格納用配列
	int playerGHandle[12];  // 俺のグラフィックハンドル格納用配列
			// 0-2:後ろ向き、3-5:右向き、6-8:前向き、9-11:左向き
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, enemyGHandle);
	LoadDivGraph("charall.png", 12, 3, 4, 49, 66, playerGHandle);
	int enemyImage = enemyGHandle[11];    // 敵 左向き
	int playerImage = playerGHandle[5];   // 俺 右向き

	const int MOVE_INTERVAL = 1000; // 何ミリ秒ごとに移動処理をするか
	int nextMoveTime = GetNowCount() + MOVE_INTERVAL; // 次回移動処理をする時刻
	int stopCount = 0; // 動かないのがあと何回か

	while (ProcessMessage() == 0) {

		gpUpdateKey();  // キーの入力状態を取得

		// 俺の移動
		if (Key[KEY_INPUT_RIGHT] == 1 && playerX < 2) {
			playerMove = 1; playerX++; playerImage = playerGHandle[4];
		}
		if (Key[KEY_INPUT_LEFT] == 1 && playerX > 0) {
			playerMove = 1; playerX--; playerImage = playerGHandle[9];
		}
		if (Key[KEY_INPUT_UP] == 1 && playerY > 0) {
			playerMove = 1; playerY--; playerImage = playerGHandle[2];
		}
		if (Key[KEY_INPUT_DOWN] == 1 && playerY < 2) {
			playerMove = 1; playerY++; playerImage = playerGHandle[8];
		}

		if (Key[KEY_INPUT_R] == 1 && playerY==enemyY) {
			enemyImage = enemyGHandle[6];
			if (Key[KEY_INPUT_A] == 1) {  // アタック
				playerX = enemyX - 1;
				playerX = playerX;
				playerMove = 1; playerImage = playerGHandle[4];
				enemyMove = 1; enemyImage = enemyGHandle[10];
			}

			
		}
		else {
			// 敵の移動
			int t = GetNowCount();
			if (t >= nextMoveTime) { // 指定の時間が経ったら(1sごとに)
				nextMoveTime = t + MOVE_INTERVAL; // 次回移動処理をする時刻
				if (stopCount > 0) { // 停止中のとき
					stopCount--; // 止まっている残り時間(回数)を減らす
				}
				else { // 普通の状態のとき
					if (GetRand(99) < 10) { // たまに(10%の確率で)
						stopCount = GetRand(4); // 数秒間(1~5秒間)その場に止まる
					}
					else { // 9マス上のいずれかのパネルに移動させる
						int cy = enemyY, cx = enemyX;
						do {
							enemyY = GetRand(2);
							enemyX = GetRand(2) + 3;
						} while (enemyX == cx && enemyY == cy ||
							enemyX == playerX && enemyY == playerY);
						enemyImage = enemyGHandle[10];
						enemyMove = 1;
					}
				}
			}

			
			
		}
		if (enemyMove > 0 && ++enemyMove > 20) {
			enemyMove = 0; enemyImage = enemyGHandle[11];
		}
		if (playerMove > 0 && ++playerMove > 20) {
			playerMove = 0; playerImage = playerGHandle[5];
		}

		ClearDrawScreen();  // 裏画面をクリア

		// ステージの描画
		int stageColor = GetColor(160, 64, 64);
		for (int i = 0; i < 4; i++)
			DrawLine(stage[i][0][0], stage[i][0][1],
				stage[i][6][0], stage[i][6][1], stageColor, 5);
		for (int j = 0; j < 7; j++)
			DrawLine(stage[0][j][0], stage[0][j][1],
				stage[3][j][0], stage[3][j][1], stageColor, 5);

		DrawGraph(pos[enemyY][enemyX][0], pos[enemyY][enemyX][1],
			enemyImage, true);   // 敵キャラの描画
		DrawGraph(pos[playerY][playerX][0], pos[playerY][playerX][1],
			playerImage, true);  // 俺キャラの描画

		if (lock) DrawFormatString(100, 200, GetColor(255, 255, 255), "LOCK");
		ScreenFlip();  // 裏画面を表画面に反映
	}

	DxLib_End();  // DXライブラリ使用の終了処理
	return 0;  // ソフトの終了 
}

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#24

投稿記事 by Ouxiy » 4年前

解答して頂かなくても大丈夫です!問題は解決しました!!
ありがとうございます。

かずま

Re: int box[4][7][2]の役割。

#25

投稿記事 by かずま » 4年前

Ouxiy さんが書きました:
4年前
解答して頂かなくても大丈夫です!問題は解決しました!!
この掲示板のルールで、
解決した場合は、どのようにして解決したかを書かないといけません。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#26

投稿記事 by Ouxiy » 4年前

すみません。実はまだ解決していないですが、自分で解決しなければ技術が身につかないので嘘を言いました。
ただ、何かヒントなど教えて頂けると嬉しいです。

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#27

投稿記事 by Ouxiy » 4年前

すいません、どうか助けてください。どんな方法で作ればいいのか、、、

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: int box[4][7][2]の役割。

#28

投稿記事 by みけCAT » 4年前

Ouxiy さんが書きました:
4年前
if (Key[KEY_INPUT_R] == 1 && playerY==enemyY) {}の中にif文でif (Key[KEY_INPUT_A] == 1)を書いたのになぜ反映されないのでしょうか。

コード:

		if (Key[KEY_INPUT_R] == 1 && playerY==enemyY) {
			enemyImage = enemyGHandle[6];
			if (Key[KEY_INPUT_A] == 1) {  // アタック
				playerX = enemyX - 1;
				playerX = playerX;
				playerMove = 1; playerImage = playerGHandle[4];
				enemyMove = 1; enemyImage = enemyGHandle[10];
			}

		}
このプログラムでは、RキーとAキーをぴったり同じフレームで押さないと反映されません。
操作が下手、もしくはキーボードやOSなどの仕様?により同じフレームでの入力ができていないため、
反映されていないと考えられます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 173
登録日時: 4年前

Re: int box[4][7][2]の役割。

#29

投稿記事 by Ouxiy » 4年前

みけCATさん解答ありがとうございます。
今のところ時間の関数を利用して、ロックオンしてからある一定の時間の間にAを押すと攻撃
キーでRを押した後もRを押したことを記憶するメモリを変数として作っておき、Aを押しと攻撃するなども考えています。

返信

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