マップ画面での情報の渡し方について教えてください

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

マップ画面での情報の渡し方について教えてください

#1

投稿記事 by たなごころ » 3週間前

始めまして。
こんばんはございます、たなごころです。
既出でしたらお恥ずかしいですが、マップ画面での情報の渡し方について質問です。

現在、ローグライク風なゲームのマップ画面を製作しています。
マップのイメージとしては、RPGツクールでできるような、x座標y座標にパネルが何枚もあってその上を移動できるというものです。

それで作っていく上で疑問に感じたのが情報の渡し方です。
例えば主人公が移動する時であれば、「移動先のパネルが通行可能かどうか」の判定をする必要がありますが、現在、主人公の情報が入っているCreatureクラスとパネル情報が入っているPanelクラスは別ものです。

そのため必要な情報を渡す必要があります。
一番に思いついたのが毎回の移動処理を呼ぶときに必要なクラス情報を渡すというものですが、何度も渡すのはコストがかかると思います。
そこで今はCreatureクラスのインスタンス化の際に、全Panelクラスを管理するstd::vector<std::vector<Panel*>>をポインタで渡しています。
そうすることで毎回の移動処理を呼ぶときには引数が必要なく済んでいるのですが、この方法でいいのか意見を聞きたいです。

あと書いていてふと思いましたが、Panelクラス以外のクラスも必要になる場合もあるでしょう。
そのため「Creatureに渡すクラスを取りまとめたクラス」でも用意するべきでしょうか。

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#2

投稿記事 by usao » 3週間前

>「移動先のパネルが通行可能かどうか」の判定をする必要
が生じる処理を行う箇所に対しては,
std::vector<std::vector<Panel*>> なる「具体的なデータ」を渡す必要は無く,
「必要な判定を行うための手段」を渡せばよいのではないでしょうか.

例えば,「座標(x,y)が通行可能な場所であるか否かを判定する」ことだけが必要であれば,
その判定処理メソッドを有するインタフェースクラスとかの形で渡す.

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#3

投稿記事 by usao » 3週間前

(クラス名やメソッド名が微妙だけど)前記した事柄をコードっぽく.

コード:

//Creatureが移動方向の意思決定を行うのに必要な情報を提供する
class IMapInfo
{
public:
  //座標(x,y)が通過可能であるか否かを調べる
  virtual bool IsWalkable( int x, int y ) const = 0;
  ...
};


class Creature
{
  ...
public:
  //移動に関する意思決定を行う.
  //戻り値:何か移動に関する決定結果
  MoveDecision DecideMove( const IMapInfo &Info );
};

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#4

投稿記事 by usao » 3週間前

> そこで今はCreatureクラスのインスタンス化の際に、全Panelクラスを管理するstd::vector<std::vector<Panel*>>をポインタで渡しています。
> そうすることで毎回の移動処理を呼ぶときには引数が必要なく済んでいるのですが、この方法でいいのか意見を聞きたいです。

毎回渡してもコストがどうのということはそうそう無いと思うけど,
引数渡しが面倒だとかで,最初に渡しておくとしても
> std::vector<std::vector<Panel*>>をポインタ
という実際のデータ(なんですよね?)へのポインタそのものを渡してしまうような形だと,
マップの情報が変化したとき(別のマップに行ったときとか)はどうするのか,とか別の面倒が生じるから,あまり楽にならない.
(コンストラクタで注入するにしても,前記IMapInfoのようなのを注入するほうが楽な予感)

たなごころ
記事: 5
登録日時: 3週間前

Re: マップ画面での情報の渡し方について教えてください

#5

投稿記事 by たなごころ » 3週間前

usao さんが書きました:
3週間前
>「移動先のパネルが通行可能かどうか」の判定をする必要
が生じる処理を行う箇所に対しては,
std::vector<std::vector<Panel*>> なる「具体的なデータ」を渡す必要は無く,
「必要な判定を行うための手段」を渡せばよいのではないでしょうか.

