本格的なrpg マップ処理。

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

本格的なrpg マップ処理。

#1

投稿記事 by heyman » 10年前

いつもお世話になっております。
今回は、依然作ったrpg(試作)があるんですが、
そのゲームを本格的に作り治すにあたっての、アドバイスを
いただきたいと思い質問させていただきました。
依然作ったrpgというのも、取り合えず動くんですが、
プログラムもごちゃごちゃ、グローバル変数も使い放題、
ソースファイルは1つだけというひどいものになったので、
きれいに書く、なおかつ、あとからいろいろ修正できるような、
ちゃんとしたものを作ろうかと思っております。いろいろ試行錯誤したものの、
マップの処理で行き詰ってしまいました。いつもマップは、適当なもので、
2次配列をグローバルで宣言し、マップデータを配列に手作業で入れていくという
作業を繰り返し手たので、いませっかく作りなおしているのだから、
マップの処理をちゃんとしょうということで、質問させていただきました。
マップのロードと後始末の橇の仕方に苦戦しております。
使ってる言語は、c/c++、ライブラリは、dxライブラリです。
よろしくお願いします

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

Re: 本格的なrpg マップ処理。

#2

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

私はplatinum と言うマップエディタを推薦させて頂いております。
「HyperDevice software.」
http://www.hyperdevice.net/
readme.txtを御覧頂いて分からないことがあればご質問頂ければと思います。
※ 私のRPG講座でも解説しています。

【補足】
既に別ツールをお使いでしたら、データと問題の有るソースコードを見せてもらえるとよろしいかと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#3

投稿記事 by heyman » 10年前

softyaさん
返信ありがとうございます
本当に申し訳ないのですが、質問をかえさせていただきます。
マップをそれぞれ

マップの地形データ[h*w]・・・その名のとうりマップの地形、土台など
マップ上の設置物データ[h*w]・・・この前、トピックを建てた時に説明したように、物をおける用にしたいので、置いたものを保存する配列
マップの当たり判定[h*w]・・・マップの当たり判定1は通れない、など
マップのイベント[h*w]・・・触れたらマップ移動とか、
マップ上のモンスターのいる場所[h*w]・・・マップ上のモンスターのいる場所の記録するやつ(アクションrpgみたいなかんじ)
マップの画像データ[h*w]・・・マップチップの画像
のような感じで管理したいのですが、何かいい手はないですか?

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

Re: 本格的なrpg マップ処理。

#4

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

platinum がそんな感じですが問題がありますでしょうか?

あとマップ上の設置物データ[h*w]は、一部のマップだけなので常に必要ないのでは?
それとマップの地形データ[h*w]とマップの画像データ[h*w]の違いが分かりません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#5

投稿記事 by heyman » 10年前

すいませんマップの画像データ[h*w]というのはミス表記です
正しくは、 画像データ[マップチップの数]という、画像を入れとく配列です。
マップ上の設置物データ[h*w]は、フィールド上の家もここに入れておくため、
一応入れてます。
>platinum がそんな感じですが問題がありますでしょうか?

platinumをゲームに組み込む方法がわからないのです。

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

Re: 本格的なrpg マップ処理。

#6

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

platinumのドキュメントを読まれましたか?
あるいは、私のRPG講座でも良いのですが。

【補足】
過去ログも貼っておきますね。
「ソフト屋さん公開のRPG講座マップ表示について • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=8675
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 本格的なrpg マップ処理。

#7

投稿記事 by usao » 10年前

>マップの地形データ[h*w]・・・その名のとうりマップの地形、土台など
>マップ上の設置物データ[h*w]・・・この前、トピックを建てた時に説明したように、物をおける用にしたいので、置いたものを保存する配列
>マップの当たり判定[h*w]・・・マップの当たり判定1は通れない、など
>マップのイベント[h*w]・・・触れたらマップ移動とか、
>マップ上のモンスターのいる場所[h*w]・・・マップ上のモンスターのいる場所の記録するやつ(アクションrpgみたいなかんじ)
>マップの画像データ[h*w]・・・マップチップの画像

こうしたいならそれをせっせと実装すればいいんじゃないですかね.
今のところ何も困ったことないですよね.何が問題???

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

Re: 本格的なrpg マップ処理。

#8

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

実際の所、あーでもないこーでもないと色々実装してみて悩んだ末にポイントごとで質問してもらった方が理解が進みやすい問題かと思います。
初心者でぶつかる壁とはレベルが違うので聞いてすぐ応用できるという代物でもありません。、ご自分なりの理解が熟成されている必要があるのです。
問題を分解してみましょう。
1.バイナリファイルの入出力が理解できない。
2.マップの読み込み・書き出しが理解できない。
3.固定配列から動的配列にしてマップ管理が作れない。
4.platinumのフォーマットが理解できない。
5.モジュール化(ファイル分割)が出来ない。
私には、1から5を同時進行している様に見えます。

【補足】
RPGの場合、コードの規模が大きくなるのとやることが多くなるので初心者のまま作ることはたぶん出来ません。
ある程度中級者への道のりを進めなくてはいけませんので、問題を分解して考える事が出来るようになる事は重要なスキルとなります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: 本格的なrpg マップ処理。

#9

投稿記事 by ISLe » 10年前

とりあえずh*wを動的に扱う方法を勉強するなりアドバイスを受けるなりするのが良いのではないでしょうかね。

マップデータをプログラム内に固定で持たず、大きさの異なるマップ間を移動する処理を考えてみてください。

その際マップの中身はプログラムで適当に生成すれば良いかと思います。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#10

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました:実際の所、あーでもないこーでもないと色々実装してみて悩んだ末にポイントごとで質問してもらった方が理解が進みやすい問題かと思います。
初心者でぶつかる壁とはレベルが違うので聞いてすぐ応用できるという代物でもありません。、ご自分なりの理解が熟成されている必要があるのです。
問題を分解してみましょう。
1.バイナリファイルの入出力が理解できない。
2.マップの読み込み・書き出しが理解できない。
3.固定配列から動的配列にしてマップ管理が作れない。
4.platinumのフォーマットが理解できない。
5.モジュール化(ファイル分割)が出来ない。
私には、1から5を同時進行している様に見えます。
おっしゃる通りでございます。いろいろやってた結果、
モジュール化だいたいできたんですが、構造体の実体化は、
どのソース内でするもんなのでしょうか?
今は、main.c内でやってるんですが、実体化を、グローバルでしないと
ちゃんと動きません。というのも、関数に異常な値がはいってしまうのです。
そういうものなのでしょうか?

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

Re: 本格的なrpg マップ処理。

#11

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

>モジュール化だいたいできたんですが、構造体の実体化は、どのソース内でするもんなのでしょうか?

実体化は定義のことと解釈します。型だけを決めるのは宣言です。
必要に応じてとしか言えませんが、他のモジュールから隠蔽したいなら当該モジュールで定義します。

> 実体化を、グローバルでしないとちゃんと動きません。というのも、関数に異常な値がはいってしまうのです。
> そういうものなのでしょうか?

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

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#12

投稿記事 by heyman » 10年前

プログラム
player.h

コード:

#ifndef PLAYER_H //二重include防止
#define PLAYER_H

//-----------------------------
//向きの定数
//-----------------------------
enum DIRECTION
{
	UP, //上の時
	DOWN, //下の時
	RIGHT, //右右右右右右右右ィーーーーーッ
	LEFT, //左の時
};

//-----------------------------
//プレイヤーの情報の構造体
//-----------------------------
struct PLAYER
{
	int m_vplayerx,m_vplayery; //画面上のプレイヤーの座標
	int m_movex,m_movey; //移動した距離
	int m_moveflag; //現在歩いているかのフラグ
	int m_walkflag; //歩ける場所か
	int m_scrx,m_scry ; //スクロールした距離
	int m_mplayerx,m_mplayery; //マップ上のプレイヤーの座標
	int m_handle[20]; //キャラの画像
	int m_nowhandle; //現在の画像
	int m_sp; //歩く速さ
	int m_mcount; //アニメーションさせるカウント
	int m_img; //プレイヤーの画像番号
	DIRECTION direction;
};




//---------------
//プレイヤーの処理
//---------------
extern void PlayrProcess(void); //プレイヤーの基本処理

extern void PlayerMove(PLAYER *pl); //プレイヤーの移動処理

//---------------
//プレイヤーの描画 
//---------------
extern void PlayerDraw(PLAYER pl); //プレイヤーの描画

extern void PlayerAnimation(PLAYER *pl); //プレイヤーのアニメーション 

extern int Format(PLAYER *pl); //データの初期化
#endif 
player.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"

#define ASPEED 10


//---------------
//プレイヤーのアニメ―ション 縦 横 速さ ハンドル
//---------------
void PlayerAnimation(PLAYER *pl)
{
	pl->m_mcount++;
	pl->m_img=(pl->m_mcount%(4*ASPEED))/ASPEED;
	if(pl->m_img==3)pl->m_img=1;
}

void PlayerDraw(PLAYER pl )
{
	
	if (pl.m_moveflag==0){ //歩いているかのフラグ

		if (pl.direction==UP){ //上向きの画像
			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[1],TRUE);
		}
		if (pl.direction==DOWN){ //下向きの画像
			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[7],TRUE);
		}
		if (pl.direction==RIGHT){ //右向きの画像
			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[4],TRUE);
		}
		if (pl.direction==LEFT){ //左向きの画像
			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[10],TRUE);
		}

	}
		if (pl.m_moveflag==1){ //歩いているかのフラグ

		if (pl.direction==UP){ //上向きに移動時の画像

			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[0+pl.m_img],TRUE);
		}
		if (pl.direction==DOWN){ //下向きに移動時の画像

			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[6+pl.m_img],TRUE);
		}
		if (pl.direction==RIGHT){ //右向きに移動時の画像

			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[3+pl.m_img],TRUE);
		}
		if (pl.direction==LEFT){ //左向きに移動時の画像

			DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[9+pl.m_img],TRUE);
		}

	}
}	

void PlayrProcess(void)
{

}

void PlayerMove(PLAYER *pl)
{
	int newx,newy;
	int newsx,newsy;

	newsx=pl->m_scrx; //現在のスクロールxの代入
	newsy=pl->m_scry; //現在のスクロールyの代入
	newx=pl->m_mplayerx; //現在のx座標を代入
	newy=pl->m_mplayery; //現在のy座標を代入
	if(CheckHitKey(KEY_INPUT_UP)==1)pl->direction=UP ,newsy+=pl->m_sp ,newy-=pl->m_sp;//上に移動
	if(CheckHitKey(KEY_INPUT_DOWN)==1)pl->direction=DOWN ,newsy-=pl->m_sp ,newy+=pl->m_sp;//下に移動
	if(CheckHitKey(KEY_INPUT_LEFT)==1)pl->direction=LEFT ,newsx+=pl->m_sp ,newx-=pl->m_sp;//左に移動
	if(CheckHitKey(KEY_INPUT_RIGHT)==1)pl->direction=RIGHT ,newsx-=pl->m_sp ,newx+=pl->m_sp;//右に移動

	if(newx != pl->m_mplayerx || newy != pl->m_mplayery)pl->m_moveflag=1;else pl->m_moveflag=0; //動いたら、動いたフラグを建てる

		if(pl->m_walkflag==0){ //歩ける
			pl->m_scrx=newsx;
			pl->m_scry=newsy;
			pl->m_mplayerx=newx; //x座標を代入
			pl->m_mplayery=newy; //y座標を代入
	}
		DrawFormatString(0,0,GetColor(255,0,255), "mx%d my%d %d  %d  %d  %d",pl->m_mplayerx,pl->m_mplayery,pl->m_vplayerx,pl->m_vplayery,pl->m_scry,pl->m_walkflag);
}


//----------------
//初期化
//----------------
int Format(PLAYER *pl)//データの初期化
{
	pl->m_sp=1;
	pl->m_mplayerx=300;
	pl->m_mplayery=200;
	pl->m_scrx=0;
	pl->m_scry=0;
	pl->m_vplayerx = pl->m_mplayerx-pl->m_scrx;
	pl->m_vplayery=pl->m_mplayery-pl->m_scry; //画面上のプレイヤーの座標
	pl->direction=UP;
	LoadDivGraph("キャラ.png",12,3,4,23,32,pl->m_handle);
	return 0;

}
map.h

コード:

#ifndef MAP_H //二重include防止
#define MAP_H
#include "Player.h"
#include <stdio.h>
#include <stdlib.h>

#define MAP_SIZE    32          // マップチップ一つのドットサイズ
#define MAP_WIDTH   5         // マップの幅
#define MAP_HEIGHT  5         // マップの縦長さ
//-----------------------------
//マップの情報の構造体
//-----------------------------
struct MAP
{
	int m_map[MAP_HEIGHT*MAP_WIDTH]; //マップの地形データ
	int m_graph[20]; //画像を入れとく
};

//----------------
//マップを書く
//----------------
extern int MapDraw(PLAYER pl ,MAP mp); //マップを書く

//----------------
//
//----------------
extern int MapFormat(MAP *mp);

#endif 
map.c

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <stdlib.h>


