マップの木や建物などの描画方法について

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

マップの木や建物などの描画方法について

#1

投稿記事 by イマダニ » 10年前

こんにちは。
今回はマップの木や建物などの描画方法について質問しに来ました。

今、DXライブラリでクォータービューのアクションゲームを作っています。
FFTのような、指定した場所に規則的にコマのように動くのではなく、

ぐるぐる走りまわり、でんぐり返しもジャンプもするアクションゲームです。
pcゲームのbastionやアドバンス版のキングダムハーツの様なゲームです。

現段階ではまだ四角い菱形系のチップをただ並べただけの殺風景なマップを
方向キーを押すとキャラが走り回り、SHIFTを押すとでんぐり返し、SPACEを押すとジャンプをするというものです。

マップは以下のように書かれたテキストファイルを読み込み、描画しています。

コード:

8,10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1が地面で0がいけない所という、基本的な二次元配列のマップです。
そこでこれでは寂しすぎると、描き溜めた素材をいい加減使いたいのもあり、
木や建物などの物を置いたり、
いずれはマップの地形をBASTIONというゲームのように円形にしたりしたいなと思い実践しようとしたのですが、

ぼくはそういったマップの物の配置?というのをやったことがありません。

唯一マップをいじる機会があった横スクロールアクションでのマップは、
マリオのブロックをただ並べたひらぺったいつまらないものでした。
なのでいまいち描画方法がわかりません。当たり判定なんて想像もつきません。

建物とか木の描画方法は、
今使ってるチップのサイズに分割し、二次元配列で分割した物をそろえるのでしょうか?
それとも分割せずそのまま描画し、矩形などを用いて、当たり判定を細かくするのでしょうか?

マップエディタとかだと前者の方法だと思うのですが、当たり判定があいまいになりそうです。
かといって後者だと、コードの量がすごい事になり、管理が大変そうです。

となるとやはり前者が正しいのでしょうか?

トップビューのRPGならそれでいいのでしょうが、クォーターのアクションとなるとぐるぐる動く上、ジャンプもするため
あいまいな当たり判定だとまずい気がします。

ひとまず当たり判定は置いといて、描画方法だけ、どの方法がいいのかしっかり確認しておきたいです。

初歩的な質問ですが、アドバイスお願いします。

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

Re: マップの木や建物などの描画方法について

#2

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

いまどきのPCの性能だとキャラクタと同様にスプライト的な扱いで移動しない物として置けば良いと思います。
当たり判定も敵キャラクタ同様に行います。ダメージがないだけって感じでしょうか。

擬似的に3Dぽくなるので、難易度は上がるかなぁと思いますけど。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: マップの木や建物などの描画方法について

#3

投稿記事 by ISLe » 10年前

Zソートが必要なので、描画自体は地面と同じに行うほうが効率は良いのではないかと思います。

トップビューでも高い建物とか橋とかの立体交差で同じような手法を使いますし。
当たり判定もトップビュー同様にチップ単位のほうが楽な気がしますけど。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#4

投稿記事 by イマダニ » 10年前

soft屋さん、ISLeさん返信ありがとうございます。

soft屋さん さんが書きました: いまどきのPCの性能だとキャラクタと同様にスプライト的な扱いで移動しない物として置けば良いと思います。
当たり判定も敵キャラクタ同様に行います。ダメージがないだけって感じでしょうか。
極端に言うと家や木の画像を読み込み、
それをDrawGraphなどで表示するということいいのでしょうか?
それで描画だけやってみたのですが、楽ちんでした。
ただこの方法だと、ぼくが試した方法が極端なのもありますが
ステージが変わるごとにマップ素材の配置と差し替えのためにコードを書くのは手間が大変そうです。

ISLeさん さんが書きました: 描画自体は地面と同じに行うほうが効率は良いのではないかと思います。
まず以下に張った
家の画像を今使っているチップの画像サイズに分割し、
それらを二次元配列で以下の様に描画すると言う事でいいのでしょうか?

コード:

8,10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 2, 3, 1, 1, 1, 1, 1, 1, 0 /*←234*/
0, 4, 5, 1, 1, 1, 1, 1, 1, 0 /*←567のところに家のパーツを表示する*/
0, 6, 7, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 1, 1, 1, 1, 1, 1, 1, 1, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Zソートなどはまだよくわかりませんが、
ぼくもチップ単位で扱った方が管理が楽だと思います。
とは思うのですが、

素材の用意の仕方とそれの扱い方が本当に分かりません。
上記のような解釈、やり方でいいのでしょうか?

アドバイスお願いします。
添付ファイル
housewake.jpg
家の素材を今使っているチップで割る?
housewake.jpg (28.35 KiB) 閲覧数: 16136 回

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

Re: マップの木や建物などの描画方法について

#5

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

>ステージが変わるごとにマップ素材の配置と差し替えのためにコードを書くのは手間が大変そうです。

こういうものを本格的に作るには、マップエディタを使います。
マップデータの配置情報や画像情報を記録したファイルを出力するツールです。ついでに当たり判定なども情報も設定します。
目的に適う汎用ツールがない場合は自分で作らないと行けません。
※ DXライブラリで作成可能です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: マップの木や建物などの描画方法について

#6

投稿記事 by ISLe » 10年前

イマダニ さんが書きました:まず以下に張った
家の画像を今使っているチップの画像サイズに分割し、
それらを二次元配列で以下の様に描画すると言う事でいいのでしょうか?
建物等の画像を分割する必要はありません。
地面のマップチップを描画するのと同じタイミングで、地面の座標を基準に建物の画像の高さ分上にズラした座標から建物の画像を描画するだけです。
マップチップ自体の大きさが変化すると考えていただくのが良いと思います。

指定された座標に指定されたマップチップIDの画像が描画される仕組みになってさえいれば良いです。
独立した画像をポンとひとつ描くだけでも良いし、配列テーブルを元に複数の画像を組み合わせて描画するようになっていても良いです。
イマダニ さんが書きました:Zソートなどはまだよくわかりませんが、
ぼくもチップ単位で扱った方が管理が楽だと思います。
とは思うのですが、
高さがあると前後に重なる場合があるので、地面と別でも別でなくてもどのみちZソートは必要だと思いますが。


汎用のマップエディタだと通過可能な部分(いわゆる道路)と建物が重なってしまうので、建物の二階以上の部分を別のレイヤーに分けるような工夫が必要になる場合もあると思います。
そういった場合、マップエディタ用のチップ画像と本番用のチップ画像を分けるとか、あとからマップデータのレイヤーを合成する(あるいは最下層以外を無視する)などの処理を行うことになります。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#7

投稿記事 by イマダニ » 10年前

マップエディタを作ろうとプログラム撃っていたら遅くなりました

>>こういうものを本格的に作るには、マップエディタを使います。

やはりそうなりますよね。
ISLeさんのアドバイスとまとめると理想としては

1.地面マップチップの配列データ

2.その上に置かれる建物などのオブジェクトの座標

3.オブジェクトの当たり判定

上記三つの情報が書き込まれたデータを吐き出すエディタを作るという事でいいんでしょうか?

二次元配列を使えばマップを表示できるぜ!程度の知識しか持ってない自分には
そのデータをどういう形にするのか、おぼろげに推測しかできないので、
ひとまず一番簡単そうな

地面マップチップの配列情報を吐くマップエディタを作った後で考えよう

と簡単な事から段階的にやってみたいと思い

クリックであの菱形の地面チップを表示するプログラムを書いてみたのですが、
クリックしても明後日の方に表示されます。以下がそのコードになります。

コード:

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

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  8
#define CHIP_NUMBER_X  10

//マップデータの二次元配列
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ] =
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetMainWindowText("マップエディタ");ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img,x,y,Mouse,Wheel;
	//クリックした座標の記録用変数
	int imgx=0;
	int imgy=0;
	//クリックされた配列を記録する変数
	int hnum=0;
	int wnum=0;

	//チップ画像読み込み
	chip_img=LoadGraph("img/mapchip01.bmp");

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&x,&y);
		
		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=x;imgy=y;
			
			//押された配列の要素を確認し、そこを1に変える
			MapData[imgx/64][imgy/64]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=x;imgy=y;

			//そこを0に変える
			MapData[imgx/64][imgy/64]=0;
		}
		printf("%d",imgx);

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が1である所に画像を表示する。
				if(MapData[x][y]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), chip_img,TRUE);
				}
			}
		}
	}
	DxLib_End();
	return 0;
}
そんなこんなで今感じてる疑問は三つです。

1.どのようなデータを作ればいいの?

愚直に、地面の配列データと、家の座標、を書いたtxtファイルではだめなのではと悩んでいます。
そもそもtxtでいいのでしょうか?
なにより一番わからないのが当たり判定のファイル化です。
0はいけないとかならシンプルなのでいいのですが、家などはそれで済ませられない気がします。
どのようにファイルとしてまとめるのでしょう?
それがわからないため、どのようなエディタを作ればいいのか、いまいちビジョンが見えません。

