ページ 11

RPGなどのアイテム処理

Posted: 2011年6月17日(金) 18:16
by ゆきなす
RPGなどのアイテム処理プログラムを作ってみたのですがうまくいきません。
どこがおかしいのか御教授お願いします。

※アイテムデータセットの最初が "9999" なのは "0" にするとソートをした時に一番最初に来てしまいfor文がbreakされるのを防ぐためです(ソート関数は省略しています)

コード:

#include <iostream>
using namespace std;

int ItemEquipment(int PlayerEquipBox, int PlayerItemBox);
void ItemDataGet(int PlayerItemBox, int GetItem);
int AddItem(int GetItem);
int DeleteItem(int PlayerItemBox);

//----------define----------
#define NOT_ITEM 0
#define ITEM_NORMAL 1
#define ITEM_EQUIP 2
#define ITEM_EVENT 3

#define Equipment_MAX 4
#define HAVE_MAX 10

//----------アイテムデータ変数struct----------
struct RPG_ITEM_DATA
{
	int ItemNo;
	char *ItemName;
	int ItemType;
	int Have;
};
//----------プレイヤーデータstruct----------
struct PLAYER_DATA
{
	RPG_ITEM_DATA PlayerData[HAVE_MAX];
	RPG_ITEM_DATA PlayerEquipment[Equipment_MAX];
};
//----------アイテムデータセット----------
static RPG_ITEM_DATA DataItem[] =
{
	{9999, "なし", NOT_ITEM, 0,},
	{1, "薬草", ITEM_NORMAL, 1,},
	{2, "回復薬", ITEM_NORMAL, 1,},
	{3, "剣", ITEM_EQUIP, 1,},
	{4, "盾", ITEM_EQUIP, 1,},
	{5, "宝石", ITEM_EQUIP, 1,},
};

PLAYER_DATA Player;
//----------アイテム装備関数----------
int ItemEquipment(int PlayerEquipBox, int PlayerItemBox)
{
	Player.PlayerEquipment[PlayerEquipBox].ItemNo = Player.PlayerData[PlayerItemBox].ItemNo;
	Player.PlayerEquipment[PlayerEquipBox].ItemName = Player.PlayerData[PlayerItemBox].ItemName;
	Player.PlayerEquipment[PlayerEquipBox].ItemType = Player.PlayerData[PlayerItemBox].ItemType;
	Player.PlayerData[PlayerItemBox].Have--;

	return true;
}
//----------アイテム情報コピー関数----------
void ItemDataGet(int PlayerItemBox, int GetItem)
{
	Player.PlayerData[PlayerItemBox].ItemNo = DataItem[GetItem].ItemNo;
	Player.PlayerData[PlayerItemBox].ItemName = DataItem[GetItem].ItemName;
	Player.PlayerData[PlayerItemBox].ItemType = DataItem[GetItem].ItemType;
	Player.PlayerData[PlayerItemBox].Have += DataItem[GetItem].Have;
}
//----------アイテム取得/複数所持関数----------
int AddItem(int GetItem)
{
	int CopyGetItem = GetItem;

	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		//Player.PlayerData[i].ItemNo が CopyGetItem と同じなら
		if(Player.PlayerData[i].ItemNo == CopyGetItem)
		{
			//Player.PlayerData[i].Have に ++
			Player.PlayerData[i].Have++;
			return true;
		}

		//そうでないなら新規追加
		else if(Player.PlayerData[i].ItemNo == 9999)
		{
			ItemDataGet(i, GetItem);
			return true;
		}
	}

	return false;
}
//----------アイテム削除関数----------
int DeleteItem(int PlayerItemBox)
{
	for(int i = PlayerItemBox ; i < (HAVE_MAX - 1) ; i++)
	{
		Player.PlayerData[i].ItemNo = Player.PlayerData[i + 1].ItemNo;
		Player.PlayerData[i].ItemName = Player.PlayerData[i + 1].ItemName;
		Player.PlayerData[i].ItemType = Player.PlayerData[i + 1].ItemType;
		Player.PlayerData[i].Have = Player.PlayerData[i + 1].Have;
	}

	Player.PlayerData[HAVE_MAX - 1].ItemNo = DataItem[0].ItemNo;
	Player.PlayerData[HAVE_MAX - 1].ItemName = DataItem[0].ItemName;
	Player.PlayerData[HAVE_MAX - 1].ItemType = DataItem[0].ItemType;
	Player.PlayerData[HAVE_MAX - 1].Have = 0;

	return true;
}
//----------メイン関数----------
void main()
{
	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		Player.PlayerData[i].ItemNo = DataItem[0].ItemNo;
		Player.PlayerData[i].ItemName = DataItem[0].ItemName;
		Player.PlayerData[i].ItemType = DataItem[0].ItemType;
		Player.PlayerData[i].Have = 0;
	}
	//----------アイテム取得----------
	AddItem(1);			// 0番目 =  薬草
	AddItem(2);			// 1番目 =  回復薬
	AddItem(4);			// 2番目 =  盾 
	AddItem(5);			// 3番目 =  宝石
	AddItem(1);			// 複数所持テスト
	AddItem(3);			// 4番目 =  剣
	//----------アイテム削除----------
	DeleteItem(4);		// 4番目 =  剣

	cout << "所持アイテムの整理/抽出" << endl;
	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		if(Player.PlayerData[i].Have <= 0)
		{
			DeleteItem(i);
		}

		if(Player.PlayerData[i].ItemNo == 9999)
		{
			break;
		}
		
		cout << Player.PlayerData[i].ItemNo << " " << Player.PlayerData[i].ItemType << " " << Player.PlayerData[i].ItemName << " " << Player.PlayerData[i].Have << endl;
	}
	//----------アイテム装備----------
	ItemEquipment(0, 0);		//装備欄[0] に 所持アイテム[0]
	ItemEquipment(1, 1);		//装備欄[1] に 所持アイテム[1]
	ItemEquipment(2, 2);		//装備欄[2] に 所持アイテム[2]
	ItemEquipment(3, 3);		//装備欄[3] に 所持アイテム[3]

	cout << "\n装備アイテムの抽出" << endl;
	for(int i = 0 ; i < Equipment_MAX ; i++)
	{
		cout << Player.PlayerEquipment[i].ItemNo << " " << Player.PlayerEquipment[i].ItemType << " " << Player.PlayerEquipment[i].ItemName << endl;
	}

	cout << "\n所持アイテムの整理/抽出2" << endl;
	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		if(Player.PlayerData[i].Have <= 0)
		{
			DeleteItem(i);
		}

		//コメントアウト
		/*if(Player.PlayerData[i].ItemNo == 9999)
		{
			break;
		}*/
		
		cout << Player.PlayerData[i].ItemNo << " " << Player.PlayerData[i].ItemType << " " << Player.PlayerData[i].ItemName << " " << Player.PlayerData[i].Have << endl;
	}
}

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 18:18
by h2so5
どのような結果を望んでいて、どううまくいかないのかを教えてください。

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 18:20
by ゆきなす
上記のプログラムの実行結果です。