int MapFormat(MAP *mp)
{	
	char filename[] = "test.txt"; /* データファイル名 */
    FILE *fp;
	
    /* ファイルを開く */
    if ((fp=fopen("test.txt", "r")) == NULL)
    {DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        
       exit(1);
    }
	//int count=0;
	 /* データ処理 */
    
//mp->m_map[0] = getc(fp);
	 int i,j;  
	 for(j=0;j<MAP_HEIGHT;j++)for(i=0;i<MAP_WIDTH;i++)fscanf(fp,"%d",&mp->m_map[MAP_WIDTH*j+i]);
	mp->m_graph[0]=LoadGraph( "マップチップ.png" ) ;

	//fclose(fp);

	return 0;
}


int MapDraw(PLAYER pl,MAP mp)
{        

	int i,j;
	
	for(i=0;i<MAP_WIDTH;i++){

		for(j=0;j<MAP_HEIGHT;j++){
			int n=MAP_WIDTH*j+i;
			if(mp.m_map[n]==1)DrawGraph(pl.m_scrx+MAP_SIZE*i,pl.m_scry+MAP_SIZE*j,mp.m_graph[0],TRUE);
			//if(mp.m_map[n]==1)DrawGraph(pl.m_scrx+MAP_SIZE*i,pl.m_scry+MAP_SIZE*j,mp.m_graph[1],TRUE);
		}
	}
	return 0;
}
main.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"
#include <string.h>


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{	
	MAP mp;
PLAYER pl2 ;
	
	ChangeWindowMode( TRUE ) ;// ウインドウモードで起動
	
    if( DxLib_Init() < 0 ) return -1;// DXライブラリの初期化
	
	SetDrawScreen( DX_SCREEN_BACK ) ;// 描画先を裏画面にする

	Format(&pl2);
	MapFormat(&mp);

	while( ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){

		ClearDrawScreen(); //画面をクリアにする
		DrawFormatString(10,100,GetColor(255,0,255),"%d\n",mp.m_map[2]);
		MapDraw( pl2,mp);
		
		PlayerDraw(pl2 );

		PlayerMove(&pl2 );

		PlayerAnimation( &pl2);

        ScreenFlip() ;// 裏画面の内容を表画面に反映

	}
	
    DxLib_End();// DXライブラリの後始末

	return 0;

}
です
あと、一応txtから配列に値を入れられるようにしました。

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

Re: 本格的なrpg マップ処理。

#13

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

値渡しのPlayerDraw(PLAYER pl)関数があるので、main.cもstruct PLAYERの構造を知る必要があります。
なので、struct PLAYERの宣言がplayer.hに必要になります。
PlayerDrawもポインタ渡しにすれば、struct PLAYERは中身が見えない前方参照だけで良くなります。
この場合実体の生成は、player.cが受け持つことになります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#14

投稿記事 by heyman » 10年前

とりあえず、異常な値になるバグは解消されました。
普通に構造体のメンバを全て初期化したら治りました。
つぎのかだいは
ISLeさんも言ってるとうり
>とりあえずh*wを動的に扱う方法を勉強するなりアドバイスを受けるなりするのが良いのではないでしょうかね。
>マップデータをプログラム内に固定で持たず、大きさの異なるマップ間を移動する処理を考えてみてください。
ですね。とりあえずは自力で頑張ってみます。
これができたら
platinumのファイルの処理ですかね。

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

Re: 本格的なrpg マップ処理。

#15

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

>とりあえず、異常な値になるバグは解消されました。
>普通に構造体のメンバを全て初期化したら治りました。

ちゃんと出来ているでしょうか? よく分からず、ねじ伏せたなら後々危険ですが。
まぁ、それも経験なので、とりあえずこのまま行きますか。

ただ、直した部分のコードはフォーラムルール上掲載をお願いします。
コードじゃなくても直した所さえ正確にわかればよいです。

> ISLeさんも言ってるとうり
>とりあえずh*wを動的に扱う方法を勉強するなりアドバイスを受けるなりするのが良いのではないでしょうかね。
>マップデータをプログラム内に固定で持たず、大きさの異なるマップ間を移動する処理を考えてみてください。

これが
3.固定配列から動的配列にしてマップ管理が作れない。
に辺ります。

と言うことで、1.2.4が残ります。
1.バイナリファイルの入出力が理解できない。
2.マップの読み込み・書き出しが理解できない。
4.platinumのフォーマットが理解できない。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#16

投稿記事 by heyman » 10年前

おもに直した部分は、
次のソースの、int Format(PLAYER *pl)//データの初期化の部分です
構造体の中のメンバをほぼ初期化しました。(よく考えたらこれが基本だったのかもしれない)

player.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"

#define ASPEED 10


//---------------
//プレイヤーのアニメ―ション 縦 横 速さ ハンドル
//---------------
void PlayerAnimation(PLAYER *pl)
{
	pl->m_mcount++;
	pl->m_img=(pl->m_mcount%(4*ASPEED))/ASPEED;
	if(pl->m_img==3)pl->m_img=1;
}

void PlayerDraw(PLAYER *pl )
{
	
	if (pl->m_moveflag==0){ //歩いているかのフラグ

		if (pl->direction==UP){ //上向きの画像
			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[1],TRUE);
		}
		if (pl->direction==DOWN){ //下向きの画像
			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[7],TRUE);
		}
		if (pl->direction==RIGHT){ //右向きの画像
			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[4],TRUE);
		}
		if (pl->direction==LEFT){ //左向きの画像
			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[10],TRUE);
		}

	}
		if (pl->m_moveflag==1){ //歩いているかのフラグ

		if (pl->direction==UP){ //上向きに移動時の画像

			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[0+pl->m_img],TRUE);
		}
		if (pl->direction==DOWN){ //下向きに移動時の画像

			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[6+pl->m_img],TRUE);
		}
		if (pl->direction==RIGHT){ //右向きに移動時の画像

			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[3+pl->m_img],TRUE);
		}
		if (pl->direction==LEFT){ //左向きに移動時の画像

			DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[9+pl->m_img],TRUE);
		}

	}
}	

void PlayrProcess(void)
{

}

void PlayerMove(PLAYER *pl)
{
	int newx,newy;
	int newsx,newsy;

	newsx=pl->m_scrx; //現在のスクロールxの代入
	newsy=pl->m_scry; //現在のスクロールyの代入
	newx=pl->m_mplayerx; //現在のx座標を代入
	newy=pl->m_mplayery; //現在のy座標を代入
	if(CheckHitKey(KEY_INPUT_UP)==1)pl->direction=UP ,newsy+=pl->m_sp ,newy-=pl->m_sp;//上に移動
	if(CheckHitKey(KEY_INPUT_DOWN)==1)pl->direction=DOWN ,newsy-=pl->m_sp ,newy+=pl->m_sp;//下に移動
	if(CheckHitKey(KEY_INPUT_LEFT)==1)pl->direction=LEFT ,newsx+=pl->m_sp ,newx-=pl->m_sp;//左に移動
	if(CheckHitKey(KEY_INPUT_RIGHT)==1)pl->direction=RIGHT ,newsx-=pl->m_sp ,newx+=pl->m_sp;//右に移動

	if(newx != pl->m_mplayerx || newy != pl->m_mplayery)pl->m_moveflag=1;else pl->m_moveflag=0; //動いたら、動いたフラグを建てる

		if(pl->m_walkflag==0){ //歩ける
			pl->m_scrx=newsx;
			pl->m_scry=newsy;
			pl->m_mplayerx=newx; //x座標を代入
			pl->m_mplayery=newy; //y座標を代入
	}
		DrawFormatString(0,0,GetColor(255,0,0), "mx%d my%d %d  %d  %d  %d",pl->m_mplayerx,pl->m_mplayery,pl->m_vplayerx,pl->m_vplayery,pl->m_scry,pl->m_img);
}


//----------------
//初期化
//----------------
int Format(PLAYER *pl)//データの初期化
	
{  
	pl->m_mcount=0; 
	pl->m_walkflag=0;
    pl->m_img=0;
	pl->m_sp=1;
	pl->m_mplayerx=300;
	pl->m_mplayery=200;
	pl->m_scrx=0;
	pl->m_scry=0;
	pl->m_vplayerx = pl->m_mplayerx-pl->m_scrx;
	pl->m_vplayery=pl->m_mplayery-pl->m_scry; //画面上のプレイヤーの座標
	pl->direction=UP;
	LoadDivGraph("キャラ.png",12,3,4,23,32,pl->m_handle);
	return 0;

}
次の課題は3.固定配列から動的配列にしてマップ管理が作れない。
の予定ですね、
txtファイルでできたらバイナリになおそうと思いましたが、
txtとバイナリの処理はかけ離れていて、バイナリには
txtの応用でできないとかありますか?
ないようならとりあえずはtxtでやってみたいと思います。

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

Re: 本格的なrpg マップ処理。

#17

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

バイナリは元を作るのは面倒です。
配列のマップをバイナリ出力してバイナリで読むのなら良いですが、その場合は別プログラムで実験した方がよいでしょう。
ちなみにテキストの場合でも、マップサイズの情報がテキストに必要になります。
よくあるパターンは、先頭2行がそれぞれ縦横のサイズってやつです。

【補足】
ちなみにバグらせないコツは、初期化時に定義の順番で行う。 ← 抜けを発見しやすい。
初期化の不要なメンバ変数はローカル変数で良いんじゃないかと疑う。

player.cに全部構造体を持ってきたのなら、ヘッダに必要なのはstruct PLAYER;の前方宣言だけに成るはずです。
あと、実体の定義をplayer.cでされていないようです。Format()からポインタで戻すと良いと思いますよ。
※ 何を初期化するFormat()なのか分からないので、PlayerFormat()とでもすべきかと思います。私の好み言えばPlayerInit()ですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

白い時空
記事: 18
登録日時: 13年前
住所: 埼玉県さいたま市

Re: 本格的なrpg マップ処理。

#18

投稿記事 by 白い時空 » 10年前

問題とは別ですが個人的に気になるのがPlayerDraw関数でのDrawGraph関数の多さですね。

あらかじめ、pl.m_handleの配列内の数値を変数もしくは関数で取得すればDrawGraph関数を1つ書くだけで済み、見やすく修正が楽になると思います。

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

Re: 本格的なrpg マップ処理。

#19

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

白い時空 さんが書きました:問題とは別ですが個人的に気になるのがPlayerDraw関数でのDrawGraph関数の多さですね。

あらかじめ、pl.m_handleの配列内の数値を変数もしくは関数で取得すればDrawGraph関数を1つ書くだけで済み、見やすく修正が楽になると思います。
heymanさんにお断りしておきますと、他にも後で困りそうな所が何箇所かあります。
ただ、まだまだ始めたばかりですので、過大な要求と成るかもしれないと今回は触れずに後回しにさせていただきます。
どちらにしても、リファクタリングは必須なので直すことにはなると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#20

投稿記事 by heyman » 10年前

白い時空 さんが書きました:問題とは別ですが個人的に気になるのがPlayerDraw関数でのDrawGraph関数の多さですね。

あらかじめ、pl.m_handleの配列内の数値を変数もしくは関数で取得すればDrawGraph関数を1つ書くだけで済み、見やすく修正が楽になると思います。
とりあえず、DrawGraph関数を1つにおさえました。 

player.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"

#define ASPEED 10

//---------------
//プレイヤーのアニメ―ション 縦 横 速さ ハンドル
//---------------
void PlayerAnimation(PLAYER *pl)
{
	pl->m_mcount++;
	pl->m_img=(pl->m_mcount%(4*ASPEED))/ASPEED;
	if(pl->m_img==3)pl->m_img=1;
}

void PlayerDraw(PLAYER *pl )
{
	if (pl->m_moveflag==0){ //歩いているかのフラグ

		if (pl->direction==UP){ //上向きの画像
			pl->m_nowhandle=1;
		}
		if (pl->direction==DOWN){ //下向きの画像
			pl->m_nowhandle=7;
		}
		if (pl->direction==RIGHT){ //右向きの画像
			pl->m_nowhandle=4;
		}
		if (pl->direction==LEFT){ //左向きの画像
			pl->m_nowhandle=10;
		}

	}
		if (pl->m_moveflag==1){ //歩いているかのフラグ

		if (pl->direction==UP){ //上向きに移動時の画像

			pl->m_nowhandle=0+pl->m_img;
		}
		if (pl->direction==DOWN){ //下向きに移動時の画像

			pl->m_nowhandle=6+pl->m_img;
		}
		if (pl->direction==RIGHT){ //右向きに移動時の画像

			pl->m_nowhandle=3+pl->m_img;
		}
		if (pl->direction==LEFT){ //左向きに移動時の画像

			pl->m_nowhandle=9+pl->m_img;
		}

	}
	DrawGraph(pl->m_vplayerx,pl->m_vplayery,pl->m_handle[pl->m_nowhandle],TRUE);
	
}	

void PlayrProcess(void)
{

}

