System przedmiotów i ekwipunku

0

Stworzyłem system ekwipunku oraz przedmiotów który wydaje mi się strasznie zagmatwany. Chcę to stworzyć jeszcze raz od początku, jednak nie obejdzie się bez waszej pomocy :)

Na początku opiszę jak będzie to działać:
-Każdy przedmiot jest unikalny, nie mają żadnych ID, tworzę je po prostu podając typ przedmiotu, np. EATABLE,HELMET,COINS,WEAPON.

Load=[WEAPON]
[(BITMAPID:Items)(POSITION:290,100)(RECT:64,0)(TILESIZE:32,32)(DAMAGE:20)] itd.

Dzięki temu będę mógł robić losowo generowane przedmioty. Jeżeli gracz zbierze przedmiot typu COINS, to po prostu szuka tego przedmiotu w ekwipunku i tam zwiększa wartość zmiennej amount.

Chcę stworzyć taki system gdzie będzie można handlować przedmiotami i umieszczać je też w skrzyniach, tych elementów nie dodałem bo uznałem że obecny system już jest nazbyt zagmatwany i nie warto w to brnąć dalej, tylko zaprojektować od nowa.

Ogólnie każdy przedmiot == jednemu slotowi ekwipunku, tak jak tutaj :)
user image
http://hydra-media.cursecdn.com/minecraft-pl.gamepedia.com/9/98/Ekwipunek.png

Teraz pokażę wam kod:

Tutaj jest główna klasa ITEM

#pragma once

#include <SFML\Graphics.hpp>
#include <memory>
#include "TextureManager.hpp"
#include "FileManager.hpp"
#include "ItemType.hpp"
#include "Bullet.hpp"
#include "ItemGUI.hpp"
#include "Label.hpp"

class Item : public sf::Drawable
{
public:
	Item(void);
	void draw(sf::RenderTarget& target, sf::RenderStates states) const;
	virtual void update(sf::Time dt);
	virtual void useItem(std::vector <std::unique_ptr <Bullet> > &bullet,sf::Vector2f pPosition, sf::Vector2f mPosition);
	virtual void inventoryUpdate();

	sf::FloatRect getGlobalBounds();
	sf::Vector2f getVelocity();
	sf::Vector2f getPosition();
	bool getOnInventory();
	bool getDestroy();
	bool getWear();
	ItemType getType();

	void setPosition(sf::Vector2f position);
	void setOnGround(bool status);
	void setOnInventory(bool status);
	void setWear(bool status);
	void setShowItemWindow(bool status);

	void moveX(sf::Time dt);
	void moveY(sf::Time dt);

	void stackItem(int i);
	int getStack();
protected:
	void gravity();

	sf::Sprite sprite;
	sf::Vector2f position;
	sf::Vector2i rect;
	sf::Vector2i tileSize;

	ItemType type;
	std::string actionString;

	sf::Vector2f velocity;
	float currentFallSpeed,fallAcceleration,maxFallSpeed;
	bool onGround;

	bool wear;
	bool onInventory,onMap,destroy;
	bool showItemWindow;

	sf::Font font;

	TextureManager textureManager;
	ItemGUI itemGUI;

	int stack;
};

Od niej dziedziczą inne przedmioty.

Przedmioty są na mapie w kontenerze: std::vector <std::unique_ptr <Item> > item;
Umieszczane w taki sposób: item.push_back(std::unique_ptr<Weapon>(new Weapon(contents[i][j],textureManager)));
contents[i][j] to są informacje o przedmiocie potem odczytywane w konstruktorze danego przedmiotu.
Czyli mamy wczytaną taką linijkę [(BITMAPID:Items)(POSITION:290,100)(RECT:64,0)(TILESIZE:32,32)(DAMAGE:20)]
to potem dzielę tak:

//TO JEST KONSTRUKTOR PRZEDMIOTU
FileManager fileManager;
std::vector <std::string> contents,attributes; 
fileManager.SetContent(")",data,contents,attributes);


void FileManager::SetContent(std::string c, std::string data,std::vector <std::string> &contents,std::vector <std::string> &attributes)
{
	std::string att,con;

	while(!data.empty())
	{
		att = data.substr(1, data.find(':') - 1);
		data.erase(0, data.find(':')+1);
		attributes.push_back(att);

		con = data.substr(0, data.find(c));
		data.erase(0, data.find(c)+1);
		contents.push_back(con);
	}
}