所持アイテムの整理/抽出
1 1 薬草 2
2 1 回復薬 1
4 2 盾 1
5 2 宝石 1

装備アイテムの抽出
1 1 薬草
2 1 回復薬
4 2 盾
5 2 宝石

所持アイテムの整理/抽出2
1 1 薬草 1
4 2 盾 0 ← おかしい所
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
続行するには何かキーを押してください . . .

こうなるのが理想像です
所持アイテムの整理/抽出2
1 1 薬草 1
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 19:04
by dic
最後の表示するときに期待したとおりの動作をしないようです

DeleteItem(i); でi 番号のアイテムを削除して、i+1 のアイテムのコピーを代入しているので
そのまま次の処理に流れて表示されています

私が改善したところ表示されませんでした

コード:

    cout << "\n所持アイテムの整理/抽出2 の前に整理" << endl;
	for( i=0; i<HAVE_MAX; i++ )
	{
		if( Player.PlayerData[i].Have <= 0 )
			DeleteItem(i);
	}

    cout << "\n所持アイテムの整理/抽出2" << endl;
    for(i = 0 ; i < HAVE_MAX ; i++)
    {
        if(Player.PlayerData[i].Have <= 0)
        {
            DeleteItem(i);
        }
 

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 19:29
by Tatu
アイテム装備後の表示で回復薬を消した後に
その場所に盾が来て、それが消されないまま表示されているようです。

これはアイテムの数が0であるものが2つ以上連続した場合はうまくいかないと
いうことなので、この場合に対応できるようにする必要があります。

アイテムの数が0でないかを確認し、0だったら消すという作業を一回だけではなく、
アイテムの数が0でなくなるか、「なし」になるかのどちらかまで繰り返すというやり方でどうでしょうか。


dicさんがコードを書いてますね。
整理のところでアイテムの数が0であるものが連続した場合を考えるとwhileなどの繰り返しが必要になるはずです。
また、整理ができているのならば、その後にアイテムを消す必要があるはずありません。

dicさんのコードで(盾が)表示されなくなっていることについては
整理で回復薬と宝石が消え、
表示時に盾が消されているので
うまくいっているように見えるだけだと思います。
アイテム名が「なし」でなく、かつ、アイテムの数が0であるものが4つ連続した場合はどうですか?

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 19:59
by ゆきなす
御返信ありがとうございます!!

dicさんのコードのように書くと理想像と同じようになるのですが、 AddItem(1);// 複数所持テスト をコメントアウト(Tatuさんの言うアイテム数の "0" が4つ連続した場合)すると以下のようになり、

所持アイテムの整理/抽出2
5 2 宝石 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0

dicさんのコードがない場合だと

所持アイテムの整理/抽出2
2 1 回復薬 0
5 2 宝石 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0
9999 0 なし 0

のようになってしまいます。

アイテム数 "0" が2つ異常連続した場合はうまくいかないと指摘を受けたので、それに対応できるようにしてみます。

Re: RPGなどのアイテム処理

Posted: 2011年6月17日(金) 23:20
by ゆきなす
以下の関数を追加することで理想像と同じ実行結果になり、アイテム数 "0" が2つ以上連続で出ても問題なくできるようになりました!!

~追加文

コード:

//----------アイテム削除関数----------
void SuperDeleteItem()
{
	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		for(int n = 0 ; Player.PlayerData[n].ItemNo != 9999 ; n++)
		{
			if(Player.PlayerData[n].Have <= 0)
			{
				DeleteItem(n);
			}

			else if(Player.PlayerData[n].Have > 0)
			{
				continue;
			}
		}
	}
}
~変更点

コード:

cout << "\n所持アイテムの整理/抽出2" << endl;
	for(int i = 0 ; i < HAVE_MAX ; i++)
	{
		SuperDeleteItem();

		//コメントアウト
		/*if(Player.PlayerData[i].Have <= 0)
		{
			DeleteItem(i);
		}*/

		//コメントアウト
		/*if(Player.PlayerData[i].ItemNo == 9999)
		{
			break;
		}*/
		
		cout << Player.PlayerData[i].ItemNo << " " << Player.PlayerData[i].ItemType << " " << Player.PlayerData[i].ItemName << " " << Player.PlayerData[i].Have << endl;
	}
御相談に乗ってくれた皆様方本当にありがとうございました!!