void PlayerMove(PLAYER *pl)
{
	int newx,newy;
	int newsx,newsy;

	newsx=pl->m_scrx; //現在のスクロールxの代入
	newsy=pl->m_scry; //現在のスクロールyの代入
	newx=pl->m_mplayerx; //現在のx座標を代入
	newy=pl->m_mplayery; //現在のy座標を代入
	if(CheckHitKey(KEY_INPUT_UP)==1)pl->direction=UP ,newsy+=pl->m_sp ,newy-=pl->m_sp;//上に移動
	if(CheckHitKey(KEY_INPUT_DOWN)==1)pl->direction=DOWN ,newsy-=pl->m_sp ,newy+=pl->m_sp;//下に移動
	if(CheckHitKey(KEY_INPUT_LEFT)==1)pl->direction=LEFT ,newsx+=pl->m_sp ,newx-=pl->m_sp;//左に移動
	if(CheckHitKey(KEY_INPUT_RIGHT)==1)pl->direction=RIGHT ,newsx-=pl->m_sp ,newx+=pl->m_sp;//右に移動

	if(newx != pl->m_mplayerx || newy != pl->m_mplayery)pl->m_moveflag=1;else pl->m_moveflag=0; //動いたら、動いたフラグを建てる

		if(pl->m_walkflag==0){ //歩ける
			pl->m_scrx=newsx;
			pl->m_scry=newsy;
			pl->m_mplayerx=newx; //x座標を代入
			pl->m_mplayery=newy; //y座標を代入
	}
		DrawFormatString(0,0,GetColor(255,0,0), "mx%d my%d %d  %d  %d  %d",pl->m_mplayerx,pl->m_mplayery,pl->m_vplayerx,pl->m_vplayery,pl->m_scry,pl->m_img);
}


//----------------
//初期化
//----------------
int PlayerFormat(PLAYER *pl)//データの初期化
	
{   
	pl->m_nowhandle=0;
	pl->m_mcount=0; 
	pl->m_walkflag=0;
    pl->m_img=0;
	pl->m_sp=1;
	pl->m_mplayerx=300;
	pl->m_mplayery=200;
	pl->m_scrx=0;
	pl->m_scry=0;
	pl->m_vplayerx = pl->m_mplayerx-pl->m_scrx;
	pl->m_vplayery=pl->m_mplayery-pl->m_scry; //画面上のプレイヤーの座標
	pl->direction=UP;
	LoadDivGraph("キャラ.png",12,3,4,23,32,pl->m_handle);
	return 0;

}
softya(ソフト屋) さんが書きました:player.cに全部構造体を持ってきたのなら、ヘッダに必要なのはstruct PLAYER;の前方宣言だけに成るはずです。
あと、実体の定義をplayer.cでされていないようです。Format()からポインタで戻すと良いと思いますよ。
>Format()からポインタで戻すと良いと思いますよ。
とはどういう意味でしょうか?
あと前方宣言という言葉を初めて聞きました。
分からないことだらけです。もっと勉強が必要ですね・・・

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

Re: 本格的なrpg マップ処理。

#21

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

>>Format()からポインタで戻すと良いと思いますよ。
>とはどういう意味でしょうか?
>あと前方宣言という言葉を初めて聞きました。
>分からないことだらけです。もっと勉強が必要ですね・・・

player.cに構造体の実体が来て外部的には構造体の前方宣言だけになるので、ポインタしか戻せなくなるからです。
※ 構造体の構造をplayer.c以外には隠蔽します。

これをplayer.hからplayer.cの頭の方に引っ越して、static struct PLAYER player;を宣言定義して実体を作ります。

コード:

struct PLAYER
{
    int m_vplayerx,m_vplayery; //画面上のプレイヤーの座標
    int m_movex,m_movey; //移動した距離
    int m_moveflag; //現在歩いているかのフラグ
    int m_walkflag; //歩ける場所か
    int m_scrx,m_scry ; //スクロールした距離
    int m_mplayerx,m_mplayery; //マップ上のプレイヤーの座標
    int m_handle[20]; //キャラの画像
    int m_nowhandle; //現在の画像
    int m_sp; //歩く速さ
    int m_mcount; //アニメーションさせるカウント
    int m_img; //プレイヤーの画像番号
    DIRECTION direction;
};
代わりにplayer.hには
struct PLAYER; ← 前方宣言
と書いておきます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#22

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました: player.cに構造体の実体が来て外部的には構造体の前方宣言だけになるので、ポインタしか戻せなくなるからです。
※ 構造体の構造をplayer.c以外には隠蔽します。
という事は、MapDraw()とかは使えなくなるんじゃないでしょうか?

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

Re: 本格的なrpg マップ処理。

#23

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

heyman さんが書きました:
softya(ソフト屋) さんが書きました: player.cに構造体の実体が来て外部的には構造体の前方宣言だけになるので、ポインタしか戻せなくなるからです。
※ 構造体の構造をplayer.c以外には隠蔽します。
という事は、MapDraw()とかは使えなくなるんじゃないでしょうか?
逆に考えれば、Player単体が保持していなくて良い情報や処理しなくて良い処理をしているとも考えれると思います。
Mapで完結できる方法を考えてみる良い機会かと思います。

※ きれいなプログラムを書くことの一つに結合度を弱めるがあります。
つまり、1つのモジュールの構造体が外部に公開されているのは結合度が強い状態です。
なので、できるだけ弱める工夫をしてみましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 本格的なrpg マップ処理。

#24

投稿記事 by usao » 10年前

オフトピック
そういう書き方的な面も重要ではありますが,本題である
>固定配列から動的配列
みたいな話とどちらを先にやるか,みたいなことをはっきりさせた方がいいような気がします.
リファクタリングが先か,内容が先か,みたいな.
(「良い書き方」で「内容側」を進めていけるのがベストではあるのでしょうけど)

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

Re: 本格的なrpg マップ処理。

#25

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

内容が先のほうが良いですね。
ということで綺麗なコード計画の話は一時保留としたいと私は思います。

【補足】
・コードを綺麗に書く技能を磨く
・処理ロジックを組み立てる知識・技能を磨く
この2つは別のベクトルですから。
usaoさんの言われるように同時並行は難しい気がします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#26

投稿記事 by heyman » 10年前

動的配列のプログラムを組んでみました。
こんな感じで良いでしょうか?

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <stdlib.h>

struct MAP
{
	int m_xn;//縦と横のマップチップの数 
    int m_yn; 
	int* m_map; //マップの地形データ
	int m_graph[20]; //画像を入れとく
};

static struct MAP mp;

int MapFormat()
{	mp.m_xn=5;//縦と横のマップチップの数 
    mp.m_yn=5;
	char filename[] = "test.txt"; /* データファイル名 */
    FILE *fp;
	
    /* ファイルを開く */
    if ((fp=fopen("test.txt", "r")) == NULL)
    {DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        
       exit(1);
    }
	 /* データ処理 */
    mp.m_map=(int*)malloc( sizeof(int) * (mp.m_xn * mp.m_yn) );
//mp->m_map[0] = getc(fp);
	 int i,j;  
	 for(j=0;j<MAP_HEIGHT;j++)for(i=0;i<MAP_WIDTH;i++)fscanf(fp,"%d",&mp.m_map[MAP_WIDTH*j+i]);
	mp.m_graph[0]=LoadGraph( "マップチップ.png" ) ;

	fclose(fp);

	return 0;
}


int MapDraw(PLAYER pl)
{        

	int i,j;
	
	for(i=0;i<MAP_WIDTH;i++){

		for(j=0;j<MAP_HEIGHT;j++){
			int n=MAP_WIDTH*j+i;
			if(mp.m_map[n]==1)DrawGraph(pl.m_scrx+MAP_SIZE*i,pl.m_scry+MAP_SIZE*j,mp.m_graph[0],TRUE);
			//if(mp.m_map[n]==1)DrawGraph(pl.m_scrx+MAP_SIZE*i,pl.m_scry+MAP_SIZE*j,mp.m_graph[1],TRUE);
		}
	}
	return 0;
}

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

Re: 本格的なrpg マップ処理。

#27

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

動的と言いながらmallocしている以外固定値だと思います。
MAP_HEIGHTやMAP_WIDTHとmp.m_xn=5;とmp.m_yn=5;
それとint m_graph[20]; //画像を入れとく
やmp.m_graph[0]=LoadGraph( "マップチップ.png" ) ;
このプログラムで、例えば100x100サイズのマップとマップチップ画像50個の場合どうするんでしょうか?

プログラムを変更せずに20x20から1000x1000まで読み込める1つのプログラムを作ることを意識してください。

【補足】
読むマップ名が固定されていますが、これを可変にして次のマップを読めるようにした場合、次のマップを読むとメモリリークするのでメモリの解放も必要です。
終了時にもメモリの解放はないのでメモリリークします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#28

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました:動的と言いながらmallocしている以外固定値だと思います。
MAP_HEIGHTやMAP_WIDTHとmp.m_xn=5;とmp.m_yn=5;
それとint m_graph[20]; //画像を入れとく
やmp.m_graph[0]=LoadGraph( "マップチップ.png" ) ;
このプログラムで、例えば100x100サイズのマップとマップチップ画像50個の場合どうするんでしょうか?
マップチップのサイズと、マップチップの数や、その画像の名前はどうやって得ますかtxtファイルの先頭とかに書いとくのでしょうか?

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

Re: 本格的なrpg マップ処理。

#29

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

> マップチップのサイズと、マップチップの数や、その画像の名前はどうやって得ますかtxtファイルの先頭とかに書いとくのでしょうか?

専用の定義ファイルを作っておくとかが必要でしょうね。構造体配列でも出来なくはないです。
どちらが良いかは考えてみください。
マップ自体のサイズは、マップファイルが持たないと管理がややこしいでしょう。

> txtファイルの先頭とかに書いとくのでしょうか?

それも自由ですよ。自分が楽にできそうな方法を考えて案を出してみてください。

こういう事を考えるのが、プログラム設計の作業の一部でファイル構造・データ構造を設計すると言うことです。
ご自身で考えないと行けない事なので、わざと曖昧に回答しております。
案を出してもられば、出来そうかなどの回答はしますので案を出してみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#30

投稿記事 by heyman » 10年前

試行錯誤して頑張ったんですけど、あと何をしたらいいかわからないので、やったことと、プログラムを乗せておきます。
main.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"
#include <string.h>

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{	
	
	//MAP mp;
	//PLAYER pl2;
	static int scrx,scry;

	ChangeWindowMode( TRUE ) ;// ウインドウモードで起動
	
    if( DxLib_Init() < 0 ) return -1;// DXライブラリの初期化
	
	SetDrawScreen( DX_SCREEN_BACK ) ;// 描画先を裏画面にする
    
	PlayerFormat();
	MapFormat();

	while( ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){

		ClearDrawScreen(); //画面をクリアにする
		
		MapDraw(scrx,scry);
		
		PlayerDraw( );

		PlayerMove(&scrx,&scry);

		PlayerAnimation();

        ScreenFlip() ;// 裏画面の内容を表画面に反映
	
	}
	MapDelete();
    DxLib_End();// DXライブラリの後始末

	return 0;

}
player.h

コード:

#ifndef PLAYER_H //二重include防止
#define PLAYER_H

//-----------------------------
//向きの定数
//-----------------------------
enum DIRECTION
{
	UP, //上の時
	DOWN, //下の時
	RIGHT, //右右右右右右右右ィーーーーーッ
	LEFT, //左の時
};

//-----------------------------
//プレイヤーの情報の構造体
//-----------------------------
struct PLAYER;


//---------------
//プレイヤーの処理
//---------------

// 名前---
// 引数---
//---
extern void PlayrProcess(void); //プレイヤーの基本処理

// 名前 void PlayerMove(int *scrx,int *scry);
// 引数 int *scrx x方向のスクロール数,int *scry y方向のスクロール数
// プレイヤーの移動処理
extern void PlayerMove(int *scrx,int *scry); //プレイヤーの移動処理

// 名前 int PlayerFormat();
// 引数 無
// プレイヤーの初期化
extern int PlayerFormat(); //データの初期化

//---------------
//プレイヤーの描画 
//---------------

// 名前 void PlayerDraw();
// 引数 無
// プレイヤーの描画
extern void PlayerDraw(); //プレイヤーの描画

// 名前 void PlayerAnimation();
// 引数 無
// プレイヤーのアニメーション
extern void PlayerAnimation(); //プレイヤーのアニメーション 


#endif 
player.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"

#define ASPEED 10

struct PLAYER
{
	int m_vplayerx,m_vplayery; //画面上のプレイヤーの座標
	int m_movex,m_movey; //移動した距離
	int m_moveflag; //現在歩いているかのフラグ
	int m_walkflag; //歩ける場所か
	int m_scrx,m_scry ; //スクロールした距離
	int m_mplayerx,m_mplayery; //マップ上のプレイヤーの座標
	int m_handle[20]; //キャラの画像
	int m_nowhandle; //現在の画像
	int m_sp; //歩く速さ
	int m_mcount; //アニメーションさせるカウント
	int m_img; //プレイヤーの画像番号
	DIRECTION direction;
};
static struct PLAYER pl;
//---------------
//プレイヤーのアニメ―ション 縦 横 速さ ハンドル
//---------------
void PlayerAnimation()
{
	pl.m_mcount++; //アニメのカウント+1
	pl.m_img=(pl.m_mcount%(4*ASPEED))/ASPEED; //アニメションさせる
	if(pl.m_img==3)pl.m_img=1; //pl.m_img==3ならpl.m_img=1
	if(pl.m_mcount>=(4*ASPEED))pl.m_mcount=0; //アニメのカウントを0に戻す
}