2.エディターで二次元配列を使う事は正しいのか?

どのような設計にすればいいのかわからず、
ひとまずググってみてエディターのサンプルプログラムを探しました。
すると、大半は二次元配列を0で初期化などせず、一次元配列、
int data[DATA_MAX]のようなものヘッダ内の構造体のメンバとして宣言し、それを使用してました。
二次元配列よりもそちらの方が効率がいいのでしょうか?

3.何故明後日の方向へチップが表示されるのか?

上記プログラムではトップビューのチップは思い通りに表示できました。
クリックしたまま画面外に行くと配列外にアクセスするのか
フリーズを起こしますけど、それ以外は問題ありませんでした。
ですが、クォータの画像で行うとクリックした所に表示されず、別のところで表示されます。
マップ座標の配列判定はトップのままで
描画の時だけクォーターの公式に当てはめるのではダメなのでしょうか?

以上が疑問点です。

上記の疑問点が脳内でごちゃまぜになり、
整理するのに時間がかかったというのもあって、返信がだいぶ遅れてしまいました。
ISLeさんに家の表示についてのアドバイスを書き込んでもらったのに、
はやいとこ家や木の表示をしたいのに、
上記のような、”それ以前の問題”にぶつかってしまいました。

ISLeさんすみません……

質問が多く、整理しきれてないので、ごちゃごちゃしてますが、

とりあえず今は、クリックするとそこにちゃんと地面や家を表示する、クリックするだけのプログラムを作ろうと思ってます。
まずは地面!

以上の考えに対する、アドバイスお願いします。

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

Re: マップの木や建物などの描画方法について

#8

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

マップ配列と画面で座標系が違うので、相互に変換が必要です。

DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), chip_img,TRUE);
これが表示のために行う変換。 マップ配列の座標系から、表示座標系に変換しています。 
マウスは表示座標系に属するので、マップ配列の座標系に変換しないと明後日の位置に表示されるかなと。
クォータービューじゃなければ、 MapData[imgx/64][imgy/64]=1;で良いんですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#9

投稿記事 by イマダニ » 10年前

配列要素の、yとxが逆になってたので修正。

コード:

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

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  100
#define CHIP_NUMBER_X  100