例えば,「座標(x,y)が通行可能な場所であるか否かを判定する」ことだけが必要であれば,
その判定処理メソッドを有するインタフェースクラスとかの形で渡す.
言葉だけは知っていましたがインタフェースクラスというものを使えばいいんですね。
たしかに必要最低限の機能だけを渡せばスマートだし安心して使えますね。
おっしゃる通りマップ移動の場合も楽に対応できそうです。
サンプルソースの提示も含めてありがとです。

自分でまた調べますが、何となくこんな使い方かなとプログラムしてみたので、もし気が向けばレビューでももらえると嬉しいです。

コード:

#include <iostream>
using namespace std;

class IMapInfo
{
public:
	//座標(x,y)が通過可能であるか否かを調べる
	virtual bool IsWalkable(int x, int y) const = 0;
};

class Map : public IMapInfo
{
public:
	virtual bool IsWalkable(int x, int y) const {
		//(1,3)は通行不可とする
		return (x == 1 && y == 3) ? false : true;
	}
};

class Creature
{
private:
	int _x, _y;	//現在の座標

public:
	Creature() { _x = 1; _y = 2; }
	
	//移動する
	void Move(Map *map) {
		int vx = 0;	//x方向移動量
		int vy = 1;	//y方向移動量
		if (CanMove(*map, vx, vy)) {
			_x += vx;
			_y += vy;
			printf("Move Success\n");
		}
		else {
			printf("Move Failed\n");
		}
	}

	//移動に関する意思決定を行う.
	//戻り値:移動可能か.
	bool CanMove(const IMapInfo &info, int vx, int vy) {
		return(info.IsWalkable(_x + vx, _y + vy)) ? true : false;
	}
};

int main(void) {
	Map *map = new Map();
	Creature *player = new Creature();
	
	player->Move(map);	
}

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#6

投稿記事 by usao » 3週間前

Creature::Move()の引数の型を Map* とする何らかの理由があるのでしょうか.
(Map型に用が無いならば,const IMapInfo & とかでよくないですか?)

たなごころ
記事: 5
登録日時: 3週間前

Re: マップ画面での情報の渡し方について教えてください

#7

投稿記事 by たなごころ » 3週間前

ほんとですね。特別な理由はないです、見落としてました。
IFの概念の理解と使い方がわかり感謝です。
ありがとうございました。

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#8

投稿記事 by usao » 3週間前

本題とはあまり関係ない,好みの話(?)ですが,

コード:

class Creatrue
{
	//動く.
	//	引数に与えられた情報を使って
	//	自身の座標を(ゲームのルール上,妥当である座標に)変更する
	void Move( 引数省略 );
};
という形よりも

コード:

//CreatureがDecideMove()で返した内容は,上位の存在(?)によって吟味され,
//その内容が許可された場合は,移動先がMoveTo()に渡されるので,Creatureは晴れて移動できる.
//却下された場合はMoveTo()がコールされないので,Creatureはその場に留まる結果になる.
class Creatrue
{
	//引数に与えられた情報を参考に,
	//「俺はこう動きたいぜ」という意思を決定して,その情報を返す
	MoveDecision DecideMove( 引数省略 ) const;
	
	//動く(=座標を更新する).
	//	引数の形は色々考えられるけれども…
	//	例えばこの形の例だと,自身の座標を(x,y)に変更する.
	//	(指定された座標(x,y)がゲームのルール上どうなのかは知ったことでは無く,言われた通りにする)
	void MoveTo( int x, int y );
};
みたいな形の方が,実装を書くのが何となく楽な気がする.

たなごころ
記事: 5
登録日時: 3週間前

Re: マップ画面での情報の渡し方について教えてください

#9

投稿記事 by たなごころ » 2週間前

返信遅れてすいません。
適当な言い訳で申し訳ないですが寝てました。
参考にさせてもらいます。
つまりは(きっと)、移動するクラスに視点をおいたとき、移動要求と実際の移動処理を分離することで、間に他クラスによる処理を挟めるから柔軟性があったり管理がしやすいということですね。

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#10

投稿記事 by usao » 2週間前