void PlayerDraw( )
{
	if (pl.m_moveflag==0){ //歩いているかのフラグ

		if (pl.direction==UP){ //上向きの画像
			pl.m_nowhandle=1;
		}
		if (pl.direction==DOWN){ //下向きの画像
			pl.m_nowhandle=7;
		}
		if (pl.direction==RIGHT){ //右向きの画像
			pl.m_nowhandle=4;
		}
		if (pl.direction==LEFT){ //左向きの画像
			pl.m_nowhandle=10;
		}

	}
		if (pl.m_moveflag==1){ //歩いているかのフラグ

		if (pl.direction==UP){ //上向きに移動時の画像

			pl.m_nowhandle=0+pl.m_img;
		}
		if (pl.direction==DOWN){ //下向きに移動時の画像

			pl.m_nowhandle=6+pl.m_img;
		}
		if (pl.direction==RIGHT){ //右向きに移動時の画像

			pl.m_nowhandle=3+pl.m_img;
		}
		if (pl.direction==LEFT){ //左向きに移動時の画像

			pl.m_nowhandle=9+pl.m_img;
		}

	}
	DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[pl.m_nowhandle],TRUE);
	
}	

void PlayrProcess(void)
{

}

void PlayerMove(int *scrx,int *scry)
{
	int newx,newy;
	int newsx,newsy;
	

	newsx=*scrx; //現在のスクロールxの代入
	newsy=*scry; //現在のスクロールyの代入
	newx=pl.m_mplayerx; //現在のx座標を代入
	newy=pl.m_mplayery; //現在のy座標を代入
	if(CheckHitKey(KEY_INPUT_UP)==1)pl.direction=UP ,newsy+=pl.m_sp ,newy-=pl.m_sp;//上に移動
	if(CheckHitKey(KEY_INPUT_DOWN)==1)pl.direction=DOWN ,newsy-=pl.m_sp ,newy+=pl.m_sp;//下に移動
	if(CheckHitKey(KEY_INPUT_LEFT)==1)pl.direction=LEFT ,newsx+=pl.m_sp ,newx-=pl.m_sp;//左に移動
	if(CheckHitKey(KEY_INPUT_RIGHT)==1)pl.direction=RIGHT ,newsx-=pl.m_sp ,newx+=pl.m_sp;//右に移動

	if(newx != pl.m_mplayerx || newy != pl.m_mplayery)pl.m_moveflag=1;else pl.m_moveflag=0; //動いたら、動いたフラグを建てる

		if(pl.m_walkflag==0){ //歩ける
			*scrx=newsx;
			*scry=newsy;
			pl.m_mplayerx=newx; //x座標を代入
			pl.m_mplayery=newy; //y座標を代入
	}
		DrawFormatString(0,0,GetColor(255,0,0), "mx%d my%d %d  %d  %d  %d",pl.m_mplayerx,pl.m_mplayery,pl.m_vplayerx,pl.m_vplayery,pl.m_scry,pl.m_img);
}


//----------------
//初期化
//----------------
int PlayerFormat()//データの初期化
	
{  
	pl.m_sp=1;
	pl.m_mplayerx=300;
	pl.m_mplayery=200;
	pl.m_vplayerx = pl.m_mplayerx-pl.m_scrx;
	pl.m_vplayery=pl.m_mplayery-pl.m_scry; //画面上のプレイヤーの座標
	pl.direction=UP;
	LoadDivGraph("キャラ.png",12,3,4,23,32,pl.m_handle);
	return 0;

}
map.h

コード:

#ifndef MAP_H //二重include防止
#define MAP_H
#include "Player.h"
#include <stdio.h>
#include <stdlib.h>

#define MAP_SIZE    32          // マップチップ一つのドットサイズ
#define MAP_WIDTH   5         // マップの幅
#define MAP_HEIGHT  5         // マップの縦長さ
//-----------------------------
//マップの情報の構造体
//-----------------------------
struct MAP;

//----------------
//マップを書く
//----------------

// 名前 int MapDraw(int scrx,int scry);
// 引数 int scrx x方向のスクロール数,int scry y方向のスクロール数
// マップチップを書く
extern int MapDraw(int scrx,int scry); //マップを書く

//----------------
//マップの初期化など
//----------------

// 名前 int MapFormat();
// 引数 無
// マップの初期化
extern int MapFormat();

// 名前 int MapDelete();
// 引数 無
// マップ情報の消去
extern int MapDelete();

#endif 
map.c

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct MAP
{
	int m_xn;//縦と横のマップチップの数 
    int m_yn; 
	int *m_map; //マップの地形データ
	char m_filename[256];
	int m_mxn,m_myn; //マップチップの画像の縦と横の数
	int m_graph[20]; //画像を入れとく
};

static struct MAP mp;

int MapFormat()
{	
	char filename[] = "test.txt"; /* データファイル名 */
    FILE *fp; //ファイルぽいんた

    /* ファイルを開く */
    if ((fp=fopen(filename, "r")) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        
       exit(1);
    }

	strncpy(mp.m_filename, "マップチップ.png", sizeof(mp.m_filename));
	mp.m_mxn=1; //マップチップ画像の縦横の数
	mp.m_myn=1; //

	fscanf(fp,"%d",&mp.m_xn);//マップの横の数
	fscanf(fp,"%d",&mp.m_yn);//マップの縦の数

	 /* データ処理 */

    mp.m_map= (int *)calloc( (mp.m_xn * mp.m_yn), sizeof( int ) ); 
	int i,j;
	

	for(j=0;j<mp.m_yn;j++)for(i=0;i<mp.m_xn;i++)fscanf(fp,"%d",&mp.m_map[mp.m_xn*j+i]);

	LoadDivGraph(mp.m_filename, (mp.m_mxn*mp.m_myn) , mp.m_mxn , mp.m_myn ,32,32,mp.m_graph);//マップチップの読み込み

	fclose(fp); //ファイルを閉じる

	return 0;
}


int MapDraw(int scrx,int scry)
{        

	int i,j;
	
	for(i=0;i<mp.m_xn;i++){

		for(j=0;j<mp.m_yn;j++){
			int n=mp.m_xn*j+i;
			if(mp.m_map[n]==1)DrawGraph(scrx+MAP_SIZE*i,scry+MAP_SIZE*j,mp.m_graph[0],TRUE);//マップの描画
		}
	}DrawFormatString(20,20,GetColor(255,0,0), " %d %d %d %s",mp.m_xn,mp.m_yn,mp.m_map[12],mp.m_filename);
	return 0;
}

int MapDelete()
{    
	 free( mp.m_map );//メモリの解放
	 int i;
	 for (i=0;i<mp.m_mxn*mp.m_myn-1;i++) DeleteGraph( mp.m_graph[i] ) ; //画像の消去
	
	 return 0;
}
変えたとこ、
コメントを入れた map.cがplayerの構造体を知らなくてもいいようにした 
マップのでかさもファイルから得られるようにした メモリの解放、画像の削除など


ここができてないとか、ここがおかしいなどあれば行ってください、できるだけよくなるように努力します

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

Re: 本格的なrpg マップ処理。

#31

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

この時点では、これで十分だと思います。
m_graphの可変に対応できていませんが次で否が応でも対応が必要となるので次に行くと言うことでどうでしょう。
※ 変数名が分かりづらいので、検討して頂きたいところではあります。

【補足】
次はマップチェンジですか?
それともバイナリファイルでしょうか?
heymanさんの好みで決めてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#32

投稿記事 by heyman » 10年前

出来ればマップチェンジでお願いしたいです。
バイナリはあとからでも十分な気がしますので。

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

Re: 本格的なrpg マップ処理。

#33

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

heyman さんが書きました:出来ればマップチェンジでお願いしたいです。
バイナリはあとからでも十分な気がしますので。
どちらでも構いませんよ。
というか、何か質問が無いのでしょうか?
能動的に動くのはheymanさんじゃないと進みませんよ。
質問が無さそうなら、マップチェンジを実装してみてください。
※ 少ないともまず複数のマップ情報を扱う仕組みの実装ですね。あとマップチェンジを実現する仕組みの検討です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#34

投稿記事 by heyman » 10年前

今思ってるマップチェンジの基本的な流れは、
マップ1から、マップ2への移動の場合、

 マップ1のデータが入ったファイルを読み込む => MAP構造体にデータを代入 =>マップチェンジ=>
 今入れてるMAP構造体のデータの初期化 && 必要なデータの保存 && ファイルを閉じる => 
 マップ2のデータが入ったファイルを読み込む => MAP構造体にデータを代入

という流れなのかなと思ってるんですが、おかしくないでしょうか?
おかしくないのなら、 ファイルの名前などはどうやって変えますか?
MapFormat(); 関数の引数をファイルの名前にして、マップチェンジのたびに、
MapFormat(); 関数と、その引数を変えるのでしょうか?
あと前にも言ったように、家具を設置できるようにしたいのですが、
設置した位置などはどうやって保存するのでしょうか?ファイルに上書きするんでしょうか?

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

Re: 本格的なrpg マップ処理。

#35

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

> という流れなのかなと思ってるんですが、おかしくないでしょうか?

「必要なデータの保存」以外はおかしくないです。
このタイミングで保存する必要性が私には分かりません。
あと「ファイルを閉じる」が、ここに出てくる必要性を感じません。
仕様の話であって、実装レベルの「ファイルを閉じる」が出てこないて良いのでは。

>おかしくないのなら、 ファイルの名前などはどうやって変えますか?
>MapFormat(); 関数の引数をファイルの名前にして、マップチェンジのたびに、
>MapFormat(); 関数と、その引数を変えるのでしょうか?

引数が妥当ではないでしょうか?
他にも方法がありそうですが、冗長だったり、グローバル変数だったりしそうです。
※ 関数は1つにして共通化すべきだと思います。

>あと前にも言ったように、家具を設置できるようにしたいのですが、
>設置した位置などはどうやって保存するのでしょうか?ファイルに上書きするんでしょうか?

自動で保存されるんでしょうか?
家具を配置したマップは、どう考えてもセーブデータ扱いではないでしょうか。
ゲームのプレーヤーに知らない間に保存される仕様となっているのならそれでも良いですが、ゲームのプレーヤーが保存したと自覚的に分かるのはセーブした時だと私は思います。
仕様としては、セーブデータを作成するタイミングを決めてますか? ゲームの仕様として考えてください。
プログラミングとしてはセーブデータの作り方がわかりますか?
※ 元々有るファイルに上書きしたら、その内容は残りませんので色々不都合があるのでは。

【補足】
話がでかくなりそうなので、マップチェンジと分けることをおすすめします。
それでなくても、マップチェンジの話は長く掛かると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#36

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました: 「必要なデータの保存」以外はおかしくないです。
このタイミングで保存する必要性が私には分かりません。
必用なデータの保存というのは家具のある位置とかもそうですが、
宝箱のフラグとかもその一部です。
softya(ソフト屋) さんが書きました: 自動で保存されるんでしょうか?
家具を配置したマップは、どう考えてもセーブデータ扱いではないでしょうか。
ゲームのプレーヤーに知らない間に保存される仕様となっているのならそれでも良いですが、ゲームのプレーヤーが保存したと自覚的に分かるのはセーブした時だと私は思います。
考えている中では、家具を置ける場所に、家具レイヤを作っておいて、家具を置いたら、そのレイヤを書き換える。例えば、0から1にする、
1なら家具aを描画という風に考えてました。なので、マップチェンジするときいったん全部消してしまうので、どこかに
保存しとくのかなと思っていました。
softya(ソフト屋) さんが書きました:【補足】
話がでかくなりそうなので、マップチェンジと分けることをおすすめします。
それでなくても、マップチェンジの話は長く掛かると思います。
確かに先にマップチェンジですね。
思いついたのは、
マップの情報をswitchで分けて、初期化する、何を言ってるかわからないと思うので、例を書くと、
switch(stage) {
case 1:
MapDelete();
MapFormat("stage1.txt");
break;
case 2:
MapDelete();
MapFormat("stage2.txt");
break;
}
みたいな感じですがどうでしょうか?

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

Re: 本格的なrpg マップ処理。

#37

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

家具レイヤはセーブまでメモリに置いておけば良いのでは? それこそ実装で何とでもなります。

>思いついたのは、
>マップの情報をswitchで分けて、初期化する、何を言ってるかわからないと思うので、例を書くと、

本格的とのことなので50個もマップが有る時のことを考えると実用的ではなくなります。
それに殆ど同じことが書いてあると言うことは、実はループや関数化で処理できると言うことです。

テーブル(構造体配列)って考え方が一つの方法です。 → 龍神録でも敵の発生情報として使われています。
http://dixq.net/rp/11.html

あるいはリスト構造を使っても良いでしょう。
「ポインタ虎の巻~リスト構造」
http://www.nurs.or.jp/~sug/soft/tora/tora75.htm

良い機会なので、もし良かったら一般的なアルゴリズムにも目を通しておくことをおすすめします。
RPGだと他にもアルゴリズムは出てくる可能性があります。知らないと損することも多いです。
ざっとどんなものかを知っておくだけでも良いですよ。
「Programming Place Plus アルゴリズムとデータ構造編 トップページ」
http://www.geocities.jp/ky_webid/Progra ... index.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: 本格的なrpg マップ処理。

#38

投稿記事 by ISLe » 10年前