I potem już dalej w konstruktorze przedmiotu:

	for(int i = 0; i < attributes.size(); i++)
	{
		if(attributes[i] == "POSITION")
		{
			position.x = (stof(contents[i].substr(0, contents[i].find(','))));
			contents[i].erase(0, contents[i].find(',') +1);
			position.y = (stof(contents[i].substr(0, contents[i].find(','))));
		}
		else if(attributes[i] == "TILESIZE")
		{
			tileSize.x = (stoi(contents[i].substr(0, contents[i].find(','))));
			contents[i].erase(0, contents[i].find(',') +1);
			tileSize.y = (stoi(contents[i].substr(0, contents[i].find(','))));
		}
		else if(attributes[i] == "RECT")
		{
			rect.x = (stoi(contents[i].substr(0, contents[i].find(','))));
			contents[i].erase(0, contents[i].find(',') +1);
			rect.y = (stoi(contents[i].substr(0, contents[i].find(','))));
		}
          }

Jak gracza koliduje z przedmiotem to uruchamia się taka metoda:

void Player::takeItem(std::vector <std::unique_ptr <Item> > &item)
{
	for(int i = 0; i < item.size(); i++)
	if( (item[i]) -> getGlobalBounds().intersects(sprite.getGlobalBounds()))
	{
		inventoryManager.itemsStack.push_back(std::unique_ptr<Item>(std::move(item[i])));
		item.erase(item.begin() + i);
		inventoryManager.insertItem();
		break;
	}
}

===================================================================
Teraz jeśli chodzi o sam ekwipunek wygląda to tak:

#pragma once

#include <memory>
#include <SFML\Graphics.hpp>
#include "TextureManager.hpp"
#include "InventoryBar.hpp"
#include "Cursor.hpp"
#include "Item.hpp"
#include "Bullet.hpp"
#include "ItemType.hpp"

class InventoryManager : public sf::Drawable
{
public:
	InventoryManager();
	void setInventoryManager(sf::Vector2f pos, int size);
	void draw(sf::RenderTarget& target, sf::RenderStates states) const;

	void update(Cursor &cursor,std::vector <std::unique_ptr <Bullet> > &bullet, sf::Vector2f pPostion, sf::Vector2f mPostion);

	void insertItem();
	void insertSprite();
	void useItem(ItemType iType, std::vector <std::unique_ptr <Bullet> > &bullet, sf::Vector2f pPostion, sf::Vector2f mPostion);
	void handleEvent(sf::Event &event);

   std::vector <std::unique_ptr <Item> > itemsStack;
   std::vector <std::unique_ptr <Item> > dropItemsStack;
	std::vector <std::unique_ptr <InventoryBar> > inventoryBar;
private:
	TextureManager textureManager;

	bool handleItem, lMouse, rMouse, showInfoBox;
};


#include "InventoryManager.hpp"

void InventoryManager::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	for(int i = 0; i < inventoryBar.size(); i++)
		target.draw(*inventoryBar[i]);

	for(int i = 0; i < inventoryBar.size(); i++)
		if(inventoryBar[i] -> item != NULL)
		target.draw(*inventoryBar[i] -> item);
}