あくまでも
>何となく楽な気がする
という,気配的な(?)感じでしかない話ですが…

(1)
移動に関する(現在の)ルールをどこに実装するのか? という点に関する 好み かなぁ.
Creature::DecideMove()は,{いいかげんでも,賢くなくなくても,etc...}良い場所にしたいというか,
キャラクタの移動アルゴリズムに,移動可否のルールをどこまで考慮するかに関する自由度を持たせたい,というか?
(いろんな種類のキャラクタをあとからあとから実装するときに,その全ての種類の移動アルゴリズムに,「完全に(現在の)ルールに即した場所に移動せねばならない」という制約があるのは面倒な気がする)


(2)
>ローグライク
ってあまり経験無いので,誤解しているかもしれないけど,
複数のキャラクターが「同時に」動くようなのを想像.
 ↓
Creatureのインスタンスが複数存在して,
Creature::Move()が「移動先を判断して,即座に移動(座標更新)」という実装になっている場合だと,例えば

・CreatureAの移動先希望が位置Xで,CreatureBは位置Xから位置Yに動きたいみたいな場合
 (たまたまB側が先に処理されたらAも動けるが,逆順だとAは動けないの?)

みたいな話を扱い難いとか,そういうことがあったりするかも?とか.

たなごころ
記事: 5
登録日時: 3週間前

Re: マップ画面での情報の渡し方について教えてください

#11

投稿記事 by たなごころ » 1週間前

冗長な文章となってしまいますが、書いたほうが自分の考えの整理になると思ったので書きました。

(1)について。
 よくわかりませんでした。
 (誰かを攻めてるわけでもさらなる説明を求めてるわけでもないです。ただわからなかったのでわからないと書いただけで、他意はないです)

(2)について。
「同時に動く」という想像で大丈夫です。
それで危惧していることは、Move()をDecideMove()とMoveTo()に分離しなければ、Creatureごとに逐次的に移動処理を行わなければならない。
→すると全Creatureの移動処理というものに、確実に「優先順位」という概念が生まれる(Move()の中に「移動希望の決定処理」と「移動希望を許可する処理」と「移動処理」がつまっているため)
→そのため、全Creatureの移動希望情報を集めて、その上で全Creatureの移動処理を決めることができない。
→Creature間やCreatureと他クラスの間で、移動希望情報のやり取りが必要になれば、実装が大変だよ。

ということだと解釈しました。
たしかにそういうパターンもありそうです。
提示してくれた例のケースも、答えはどのような動作とするか決めかねてますが、場合によっては分離していたほうが楽ですね。

ちなみに作成中のゲームも、分離案を使わせてもらってます。
ありがとうございます。

アバター
usao
記事: 1406
登録日時: 5年前

Re: マップ画面での情報の渡し方について教えてください

#12

投稿記事 by usao » 1週間前

> (1)について
書いてる方も ふわっとした話 をしてるだけなので大丈夫です.
Creatureにいくつか種類があった場合,それぞれの「移動希望」の決定処理を,例えば

・馬鹿な敵:乱数で4方向のどれかを返すだけ
 (そっちに移動できないならそのターンは移動できなくてもいいです,という希望)
・ちょいまともな敵:地形は考慮する(壁の方に移動したいとは言わない)が,マップ上のオブジェクト(他のCreatureとか)があることまでは考えない
 (結果として,そっちに移動できないなら…同上)
・賢い敵:他のオブジェクト等を考慮した経路探索処理をしっかり行った結果を返す

という感じで「書きたいかも/書けるようにしたいかも」という程度の話ですね.
全ての処理に壁やらオブジェクトやらの判定処理を書かなくてもいいってのが楽かな,というか,そんな.
(賢い奴と上位側とで多重に壁の判定を行うみたいな無駄っぽいことになりそうな面もある)


> (2)について。
そんな感じです.
移動先の決定を行う上位側の処理は,必要ならば(複数のCreatureの希望がかち合った場合とかに)Creatureに第二希望を問うたりもできるかもですし.

返信

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