こちらのトピックが参考になるのではありませんか?
同じ二次元配列を複数つくる

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#39

投稿記事 by heyman » 10年前

今まで理解するのに時間がかかってました。
そして、配列構造体で頑張ろうと思います。
でも、イメージがうまくつかめないので、
分からないままがんばって考えた結果、

ファイル1にマップの情報が入ったファイルの名前の一覧を書いておく、 => 
ファイル1を読み込み、 =>
マップの情報が入ったファイルの情報を、配列構造体に1つずつ入れる、 => 
マップ情報が入った配列構造体の情報をMapFormat() に引数として渡す、 =>
それをもとにMAP構造体に情報を代入 => 表示、

てな感じでしょうか?

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

Re: 本格的なrpg マップ処理。

#40

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

ちょっと説明が分かりづらいですが、たぶん合っています。
できればファイルの構造などの例を書いて貰うとわかりやすくかったかなと。

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

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#41

投稿記事 by heyman » 10年前

>ちょっと説明が分かりづらいですが、たぶん合っています。

すいません説明が下手なもので。
詳しく書きます。
使用するファイルをlist.txtと、test.txt、test2.txt etc・・・
として、
test.txtたちの中身がマップの情報
list.txtの中身を
//----list.txtの中身-----
test.txt
test2.txt


//------------
として、

例えばMAPLISTという構造体配列の中に
ファイル名を1つずつ代入、(MAPLIST構造体の中メンバはファイルの名前やその他の情報)。
そして、マップを移動するイベントに触れたら、
そのたびにMapFormat(MAPLIST mpl)関数に引数を渡す。
その関数の中で、引数に対応するファイルを開き、情報を代入。
みたいな感じです。
こうした方がいいというものがあれば行ってください。

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

Re: 本格的なrpg マップ処理。

#42

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

たぶん作らないと分からないと思うので、作ってみてください。
色々と不足している感じがありますが、随時追加でも問題は無いでしょう。
ここで、あれもこれも必要と言ってもうまく組み込めないと思います。

初めから上手く設計できる人なんていません。作ることで設計のコツを掴んでください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#43

投稿記事 by heyman » 10年前

初歩的な質問ですいません。
ファイルから取り出した文字列を使ってファイルを開こうと
思ったんですが、できません。list.txtを開いて、fgets()で、
1行取得して、取得したファイル名でファイルを開こうと思ったんですが、
できないです。list.txtの中には、"test.txt"とだけ書いてあります。
なぜでしょうか?

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct MAP
{
	char m_filename[226];
	int m_xnum;//縦と横のマップチップの数 
    int m_ynum; 
	int *m_map; //マップの地形データ
	char m_graphname[256];
	int m_chipnumx,m_chipnumy; //マップチップの画像の縦と横の数
	int *m_mapchip; //画像を入れとく
};

struct MAPLIST
{
	char m_filename[225];
};

static struct MAP mp[10];
static struct MAPLIST mpl[10];

int MapListDate()
{
	FILE *fp;
	if ((fp=fopen("list.txt", "r")) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        
       exit(1);
    }

	fgets(mpl[0].m_filename,100,fp);

	return 0;
}

int MapFormat()
{	
	char filename[255]={'/0'};
	memcpy(mpl[0].m_filename, filename,sizeof(mpl[0].m_filename) );
    FILE *fp; //ファイルぽいんた

    /* ファイルを開く */
    if ((fp=fopen(filename, "r")) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        
       exit(1);
    }

	strncpy(mp[0].m_graphname, "マップチップ.png", sizeof(mp[0].m_graphname));
	mp[0].m_chipnumx=1; //マップチップ画像の縦横の数
	mp[0].m_chipnumy=1; //

	fscanf(fp,"%d",&mp[0].m_xnum);//マップの横の数
	fscanf(fp,"%d",&mp[0].m_ynum);//マップの縦の数

	 /* データ処理 */

    mp[0].m_map= (int *)calloc( (mp[0].m_xnum * mp[0].m_ynum), sizeof( int ) ); 
	mp[0].m_mapchip= (int *)calloc( (mp[0].m_chipnumx * mp[0].m_chipnumy), sizeof( int ) ); 

	int i,j;
	

	for(j=0;j<mp[0].m_ynum;j++)for(i=0;i<mp[0].m_xnum;i++)fscanf(fp,"%d",&mp[0].m_map[mp[0].m_xnum*j+i]);

	LoadDivGraph(mp[0].m_graphname, (mp[0].m_chipnumx*mp[0].m_chipnumy) , mp[0].m_chipnumx , mp[0].m_chipnumy ,32,32,mp[0].m_mapchip);//マップチップの読み込み

	fclose(fp); //ファイルを閉じる

	return 0;
}


int MapDraw(int scrx,int scry)
{        

	int i,j;
	
	for(i=0;i<mp[0].m_xnum;i++){

		for(j=0;j<mp[0].m_ynum;j++){
			int n=mp[0].m_xnum*j+i;
			if(mp[0].m_map[n]==1)DrawGraph(scrx+MAP_SIZE*i,scry+MAP_SIZE*j,mp[0].m_mapchip[0],TRUE);//マップの描画
		}
	}DrawFormatString(20,20,GetColor(255,0,0), " %d %d %d %s",mp[0].m_xnum,mp[0].m_ynum,mp[0].m_map[12],mp[0].m_graphname);
	return 0;
}

int MapDelete()
{    
	 free( mp[0].m_map );//メモリの解放
	 free( mp[0].m_mapchip );//メモリの解放
	 int i;
	 for (i=0;i<mp[0].m_chipnumx*mp[0].m_chipnumy-1;i++) DeleteGraph( mp[0].m_mapchip[i] ) ; //画像の消去
	
	 return 0;
}

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

Re: 本格的なrpg マップ処理。

#44

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

fgetsで取得した文字列には、最後に改行文字がついていることがあります。
改行文字があったら削除する、という処理を入れてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 本格的なrpg マップ処理。

#45

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

それ以前の問題として、せっかく読み込んだファイル名をNUL文字で上書きし、0文字のファイル名を持つファイルを開こうとしていますね。

【訂正】
ごめんなさい。よく見たら0文字のファイル名ではなく、"/"というファイル名のファイルでした。
最後に編集したユーザー みけCAT on 2014年3月23日(日) 00:08 [ 編集 1 回目 ]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 本格的なrpg マップ処理。

#46

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

直接は関係ないですが、DXライブラリを使っていて、DxLib_Initを呼んだ後なら、
いきなりexit(1)するのは危険であり、DxLib_Endを呼んでから終了したほうがいいと思います。
ただし、atexitでDxLib_Endを呼ぶ処理を登録してあれば大丈夫かもしれません。(本当かはわかりませんが)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 本格的なrpg マップ処理。

#47

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

MapDelete関数でfreeしたあとの領域にアクセスしているのは、非常に危険な気がします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 本格的なrpg マップ処理。

#48

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

MapListDate関数でファイルを閉じる処理が無いようですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: 本格的なrpg マップ処理。

#49

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

fgetsだと改行コードを取り込みますので、その性だと思います。
改行コードをNUL文字に置き換えてください。
ちなみにDXライブラリのFileRead_openとFileRead_getsで読みこめば改行コードの処理は不要になりはずです(要動作確認)
FileRead_open系はDXアーカイブにも対応するので、こちらを積極的に使うべきかと思います。
「DXライブラリ置き場 ミニテク」
http://homepage2.nifty.com/natupaji/DxL ... c.html#T11

後気になる所

コード:

    char filename[255]={'/0'}; → '\0'
    memcpy(mpl[0].m_filename, filename,sizeof(mpl[0].m_filename) ); → strcpyを使おう! パラメータの順場が間違っている!
    if ((fp=fopen(filename, "r")) == NULL){ → デバッガでfilenameを必ず確認すること。
でも、コピーする必要もないので構造体から直使ったほうが良いです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#50

投稿記事 by heyman » 10年前

出来ました。ありがとうございます。
変えたところは、file系の関数を、
全てdxライブラリのものに変えました。

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct MAP
{
	char m_filename[226];
	int m_xnum;//縦と横のマップチップの数 
    int m_ynum; 
	int *m_map; //マップの地形データ
	char m_graphname[256];
	int m_chipnumx,m_chipnumy; //マップチップの画像の縦と横の数
	int *m_mapchip; //画像を入れとく
};

struct MAPLIST
{
	char m_filename[225];
};

static struct MAP mp[10];
static struct MAPLIST mpl[10];

int MapListDate()
{
	int fp;
	if ((fp=FileRead_open("list.txt")) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        DxLib_End();
       exit(1);
    }

	 FileRead_gets( mpl[0].m_filename, 256, fp ) ;
	

	 
    FileRead_close(fp ) ;// ファイルを閉じる
	return 0;
}

int MapFormat()
{	
	char filename[255]={'\0'};
	strncpy(filename, mpl[0].m_filename,sizeof(mpl[0].m_filename) );
    int fp; //ファイルぽいんた

    /* ファイルを開く */
    if ((fp=FileRead_open(filename)) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        DxLib_End();
        exit(1);
    }

	strncpy(mp[0].m_graphname, "マップチップ.png", sizeof(mp[0].m_graphname));
	mp[0].m_chipnumx=1; //マップチップ画像の縦横の数
	mp[0].m_chipnumy=1; //

	FileRead_scanf(fp,"%d",&mp[0].m_xnum);//マップの横の数
	FileRead_scanf(fp,"%d",&mp[0].m_ynum);//マップの縦の数

	 /* データ処理 */

    mp[0].m_map= (int *)calloc( (mp[0].m_xnum * mp[0].m_ynum), sizeof( int ) ); 
	mp[0].m_mapchip= (int *)calloc( (mp[0].m_chipnumx * mp[0].m_chipnumy), sizeof( int ) ); 

	int i,j;
	

	for(j=0;j<mp[0].m_ynum;j++)for(i=0;i<mp[0].m_xnum;i++)FileRead_scanf(fp,"%d",&mp[0].m_map[mp[0].m_xnum*j+i]);

	LoadDivGraph(mp[0].m_graphname, (mp[0].m_chipnumx*mp[0].m_chipnumy) , mp[0].m_chipnumx , mp[0].m_chipnumy ,32,32,mp[0].m_mapchip);//マップチップの読み込み

	FileRead_close(fp); //ファイルを閉じる

	return 0;
}


int MapDraw(int scrx,int scry)
{        

	int i,j;
	
	for(i=0;i<mp[0].m_xnum;i++){

		for(j=0;j<mp[0].m_ynum;j++){
			int n=mp[0].m_xnum*j+i;
			if(mp[0].m_map[n]==1)DrawGraph(scrx+MAP_SIZE*i,scry+MAP_SIZE*j,mp[0].m_mapchip[0],TRUE);//マップの描画
		}
	}

	
	DrawFormatString(20,20,GetColor(255,0,0), " %d %d %d %s %s %s",mp[0].m_xnum,mp[0].m_ynum,mp[0].m_map[12],mp[0].m_graphname,mpl[0].m_filename);
	return 0;
}

int MapDelete()
{   
         int i;
	 for (i=0;i<mp[0].m_chipnumx*mp[0].m_chipnumy-1;i++) DeleteGraph( mp[0].m_mapchip[i] ) ; //画像の消去
	 free( mp[0].m_map );//メモリの解放
	 free( mp[0].m_mapchip );//メモリの解放
	
	 return 0;
}

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#51

投稿記事 by heyman » 10年前

時間があいてすいません。いろいろ忙しかったので・・・
キーボード入力でマップを変えることができました。
マップ移動の基礎が出来上がったと思います。
次は、イベントを踏んでからのマップ移動かなぁと思います。
イベントは、イベントレイヤを作ってしたいと思います。
そこで、レイヤの読み込みは、
マップ.txtファイルの、マップ地形のしたにレイヤの情報を入れとく、 => 
マップ地形とどうようレイヤの数を二次配列に代入、
二次配列 例)
maplayer[レイヤの番号 1ならイベント、など][レイヤ情報]

で行こうと思います。どうでしょうか?

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

Re: 本格的なrpg マップ処理。

#52

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

はい。それで良いと思います。

懸念事項は、
maplayer[レイヤの番号 1ならイベント、など][レイヤ情報]
↑ これはポインタ配列を使わないと表現できませんので、ポインタ配列を宣言するところからやってみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#53

投稿記事 by heyman » 10年前

まえにMap.cとPlayer.cの情報を共有しない的な事を言われた
と思いますが、
例えば、Player.c内の関数の値をmap.c内の関数で使いたいとき、
関数 PlayerPos()とMapEvent()があるとして、MapEvent()の処理内で、
PlayerPos()の値を使うときは、どうするのがいいでしょうか、
例えば、Main.cの中で、変数 仮にposを宣言して、PlayerPos(int *pos)で
ポインタで返して、それをMapEvent(int pos)に、引数として渡す
というやり方でいいでしょうか?(前の時はそうした)
というか、posなどの変数は、Main.cの中で宣言してもいいですか?
それともほかの場所でするべきですか?

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

Re: 本格的なrpg マップ処理。

#54

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