//マップデータの二次元配列
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ];

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetMainWindowText("マップエディタ");ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	/*AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用*/

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img,mx,my,Mouse,Wheel;
	//クリックした座標の記録用変数
	int imgx=0;
	int imgy=0;
	//クリックされた配列を記録する変数
	int hnum=0;
	int wnum=0;

	//チップ画像読み込み
	chip_img=LoadGraph("img/mapchip01.bmp");

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			
			//押された配列の要素を確認し、そこを1に変える
			MapData[imgy/64][imgx/64]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;

			//そこを0に変える
			MapData[imgy/64][imgx/64]=0;
		}

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が1である所に画像を表示する。
				if(MapData[y][x]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), chip_img,TRUE);
                }
            }
        }
    }
    DxLib_End();
    return 0;
}
softya さんが書きました:マウスは表示座標系に属するので、マップ配列の座標系に変換しないと明後日の位置に表示されるかなと。
なんとややこしい……(´Д` ;)

その変換式の求め方は

w,h チップの幅と高さ
x,y マップデータの要素数というかマップチップ座標
X,Y クォータ座標

X=w(x-y)

Y=h(x+y)

上記の式を方程式で逆算すればいいのですか?

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

Re: マップの木や建物などの描画方法について

#10

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

> 上記の式を方程式で逆算すればいいのですか?

そう言うことです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: マップの木や建物などの描画方法について

#11

投稿記事 by ISLe » 10年前

イマダニ さんが書きました:1.どのようなデータを作ればいいの?

愚直に、地面の配列データと、家の座標、を書いたtxtファイルではだめなのではと悩んでいます。
そもそもtxtでいいのでしょうか?
なにより一番わからないのが当たり判定のファイル化です。
0はいけないとかならシンプルなのでいいのですが、家などはそれで済ませられない気がします。
どのようにファイルとしてまとめるのでしょう?
それがわからないため、どのようなエディタを作ればいいのか、いまいちビジョンが見えません。
チップ単位でそこに何があるかを数値で表現すれば良いと思います。
最初に投稿されたテキストファイルで、2は木、3は家、というふうにすれば良いと思います。
どうしてそれで済ませられないと思われるのでしょうか。
フリーソフトのマップエディタを利用して見取り図のようにデータを作るのが楽な方法かと思います。
イマダニ さんが書きました:2.エディターで二次元配列を使う事は正しいのか?

どのような設計にすればいいのかわからず、
ひとまずググってみてエディターのサンプルプログラムを探しました。
すると、大半は二次元配列を0で初期化などせず、一次元配列、
int data[DATA_MAX]のようなものヘッダ内の構造体のメンバとして宣言し、それを使用してました。
二次元配列よりもそちらの方が効率がいいのでしょうか?
一次元配列だと最小限のメモリ消費で動的にサイズを変更できます。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#12

投稿記事 by イマダニ » 10年前

softya さんが書きました: > 上記の式を方程式で逆算すればいいのですか?

そう言うことです。
ということで、
X=w(x-y)とY=h(x+y)のXYを区別がつくようABに変えて

A=w(x-y) B=h(x+y) ← こんな感じ

方程式で逆算してみました。
まずは A=w(x-y) から x と y を求めてみます。

①A=w(x-y)

②A=wx-wy

③wx=A+wy

④x=A+wy/w 

xがわかったので次はyです

②A=wx-wy

③wy=-A+wx

④y=-A+wx/w


次はB=h(x+y)から求めてみます。

①B=h(x+y)

②B=hx+hy

③hx=B-hy

④x=B-hy/h

xがわかったので次はy行きます。

②B=hx+hy

③hy=B-hx

④y=B-hx/h

ここまでもとめた計算式をまとめると

x = A+wy/w = B-hy/h

y = -A+wx/w = B-hx/h

こうなります
方程式から逆算というのはこれでおkですかね?
ISLe さんが書きました:チップ単位でそこに何があるかを数値で表現すれば良いと思います。
最初に投稿されたテキストファイルで、2は木、3は家、というふうにすれば良いと思います。
あ、それでよかったんですね。
ISLe さんが書きました: どうしてそれで済ませられないと思われるのでしょうか。
すいません…無知ゆえの憶測というやつです……
木とか家とか大きく複雑な形をしてるから、0の場所にはいけないというシンプルな当たり判定では
判定が甘く、すり抜けちゃうのではとか、
だったら矩形の当たり判定を組み合わせなきゃいけないんじゃないんだろうかと
勝手に思い込んでしまいました……
ISLe さんが書きました: フリーソフトのマップエディタを利用して見取り図のようにデータを作るのが楽な方法かと思います。
0が何もない行けない場所(マップ外)、1が地面、2が家、3が木として
それらを使って、数字の地図をエディタで作ればいいということですね
それでその地図が書かれたファイルをプログラムで読み込むと

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

Re: マップの木や建物などの描画方法について

#13

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

式を検証しましたが、最初の④x=A+wy/w の所がヘンです。
あと数値を当てはめて逆変換を検算していないのも良くないですよ。
プログラムもそうですがテストしていないものは、ちゃんと動かないと思えです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#14

投稿記事 by イマダニ » 10年前

[0][0] (64,20) w=32,h=20
[y][x] (A , B)

これで検算すると

y=-A+wx/w

0=-64+32*0/32

0=-64+0/32

0=-64/32

0=-2

……おかしいですね

A=w(x-y)を方程式で
x=????に変えるっていうの考えでいいんですよね?

アバター
へにっくす
記事: 634
登録日時: 11年前
住所: 東京都

Re: マップの木や建物などの描画方法について

#15

投稿記事 by へにっくす » 10年前

式の表現が違うことを言いたかったんじゃないのかな
y=-A+wx/w
これをそのまま解釈すると、除算・乗算の方が優先度高いので、wx/wを先に計算することになってしまいます。
y=(-A+wx)/w
と書かなきゃだめでは。
イマダニ さんが書きました:[0][0] (64,20) w=32,h=20
[y][x] (A , B)

これで検算すると
あてはめる値が違います。
元の式
A=w(x-y)…①
B=h(x+y)…②
にあてると
64=32(0-0)…①
20=20(0-0)…②
と①②ともに成立していない式となるので①の逆算の式
y=(-A+wx)/w
の検算が合わないのは当然です。
逆算の意味、分かってる?
written by へにっくす

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#16

投稿記事 by イマダニ » 10年前

[quote=へにっくす]逆算の意味、分かってる?[/quote]

わ か っ て な か っ た

わかってなかったです……

グーグルで調べたら虫食い算が出てきて、
これがぎゃくさん?となった自分の頭の悪さを自覚したので

http://gunsyu3.hatenadiary.jp/entry/20100501/1272676155

ここに書いてある連立方程式で逆算という意味を
理解するためちょっと勉強してきます

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#17

投稿記事 by イマダニ » 10年前

補正値入れてたらそりゃあわないわ
ということで補正値抜いてもう一度計算してみました。

配列の要素数 [0][1]
そこのクォーター座標 (32,20)
表示されるチップの幅と高さw=32,h=20

として、まず
y=(-A+wx)/w
に代入

0=(-32+32*1)/32

0=0/32

0=0

そして
x=(A+wy)/w
に代入

1=(32+32*0)/32

1=(32+0)/32

1=1

ということで

x = (A+wy)/w = (B-hy)/h

y = (-A+wx)/w = (B-hx)/h

これが正解だと思います。

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

Re: マップの木や建物などの描画方法について

#18

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

スマホからです。
式ですがxとyが未知なのに右辺に出てくる時点で逆変換になっていないと思います。
AとBだけが変数として出てくるようにしてみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#19

投稿記事 by イマダニ » 10年前

できたああああああああああああああ!!!
できましたよおおおおおおおおおおお!!!!

コード:

/*まず以下の式のwとhを*/
A=w(x-y)

B=h(x+y)

/*左に持ってきます*/
A/w=x-y

B/h=x+y


/*そしてそれを連立方程式で計算*/
  x-y=A/w

+)x+y=B/h
--------------
2x=A/w+B/h

x=(A/w+B/h)/2  /*まずは x から求める*/


/*そして次は y を求める*/
  x-y=A/w

-)x+y=B/h
--------------
-2y=A/w-B/h

y=(A/w-B/h)/-2

よって答えは

x=(A/w+B/h)/2
y=(A/w-B/h)/-2

です!

検算もちゃんとやりました。条件は前レスと同じです。

コード:

/*配列の要素数 [0][1]

そこのクォーター座標 (32,20)

表示されるチップの幅と高さw=32,h=20*/


x=(A/w+B/h)/2

x=(32/32+20/20)/2

x=1


y=(A/w-B/h)/-2

y=(32/32-20/20)/-2

y=0
というわけで早速コードに反映してみました。以下がそのコードになります。

コード:

#include <DxLib.h>
#include "main.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  100
#define CHIP_NUMBER_X  100

//マップデータの二次元配列
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ];

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetMainWindowText("マップエディタ");
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);

	/*AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用*/

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img1,chip_img2;
	int mx,my,Mouse,Wheel;
	//クリックした座標の記録用変数
	int imgx=0;
	int imgy=0;
	//クリックされた配列を記録する変数
	int hnum=0;
	int wnum=0;

	//チップ画像読み込み
	chip_img1=LoadGraph("img/mapchip01.bmp");
	chip_img2=LoadGraph("img/house.png");

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/32+imgy/16)/2;		/*例の式はここ*/
			hnum=(imgx/32-imgy/16)/-2;
			//そこを1に変える
			MapData[hnum][wnum]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			
			wnum=(imgx/32+imgy/16)/2;
			hnum=(imgx/32-imgy/16)/-2;
			//そこを0に変える
			MapData[hnum][wnum]=0;
		}

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が1である所に画像を表示する。
				if(MapData[y][x]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), chip_img1,TRUE);
                }
            }
        }
    }
    DxLib_End();
    return 0;
}
菱形の地形チップ、配列要素の中央ではなく、左端の角をクリックしないとチップが表示、消去できませんが、それ以外は特に問題はありませんでした。

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

Re: マップの木や建物などの描画方法について

#20

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

もう少しですよ!
なぜ角しかダメなのか考えてみましたか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#21

投稿記事 by イマダニ » 10年前

トップビューチップの左上の座標のような
描画位置的な問題でしょうか?オフセット?というやつです。

クォーターというか、今のぼくのコードだと
それが左端角になってしまってるので左端角をクリックしないと表示できないということなんですかね?

もしそうだとしてオフセットなんですか?
なんとなくどういったものか感じられるんですけど、事細かに説明しろと言われると

「描画の初期位置みたいなのじゃね?」

としか言えないのでよかったら教えてください。

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

Re: マップの木や建物などの描画方法について

#22

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

説明できない場合、イマダニさんは、どこがどれだけずれるのか検証と、あと整数で計算していて大丈夫なのかも調べてみて下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#23

投稿記事 by イマダニ » 10年前

チップ一個分右にずれてるようです。
詳細は画像に
添付ファイル
チップのずれ.jpg
一個分ずれてる

アバター
へにっくす
記事: 634
登録日時: 11年前
住所: 東京都

Re: マップの木や建物などの描画方法について

#24

投稿記事 by へにっくす » 10年前

softya(ソフト屋) さんが書きました:整数で計算していて大丈夫なのか
これは?
式は除算を含むので、型は自ずから何でなければなりませんか?
written by へにっくす

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#25

投稿記事 by イマダニ » 10年前

へにっくす さんが書きました:これは?
今現在試行錯誤中です
へにっくす さんが書きました:式は除算を含むので、型は自ずから何でなければなりませんか?
intだと少数点以下が切り捨てられちゃうので、ひとまずdoubleに変えたりしたのですが、そこからどう粗を探すのかがわからず、そこで止まっています。

コード:

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img1;
	int Mouse,Wheel;
	int mx,my;
	//クリックした座標の記録用変数
	double imgx=0;/*doubleに変更*/
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//チップ画像読み込み
	chip_img1=LoadGraph("img/mapchip01.bmp");

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/32.0+imgy/16.0)/2.0;		/*doubleにしたので一応小数に*/
			hnum=(imgx/32.0-imgy/16.0)/-2.0;
			//そこを1に変える
			MapData[(int)hnum][(int)wnum]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			
			wnum=(imgx/32.0+imgy/16.0)/2.0;
			hnum=(imgx/32.0-imgy/16.0)/-2.0;
			//そこを0に変える
			MapData[(int)hnum][(int)wnum]=0;
		}

		printf("[%f][%f] (%d,%d)\n",hnum,wnum,mx,my);/*デバッグ*/
マウスの座標であるmx,myはDXライブラリの性質上intでなければいけません。
なのでそれを記録する変数imgx,imgyとその値をもとに計算する計算式、その結果を代入するhnum,wnumの配列要素変数の型をdoubleに変えました。

その後、printfでデバッグで値の中身をのぞいたりしてます。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#26

投稿記事 by イマダニ » 10年前

マップ描画部分のオフセットを調整したらずれが無くなりました。
星の部分です。

コード:

#include <DxLib.h>
#include "main.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  100
#define CHIP_NUMBER_X  100

//マップデータの二次元配列
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ];

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	SetMainWindowText("マップエディタ"),SetMouseDispFlag( TRUE ) ;

	AllocConsole();
	freopen("CONOUT$","w",stdout);
	printf( "これでprintfが使えます\n" );

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img1;
	int Mouse,Wheel;
	int mx,my;
	//クリックした座標の記録用変数
	double imgx=0;
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//チップ画像読み込み
	chip_img1=LoadGraph("img/mapchip01.bmp");

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/32.0+imgy/16.0)/2.0;		/*例の式はここ*/
			hnum=(imgx/32.0-imgy/16.0)/-2.0;
			//そこを1に変える
			MapData[(int)hnum][(int)wnum]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			
			wnum=(imgx/32.0+imgy/16.0)/2.0;
			hnum=(imgx/32.0-imgy/16.0)/-2.0;
			//そこを0に変える
			MapData[(int)hnum][(int)wnum]=0;
		}

		printf("[%f][%f] (%f,%f)\n",hnum,wnum,imgx,imgy);

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が1である所に画像を表示する。
				if(MapData[y][x]==1){
					DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET, MAP_PARTS_HSIZEY*(x+y), chip_img1,TRUE);/*☆オフセットをマイナスに*/
                }
            }
        }
    }
    DxLib_End();
    return 0;
}
ソースファイルも一応貼っときますね。
だれか動作確認してくれないかなー(チラッチラッ
添付ファイル
クォーターマップエディタを作りたいな.zip
(7.66 MiB) ダウンロード数: 127 回

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

Re: マップの木や建物などの描画方法について

#27

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

ダウンロードしてみました。
エディタとしては、こんな感じでOKだと思います。
※ 範囲とか今の位置とかが分かりづらいかとは思いましたが今後追加されるんだと思います。パーツのカーソルは表示した方が良いような。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#28

投稿記事 by イマダニ » 10年前

softya さんが書きました: ダウンロードしてみました。
エディタとしては、こんな感じでOKだと思います。
お忙しい中、確認ありがとうございます。
プログラミングを詳しい人にOKをもらえると安心します。
softya さんが書きました: ※ 範囲とか今の位置とかが分かりづらいかとは思いましたが今後追加されるんだと思います。パーツのカーソルは表示した方が良いような。
というわけで、カーソルはまだですがグリッド線を表示してみました。
0のところに線だけの透明な地面の画像を表示するというやり方です。

ついでに将来のために二次元配列から一次元配列に変えました。
二次元配列を一次元として扱う

[y*width+x]

という方法は
「ゲームプログラマになる前に覚えておきたいこと」を参考にしました。

そしてスクロール機能をつけたところでバグが発生。
チップが思った所に配置されないというバグです。
今現在そこで混乱中です。

以下がそれらの機能を追加したコードになります。
変更したところはわかりやすいようコメントアウトしておきます。

コード:

#include <DxLib.h>
#include "main.h"
#include "Key.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  20
#define CHIP_NUMBER_X  20

//マップデータの一次元配列
int MapData[CHIP_NUMBER_X*CHIP_NUMBER_Y];     /*☆*/

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	SetMainWindowText("マップエディタ"),SetMouseDispFlag( TRUE ) ;

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img1,chip_img2,grid_img;
	int Mouse,Wheel;
	//マウス座標
	int mx,my;
	
	//カメラの座標  /*☆*/
	int CameraX,CameraY,cx,cy;   /*☆*/
	//それらの初期化
	CameraX=0;CameraY=0,cx=0,cy=0;   /*☆*/
	
	//クリックした座標の記録用変数
	double imgx=0;
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//チップ画像読み込み
	chip_img1=LoadGraph("img/mapchip01.bmp");/*地面*/
	chip_img2=LoadGraph("img/house.png");	 /*家*/
	grid_img =LoadGraph("img/grid.bmp");     /*グリッド線。白い線だけの透明な地面*/

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && UpdateKey()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		

		//マップスクロール処理           /*☆*/
		//カメラの移動処理
		if(CheckKey(KEY_INPUT_A)>0){//左/*☆*/
			CameraX-=10;
		}
		if(CheckKey(KEY_INPUT_D)>0){//右/*☆*/
			CameraX+=10;
		}
		if(CheckKey(KEY_INPUT_W)>0){//上/*☆*/
			CameraY-=10;
		}
		if(CheckKey(KEY_INPUT_S)>0){//下/*☆*/
			CameraY+=10;
		}
		//カメラの位置設定/*☆*/
		cx = CameraX-SCREEN_WIDTH/2;/*☆*/
		cy = CameraY-SCREEN_HEIGHT/2;/*☆*/


		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY)/2.0;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY)/-2.0;
			//そこを1に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=1;           /*☆*/
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
						
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY)/2.0;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY)/-2.0;
			//そこを0に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;             /*☆*/
		}

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が0である所にはグリッド線を表示する。

				if(MapData[y*CHIP_NUMBER_X+x]==0){  /*☆*/

					//マップの横サイズ × (x要素数 - y要素数) - 描画位置調整のためのオフセット - スクロールカメラ
					DrawGraph(MAP_PARTS_HSIZEX*(x-y) - MAP_VIEW_OFFSET - cx/*☆*/, MAP_PARTS_HSIZEY*(x+y) - cy/*☆*/, grid_img,TRUE);
				}
				//1の所は地面を表示。
				if(MapData[y*CHIP_NUMBER_X+x]==1){  /*☆*/
					DrawGraph(MAP_PARTS_HSIZEX*(x-y) - MAP_VIEW_OFFSET - cx/*☆*/, MAP_PARTS_HSIZEY*(x+y) - cy/*☆*/, chip_img1,TRUE);
                }
            }
		}
		//escapeが押されたら終わり
		if(CheckKey(KEY_INPUT_ESCAPE)==1)break;
	}
    DxLib_End();
    return 0;
}
スクロール機能を追加するためcx,cyを引くと
描画の部分をいじった結果、チップを思うように配置ができなくなりました。
クリックすると明後日の方向に表示されると言う奴です。

まあ描画部分をいじれば描画位置がずれるのは当然なのですが……

で、それを調整しようというところで足踏みしています。
プレイヤーなどの座標は同じようにcx,cyを引けば事が済んだのですが、

今回スクロールとずれてる座標?は、マウスな上に配列要素が絡んでいたりと
ちょっと複雑でイメージがし辛く、混乱してます。

よろしければヒント、アドバイスをください。
ヒントとかなに甘えてんの?こんなのアドバイスするまでもねえよ。ちょっとは自分で考えろゴミめ
と思ったら突き放してくれて構わないので、お願いします。
それ以外、グリッド線の表記法、一次元配列について、もしなにかあったらコメントお願いします。

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

Re: マップの木や建物などの描画方法について

#29

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

とりあえず、図を書いてみましょう!
あと式を作り直しです。もう一度、チャレンジ!
逆計算の検証のための理想値も先に用意しておきましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#30

投稿記事 by イマダニ » 10年前

softya さんが書きました:あと式を作り直しです。もう一度、チャレンジ!
うげー!となりますが、がんばります。
作り直す式は以下のものでいいんですよね?
あの連立方程式で出したあの式です。

wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY)/2.0;
hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY)/-2.0;
softya さんが書きました:とりあえず、図を書いてみましょう!
図を書いてみました。画像として貼ります。
やはり実際の配列の位置から画面の半分描画位置がずれてるようです。
画像は白い線が実際の配列で地面が[0][0]を押したときの描画位置です。
このずれた白いグリッド線、いわゆる配列を描画位置に合わせるという考えでよろしいんですよね?
softya さんが書きました:逆計算の検証のための理想値も先に用意しておきましょう。
理想値というのをはじめて聞きました。
あらかじめ出したい数値を自分で決め、それに合わせる形で式を作るということですよね?
こんな試み初めてですがまずはこれからやってみます。
添付ファイル
エディタずれ.jpg
左上の[0][0]を押すと真ん中にチップが

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#31

投稿記事 by イマダニ » 10年前

スクロールができてしまった…

とりあえずスマホANDワイファイで報告だけ
コードは明日貼ります

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#32

投稿記事 by イマダニ » 10年前

星の部分が変えた部分です。

コード:

#include <DxLib.h>
#include "main.h"
#include "Key.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  30
#define CHIP_NUMBER_X  30

//マップデータの一次元配列
int MapData[CHIP_NUMBER_X*CHIP_NUMBER_Y];

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	SetMainWindowText("マップエディタ"),SetMouseDispFlag( TRUE ) ;

    AllocConsole();
    freopen("CONOUT$","w",stdout);
    printf( "これでprintfが使えます\n" );

	//チップ画像格納変数、マウスポインタの座標変数、マウスとホイール用の変数
	int chip_img1,chip_img2,grid_img;
	int Mouse,Wheel;
	//マウス座標
	int mx,my;
	
	//カメラの座標
	double cx,cy;
	//それらの初期化
	cx=0;cy=0;
	//クリックした座標の記録用変数
	double imgx=0;
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//チップ画像読み込み
	chip_img1=LoadGraph("img/mapchip01.bmp");/*地面*/
	chip_img2=LoadGraph("img/house.png");	 /*家*/
	grid_img =LoadGraph("img/grid.bmp");     /*グリッド線。白い線だけの透明な地面*/

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && UpdateKey()==0)
	{
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		//マップスクロール処理
		//カメラの移動処理
		if(CheckKey(KEY_INPUT_A)>0){//左
			cx-=0.2;
			cy+=0.2;
		}
		if(CheckKey(KEY_INPUT_D)>0){//右
			cx+=0.2;
			cy-=0.2;
		}
		if(CheckKey(KEY_INPUT_W)>0){//上
			cx-=0.2;
			cy-=0.2;
		}
		if(CheckKey(KEY_INPUT_S)>0){//下
			cx+=0.2;
			cy+=0.2;
		}

		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*☆*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0  + cy;		/*☆*/
			//そこを1に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=1;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
						
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*☆*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0  + cy;		/*☆*/
			//そこを0に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;
		}

		printf("[%f][%f] (%f,%f)\n",hnum,wnum,imgx,imgy);

		//マップチップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素が0である所にはグリッド線を表示する。
				if(MapData[y*CHIP_NUMBER_X+x]==0){
					DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), grid_img,TRUE);		/*☆*/
                }//配列要素が0である所にはグリッド線を表示する。
				if(MapData[y*CHIP_NUMBER_X+x]==1){
					DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), chip_img1,TRUE);		/*☆*/

				}
			}
		}
		//escapeが押されたら終わり
		if(CheckKey(KEY_INPUT_ESCAPE)==1)break;
	}
    DxLib_End();
    return 0;
}
抜粋するとこんな感じ。

コード:

/*マウス部分*/
wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*例の式にカメラ座標のcxを加算*/
hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0  + cy;		/*cyを加算*/

コード:

/*描画部分*/
		  /*描画座標クォーター変換 - 描画位置指定 - カメラ座標クォーター変換*/
DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy), 

		  /*描画座標クォーター変換 - カメラ座標クォーター変換*/
		  MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy),
		  
		  grid_img,TRUE);
ファイルも上げときます。
問題なければ次は家の表示に挑戦します。
添付ファイル
クォーターマップエディタ.zip
(7.87 MiB) ダウンロード数: 126 回

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#33

投稿記事 by イマダニ » 10年前

File_ReadOpenとfopenの違いがよくわかりません。
今まではこのようなテキストファイルを

コード:

30,30/*配列の要素数*/
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
0,1,1,1,1,1,1,1,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

以下のように読み込んでいたのですが、

コード:

int MapLoad(){
	bool mapload=false;
	int FileHandle=0;
	int FileData=0;
	int ReadNumY=0;
	int ReadNumX=0;

	/*読み込みフラグが建ってない時*/
	if(mapload == false){
		/*ハンドルにファイルを代入*/
		FileHandle = FileRead_open("GroundData.txt");

		/*ハンドルが空っぽだったらエラー*/
		if(FileHandle == NULL){
			MessageBox(NULL,"ファイルの読み込みに失敗しました","エラー",MB_OK);
			return -1;
		/*それ以外なら*/
		} else {
			/*要素数読み込み*/
			FileRead_scanf(FileHandle,"%d,%d",&ReadNumY,&ReadNumX);
			/*要素数分だけデータ変数にハンドル内容を代入*/
			for(int y=0;y<ReadNumY;y++){
				for(int x=0;x<ReadNumX;x++){
					FileRead_scanf(FileHandle,"%d[^,]",&FileData);
					/*マップデータにファイルデータを渡す*/
					MapData[y*ReadNumX+x] = FileData;
				}
			}
		}
		/*読んだのでファイルを閉じる*/
		FileRead_close(FileHandle);
		/*読んだフラグを立てる*/
		mapload = true;
		}
	return 0;
}
これをfopenなどのC言語形式に書き換えたところ

コード:

int MapLoad(){
	bool mapload=false;
	FILE *fp;
	int FileData=0;
	int ReadNumY=0;
	int ReadNumX=0;

	/*読み込みフラグが建ってない時*/
	if(mapload == false){
		/*ハンドルにファイルを代入*/
		fp = fopen("GroundData.txt","r");

		/*ハンドルが空っぽだったらエラー*/
		if(fp == NULL){
			MessageBox(NULL,"ファイルの読み込みに失敗しました","エラー",MB_OK);
			return -1;
		/*それ以外なら*/
		} else {
			fscanf(fp,"%d,%d",&ReadNumY,&ReadNumX);
			/*要素数分だけデータ変数にハンドル内容を代入*/
			for(int y=0;y<ReadNumY;y++){
				for(int x=0;x<ReadNumX;x++){
					fscanf(fp,"%d[^,]",&FileData);
					/*マップデータにファイルデータを渡す*/
					MapData[y*ReadNumX+x] = FileData;
				}
			}
		}
		/*読んだのでファイルを閉じる*/
		fclose(fp);
		/*読んだフラグを立てる*/
		mapload = true;
		}
	return 0;
}
ファイルが読み込めなくなりました。
デバッグで return 0; まで辿っていくとfpの中身が不適切なPtrとなっていました。
目立った違いは読み込んだファイルを入れるハンドルの形式ぐらいですが

FILE *fp

int FileHandle

いったい何が問題なのでしょう?アドバイスお願いします。

アバター
へにっくす
記事: 634
登録日時: 11年前
住所: 東京都

Re: マップの木や建物などの描画方法について

#34

投稿記事 by へにっくす » 10年前

イマダニ さんが書きました:デバッグで return 0; まで辿っていくとfpの中身が不適切なPtrとなっていました。
そりゃ当然でしょう。fclose(fp)した後なんですから。
fclose(fp)の手前でブレークしてみてください。不適切なPtrとはなっていないはずです。

FileRead_scanfとscanfの違いは分かりませんが、おそらくはFileRead_scanfだと改行をデフォルトで捨てるのかな?
fopenのモードが"r"でバイナリモードにもなってるみたいだけど。
ここは詳しい人にお任せします。(^^;
written by へにっくす

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

Re: マップの木や建物などの描画方法について

#35

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

へにっくす さんが書きました:fopenのモードが"r"でバイナリモードにもなってるみたいだけど。
バイナリモードにはなっていないと思います。

fscanfで読み込めない件は、1個目のfscanfの直後に

コード:

while(fgetc(fp)!='\n'); //改行まで読み飛ばす
という行を入れてみてください。

ちなみに、mapload変数は全く無駄に見えます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: マップの木や建物などの描画方法について

#36

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

2番目のfscanfも怪しいと感じました。
最初の修正で動かなければ、

コード:

fscanf("%d%*c",&FileData");
としてみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: マップの木や建物などの描画方法について

#37

投稿記事 by ISLe » 10年前

DXライブラリ関数のFileRead_*はアーカイブ機能に対応しているのだと思います。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#38

投稿記事 by イマダニ » 10年前

すみません返信が遅れました。
へにっくす さんが書きました: そりゃ当然でしょう。fclose(fp)した後なんですから。
fclose(fp)の手前でブレークしてみてください。不適切なPtrとはなっていないはずです。
確認したところ、なってなかったです。なんという凡ミス。
みけCAT さんが書きました: 2番目のfscanfも怪しいと感じました。
最初の修正で動かなければ、

コード[C++]: 全て選択
1 fscanf("%d%*c",&FileData");

としてみてください。
そこが原因だったようです。みけCATさんのアドバイス通り、
修正したところちゃんとファイルを読み込みました。
数値の後にあるカンマが原因という認識でいいんですよね?
ISLe さんが書きました: DXライブラリ関数のFileRead_*はアーカイブ機能に対応しているのだと思います。
そんな違いが……
DXライブラリの関数は懐がでかいというかなんというか。
いろいろ対応していて、やはり便利ですね。

みなさんアドバイス感謝です。
それでまた二つほど質問があります。またかよって感じですが……
まずその一つ目の質問をしたいと思います。

①DXライブラリのドラッグドロップ関数はWin32apiのhwndが絡むと使えない?

まずDxlibのD&D(ドラッグ&ドロップ)の関数を用いて、マップチップをカーソルに読み込むプログラムを作りました。

仕様は

①まず50個の配列を用意し、それを元に、50この枠組みがくっついたカーソルを画面右端に作る。一つの枠の大きさは32×32の四角い箱。

②ゲーム画面にドロップしたチップ画像を、上記のカーソルの内の一つの枠に収める。一回のドロップに入れられる画像は一つまで。服うは不可能。

③そして、チップ画像が収められた枠を選択した状態で、クリックするとそのチップ画像がクリックした場所に表示されるというわけだぁ。

以下がそんなプログラムのコードである。

コード:

//カーソルの枠の数
#define CARSOL_X 5
#define CARSOL_Y 10
//カーソルの枠のサイズ
#define CARSOL_SIZE 32.0

/*main.cppに書かれたグローバル変数*/
//チップ選択のカーソル配列データ
int SelectData[CARSOL_Y*CARSOL_X];
//選択されてるチップナンバー
int SelectNum;

/*main.hに書かれたD&D構造体*/
typedef struct{
	int open;             //ドラッグドロップされたファイルを保管する変数
	int gridimg,Carsolimg;//カーソルのグリッド画像と選択カーソルの画像
	int readx,ready;      //カーソルの添字
	int SX,SY;			  //読みこんだ画像の縦幅横幅
	double SizeX,SizeY;   //それを縮小したのを入れる変数
	char file[256];       //ファイル名
}DDROP;

/*main.cppに書かれたD&Dに関する関数共*/
/*ドロップ関連初期化関数*/
void Dini(DDROP *drop){
	SelectNum = 0;								  //チップナンバー初期化
	memset(drop,0,sizeof(DDROP));				  //D&D構造体の初期化
	SelectData[0]=LoadGraph("img/grid.bmp");	  //配列要素0に表示される画像をグリッド線と事前に初期化
	drop->Carsolimg = LoadGraph("img/Carsol.bmp");//カーソルの選択カーソル画像読み込み
	drop->gridimg   = LoadGraph("img/Cgrid.bmp"); //カーソルの枠組み画像読み込み
}

/*D&D処理関数*/
void DropDrag(DDROP *drop){
	drop->open=GetDragFilePath(drop->file);//D&Dでファイル獲得する open:ファイル獲得が成功か失敗か判定 
	GetDragFileNum();//D&Dされたファイルの数を得るらしい
	
	//0配列に既に入っている画像のサイズ取得
	GetGraphSize(SelectData[ 0 ],&drop->SX,&drop->SY);
	//それをカーソル枠に合わせるため縮小
	drop->SizeX = CARSOL_SIZE / drop->SX;
	
	//D&D処理
	if(drop->open!=-1){		
		//もし配列が空っぽでなければ
		if(SelectData[ drop->ready * CARSOL_X + drop->readx]!=0){
			drop->readx++;//次の配列へ行き、そこにドロップされた画像を放り込むようにしとく
			if(drop->readx == CARSOL_X){//配列行の末尾まで行ったら
				drop->readx = 0;
				drop->ready++;//下の行へ
			}
		}
		
		//配列にD&Dされた画像を放り込む
		SelectData[ drop->ready * CARSOL_X + drop->readx ] = LoadGraph(drop->file);
		//放り込まれた画像のサイズを得る
		GetGraphSize(SelectData[ drop->ready * CARSOL_X + drop->readx ],&drop->SX,&drop->SY);
		//それをカーソルの枠に合うよう縮小
		drop->SizeX = CARSOL_SIZE / drop->SX;

	}
}

/*チップ選択カーソルの移動処理*/
void DCarsolmove(DDROP *drop){
	//カーソルの移動処理
	if(CheckKey(KEY_INPUT_Z)==1){
		SelectNum++;//チップナンバーを足す事でカーソルを右に移動
		if(SelectNum == CARSOL_Y*CARSOL_X)//移動制御
			SelectNum = 0;
	}
	if(CheckKey(KEY_INPUT_X)==1){
		SelectNum--;//チップナンバーを引く事でカーソルを左に移動
		if(SelectNum<0)
			SelectNum = CARSOL_Y*CARSOL_X-1;
	}
}

/*D&D関連描画関数*/
void DDraw(DDROP drop){
	for(int y=0;y<CARSOL_Y;y++){
		for(int x=0;x<CARSOL_X;x++){				
			DrawGraph(640+x*32,y*32,drop.gridimg,TRUE);/*カーソル枠描画*/
			DrawRotaGraph(656+x*32,16+y*32,drop.SizeX,0.0,SelectData[y*CARSOL_X+x],TRUE);/*カーソル枠内のチップ画像描画*/
			if(y*CARSOL_X+x == SelectNum){
				DrawGraph(640+x*32,y*32,drop.Carsolimg,TRUE);/*カーソルの選択カーソル画像描画*/
			}
		}
	}
}

		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0 + cy;
			//そこを選択されてるチップナンバーに変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=SelectNum; /*☆*/
		}

/*マップ描画方法*/
	//地面チップ描画
	for(int y=0;y<CHIP_NUMBER_Y;y++){
		for(int x=0;x<CHIP_NUMBER_X;x++){
			//配列要素に合わせてチップを表示。
			for(int i=0;i<50;i++){/*選択カーソルの50個*/
				if(MapData[y*CHIP_NUMBER_X+x]==i){/*MapDataとSelectDataを添字を i でリンクさせる事で描画しているのだ*/
					DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), SelectData[i],TRUE);
				}
			}
		}
コードの全体は以下の通りです。

コード:

/*key.h*/
#ifndef DEF_KEY_H
#define DEF_KEY_H

int UpdateKey();

int CheckKey(int KeyCode);

#endif


/*main.h*/
#ifndef DEF_MAIN_H
#define DEF_MAIN_H

#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600
#define COLOR_BIT     32

typedef struct{
	int open;
	int gridimg,Carsolimg;
	int readx,ready;
	int SX,SY;
	double SizeX,SizeY;
	char file[256];
}DDROP;

#endif

コード:

/*main.cpp*/
#include <DxLib.h>
#include "main.h"
#include "Key.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  30
#define CHIP_NUMBER_X  30

//カーソルの枠の数
#define CARSOL_X 5
#define CARSOL_Y 10
//カーソルの枠のサイズ
#define CARSOL_SIZE 32.0

//マップデータの一次元配列
int MapData[CHIP_NUMBER_X*CHIP_NUMBER_Y];   /*地形マップデータ*/
int BuildData[CHIP_NUMBER_X*CHIP_NUMBER_Y]; /*建物マップデータ*/
//チップ選択のカーソル配列データ
int SelectData[CARSOL_Y*CARSOL_X];
//選択されてるチップナンバー
int SelectNum;

//ロード関数
/*地面チップの配置データロード*/
int MapGroundLoad(){
	FILE *fp;
	int FileData=0;
	int ReadNumY=0;
	int ReadNumX=0;

	/*ハンドルにファイルを代入*/
	fp = fopen("GroundData.txt","r");
	
	/*ハンドルが空っぽだったらエラー*/
	if(fp == NULL){
		MessageBox(NULL,"ファイルの読み込みに失敗しました","エラー",MB_OK);
		return -1;
	/*それ以外なら*/
	} else {
		fscanf(fp,"%d,%d",&ReadNumY,&ReadNumX);
		/*要素数分だけデータ変数にハンドル内容を代入*/
		for(int y=0;y<ReadNumY;y++){
			for(int x=0;x<ReadNumX;x++){
				fscanf(fp,"%d%*c",&FileData);
				/*マップデータにファイルデータを渡す*/
				MapData[y*ReadNumX+x] = FileData;
			}
		}
	}
	/*読んだのでファイルを閉じる*/
	fclose(fp);
	return 0;
}

//セーブ関数
/*地面チップの配置データロード*/
int Map_GroundSave(){
	FILE *fp;
	fp=fopen("GroundData.txt","w");

	if(fp==NULL){
		return 0;
	}

	/*配列の要素数を書き込み*/
	fprintf(fp,"%d,%d\n",CHIP_NUMBER_Y,CHIP_NUMBER_X);

	for(int y=0;y<CHIP_NUMBER_Y;y++){
		for(int x=0;x<CHIP_NUMBER_X;x++){
			fprintf(fp,"%d",MapData[y*CHIP_NUMBER_X+x]);
			
			/*末尾直前までコンマを間に挟む*/
			if(x<CHIP_NUMBER_X-1){
				fprintf(fp,",");
			}
			/*末尾には改行*/
			if(x==CHIP_NUMBER_X-1){
				fprintf(fp,"\n");
			}
		}
	}

	fclose(fp);
	return 0;
}

void Dini(DDROP *drop){
	SelectNum = 0;								  //チップナンバー初期化
	memset(drop,0,sizeof(DDROP));				  //D&D構造体の初期化
	SelectData[0]=LoadGraph("img/grid.bmp");	  //配列要素0に表示される画像をグリッド線と事前に初期化
	drop->Carsolimg = LoadGraph("img/Carsol.bmp");//カーソルのカーソル画像読み込み
	drop->gridimg   = LoadGraph("img/Cgrid.bmp"); //カーソルの枠組み画像読み込み
}

void DropDrag(DDROP *drop){
	drop->open=GetDragFilePath(drop->file);//D&Dでファイル獲得する open:ファイル獲得が成功か失敗か判定 
	GetDragFileNum();//D&dされたファイルの数を得るらしい
	
	//0配列に既に入っている画像のサイズ取得
	GetGraphSize(SelectData[ 0 ],&drop->SX,&drop->SY);
	//それをカーソル枠に合わせるため縮小
	drop->SizeX = CARSOL_SIZE / drop->SX;
	
	//D&D処理
	if(drop->open!=-1){		
		//もし配列が空っぽでなければ
		if(SelectData[ drop->ready * CARSOL_X + drop->readx]!=0){
			drop->readx++;//次の配列へ
			if(drop->readx == CARSOL_X){//配列行の末尾まで行ったら
				drop->readx = 0;
				drop->ready++;//下の行へ
			}
		}
		
		//配列にD&Dされた画像を放り込む
		SelectData[ drop->ready * CARSOL_X + drop->readx ] = LoadGraph(drop->file);
		//放り込まれた画像のサイズを得る
		GetGraphSize(SelectData[ drop->ready * CARSOL_X + drop->readx ],&drop->SX,&drop->SY);
		//それをカーソルの枠に合うよう縮小
		drop->SizeX = CARSOL_SIZE / drop->SX;

	}
}

void DCarsolmove(DDROP *drop){
	//カーソルの移動処理
	if(CheckKey(KEY_INPUT_Z)==1){
		SelectNum++;//チップナンバーを足す事でカーソルを右に移動
		if(SelectNum == CARSOL_Y*CARSOL_X)//移動制御
			SelectNum = 0;
	}
	if(CheckKey(KEY_INPUT_X)==1){
		SelectNum--;//チップナンバーを引く事でカーソルを左に移動
		if(SelectNum<0)
			SelectNum = CARSOL_Y*CARSOL_X-1;
	}
}

void DDraw(DDROP drop){
	for(int y=0;y<CARSOL_Y;y++){
		for(int x=0;x<CARSOL_X;x++){				
			DrawGraph(640+x*32,y*32,drop.gridimg,TRUE);/*カーソル枠描画*/
			DrawRotaGraph(656+x*32,16+y*32,drop.SizeX,0.0,SelectData[y*CARSOL_X+x],TRUE);/*カーソル枠内のチップ画像描画*/
			if(y*CARSOL_X+x == SelectNum){
				DrawGraph(640+x*32,y*32,drop.Carsolimg,TRUE);/*カーソルのカーソル画像描画*/
			}
		}
	}
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);
	ChangeWindowMode(TRUE),DxLib_Init(),SetDragFileValidFlag(TRUE),SetDrawScreen(DX_SCREEN_BACK);
	SetMainWindowText("マップエディタ"),SetMouseDispFlag( TRUE ) ;

	/*デバックのためのコンソール画面*//*
    AllocConsole();
    freopen("CONOUT$","w",stdout);
    printf( "これでprintfが使えます\n" );*/

	//マウスポインタの座標変数、マウスとホイール用の変数
	int Mouse,Wheel;
	//マウス座標
	int mx,my;
	
	//カメラの座標
	double cx,cy;
	//それらの初期化
	cx=0;cy=0;
	//クリックした座標の記録用変数
	double imgx=0;
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//D&D構造体宣言
	DDROP drop;
	//D&Dに関する変数などの初期化
	Dini(&drop);
	
	//マップデータロード
	MapGroundLoad();

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && UpdateKey()==0)
	{

		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		//ドロップ処理関数
		DropDrag(&drop);
		//右にあるカーソルの選択カーソル移動処理
		DCarsolmove(&drop);

		//マップスクロール処理
		//カメラの移動処理
		if(CheckKey(KEY_INPUT_A)>0){//左
			cx-=0.2;
			cy+=0.2;
		}
		if(CheckKey(KEY_INPUT_D)>0){//右
			cx+=0.2;
			cy-=0.2;
		}
		if(CheckKey(KEY_INPUT_W)>0){//上
			cx-=0.2;
			cy-=0.2;
		}
		if(CheckKey(KEY_INPUT_S)>0){//下
			cx+=0.2;
			cy+=0.2;
		}

		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0 + cy;
			//そこを選択されてるチップナンバーに変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=SelectNum;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
						
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0  + cy;
			//そこを0に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;
			/*BuildData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;*/
		}

		//地面チップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素に合わせてチップを表示。
				for(int i=0;i<50;i++){
					if(MapData[y*CHIP_NUMBER_X+x]==i){
						DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), SelectData[i],TRUE);
					}
				}
			}
		}

		//ドロップ関連描画
		DDraw(drop);

		//セーブ
		Map_GroundSave(); /*地面チップの配置をセーブ*/
		//ドロップ関連をクリアする関数らしい
		DragFileInfoClear(); 
		//escapeが押されたら終わり
		if(CheckKey(KEY_INPUT_ESCAPE)==1)break;
	}
    DxLib_End();
    return 0;
}
このプログラムを作った後、メニューバーをつけ、
メニューのファイルからダイアログで、マップデータを 名前をつけて保存 、 開く 、をできるようにしました。
以下がそのコードです。

コード:

#include <DxLib.h>
#include "main.h"
#include "Key.h"

//トップビューのチップサイズ
#define VTOP_PARTS_SIZEX  64
#define VTOP_PARTS_SIZEY  64
//クォータビューーのチップサイズ
#define MAP_PARTS_HSIZEX 32
#define MAP_PARTS_HSIZEY 16//ほんとは20
//マップのオフセット
#define MAP_VIEW_OFFSET 32
//マップ二次元配列の配列の要素数
#define CHIP_NUMBER_Y  30
#define CHIP_NUMBER_X  30

//カーソルの枠の数
#define CARSOL_X 5
#define CARSOL_Y 10
//カーソルの枠のサイズ
#define CARSOL_SIZE 32.0

//マップデータの一次元配列
int MapData[CHIP_NUMBER_X*CHIP_NUMBER_Y];   /*地形マップデータ*/
//チップ選択のカーソル配列データ
int SelectData[CARSOL_Y*CARSOL_X];
//選択されてるチップナンバー
int SelectNum;

/*ダイアログでのファイル扱い関数*/
				/*引数 読むか書くかの変数 ファイル名 ファイルのサイズ ファイルの種類*/
int Fopen_Dialog(int Read_or_Write,char *FileName,int FileNameLength,const char *FileFilter){
	OPENFILENAME ofn;

	ZeroMemory(&ofn,sizeof(ofn));           /*構造体ofnを0で初期化*/
	ofn.lStructSize = sizeof(ofn);          /*ファイルのサイズを取得*/
	ofn.hwndOwner   = GetMainWindowHandle();/*ウィンドウのオーナーをDxLibに指定*/
	ofn.lpstrFilter = FileFilter; /*開けるファイルを指定*/
	ofn.nFilterIndex=0;
	ofn.lpstrFile   = FileName;
	ofn.nMaxFile    = FileNameLength;
	ofn.Flags       = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR;

	if(FileName == NULL){return 0;}
	
	FileName[0]=0;
	
	switch(Read_or_Write){/*読み込みか書き込みか*/
		case 1:/*読み込みならファイルを開く*/
			return GetOpenFileName(&ofn);
		case 2:/*書き込みなら保存*/
			return GetSaveFileName(&ofn);
	}

	return 0;
}

int MapGroundLoadSave(){
	char filename[256];
	FILE *fp;
	int R_or_W=0;  /*読み込みか書き込みか*/
	int FileData=0;
	int ReadNumY=0;
	int ReadNumX=0;
	
	if(CheckMenuItemSelect_Name("開く")==1){
		R_or_W = 1;
		if(Fopen_Dialog(R_or_W,filename,sizeof(filename),"Text(*.txt)\0*.txt")){
			fp = fopen(filename,"r");
			
			if(fp == NULL){
				MessageBox(NULL,"ファイルの読み込みに失敗しました","エラー",MB_OK);
				return -1;
			}else{
				fscanf(fp,"%d,%d",&ReadNumY,&ReadNumX);
				/*要素数分だけデータ変数にハンドル内容を代入*/
				for(int y=0;y<ReadNumY;y++){
					for(int x=0;x<ReadNumX;x++){
						fscanf(fp,"%d%*c",&FileData);
						/*マップデータにファイルデータを渡す*/
						MapData[y*ReadNumX+x] = FileData;
					}
				}
			}
			/*読んだのでファイルを閉じる*/
			fclose(fp);
		}
	}
	if(CheckMenuItemSelect_Name("名前をつけて保存")==1){
		R_or_W = 2;
		if(Fopen_Dialog(R_or_W,filename,sizeof(filename),"Text(*.txt)\0*.txt")){
			fp=fopen(filename,"w");

			if(fp==NULL){
				MessageBox(NULL,"ファイルの読み込みに失敗しました","エラー",MB_OK);
				return -1;
			}

			fprintf(fp,"%d,%d\n",CHIP_NUMBER_Y,CHIP_NUMBER_X);

			for(int y=0;y<CHIP_NUMBER_Y;y++){
				for(int x=0;x<CHIP_NUMBER_X;x++){
					fprintf(fp,"%d",MapData[y*CHIP_NUMBER_X+x]);
			
					/*末尾直前までコンマを間に挟む*/
					if(x<CHIP_NUMBER_X-1){
						fprintf(fp,",");
					}
					/*末尾には改行*/
					if(x==CHIP_NUMBER_X-1){
						fprintf(fp,"\n");
					}
				}
			}
			fclose(fp);
		}
	}
	return 0;
}

/*ドロップ関連初期化*/
void Dini(DDROP *drop){
	SelectNum = 0;								  //チップナンバー初期化
	memset(drop,0,sizeof(DDROP));				  //D&D構造体の初期化
	SelectData[0]=LoadGraph("img/grid.bmp");	  //配列要素0に表示される画像をグリッド線と事前に初期化
	drop->Carsolimg = LoadGraph("img/Carsol.bmp");//カーソルのカーソル画像読み込み
	drop->gridimg   = LoadGraph("img/Cgrid.bmp"); //カーソルの枠組み画像読み込み
}

/*D&D処理関数*/
void DropDrag(DDROP *drop){
	drop->open=GetDragFilePath(drop->file);//D&Dでファイル獲得する open:ファイル獲得が成功か失敗か判定 
	GetDragFileNum();//D&dされたファイルの数を得るらしい
	
	//0配列に既に入っている画像のサイズ取得
	GetGraphSize(SelectData[ 0 ],&drop->SX,&drop->SY);
	//それをカーソル枠に合わせるため縮小
	drop->SizeX = CARSOL_SIZE / drop->SX;
	
	//D&D処理
	if(drop->open!=-1){		
		//もし配列が空っぽでなければ
		if(SelectData[ drop->ready * CARSOL_X + drop->readx]!=0){
			drop->readx++;//次の配列へ
			if(drop->readx == CARSOL_X){//配列行の末尾まで行ったら
				drop->readx = 0;
				drop->ready++;//下の行へ
			}
		}
		
		//配列にD&Dされた画像を放り込む
		SelectData[ drop->ready * CARSOL_X + drop->readx ] = LoadGraph(drop->file);
		//放り込まれた画像のサイズを得る
		GetGraphSize(SelectData[ drop->ready * CARSOL_X + drop->readx ],&drop->SX,&drop->SY);
		//それをカーソルの枠に合うよう縮小
		drop->SizeX = CARSOL_SIZE / drop->SX;

	}
}

/*チップ選択カーソルの移動処理*/
void DCarsolmove(DDROP *drop){
	//カーソルの移動処理
	if(CheckKey(KEY_INPUT_Z)==1){
		SelectNum++;//チップナンバーを足す事でカーソルを右に移動
		if(SelectNum == CARSOL_Y*CARSOL_X)//移動制御
			SelectNum = 0;
	}
	if(CheckKey(KEY_INPUT_X)==1){
		SelectNum--;//チップナンバーを引く事でカーソルを左に移動
		if(SelectNum<0)
			SelectNum = CARSOL_Y*CARSOL_X-1;
	}
}

/*D&D関連描画関数*/
void DDraw(DDROP drop){
	for(int y=0;y<CARSOL_Y;y++){
		for(int x=0;x<CARSOL_X;x++){				
			DrawGraph(640+x*32,y*32,drop.gridimg,TRUE);/*カーソル枠描画*/
			DrawRotaGraph(656+x*32,16+y*32,drop.SizeX,0.0,SelectData[y*CARSOL_X+x],TRUE);/*カーソル枠内のチップ画像描画*/
			if(y*CARSOL_X+x == SelectNum){
				DrawGraph(640+x*32,y*32,drop.Carsolimg,TRUE);/*カーソルのカーソル画像描画*/
			}
		}
	}
}

/*メイン関数*/
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,COLOR_BIT);//画面を800,600に
	/*ウインドウモード変換、ライブラリ初期化、ドラッグを受けいれるフラグ立て、裏画面*/
	ChangeWindowMode(TRUE),DxLib_Init(),SetDragFileValidFlag(TRUE),SetDrawScreen(DX_SCREEN_BACK);
	/*ウィンドウテキスト設定、マウスを使えるフラグ立て*/
	SetMainWindowText("マップエディタ"),SetMouseDispFlag( TRUE );SetUseMenuFlag( TRUE );
	
	AddMenuItem_Name( NULL, "ファイル" );
    AddMenuItem_Name( "ファイル", "開く" );
	AddMenuItem_Name( "ファイル","名前をつけて保存");
    AddMenuItem_Name( "ファイル", "終了" );

	/*デバックのためのコンソール画面*//*
    AllocConsole();
    freopen("CONOUT$","w",stdout);
    printf( "これでprintfが使えます\n" );*/

	//マウスポインタの座標変数、マウスとホイール用の変数
	int Mouse,Wheel;
	//マウス座標
	int mx,my;
	
	//カメラの座標
	double cx,cy;
	//それらの初期化
	cx=0;cy=0;
	//クリックした座標の記録用変数
	double imgx=0;
	double imgy=0;
	//クリックされた配列を記録する変数
	double hnum=0;
	double wnum=0;

	//D&D構造体宣言
	DDROP drop;
	//D&Dに関する変数などの初期化
	Dini(&drop);

	//メインループ
	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && UpdateKey()==0)
	{
		
		//マウスの入力関係のコード
		Mouse=GetMouseInput();
		Wheel=GetMouseWheelRotVol();
		GetMousePoint(&mx,&my);
		
		//ドロップ処理関数
		DropDrag(&drop);
		//右にあるカーソルの選択カーソル移動処理
		DCarsolmove(&drop);

		MapGroundLoadSave();

		//マップスクロール処理
		//カメラの移動処理
		if(CheckKey(KEY_INPUT_A)>0){//左
			cx-=0.2;
			cy+=0.2;
		}
		if(CheckKey(KEY_INPUT_D)>0){//右
			cx+=0.2;
			cy-=0.2;
		}
		if(CheckKey(KEY_INPUT_W)>0){//上
			cx-=0.3;
			cy-=0.3;
		}
		if(CheckKey(KEY_INPUT_S)>0){//下
			cx+=0.3;
			cy+=0.3;
		}

		if(Mouse & MOUSE_INPUT_LEFT){//左クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
			//押された配列の要素を確認し
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0 + cy;
			//そこを選択されてるチップナンバーに変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=SelectNum;
		}
		if(Mouse & MOUSE_INPUT_RIGHT){//右クリックが押されたら
			//押された座標を記録
			imgx=mx;imgy=my;
						
			wnum=(imgx/MAP_PARTS_HSIZEX+imgy/MAP_PARTS_HSIZEY) /  2.0  + cx;		/*例の式はここ*/
			hnum=(imgx/MAP_PARTS_HSIZEX-imgy/MAP_PARTS_HSIZEY) / -2.0  + cy;
			//そこを0に変える
			MapData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;
			/*BuildData[(int)hnum*CHIP_NUMBER_X+(int)wnum]=0;*/
		}

		//地面チップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素に合わせてチップを表示。
				for(int i=0;i<50;i++){
					if(MapData[y*CHIP_NUMBER_X+x]==i){
						DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), SelectData[i],TRUE);
					}
				}
			}
		}

		//ドロップ関連描画
		DDraw(drop);

		//ドロップ関連をクリアする関数らしい
		DragFileInfoClear(); 
		//escapeが押されたら終わり
		if(CheckMenuItemSelect_Name("終了")==1){
			break;
		}
		if(CheckKey(KEY_INPUT_ESCAPE)==1)break;
	}
    DxLib_End();
    return 0;
}
結果、ダイアログでマップデータは読めるようになったのですが、以下の部分のせいか

コード:

	ofn.hwndOwner   = GetMainWindowHandle();/*ウィンドウのオーナーをDxLibに指定*/
ドラッグ&ドロップを受け入れなくなりました。
DXライブラリのドラッグドロップ関数はWin32apiのhwndが絡むと使えないのでしょうか?
そうだとしたら、D&D機能をつけるには、Win32apiのD&D関数を使わないと無理なのでしょうか?

アドバイスお願いします。

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#39

投稿記事 by イマダニ » 10年前

DXライブラリとWin32Apiを合わせたうえでのドラッグドロップは手間がかなりかかりそうなので諦めます。
質問しといてすみません……
今日一日チャレンジしてみましたが心が折れました……(´Д`;)ムリムリ
早く家の描画がやりたいこともあり、そちらを先にやることにしました

