본문으로 바로가기

200818_Store_Inventory.zip
5.02MB

 

1. Item

더보기
#pragma once

class Store;
class ItemSlot;

enum ItemType
{
	None,
	Helmet,
	Armor,
	Boots,
	Gloves,
	Shield,
	Weapon,
};
//
struct ItemData
{
	int key;
	ItemType type;
	string name;
	int value;
	int price;
	float frameX;
	float frameY;

	ItemData()
		: key(0), type(None), name(""),
		value(0), price(0), frameX(0), frameY(0) {};
	//
	ItemData(int _key, ItemType _type, string _name,
		int _value, int _price, float _frameX, float _frameY)
		:key(_key), type(_type), name(_name),
		value(_value), price(_price), frameX(_frameX), frameY(_frameY) {}
	//
	~ItemData() {}
};
//
class Item
{
public:
	Store* store;
	Button* button;
	ItemData data;
	//
	ItemSlot* slot;

public:
	Item();
	Item(const ItemData& _data);
	~Item();
	//
	void Update();
	void Render();
	//
	void CreateButton(wstring file);
	//
	void ShowInfo();
	void SetStore(Store* value) { store = value; }
	//
	void SetButtonTextureFrame();
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Item.h"
#include "Store.h"
#include "ItemSlot.h"

Item::Item()
{
}

Item::Item(const ItemData& _data)
	:store(nullptr), button(nullptr), data(), slot(nullptr)
{
	data = _data;
	//
	CreateButton(L"Textures/Store/items.png");
	//
}

Item::~Item()
{
	delete button;
}

void Item::Update()
{
	button->Update();
}

void Item::Render()
{
	button->Render();
}

void Item::CreateButton(wstring file)
{
	Texture* texture = Texture::Add(L"Textures/Store/items.png");
	//
	button = new Button(texture, { 6.0f, 6.0f }, { data.frameX, data.frameY });
	//
	button->SetEvent(bind(&Item::ShowInfo, this));
}

void Item::ShowInfo()
{
	if(store)
		store->selectedItemData = data;
}

void Item::SetButtonTextureFrame()
{
	Vector2 textureFrame{ data.frameX, data.frameY };
	button->SetTextureFrame(textureFrame);
}

 

2. ItemSlot

더보기
#pragma once

#include "Object/BasicObject/Quad.h"
#include "Object/GameObject/Item.h"

class Inventory;

class ItemSlot
{
public:
	Quad* slot;
	Item* item;
	Inventory* inven;
	//
public:
	ItemSlot();
	~ItemSlot();
	//
	void Update();
	void Render();
	//
	void SetItem(Item* _item);
	void SelectItem();
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "ItemSlot.h"
#include "Inventory.h"

ItemSlot::ItemSlot()
	:item(nullptr), inven(nullptr)
{
	slot = new Quad(L"Textures/Store/slot.png", L"TextureShader");
}

ItemSlot::~ItemSlot()
{
	delete slot;
}

void ItemSlot::Update()
{
	slot->Update();
	if(item)
		item->Update();
}

void ItemSlot::Render()
{
	slot->Render();
	if(item)
		item->Render();
}

void ItemSlot::SetItem(Item* _item)
{
	item = _item;
	item->slot = this;
	item->button->pos = slot->pos;
	item->button->SetEvent(bind(&ItemSlot::SelectItem, this));
	item->button->ResetParamEvent();
	item->SetButtonTextureFrame();
}

void ItemSlot::SelectItem()
{
	if (inven)
		inven->selectedItem = item;
}

 

3. Store

더보기
#pragma once
//
#include "Object/GameObject/Item.h"
//
class Store : public Transform
{
private:
	unordered_map<int, Item*> items;
	UINT x;
	UINT y;

public:
	ItemData selectedItemData;

public:
	Store(UINT _x, UINT _y);
	~Store();
	//
	void Update();
	void Render();
	void PostRender();
	//
	void LoadStoreAndCreateItems();
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Store.h"

Store::Store(UINT _x, UINT _y)
	:x(_x), y(_y), selectedItemData()
{
	Vector2	itemSize{ 98.0f, 98.0f }; // item frame size
	//
	LoadStoreAndCreateItems();
	// Set Store Transform
	pos = itemSize;
	scale.x = itemSize.x * x;
	scale.y = itemSize.y * y;
	// Set Item Transform
	Vector2 startPos = pos;
	//
	for (UINT j = 0; j < y; ++j)
		for (UINT i = 0; i < x; ++i)
		{
			Item* item = items[i + (j * x)];
			Vector2 ButtonPos = startPos + Vector2{ itemSize.x * i, itemSize.y * j };
			item->button->pos = ButtonPos;
		}
}

Store::~Store()
{
	for (auto item : items)
		delete item.second;
	items.clear();
}

void Store::Update()
{
	for (auto item : items)
		item.second->Update();
}

void Store::Render()
{
	for (auto item : items)
		item.second->Render();
}

void Store::PostRender()
{
	ImGui::Text("[Store]");
	ImGui::Text("- Selected Item -");
	//
	string type = "Type : ";
	switch (selectedItemData.type)
	{
	case None: type += "None"; break;
	case Helmet: type += "Helmet"; break;
	case Armor: type += "Armor"; break;
	case Gloves: type += "Gloves"; break;
	case Boots: type += "Boots"; break;
	case Shield: type += "Shiled"; break;
	case Weapon: type += "Weapon"; break;
	default:
		break;
	}
	ImGui::Text(type.c_str());
	//
	if(selectedItemData.name == "")
		ImGui::Text("empty");
	else
		ImGui::Text(selectedItemData.name.c_str());
	//
	ImGui::Text("Value : %d", selectedItemData.value);
	ImGui::Text("Price : %d", selectedItemData.price);
}

void Store::LoadStoreAndCreateItems()
{
	ifstream loadFile("Textures/Store/store.txt", ios::in);
	string key{};
	//
	while (true)
	{
		ItemData data{};
		//
		loadFile >> key;
		if (key == "key") // 처음 읽은 Data가 key 이면
		{ // 첫번째 행 전부 읽어 폐기
			string buffer{}; // 
			getline(loadFile, buffer);
			continue;
		}
		else // data 행이면 key값 형변환 해서 저장(string -> int)
		{
			//if (key == "15")
			//	int i = 0;
			data.key = stoi(key);
		}
		/* 참고 : FileStrem 은 -> int, string 을 자동 형변환 해준다 */
		// int, string, float data들을 순차적으로 저장
		int type{};
		loadFile >> type;
		data.type = (ItemType)type;
		//
		loadFile >> data.name >> data.value >> data.price >> data.frameX >> data.frameY;

		// 데이터의 key값이 새로운 값이면 아이템 생성
		items[data.key] = new Item(data);
		//
		items[data.key]->SetStore(this);

		// 더 Load 할 data가 없으면 loop 종료
		if (loadFile.eof())
			break;
	}
}

 

4. Inventory

더보기
#pragma once
//
#include "Object/GameObject/Item.h"
#include "Object/GameObject/ItemSlot.h"
#include "Object/GameObject/Status.h"
//
class Inventory : public Transform
{
public:
	struct InventoryData
	{
		int slotNum;
		ItemData itemData;
	};
	//
private:
	UINT x;
	UINT y;
	//
	vector<ItemSlot*> slots;
	//
	UINT money;
	//
	Status* status;
	//
public:
	Item* selectedItem;

public:
	Inventory(UINT _x, UINT _y);
	~Inventory();
	//
	void Update();
	void Render();
	void PostRender();
	//
	void CreateInventory();
	//
	void SetStatus(Status* value) { status = value; }
	//
	void Buy(ItemData value);
	void Sell();
	//
	void Save();
	void Load();
	//
	void Equip();
	void UnEquip();
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Inventory.h"

Inventory::Inventory(UINT _x, UINT _y)
	:x(_x), y(_y), money(100000), status(nullptr)
{
	CreateInventory();
}

Inventory::~Inventory()
{
	for (auto slot : slots)
		delete slot;
	slots.clear();
}

void Inventory::Update()
{
	for (auto slot : slots)
		slot->Update();
}

void Inventory::Render()
{
	for (auto slot : slots)
		slot->Render();
}

void Inventory::PostRender()
{
	ImGui::Text("[Inventory]");
	ImGui::Text("- money : %d -", money);
	ImGui::Text("- Selected Item -");
	string type = "Type : ";
	if (selectedItem)
	{
		switch (selectedItem->data.type)
		{
		case None: type += "None"; break;
		case Helmet: type += "Helmet"; break;
		case Armor: type += "Armor"; break;
		case Gloves: type += "Gloves"; break;
		case Boots: type += "Boots"; break;
		case Shield: type += "Shiled"; break;
		case Weapon: type += "Weapon"; break;
		default:
			break;
		}
		ImGui::Text(type.c_str());
		//
		if (selectedItem->data.name == "")
			ImGui::Text("empty");
		else
			ImGui::Text(selectedItem->data.name.c_str());
		//
		ImGui::Text("Value : %d", selectedItem->data.value);
		ImGui::Text("Price : %d", selectedItem->data.price);
	}
	//
	ImGui::Text("--------------------------------");
	ImGui::Text("- Items -");
	for (auto slot : slots)
	{
		if (slot->item)
		{
			if (slot->item->data.name == "")
				continue;
			else
				ImGui::Text(slot->item->data.name.c_str());
		}
	}
	ImGui::Text("================================");
}

void Inventory::CreateInventory()
{
	Vector2	itemSize{ 98.0f, 98.0f };
	// Set Inventory Transform
	pos.x = (itemSize.x * (float)x) * 2.2f;
	pos.y = itemSize.y;
	scale.x = itemSize.x * x;
	scale.y = itemSize.y * y;
	// Create Slots
	for (UINT j = 0; j < y; ++j)
		for (UINT i = 0; i < x; ++i)
		{
			ItemSlot* itemSlot = new ItemSlot;
			Vector2 slotPos = pos + Vector2{ itemSize.x * i, itemSize.y * j };
			itemSlot->slot->pos = slotPos;
			itemSlot->inven = this;
			//
			slots.emplace_back(itemSlot);
		}
}

void Inventory::Buy(ItemData data)
{
	// Check Item Slot
	int keyIdx = 0;
	while (true)
	{
		if (keyIdx >= 16)
			return;
		//
		if (slots[keyIdx]->item)
		{
			++keyIdx;
			continue;
		}
		else
			break;
	}
	Item* tempItem = new Item(data);
	slots[keyIdx]->SetItem(tempItem);
	//
	money -= data.price;
}

void Inventory::Sell()
{ // 미구현
	if (!selectedItem)
		return;
	//
	money += selectedItem->data.price;
	//
	selectedItem->slot->item = nullptr;
	//
	delete selectedItem;
	selectedItem = nullptr;
}

void Inventory::Save()
{
	BinaryWriter writer(L"TextData/inventory.inv"); // 확장자 무관
	//
	writer.UInt(money);
	//
	UINT size{};
	for (int i = 0; i < slots.size(); ++i)
		if (slots[i]->item)
			++size;
	//
	writer.UInt(size);
	//
	for (UINT i = 0; i < slots.size() ; ++i)
	{
		InventoryData invData{};
		if (slots[i]->item)
		{
			invData.slotNum = i;
			invData.itemData = slots[i]->item->data;
			//
			writer.UInt(invData.slotNum);
			//
			writer.UInt(invData.itemData.key);
			writer.UInt(invData.itemData.type);
			writer.String(invData.itemData.name);
			writer.UInt(invData.itemData.value);
			writer.UInt(invData.itemData.price);
			writer.Float(invData.itemData.frameX);
			writer.Float(invData.itemData.frameY);
		}
	}
	status->Save();
}

void Inventory::Load()
{
	// Clear Slots
	for (auto slot : slots)
		if (slot->item)
		{
			delete slot->item;
			slot->item = nullptr;
		}
	//
	BinaryReader reader(L"TextData/inventory.inv"); // 확장자 무관
	// load money
	UINT money = reader.UInt();
	this->money = money;
	// 
	UINT size = reader.UInt();
	// 
	for(int i = 0; i < size ; ++i)
	{
		InventoryData invData{};
		//
		invData.slotNum = reader.UInt();
		//
		invData.itemData.key = reader.UInt();
		invData.itemData.type = (ItemType)reader.UInt();
		invData.itemData.name = reader.String();
		invData.itemData.value = reader.UInt();
		invData.itemData.price = reader.UInt();
		invData.itemData.frameX = reader.Float();
		invData.itemData.frameY = reader.Float();
		//
		Item* item = new Item(invData.itemData);
		slots[invData.slotNum]->SetItem(item);
	}
	status->Load();
}

void Inventory::Equip()
{
	if (!selectedItem)
		return;
	//
	if (status->equipedItems[((int)(selectedItem->data.type) - 1)])
	{ // 착용할 부위에 아이템 있을 시 Swap
		Item* tempItem = status->equipedItems[((int)(selectedItem->data.type) - 1)];
		status->equipedItems[((int)(selectedItem->data.type) - 1)] = selectedItem;
		selectedItem->slot->SetItem(tempItem);
	}
	else
	{
		status->equipedItems[((int)(selectedItem->data.type) - 1)] = selectedItem;
		selectedItem->slot->item = nullptr;
	}
	status->SetEquipedItemData();
	selectedItem = nullptr;
}

void Inventory::UnEquip()
{
	if (!status->selectedItem)
		return;
	//
	// Check Item Slot
	int keyIdx = 0;
	while (true)
	{
		if (keyIdx >= 16)
			return;
		//
		if (slots[keyIdx]->item)
		{
			++keyIdx;
			continue;
		}
		else
			break;
	}
	slots[keyIdx]->SetItem(status->selectedItem);
	//
	status->equipedItems[((int)(status->selectedItem->data.type) - 1)] = nullptr;
	status->selectedItem = nullptr;
}

 

5. Status

더보기
#pragma once

#include "Object/GameObject/Item.h"

class Status
{
private:
	Quad* quad;
	//
	int hp;
	int mp;
	int attack;
	int armor;
	float moveSpeed;
	float attackSpeed;
	//
	Vector2 itemPos[6];
public:
	Item* equipedItems[6];
	Item* selectedItem;
	//
public:
	Status();
	~Status();
	//
	void Update();
	void Render();
	void PostRender();
	//
	void Open();
	void Close();
	//
	void SetEquipedItemData();
	void SelectItem(void* item);
	//
	void Save();
	void Load();
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Status.h"

Status::Status()
	:hp(0), mp(0), attack(0), armor(0), moveSpeed(0), attackSpeed(0),
	selectedItem(nullptr)
{
	quad = new Quad(L"Textures/Store/status.png", L"TextureShader");
	quad->pos = { CENTER_X, CENTER_Y };

	// Set Default Item pos To Center
	memset(itemPos, 0, 6);
	for (int i = 0; i < 6; ++i)
		itemPos[i] = quad->pos;

	// Set Each Status Item Equip Pos
	itemPos[0].y += 120.0f; // Helmet
	//
	itemPos[1].y += 10.0f; // Armor
	//
	itemPos[2].y -= 100.0f; // Boots
	//
	itemPos[3].x -= 110.0f; // Glove
	itemPos[3].y += 65.0f; // Glove
	//
	itemPos[4].x += 110.0f; // Shield
	itemPos[4].y -= 45.0f; // Shield
	//
	itemPos[5].x -= 110.0f; // Weapon
	itemPos[5].y -= 45.0f; // Weapon
	//
	memset(equipedItems, 0, 6);
}

Status::~Status()
{
	delete quad;
}

void Status::Update()
{
	quad->Update();
	//
	for (int i = 0; i < 6; ++i)
		if(equipedItems[i])
			if (equipedItems[i]->button->isActive)
				equipedItems[i]->Update();
}

void Status::Render()
{
	quad->Render();
	//
	for (int i = 0; i < 6; ++i)
		if(equipedItems[i])
			if (equipedItems[i]->button->isActive)
				equipedItems[i]->Render();
}

void Status::PostRender()
{
	ImGui::Text("[Status]");
	ImGui::Text("--------------------------------");
	ImGui::Text("HP : %d", hp);
	ImGui::Text("MP : %d", mp);
	ImGui::Text("Attack : %d", attack);
	ImGui::Text("Armor : %d", armor);
	ImGui::Text("MoveSpeed : %.3f", moveSpeed);
	ImGui::Text("AttackSpeed : %.3f", attackSpeed);
	ImGui::Text("--------------------------------");
	ImGui::Text("- Equiped Items -");
	for(int i = 0 ; i < 6 ; ++i)
		if(equipedItems[i])
			ImGui::Text(equipedItems[i]->data.name.c_str());
	ImGui::Text("--------------------------------");
	ImGui::Text("- Selected Item -");
	string type = "Type : ";
	if (selectedItem)
	{
		switch (selectedItem->data.type)
		{
		case None: type += "None"; break;
		case Helmet: type += "Helmet"; break;
		case Armor: type += "Armor"; break;
		case Gloves: type += "Gloves"; break;
		case Boots: type += "Boots"; break;
		case Shield: type += "Shiled"; break;
		case Weapon: type += "Weapon"; break;
		default:
			break;
		}
		ImGui::Text(type.c_str());
		//
		if (selectedItem->data.name == "")
			ImGui::Text("empty");
		else
			ImGui::Text(selectedItem->data.name.c_str());
		//
		ImGui::Text("Value : %d", selectedItem->data.value);
		ImGui::Text("Price : %d", selectedItem->data.price);
	}
}

void Status::Open()
{
	quad->isActive = true;
	//
	for (int i = 0; i < 6; ++i)
		if (equipedItems[i])
			equipedItems[i]->button->isActive = true;
}

void Status::Close()
{
	quad->isActive = false;
	//
	for (int i = 0; i < 6; ++i)
		if (equipedItems[i])
			equipedItems[i]->button->isActive = false;
}

void Status::SetEquipedItemData()
{
	int tempHP{}; int tempMP{};
	int tempAttack{}; int tempArmor{};
	float tempMoveSpeed{}; float tempAttackSpeed{};
	//
	for(int i = 0 ; i < 6 ; ++i)
	{
		if (equipedItems[i])
		{
			if(!quad->isActive)
				equipedItems[i]->button->isActive = false;
			//
			equipedItems[i]->button->pos = itemPos[i];
			switch (equipedItems[i]->data.type)
			{
			case Helmet: tempMP += equipedItems[i]->data.value; break;
			case Armor: tempHP += equipedItems[i]->data.value; break;
			case Boots: tempMoveSpeed += equipedItems[i]->data.value; break;
			case Gloves: tempAttackSpeed += equipedItems[i]->data.value; break;
			case Shield: tempArmor += equipedItems[i]->data.value; break;
			case Weapon: tempAttack += equipedItems[i]->data.value; break;
			default: break;
			}
			equipedItems[i]->button->SetEvent(bind(&Status::SelectItem, this, placeholders::_1), equipedItems[i]);
			equipedItems[i]->button->ResetEvent();
		}
	}
	hp = tempHP; mp = tempMP;
	attack = tempAttack; armor = tempArmor;
	moveSpeed = tempMoveSpeed; attackSpeed = tempAttackSpeed;
	//
}

void Status::SelectItem(void* item)
{
	selectedItem = (Item*)item;
}

void Status::Save()
{
	BinaryWriter writer(L"TextData/status.stat"); // 확장자 무관
	//
	UINT size{};
	for (int i = 0; i < 6; ++i)
		if (equipedItems[i])
			++size;
	//
	writer.UInt(size);
	//
	for (UINT i = 0; i < 6 ; ++i)
	{
		if (equipedItems[i])
		{
			writer.UInt(i);
			//
			writer.UInt(equipedItems[i]->data.key);
			writer.UInt(equipedItems[i]->data.type);
			writer.String(equipedItems[i]->data.name);
			writer.UInt(equipedItems[i]->data.value);
			writer.UInt(equipedItems[i]->data.price);
			writer.Float(equipedItems[i]->data.frameX);
			writer.Float(equipedItems[i]->data.frameY);
		}
	}
}

void Status::Load()
{
	// Clear equipedItems
	for (auto item : equipedItems)
		if (item)
		{
			delete item;
			item = nullptr;
		}
	//
	BinaryReader reader(L"TextData/status.stat"); // 확장자 무관
	// 
	UINT size = reader.UInt();
	// 
	for(int i = 0; i < size ; ++i)
	{
		int index = reader.UInt();
		//
		ItemData data{};
		data.key = reader.UInt();
		data.type = (ItemType)reader.UInt();
		data.name = reader.String();
		data.value = reader.UInt();
		data.price = reader.UInt();
		data.frameX = reader.Float();
		data.frameY = reader.Float();
		//
		Item* tempItem = new Item(data);
		//
		equipedItems[index] = tempItem;
	}
	//
	SetEquipedItemData();
}

 

6. GameScene

더보기
#pragma once
//
#include "Object/GameObject/Store.h"
#include "Object/GameObject/Inventory.h"
#include "Object/GameObject/Status.h"
//
class StoreScene : public Scene
{
private:
	Store* store;
	Inventory* inven;
	Status* status;
	//
public:
	StoreScene();
	~StoreScene();
	//
	virtual void Update() override;
	virtual void Render() override;
	virtual void PostRender() override;
};
////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "StoreScene.h"

StoreScene::StoreScene()
{
	store = new Store(6, 6);
	inven = new Inventory(4, 4);
	status = new Status;
	//
	inven->SetStatus(status);
}

StoreScene::~StoreScene()
{
	delete status;
	delete inven;
	delete store;
}

void StoreScene::Update()
{
	store->Update();
	inven->Update();
	status->Update();
}

void StoreScene::Render()
{
	store->Render();
	inven->Render();
	status->Render();
}

void StoreScene::PostRender()
{
	ImGui::Text("================================");
	// store
	store->PostRender();
	if (ImGui::Button("Buy", { 64, 32 }))
		inven->Buy(store->selectedItemData);
	if (ImGui::Button("Sell", { 64, 32 }))
		inven->Sell();
	ImGui::Text("================================");
	// inventory
	inven->PostRender();
	if (ImGui::Button("Equip", { 64, 32 }))
		inven->Equip();
	if (ImGui::Button("UnEquip", { 64, 32 }))
		inven->UnEquip();
	ImGui::Text("================================");
	// status
	status->PostRender();
	if (ImGui::Button("Open", { 64, 32 }))
		status->Open();
	if (ImGui::Button("Close", { 64, 32 }))
		status->Close();
	// save & load
	ImGui::Text("================================");
	if (ImGui::Button("Save", { 64, 32 }))
		inven->Save();
	if (ImGui::Button("Load", { 64, 32 }))
		inven->Load();
}