規模が大きくなるとmain→gamemain→各処理って感じになると思います。
gamemainが当たり判定を仲介して、MapEvent()とPlayerPos()を呼び出す形で良いんじゃないでしょうか。
私の提案としてはPlayerPos()は座標x,yを戻り値として構造体で戻して、MapEvent()に渡すんで良いかと思います。
規模次第では、gamemainと各処理との間にもう一つ管理モジュールを設けたほうが良いかもしれません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#55

投稿記事 by heyman » 10年前

>gamemainが当たり判定を仲介して、MapEvent()とPlayerPos()を呼び出す形で良いんじゃないでしょうか。
>私の提案としてはPlayerPos()は座標x,yを戻り値として構造体で戻して、MapEvent()に渡すんで良いかと思います。
ということは、

(main.c内に書く)
GameMain()
{
POS_XY pos;
pos=PlayerPos();
MapEvent(pos);//posを引数として渡す
}

のような感じですかね?

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

Re: 本格的なrpg マップ処理。

#56

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

そんな感じです。
それとMapEvent()に戻り値が無いとあとの処理が出来ませんね。

私の趣味だと

コード:

GameMain() {
	POS_XY pos;
	pos = getPlayerPos();
	int evtno = getMapEvent( pos ); //posを引数として渡す
	その後の処理
}
といった感じです。
関数名は動詞がないと、あとあと困るんでつけるべきだと思いますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
milfeulle
記事: 47
登録日時: 10年前
住所: マリーランド
連絡を取る:

Re: 本格的なrpg マップ処理。

#57

投稿記事 by milfeulle » 10年前

私はゲーム製作には明るくないのですが、気になった点を挙げます。

1. player.cのPlayerDraw関数ですが、 if文が連なっており、全ての条件が判断されることになる点です。else ifを使って不要な条件判断を行わない方が効率的だと思います。
2. m_directionをせっかくenum DIRECTIONで定義しているのですから、それらとハンドルの配列へのインデックスを対応づけておけば、(ファイルから読み込んでもいいですね)n[(int)UP] = 0, n[(int)DOWN] = 6, n[(int)RIGHT] = 3, n[(int)LEFT] = 9によってPlayerDraw関数の中身は、

コード:

if(pl.m_moveflag == 0) { //歩いているかのフラ
    // pl.m_handle[n[(int)pl.m_direction] + 1]を用いる
}
else if(pl.m_moveflag == 1) { //歩いているかのフラグ
    // pl.m_handle[n[(int)pl.m_direction] + pl.m_img]を用いる
}
と書けます。
3. player.cのPlayerMove関数のインデントがおかしいです。if文に限らず中括弧を省略しない方がいいと思います。
4. map.cのMapFormat関数ですが、ユーザーからの入力に対して例外処理が甘いです。数値を限定した方がいいでしょう。縦横が数値じゃなかった場合や、想定外に大きかった場合、0以下の場合など対応する必要があります。また、入力数が正しくない場合もエラーを表示した方がいいです。例えば、数値6つを読み込むのに3個しかなかった場合 :

コード:

#include <iostream>

using namespace std;

int main() {
	FILE* fp;

	fopen_s(&fp, "test.txt", "r");

	for(int i = 0; i < 6; ++i) {
		int x;
		int ret = fscanf_s(fp, "%d", &x);

		if(ret == EOF) {
			cout << "予期しない位置で終端に達した" << endl;
			break;
		}

		cout << x << "を読み込んだ" << endl;
	}

	fclose(fp);
	
	cin.get();
	return 0;
}
結果は
12を読み込んだ
15を読み込んだ
32を読み込んだ
予期しない位置で終端に達した
です。
ζ*'ヮ')ζプログラミングはみんなで奏でるシンフォニー

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

Re: 本格的なrpg マップ処理。

#58

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

ソースコードの細かいところの話は、heymanさんの腰を折らないようにわざとスルーしておりました。
heymanさんが、このソースコードの修正をやってみたいなら別トピックでお願いできますでしょうか。

それとmilfeulleさんのコードに但し書きもなくC++が混じっています。出来れば混ぜないで頂きたかったです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
milfeulle
記事: 47
登録日時: 10年前
住所: マリーランド
連絡を取る:

Re: 本格的なrpg マップ処理。

#59

投稿記事 by milfeulle » 10年前

そうですよね、(変数の定義をスコープの途中で行っていたり)better CとしてC++を利用されているのですから、STLやクラスを利用した例を提示しない方が良かったですね……。
ζ*'ヮ')ζプログラミングはみんなで奏でるシンフォニー

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

Re: 本格的なrpg マップ処理。

#60

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

milfeulle さんが書きました:そうですよね、(変数の定義をスコープの途中で行っていたり)better CとしてC++を利用されているのですから、STLやクラスを利用した例を提示しない方が良かったですね……。
heymanさんはC++であるという自覚もないと思いますので、ベターCとも言えないかもですね。
あとC99では変数の定義をスコープの途中で行うことは許されています。
※ VC++では最新版以外はC99(それも部分的)に対応していませんが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#61

投稿記事 by heyman » 10年前

何とか、キャラが通った場所のイベント番号の取得に成功しましたが、
フィールドから家に移動させるイベントを発生させたいのですが、
今考えてるのは、
キャラがイベントに触れる、=> イベント番号を取得、=>
イベントリストを作成しといて、(イベントリストの例 1なら家の中に移動 など)
イベント番号にあったイベントをおこす。

こんな感じです。
あと、イベントレイヤーは、家の出入り用、村人用という風に、分けた方が
良いですよね?

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

Re: 本格的なrpg マップ処理。

#62

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

> イベントリストの例 1なら家の中に移動 など)

家の中というのが仕様として曖昧ですね。
マップチェンジと言うことで、移動先のマップと移動先のイベント番号とかで管理したらどうでしょうか?
移動先のマップをマップ名で管理するか、マップ番号で管理するかは後々のメンテナンスで問題になります。
番号は間違えやすい・管理しづらいですが、マップを差し替えるのが容易です。
マップ名は管理しやすいですが、違う名前に変えた時に混乱が起こります。
中間案の、識別名で本物のマップ名を検索するという手段もあります。

>あと、イベントレイヤーは、家の出入り用、村人用という風に、分けた方が

家の出入りでもシナリオが動作する可能性はあります。
※ 家に入れなくなるとか。
一元化したほうが簡単なので私は分けなくても良いと思います。
それと村人が歩くとイベントレイヤーは使えません。あくまで地形専用です。

歩く場合はキャラクタにイベントが付くと考えてもらったほうが良いです。
どちらかと言うと村人発生レイヤーの番号などで管理した方が良いのでは?

私の書いているのは、こうしなきゃいけない!ってものではなく私の流儀に過ぎません。
ご自分で良いアイデアと思ったら邁進して構いませんょ。

【補足】
milfeulleさんに返信されていないようなので、フォーラムルール上の義務違反にあたりますので返答をお願いできますか。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#63

投稿記事 by heyman » 10年前

milfeulleさん返信ありがとうございます
milfeulle さんが書きました:1. player.cのPlayerDraw関数ですが、 if文が連なっており、全ての条件が判断されることになる点です。else ifを使って不要な条件判断を行わない方が効率的だと思います。
なるほど、直してみます。
milfeulle さんが書きました:2. m_directionをせっかくenum DIRECTIONで定義しているのですから、それらとハンドルの配列へのインデックスを対応づけておけば、(ファイルから読み込んでもいいですね)n[(int)UP] = 0, n[(int)DOWN] = 6, n[(int)RIGHT] = 3, n[(int)LEFT] = 9によってPlayerDraw関数の中身は、

if(pl.m_moveflag == 0) { //歩いているかのフラ
// pl.m_handle[n[(int)pl.m_direction] + 1]を用いる
}
else if(pl.m_moveflag == 1) { //歩いているかのフラグ
// pl.m_handle[n[(int)pl.m_direction] + pl.m_img]を用いる
}

と書けます。
確かにみじかくていいですね。試してみます。
milfeulle さんが書きました:3. player.cのPlayerMove関数のインデントがおかしいです。if文に限らず中括弧を省略しない方がいいと思います。
以後気を付けます。
milfeulle さんが書きました:4. map.cのMapFormat関数ですが、ユーザーからの入力に対して例外処理が甘いです。数値を限定した方がいいでしょう。縦横が数値じゃなかった場合や、想定外に大きかった場合、0以下の場合など対応する必要があります。また、入力数が正しくない場合もエラーを表示した方がいいです。
いまはいいかなと思っています。のちにやってみます。
softya(ソフト屋) さんが書きました:> イベントリストの例 1なら家の中に移動 など)

家の中というのが仕様として曖昧ですね。
マップチェンジと言うことで、移動先のマップと移動先のイベント番号とかで管理したらどうでしょうか?
ということは、 
イベントリストの例 1なら、家マップ1のイベント番号2に移動 のようなかんじですか?

あと、家は、のちに建てれる(場所などはプレイヤーが決める)様になっているので、
イベントの位置が、毎回一緒とは限らないので、処理をどうしようか迷ったのですが、

家の建てる位置を決める、=> イベントれいやに家の入口のイベントを振り分ける、(家を建てた数につれて番号を増やす)=>
キャラが触れたイベントの番号によって、家マップを呼び出す。(家マップは、家の構造体配列で管理)

という感じです。これよりもいい方法はありますか?

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

Re: 本格的なrpg マップ処理。

#64

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

> という感じです。これよりもいい方法はありますか?

なんとでも成ると言ったほうが良いかもしれませんね。
シナリオでマップを呼び出しても良いですし、専用イベント判定を作っても良いです。
イベントレイヤに付け加えるのもひとつの方法です。
どれも一長一短なので、自分のやりやすい方法でやってみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#65

投稿記事 by heyman » 10年前

イベントによるマップ移動について、家の中への移動についいては、フィールドから
家に入った場合、家の中のイベントレイヤに、プレイヤーの初期位置を示すイベントを入れて、
家の中への移動時に、イベントレイヤの中からプレイヤーの初期位置を示すイベントを探して、
キャラをそこに持ってくる、そして、出るときは、部屋に入るために使ったイベントのある
位置の一歩手前に移動させるということをしようと思ってるんですが、
どうすればいいか困ってます。というのも、マップ移動時に、マップを移動したというフラグと、
部屋のイベントレイヤのプレイヤーの初期位置を示すイベントのある位置をPlayer.cの中の関数に渡さないといけないので、
それをどう渡すべきか困っています。結合度を弱めることが頭に引っかかって、どう書けばいいか
分からないのです。どうしたら良いでしょうか(というか、結合度を弱めたままにするには、どこまでが限界か、どこまでならしても良いか
というのがよくわからなかったりします。)

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

Re: 本格的なrpg マップ処理。

#66

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

Player.cに座標を設定する関数を用意するで解決しませんか? イベントやらマップ移動したフラグとか一切Player.c側が知る必要はないと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#67

投稿記事 by heyman » 10年前

>Player.cに座標を設定する関数を用意するで解決しませんか? イベントやらマップ移動したフラグとか一切Player.c側が知る必要はないと思います。
マップ移動時に、マップを初期化する関数内で、座標を設定する関数を呼び出すということですか?

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

Re: 本格的なrpg マップ処理。

#68

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

> マップ移動時に、マップを初期化する関数内で、座標を設定する関数を呼び出すということですか?

マップ初期化を呼び出す上位(呼び元という意味で)のイベント統括モジュールが設定すべきかと思います。
マップとかプレーヤーなどの下位(呼び出され側)のモジュールには、お互いを結合しうる要素は避けてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#69

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました:マップ初期化を呼び出す上位(呼び元という意味で)のイベント統括モジュールが設定すべきかと思います。
マップとかプレーヤーなどの下位(呼び出され側)のモジュールには、お互いを結合しうる要素は避けてください。
ということは、Map.cないで、Player.cを呼び出すのではなく、ほかのモジュール内で、戻り値や、引数を使って、
データの受け渡しをするということですか?
あと、Map.cと、Player.cの関数で、共通の構造体を使ってデータを交換する場合は、その構造体をどうしますか?

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

Re: 本格的なrpg マップ処理。

#70

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

>Map.cないで、Player.cを呼び出すのではなく、ほかのモジュール内で、戻り値や、引数を使って、データの受け渡しをするということですか?

上位モジュールが一手に引き受けます。使うのは、引数や戻り値ですね。

> あと、Map.cと、Player.cの関数で、共通の構造体を使ってデータを交換する場合は、その構造体をどうしますか?

座標しかやり取りしないと思うのでstruct point{ int x,y; }程度じゃないでしょうか。
あとboolぐらいですかね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#71

投稿記事 by heyman » 10年前

最近コードを乗せてなかったので、とりあえず載せます

Main.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"
#include <string.h>

int GameMain(); //ゲームのメイン処理


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{	


	ChangeWindowMode( TRUE ) ;// ウインドウモードで起動
	
    if( DxLib_Init() < 0 ) return -1;// DXライブラリの初期化
	
	SetDrawScreen( DX_SCREEN_BACK ) ;// 描画先を裏画面にする
    MapListDate();
	PlayerFormat();
	MapFormat(1);

	while( ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){

		ClearDrawScreen(); //画面をクリアにする
		
		GameMain();

        ScreenFlip() ;// 裏画面の内容を表画面に反映
	
	}
	MapDelete();
    DxLib_End();// DXライブラリの後始末

	return 0;

}