というわけで
ISLe さんが書きました: 建物等の画像を分割する必要はありません。
地面のマップチップを描画するのと同じタイミングで、地面の座標を基準に建物の画像の高さ分上にズラした座標から建物の画像を描画するだけです。
マップチップ自体の大きさが変化すると考えていただくのが良いと思います。
このISLeさんのアドバイスをもとに家の描画に挑戦しました。
やっとでございます。

コード:

//マップデータの一次元配列
int MapData[CHIP_NUMBER_X*CHIP_NUMBER_Y];   /*地形マップデータ*/
int BuildData[CHIP_NUMBER_X*CHIP_NUMBER_Y];   /*建物マップデータ*/
地面の上に家が建っているようにしたかったので、
上記のように地面用と建物用に配列データを用意し、

コード:

		//地面チップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				//配列要素に合わせてチップを表示。
				for(int i=0;i<50;i++){
					if(MapData[y*CHIP_NUMBER_X+x]==i){
						DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy), SelectData[i],TRUE);
					}
				}
			}
		}
		//建物チップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				if(BuildData[y*CHIP_NUMBER_X+x]==2){/*2のところに家を描画*/
					/*83は地面チップとの高さの差で、その分引くことで、描画位置を調整している*/
					DrawGraph(MAP_PARTS_HSIZEX*(x-y)-MAP_VIEW_OFFSET - MAP_PARTS_HSIZEX*(cx-cy) , MAP_PARTS_HSIZEY*(x+y) - MAP_PARTS_HSIZEY*(cx+cy) - 83, chip_img2,TRUE);
				}

			}
		}
このように描画しております。
ひとまず 「描画」 だけはこのような形でいいのでしょうか? 

イマダニ
記事: 145
登録日時: 11年前

Re: マップの木や建物などの描画方法について

#40

投稿記事 by イマダニ » 10年前

マップエディターができましたー!
みなさんのおかげでマップエディタができましたー!
まだこれとか参考にしつつ

「背景とキャラクターの描画について」
http://dixq.net/forum/viewtopic.php?t=14257&p=113507

Zソートでうろうろしていて、まだ完全に解決ではないのですが、
ひとまずひと段落しましたのと、トピックがもう重いのでひとまず解決にします。
完成したエディターはaxfcに貼っときます。

http://www1.axfc.net/u/3103407.zip

パスワードは「johnson」です。

よかったら感想、またはこうしたほうがいいなどのアドバイスください。
みなさんほんとうにありがとうございました。

閉鎖

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