void InventoryManager::update(Cursor &cursor,std::vector <std::unique_ptr <Bullet> > &bullet, 
							  sf::Vector2f pPosition, sf::Vector2f mPosition)
{
	for(int i = 0; i < inventoryBar.size(); i++)
	{	
		if(inventoryBar[i] -> item != NULL)
		{
			inventoryBar[i] -> item -> inventoryUpdate();
			inventoryBar[i] -> item -> setShowItemWindow(false);
		}

		inventoryBar[i] -> setIsActive(false);
		
		if( inventoryBar[i] -> getGlobalBounds().intersects(cursor.getGlobalBounds()))
		{		
			if(inventoryBar[i] -> item != NULL)
				inventoryBar[i] -> item -> setShowItemWindow(true);

			inventoryBar[i] -> setIsActive(true);

			if(lMouse)
			{		
				if(handleItem)
					handleItem = false;
				else
				{
					if(inventoryBar[i] -> item != NULL)
					handleItem = true;
				}

				if(handleItem)
				{	
					if(inventoryBar[i] -> item != NULL)
					inventoryBar[i] -> followCursor = true;
				}
				else
				{
					for(int j = 0; j < inventoryBar.size(); j++)
					if(inventoryBar[j] -> followCursor)
					{
						if(inventoryBar[i] -> item == NULL)
						{
							inventoryBar[j] -> followCursor = false;
							inventoryBar[i] -> item = std::move(inventoryBar[j] -> item);
							inventoryBar[i] -> setItemPosition();
						}
						else
						{
							std::unique_ptr <Item> tempItem;
							inventoryBar[j] -> followCursor = false;

							tempItem = std::move(inventoryBar[j] -> item);
							inventoryBar[j] -> item = std::move(inventoryBar[i] -> item);
							inventoryBar[i] -> item = std::move(tempItem);

							inventoryBar[i] -> setItemPosition();
							inventoryBar[j] -> setItemPosition();
						}
					}
				}
			}

			if(rMouse)
			{
				if(inventoryBar[i] -> item != NULL)
				{
					if(inventoryBar[i] -> item -> getType() == USABLE)
						inventoryBar[i] -> item -> useItem(bullet,pPosition,mPosition);
					else if(inventoryBar[i] -> item -> getType() == WEAPON)
					{
						if(!inventoryBar[i] -> item -> getWear())
						{
							for(int j = 0; j < inventoryBar.size(); j++)
							if((inventoryBar[j] -> item != NULL))
								if((inventoryBar[j] -> item -> getType() == WEAPON))
									inventoryBar[j] -> item -> setWear(false);

							inventoryBar[i] -> item -> setWear(true);
						}
						else
							inventoryBar[i] -> item -> setWear(false);
					}
				}
			}
		}
		else
		{
			if(lMouse)
			if(inventoryBar[i] -> item != NULL)
				if(inventoryBar[i] -> followCursor)
				{
					bool dropItem = true;

					for(int j = 0; j < inventoryBar.size(); j++)
					if(inventoryBar[j] -> getGlobalBounds().intersects(cursor.getGlobalBounds()))
					{
						dropItem = false;
					}

					if(dropItem)
					{
						inventoryBar[i] -> item -> setPosition(pPosition);
						dropItemsStack.emplace_back(std::move(inventoryBar[i] -> item));
						inventoryBar[i] -> item = NULL;
						inventoryBar[i] -> followCursor = false;

						handleItem = false;
					}
				}
		}
	
		if(inventoryBar[i] -> followCursor)
			inventoryBar[i] -> item -> setPosition(cursor.getPosition());

		inventoryBar[i] -> update();
	}

	lMouse = rMouse = false;
}

void InventoryManager::useItem(ItemType iType,std::vector <std::unique_ptr <Bullet> > &bullet,
							   sf::Vector2f pPosition, sf::Vector2f mPosition)
{
	for(int j = 0; j < inventoryBar.size(); j++)
	if((inventoryBar[j] -> item != NULL))
		if((inventoryBar[j] -> item -> getType() == iType))
			if(inventoryBar[j] -> item -> getWear())
				inventoryBar[j] -> item -> useItem(bullet,pPosition,mPosition);
}

void InventoryManager::insertItem()
{
	if(itemsStack.size() > 0)
	{	
		auto iterator = itemsStack.begin();
		{
			//IF ITEM IS COINS TYPE
			if((*iterator) -> getType() == COINS)
			{
				bool foundCoins = false;

				for(int i = 0; i < inventoryBar.size(); i++)
				{
					if(!inventoryBar[i] -> getIsEmpty())	
						if(inventoryBar[i] -> item -> getType() == COINS)
						{
							foundCoins = true;
							inventoryBar[i] -> item -> stackItem((*iterator) -> getStack());
							itemsStack.erase(iterator);
						}
				}

				if(!foundCoins)
				{
					for(int i = 0; i < inventoryBar.size(); i++)
					{
						if(inventoryBar[i] -> getIsEmpty())
						{
							inventoryBar[i] -> item = std::move(*iterator);
							inventoryBar[i] -> setItemPosition();
							itemsStack.erase(iterator);
							break;
						}
					}
				}
			}
			//IF ITEM IS NOT COINS TYPE
			else
			{
				for(int i = 0; i < inventoryBar.size(); i++)
				{
					if(inventoryBar[i] -> getIsEmpty())
					{
						inventoryBar[i] -> item = std::move(*iterator);
						inventoryBar[i] -> setItemPosition();
						itemsStack.erase(iterator);
						break;
					}
				}
			}
			////////////////////////////
		}
	}
}

