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 :)
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 :)