int GameMain()
{
	static int evnum;
	static int walkflag;
	static int scrx,scry;
	POS_XY pos;
	PLMOVE plmove;

	pos=GetPlayerPos();

	evnum=GetMapEvent(pos);

	MapEventList(evnum);

	DrawFormatString(20,50,GetColor(255,0,0),"%d %d",evnum,walkflag);

	MapDraw(scrx,scry);
		
	MapChange();

	PlayerDraw( );

	plmove=PlayerMove(&scrx,&scry);

	walkflag=GetMapWalkFlag(plmove);

	PlayerWalk(&scrx,&scry,walkflag);
		
	PlayerAnimation();

	return 0;
}
Map.c

コード:

#include "DxLib.h"
#include "Map.h"
#include "Player.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct MAP
{
	char m_filename[226];
	int m_xnum;//縦と横のマップチップの数 
    int m_ynum; 
	int *m_map; //マップの地形データ
	char m_graphname[256];
	int m_chipnumx,m_chipnumy; //マップチップの画像の縦と横の数
	int *m_mapchip; //画像を入れとく
	int *m_maplayer[10]; //マップのレイヤーの情報
};

struct MAPLIST
{
	char m_filename[225];
};

static struct MAP mp;

static struct MAPLIST mpl[10];

int nowmap;

int MapListDate()
{
	int fp;
	if ((fp=FileRead_open("list.txt")) == NULL){ //ファイル一覧が書いてあるファイルを開く。
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        DxLib_End(); //プログラムを終了する
        exit(1);
    }
	int i;
	for(i=0;i<=1;i++){
		FileRead_gets( mpl[i].m_filename, 256, fp ) ; //1行読み込む
	}
	 
    FileRead_close(fp ) ;// ファイルを閉じる
	return 0;
}

int MapFormat(int now)
{	
	char filename[255]={'\0'};
	strncpy(filename, mpl[now].m_filename,sizeof(mpl[now].m_filename) );
    int fp; //ファイルぽいんた

    /* ファイルを開く */
    if ((fp=FileRead_open(filename)) == NULL){
		DrawFormatString(0,0,GetColor(255,0,255),"ファイルが存在しません。プログラムを終了します。\n");
        DxLib_End();
        exit(1);
    }

	strncpy(mp.m_graphname, "マップチップ.png", sizeof(mp.m_graphname));
	mp.m_chipnumx=1; //マップチップ画像の縦横の数
	mp.m_chipnumy=1; //

	FileRead_scanf(fp,"%d",&mp.m_xnum);//マップの横の数
	FileRead_scanf(fp,"%d",&mp.m_ynum);//マップの縦の数

	 /* データ処理 */

    mp.m_map= (int *)calloc( (mp.m_xnum * mp.m_ynum), sizeof( int ) ); 
	mp.m_mapchip= (int *)calloc( (mp.m_chipnumx * mp.m_chipnumy), sizeof( int ) ); 
	mp.m_maplayer[EVENT]= (int *)calloc( (mp.m_xnum * mp.m_ynum), sizeof( int ) ); 

	int i,j;
	

	for(j=0;j<mp.m_ynum;j++){
		for(i=0;i<mp.m_xnum;i++){
			FileRead_scanf(fp,"%d",&mp.m_map[mp.m_xnum*j+i]);
		}
	}
	for(j=0;j<mp.m_ynum;j++){
		for(i=0;i<mp.m_xnum;i++){
			FileRead_scanf(fp,"%d",&mp.m_maplayer[EVENT][mp.m_xnum*j+i]);
		}
	}
	LoadDivGraph(mp.m_graphname, (mp.m_chipnumx*mp.m_chipnumy) , mp.m_chipnumx , mp.m_chipnumy ,32,32,mp.m_mapchip);//マップチップの読み込み

	FileRead_close(fp); //ファイルを閉じる

	return 0;
}


int MapDraw(int scrx,int scry)
{        

	int i,j;
	
	for(i=0;i<mp.m_xnum;i++){

		for(j=0;j<mp.m_ynum;j++){
			int n=mp.m_xnum*j+i;
			if(mp.m_map[n]==1){
				DrawGraph(scrx+MAP_SIZE*i,scry+MAP_SIZE*j,mp.m_mapchip[0],TRUE);//マップの描画
			}
		}
	}

	
	DrawFormatString(20,20,GetColor(255,0,0), " %d %d %d %s %s %s ",mp.m_xnum,mp.m_ynum,mp.m_map[12],mp.m_graphname,mpl[0].m_filename,mpl[1].m_filename);
	return 0;
}

int MapDelete()
{    
	 int i;
	 for (i=0;i<mp.m_chipnumx*mp.m_chipnumy-1;i++){
		 DeleteGraph( mp.m_mapchip[i] ) ; //画像の消去
	 }
	
	 free( mp.m_map );//メモリの解放
	 free( mp.m_mapchip );//メモリの解放

	 return 0;
}

int MapChange()
{
	if(CheckHitKey(KEY_INPUT_A)==1){
		MapDelete();
		MapFormat(0);
	}
	if(CheckHitKey(KEY_INPUT_S)==1){
		MapDelete();
		MapFormat(1);
	}
	

	return 0;
}

int GetMapEvent(POS_XY pos)
{
	int evnum=0;
	int nowposx,nowposy;

	
	nowposx=pos.plposx/MAP_SIZE;
	nowposy=pos.plposy/MAP_SIZE;

	if(mp.m_maplayer[EVENT][nowposx+nowposy*mp.m_xnum]==1)evnum=1;
	DrawFormatString(20,70,GetColor(255,0,0), " %d %d",nowposx,nowposy);
	return evnum;
}

int MapEventList(int evnum)
{
	switch(evnum){
		case 1:
		MapDelete();
		MapFormat(1);
		break;}
	return 0;
}

int GetMapWalkFlag(PLMOVE plmove)
{
	int walkflag;
	int pos_lux=plmove.plposx/MAP_SIZE,pos_luy=plmove.plposy/MAP_SIZE;//←上
	int pos_rux=(plmove.plposx+25)/MAP_SIZE,pos_ruy=plmove.plposy/MAP_SIZE;//右上
	int pos_ldx=plmove.plposx/MAP_SIZE,pos_ldy=(plmove.plposy+32)/MAP_SIZE;//左下
	int pos_rdx=(plmove.plposx+25)/MAP_SIZE,pos_rdy=(plmove.plposy+32)/MAP_SIZE;//右下の位置の取得

	if(mp.m_map[mp.m_xnum*pos_luy+pos_lux]==0 || mp.m_map[mp.m_xnum*pos_ruy+pos_rux]==0 || 
		mp.m_map[mp.m_xnum*pos_ldy+pos_ldx]==0 || mp.m_map[mp.m_xnum*pos_rdy+pos_rdx]==0){
			walkflag=1;//歩けない
	}else{
		walkflag=0;//歩ける
	}
	return walkflag;
}
Map.h

コード:

#ifndef MAP_H //二重include防止
#define MAP_H
#include "Player.h"
#include <stdio.h>
#include <stdlib.h>

#define MAP_SIZE    32          // マップチップ一つのドットサイズ
#define MAP_WIDTH   5         // マップの幅
#define MAP_HEIGHT  5         // マップの縦長さ

enum MAPLAYER
{
	EVENT,//eventのレイヤ
};


//-----------------------------
//マップの情報の構造体
//-----------------------------
struct MAP;

struct MAPLIST;

//----------------
//マップを書く
//----------------

// 名前 int MapDraw(int scrx,int scry);
// 引数 int scrx x方向のスクロール数,int scry y方向のスクロール数
// マップチップを書く
extern int MapDraw(int scrx,int scry); //マップを書く

//----------------
//マップの初期化など
//----------------

// 名前 int MapFormat();
// 引数 無
// マップの初期化
extern int MapFormat(int now);

// 名前 int MapDelete();
// 引数 無
// マップ情報の消去
extern int MapDelete();

// 名前 int MapListDate();
// 引数 無
// list.txtの読み込み
extern int MapListDate();

// 名前 int MapChange();
// 引数 無
// AとSでマップ移動
extern int MapChange(); 

// 名前 int GetMapEvent();
// 引数 POS_XY pos
// 戻り値 現在地のイベント
// 0 イベントなし それ以外 何かしらのイベント
extern int GetMapEvent(POS_XY pos);

// 名前 int MapEventList(int evnum);
// 引数 int evnum
// 引数に対応するイベントを発生させる
extern int MapEventList(int evnum);

// 名前 int GetMapWalkFlag(PLMOVE plmove);
// 引数 PLMOVE plmove
// 戻り値 int walkflag
// 歩ける場所か
extern int GetMapWalkFlag(PLMOVE plmove);


#endif 
Player.c

コード:

#include "DxLib.h"
#include "Player.h"
#include "Map.h"

#define ASPEED 10

	int newx,newy; //新しいx.y座標
	int newsx,newsy; //新しいスクロール量
	static int oldposx,oldposy;//古いx.y座標
	static int oldscrx,oldscry;//古いスクロール量
struct PLAYER
{
	int m_vplayerx,m_vplayery; //画面上のプレイヤーの座標
	int m_movex,m_movey; //移動した距離
	int m_moveflag; //現在歩いているかのフラグ
	int m_walkflag; //歩ける場所か
	int m_scrx,m_scry ; //スクロールした距離
	int m_mplayerx,m_mplayery; //マップ上のプレイヤーの座標
	int m_handle[20]; //キャラの画像
	int m_nowhandle; //現在の画像
	int m_sp; //歩く速さ
	int m_mcount; //アニメーションさせるカウント
	int m_img; //プレイヤーの画像番号
	DIRECTION direction;
};
static struct PLAYER pl;
//---------------
//プレイヤーのアニメ―ション 縦 横 速さ ハンドル
//---------------
void PlayerAnimation()
{
	pl.m_mcount++; //アニメのカウント+1
	pl.m_img=(pl.m_mcount%(4*ASPEED))/ASPEED; //アニメションさせる
	if(pl.m_img==3)pl.m_img=1; //pl.m_img==3ならpl.m_img=1
	if(pl.m_mcount>=(4*ASPEED))pl.m_mcount=0; //アニメのカウントを0に戻す
}

void PlayerDraw( )
{
	int n[4];
	n[(int)UP] = 0;
	n[(int)DOWN] = 6;
	n[(int)RIGHT] = 3;
	n[(int)LEFT] = 9;

	
	if(pl.m_moveflag == 0) { //歩いているかのフラグ
		pl.m_nowhandle=n[(int)pl.direction]+1;
	}
	else{ 
		if(pl.m_moveflag == 1) { //歩いているかのフラグ
			pl.m_nowhandle=n[(int)pl.direction ]+pl.m_img;
		}
	}

	DrawGraph(pl.m_vplayerx,pl.m_vplayery,pl.m_handle[pl.m_nowhandle],TRUE);
	
}	

void PlayrProcess(void)
{

}


PLMOVE PlayerMove(int *scrx,int *scry)
{
	PLMOVE plmove;
	oldposx=pl.m_mplayerx;//前のx座標を代入
	oldposy=pl.m_mplayery;//前のy座標を代入
	oldscrx=*scrx;//前のスクロールxの代入
	oldscry=*scry;//前のスクロールyの代入

	newsx=*scrx; //現在のスクロールxの代入
	newsy=*scry; //現在のスクロールyの代入
	newx=pl.m_mplayerx; //現在のx座標を代入
	newy=pl.m_mplayery; //現在のy座標を代入

	if(CheckHitKey(KEY_INPUT_UP)==1){//上に移動
		pl.direction=UP ;
		newsy+=pl.m_sp ;
		newy-=pl.m_sp;
	}
	if(CheckHitKey(KEY_INPUT_DOWN)==1){//下に移動
		pl.direction=DOWN ;
		newsy-=pl.m_sp ;
		newy+=pl.m_sp;
	}
	if(CheckHitKey(KEY_INPUT_LEFT)==1){//左に移動
		pl.direction=LEFT ;
		newsx+=pl.m_sp ;
		newx-=pl.m_sp;
	}
	if(CheckHitKey(KEY_INPUT_RIGHT)==1){//右に移動
		pl.direction=RIGHT ;
		newsx-=pl.m_sp ;
		newx+=pl.m_sp;
	}

	if(newx != pl.m_mplayerx || newy != pl.m_mplayery){
		pl.m_moveflag=1;
	}else{
		pl.m_moveflag=0; //動いたら、動いたフラグを建てる
	}

	plmove.plposx=newx;
	plmove.plposy=newy;
	plmove.scrx=newsx;
	plmove.scry=newsy;

	DrawFormatString(0,0,GetColor(255,0,0), "mx%d my%d %d  %d  %d  %d %d %d",pl.m_mplayerx,pl.m_mplayery,pl.m_vplayerx,
		pl.m_vplayery,pl.m_scry,pl.m_img,oldscrx,oldscry);
	return plmove;
}
int PlayerWalk(int *scrx,int *scry,int walkflag)
{
	if(walkflag==0){ //歩ける
		*scrx=newsx;
		*scry=newsy;
		pl.m_mplayerx=newx; //x座標を代入
		pl.m_mplayery=newy; //y座標を代入

	}else{
		*scrx=oldscrx;
		*scry=oldscry;
		pl.m_mplayerx=oldposx; //x座標を代入
		pl.m_mplayery=oldposy; //y座標を代入
			
	}
	return 0;
}