void InventoryManager::insertSprite()
{
	for(int i = 0; i < inventoryBar.size(); i++)
	{
		inventoryBar[i] -> setItemPosition();
		inventoryBar[i] -> followCursor = false;
	}

	handleItem = false;
}

void InventoryManager::handleEvent(sf::Event &event)
{
	if (event.type == sf::Event::MouseButtonPressed)
	{
		if (event.mouseButton.button == sf::Mouse::Left)
			lMouse = true;
		else if (event.mouseButton.button == sf::Mouse::Right)
			rMouse = true;
	}
}

void InventoryManager::setInventoryManager(sf::Vector2f pos, int size)
{
	inventoryBar.clear();

	textureManager.loadTexture("Bar","Media/Textures/Inventory.png");

	sf::Vector2f position;
	position.x;
	position.y;
	handleItem = false;
	lMouse = false;
	showInfoBox = false;

	for(int i = 0; i < size; i++)
	for(int j = 0; j < size; j++)
	{
		position.x = j * textureManager.getRef("Bar").getSize().x + 1 + pos.x;
		position.y = i * textureManager.getRef("Bar").getSize().y + 1 + pos.y;
		inventoryBar.push_back(std::unique_ptr<InventoryBar>(new InventoryBar(position,textureManager)));
	}
}

InventoryManager::InventoryManager()
{
	textureManager.loadTexture("Bar","Media/Textures/Inventory.png");

	sf::Vector2f position;
	position.x = position.y = 0;
	handleItem = false;
	lMouse = false;
	showInfoBox = false;

	for(int i = 0; i < 10; i++)
	for(int j = 0; j < 10; j++)
	{
		position.x = j * textureManager.getRef("Bar").getSize().x + 1;
		position.y = i * textureManager.getRef("Bar").getSize().y + 1;
		inventoryBar.push_back(std::unique_ptr<InventoryBar>(new InventoryBar(position,textureManager)));
	}
}

A same przedmioty przechowywane są tutaj:

#pragma once

#include <SFML\Graphics.hpp>
#include <memory>
#include "TextureManager.hpp"
#include "Item.hpp"

class InventoryBar : public sf::Drawable
{
public:
	InventoryBar(sf::Vector2f position,TextureManager &textureManager);
	void draw(sf::RenderTarget& target, sf::RenderStates states) const;
	void update();
	
	void setIsActive(bool status);
	void setItemPosition();

	sf::FloatRect getGlobalBounds();
	bool getIsEmpty();

	std::unique_ptr <Item> item;
	bool followCursor;
private:
	sf::Sprite sprite;
	sf::Vector2f position;

	bool isActive;
	bool isEmpty;
};
#include "InventoryBar.hpp"

void InventoryBar::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	target.draw(sprite);
}

void InventoryBar::update()
{
	if(!item == NULL)
		isEmpty = false;
	else
		isEmpty = true;

	if(isActive)
		sprite.setColor(sf::Color(50,50,50));
	else
		sprite.setColor(sf::Color(255,255,255));

	if(!item == NULL)
		if(item -> getWear())
			sprite.setColor(sf::Color(200,100,50));

	if(!item == NULL)
		if(item -> getDestroy())
			item.reset();
}

void InventoryBar::setItemPosition()
{
	if(!item == NULL)
		item -> setPosition(sprite.getPosition());
}

bool InventoryBar::getIsEmpty()
{
	return isEmpty;
}

void InventoryBar::setIsActive(bool status)
{
	isActive = status;
}

sf::FloatRect InventoryBar::getGlobalBounds()
{
	return sprite.getGlobalBounds();
}

InventoryBar::InventoryBar(sf::Vector2f position,TextureManager &textureManager)
{
	this -> position = position;
	sprite.setTexture(textureManager.getRef("Bar"));
	sprite.setPosition(position);
	
	isActive = false;
	isEmpty = true;
	followCursor = false;

	item = NULL;
}

Jakie macie rady odnośnie tego systemu przedmiotów i ekwipunku?
Będę bardzo wdzięczny za każdą pomoc :)

0

zamiast null uzywaj nullptr

1 użytkowników online, w tym zalogowanych: 0, gości: 1