//----------------
//初期化
//----------------
int PlayerFormat()//データの初期化
	
{  
	pl.m_sp=1;
	pl.m_mplayerx=300;
	pl.m_mplayery=200;
	pl.m_vplayerx = pl.m_mplayerx-pl.m_scrx;
	pl.m_vplayery=pl.m_mplayery-pl.m_scry; //画面上のプレイヤーの座標
	pl.direction=UP;
	LoadDivGraph("キャラ.png",12,3,4,23,32,pl.m_handle);
	return 0;

}

POS_XY GetPlayerPos()
{
	POS_XY pos;
	pos.plposx=pl.m_mplayerx;
	pos.plposy=pl.m_mplayery;
	return pos;
}
Player.h

コード:

#ifndef PLAYER_H //二重include防止
#define PLAYER_H

//-----------------------------
//向きの定数
//-----------------------------
enum DIRECTION
{
	UP, //上の時
	DOWN, //下の時
	RIGHT, //右右右右右右右右ィーーーーーッ
	LEFT, //左の時
};

//-----------------------------
//プレイヤーの情報の構造体
//-----------------------------
struct PLAYER;

//-----------------------------
//プレイヤーの座標
//-----------------------------
struct POS_XY
{
	int plposx; //プレイヤーの座標
	int plposy; //
};

struct PLMOVE
{
	int plposx; //プレイヤーの座標
	int plposy; //
	int scrx;
	int scry;
};

//---------------
//プレイヤーの処理
//---------------

// 名前---
// 引数---
//---
extern void PlayrProcess(void); //プレイヤーの基本処理

// 名前 PLMOVE PlayerMove(int *scrx,int *scry);
// 引数 int *scrx x方向のスクロール数,int *scry y方向のスクロール数
// 戻り値 移動後の座標とスクロール量
// プレイヤーの移動処理
extern PLMOVE PlayerMove(int *scrx,int *scry); //プレイヤーの移動処理

// 名前 int PlayerFormat();
// 引数 無
// プレイヤーの初期化
extern int PlayerFormat(); //データの初期化

//---------------
//プレイヤーの描画 
//---------------

// 名前 void PlayerDraw();
// 引数 無
// プレイヤーの描画
extern void PlayerDraw(); //プレイヤーの描画

// 名前 void PlayerAnimation();
// 引数 無
// プレイヤーのアニメーション
extern void PlayerAnimation(); //プレイヤーのアニメーション 

// 名前 void GetPlayerPos();
// 引数 無
// 戻り値 プレイヤーのマップ座標
// プレイヤーのマップ座標を返す
extern POS_XY GetPlayerPos(); //プレイヤーの座標の取得 

// 名前 int PlayerWalk(int *scrx,int *scry,int walkflag);
// 引数 int *scrx xのスクロール量 int *scry yのスクロール量 int walkflag 歩ける場所かのフラグ
// プレイヤーを移動させる
extern int PlayerWalk(int *scrx,int *scry,int walkflag);

#endif 
乗せた目的は、いろいろ変えたとこがあるので、おかしいことをしてるかもしれないから、そのためです。
>座標しかやり取りしないと思うのでstruct point{ int x,y; }程度じゃないでしょうか。
その構造体は、どこに宣言すべきですか?

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

Re: 本格的なrpg マップ処理。

#72

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

> その構造体は、どこに宣言すべきですか?

共通で利用するヘッダを用意して宣言すべきです。
common.hなど。

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

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

Re: 本格的なrpg マップ処理。

#73

投稿記事 by ISLe » 10年前

そもそもどうして家に入る前の位置が必要なのでしょう。
扉から出たら扉の前に立たせれば良いのでは。
家から出たときに最初に立っている位置は固定で良く、その位置はフィールドに配置した家が知っているはずの情報で、フィールド上のオブジェクト同士で連携する必要はないと思います。

仮にドラクエのルーラのような魔法で家にワープしたら、次に家から出たとき、どこに出現するのでしょう。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#74

投稿記事 by heyman » 10年前

ISLe さんが書きました:そもそもどうして家に入る前の位置が必要なのでしょう。
扉から出たら扉の前に立たせれば良いのでは。
家から出たときに最初に立っている位置は固定で良く、その位置はフィールドに配置した家が知っているはずの情報で、フィールド上のオブジェクト同士で連携する必要はないと思います。
家に入る前の位置とは、家に入るのに使ったイベントの一歩手前の事ですか?簡単に,家に入るイベントの位置を書くとすると、1の位置
です。そして、家に入る前の位置とは□の位置です。□の位置は、計算により出されます。よって、家に入るイベントの位置が決まると、
自動的に家に入る前の位置が決まるというわけです。

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 □ 0 0 0
ISLe さんが書きました:仮にドラクエのルーラのような魔法で家にワープしたら、次に家から出たとき、どこに出現するのでしょう。
普通にその家へと移動す為のイベントがある位置の一歩手前になります。
家は、イベント1なら1の家、2なら2の家に移動という風にするつもりで、
例えば2の家にワープしてその家から出たら、2のイベントの一歩手前に移動させます。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#75

投稿記事 by heyman » 10年前

それと、マップ移動時のキャラの初期値の移動の事ですが、
関数を新しくMap.h内に、GetMoveAfterPos();とPlayer.h内に、ChangePlayerPos(pos,scrx,scry);
を追加しました。GetMoveAfterPos();というのは、マップ移動したのちのキャラクターの初期位置を、POS_XYで
戻り値を返します。ChangePlayerPos(POS_XY pos,int *scrx,int *scry);は、プレイヤーの位置を
引数の値に移動できます。これらを、イベントでマップ移動した時1回だけ呼ぶということがしたいのですが、
どうしたらいいかわかりません。イベントでマップを移動したときに位階だけ呼び出すというのは、プログラムを
どういう感じで組めばいいですか?

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

Re: 本格的なrpg マップ処理。

#76

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

とりあえず、GameMain()において状態の変化とデータの流れが非常に見えづらいです。
呼び出している関数の中を見に行かないと、いつどんな条件で動作するかが見えないからです。

これはif文などの条件分岐で、必要なときだけ必要な関数を呼ぶようにしないとメンテやデバッグが困難です。

>どうしたらいいかわかりません。イベントでマップを移動したときに位階だけ呼び出すというのは、プログラムをどういう感じで組めばいいですか?

マップチェンジ状態にGameMain()を遷移させればどうでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#77

投稿記事 by heyman » 10年前

>マップチェンジ状態にGameMain()を遷移させればどうでしょう。
どういうことでしょうか?

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

Re: 本格的なrpg マップ処理。

#78

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

要はマップチェンジ中と言う状態が有るわけですよね。
ならば、その状態の時だけ呼び出すプログラム流れを作ればよいのです。
状態変数を用意してif文などで分岐します。これを状態遷移と呼びます。
あるいは、GameMain()よりも上位でマップチェンジ状態に遷移するかです。わかりやすさで決めてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: 本格的なrpg マップ処理。

#79

投稿記事 by ISLe » 10年前

heyman さんが書きました:
ISLe さんが書きました:仮にドラクエのルーラのような魔法で家にワープしたら、次に家から出たとき、どこに出現するのでしょう。
普通にその家へと移動す為のイベントがある位置の一歩手前になります。
家は、イベント1なら1の家、2なら2の家に移動という風にするつもりで、
例えば2の家にワープしてその家から出たら、2のイベントの一歩手前に移動させます。
例が悪かったですね。
ある場所からワープすると入れる家があって、扉は出ることだけができるとしたら、家に入るイベントの場所は存在しないわけですが、その場合はどうなりますか?

家に入るイベントと家を出るイベントを完全に分けてしまえば良いと思うのですが。

関連付けてどんどん積み重ねていくと先に進んでいる実感はあるかもしれません。
ですが、プログラムの設計という点では関連付けることはしがらみを増やすことです。
どんどん身動きが取れなくなって変更や修正のために全部壊さないといけなくなりますよ。

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

Re: 本格的なrpg マップ処理。

#80

投稿記事 by ISLe » 10年前

マップチェンジ後に発生するイベントというのを用意してそこで各種パラメータを設定すれば、すべてイベントシステムに集約できると思います。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#81

投稿記事 by heyman » 10年前

ISLe さんが書きました:例が悪かったですね。
ある場所からワープすると入れる家があって、扉は出ることだけができるとしたら、家に入るイベントの場所は存在しないわけですが、その場合はどうなりますか?家に入るイベントと家を出るイベントを完全に分けてしまえば良いと思うのですが。
そういう意味でしたか、俺の書き方も悪かったですが、家を出たときの位置の入った時の
イベントの一歩手前というのは、家は、自由な場所にたてられるので、出た場所の計算として
入るためのイベントを使用してるだけで、出るイベントと、入るイベントは別です。
そして、まだ出るイベントは、完成してないので、絶対そうなるとは言えませんが、
予定としては、出た場所は、家特有のマップデータとして、構造体で扱ろうと思いますので、
もともとある家なら出る場所は、固定なので大丈夫です。出る場所の構造体の情報は、
出る先のマップと、位置を入れようと思います
ISLe さんが書きました: 関連付けてどんどん積み重ねていくと先に進んでいる実感はあるかもしれません。
ですが、プログラムの設計という点では関連付けることはしがらみを増やすことです。
どんどん身動きが取れなくなって変更や修正のために全部壊さないといけなくなりますよ。
参考にします。

あと、家に入った時、一回イベントを発生させるというのは、一様出来ました。
MapEventListで、マップ移動系のイベントの時は、戻り値で、それを伝えて、
ifで条件分岐し、必要に応じて関数をよんで処理をするということになりました。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#82

投稿記事 by heyman » 10年前

マップの初期化とマップ移動についてですが、list.txtファイルの中に、マップ名のほかに、
家や、フィールドを識別するための、値も一緒に入れておき、マップ移動するときに、
移動先が家の場合、家を出た位置の情報が、マップの初期化に追加させるという方法を考えたのですが、
どうでしょうか?
つまり

list.txtを呼ぶ => MAPLIST関数の中に、全マップ分の名前、種類を入れる、この時、構造体の中に、
マップの種類を表すメンバを追加しておく => 初期化の際、

初期化関数()


  共通のマップデータの初期化
  if(家の場合){
      家をでた時の位置の初期化
  }


みたいな感じで分ける。みたいなことをしようと思いますが、どうでしょうか?
あと、マップ初期化の際に、データをいちいちファイルからMAP構造体に
直接代入してるので、ファイル=>マップの情報をもとから入れとく構造体=>
MAP構造体
という風にしょうと思います。どうでしょうか?

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

Re: 本格的なrpg マップ処理。

#83

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

長くなってきたのでトピックを分けたほうが良いかもしれませんね。

さて質問ですが
  共通のマップデータの初期化
  if(家の場合){
      家をでた時の位置の初期化
  }
ISLeさんの言いたい事は後々困るので特殊な処理を増やすなって事なので、マップ毎に結びついた専用の初期化(イベント)でやれば良いことを汎用にするなって事でしょう。
中核のコードに出来るだけ特殊な条件のコードが出てこないように意識してみてください。
今回の建てられる家も、汎用的な処理でできるだけ済ませられるようにすることが第一です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#84

投稿記事 by heyman » 10年前

softya(ソフト屋) さんが書きました:  共通のマップデータの初期化
  if(家の場合){
      家をでた時の位置の初期化
  }

ISLeさんの言いたい事は後々困るので特殊な処理を増やすなって事なので、マップ毎に結びついた専用の初期化(イベント)でやれば良いことを汎用にするなって事でしょう。
中核のコードに出来るだけ特殊な条件のコードが出てこないように意識してみてください。
今回の建てられる家も、汎用的な処理でできるだけ済ませられるようにすることが第一です。
ifを付けずに済む方法を考えるということですか?

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

Re: 本格的なrpg マップ処理。

#85

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

> ifを付けずに済む方法を考えるということですか?
はい出来るだけ条件は排除してください。
if文を付けるのは屈辱だぐらい意識しておいたほうが良いです。
どうしようも無い場合や、そのほうが分かりやすくメンテナンス性が高い場合もありますが、そこは直す手間で分かるはずです。
と言っても経験値がモノ言うので今の出来る範囲で行ってください。
最近また直したなと思う箇所があったらイエロー・アラートです。
面倒だなとかバグ多発ならレッド・アラートです。
「意識すれば段々楽になるよとISLeさんは言っている」と私は思うのです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

heyman
記事: 99
登録日時: 10年前

Re: 本格的なrpg マップ処理。

#86

投稿記事 by heyman » 10年前

なら家を作った時に、家を出た時の位置を記録しようと思いますがどうでしょうか?
つまり、

家建てる=>その家の構造体の中の、家を出た位置のxy座標をその時設定する
という風です

あと、フィールドマップでは、家を出た位置のxy座標を設定する必要がないので、
値をNULLとかにしといたほうがいいですか?

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

Re: 本格的なrpg マップ処理。

#87

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

>あと、フィールドマップでは、家を出た位置のxy座標を設定する必要がないので、
>値をNULLとかにしといたほうがいいですか?

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

閉鎖

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