storing struct info in a vector (text rpg game) - c++

I'm currently writing a text-based RPG for the Game Programming Institute course. I currently have a store in which the character can purchase armor, but now I need to add items to that. I have created a items class, but am having difficulty understanding how I can relate the store class, items class and player class together using a vector array.
I think what I should be doing is create a Item vector in the player class that holds information about the struct Items. Then when the player enters the store, the purchased items are entered into that vector.
I have included, what I feel are, relevant bits of my code. If anyone could give me some pointers or tips just to clear up my brain fog on understanding how to share information across these 3 classes that would be greatly appreciated.
Thanks!
Item.h
struct Item{
int itemType;
int goldValue;
};
In player.h class I have added the private data:
std::vector<Item> mItem;
In player.cpp I'm attemping to display the items with the function
void Player::purchaseItem(Item& mItems, int itemType, int itemValue)
Here is store.h
class Store{
public:
void enterStore(Player& player);
private:
Armor mStoreArmor;
int mCost;
};

A vector is designed to be a faster dynamically-allocated array.
I would think you'd want to use a hash or just a static array, with either keys or just indices, storing the quantity of each type of item.
you would obviously store possessions in a player class, and have the store class have a list of certain items (possibly with keys for what is in stock - this is why a hash would be a good idea).
When the player sees the store items and chooses one, the quantity in the player class's hash would be incremented.

Related

UE4 How to use UMG ListView to display a list of Structs?

I apologize if this seems trivial, but I've searched for an answer for a while now, and I can't seem to find a solution.
I have a list of structs (TArray of structs to be exact.) that represent high scores in my game. (Each struct represents a high score, the fields are something like "Name, Date, Player Score, Game Mode etc" I use this SaveGame method to save a load my array of high scores to and from a file.
I used this with mock values and the system works, now I want to create a UMG widget that will display the list of high scores and this is where I ran into a snag.
I want to use a ListView to show each struct as a ListViewEntry. As far as I understand(I was following this tutorial), A UMG List View needs it's entry widgets to implement the IUserObjectListEntry specifically one has to implement the OnListItemObjectSet (UObject* ListItemObject) method. This method is responsible for assigning an object to the Listview entry and mapping its fields to the various visual widgets. You can see my problem now, I have a list of UStructs and this method needs a UObject pointer.
I'm really at a loss at what I need to do to make this work with a UStruct. Short of creating a dummy UObject that's pretty much identical to my struct and before passing the struct to this function I need to copy its fields into the dummy UObject and pass it instead. I think this method is very inelegant. There has to be a better way. Do you know any?
I wanted to avoid creating a dummy UObject just for the sake of passing it to this function.
I tried to use an array of UObjects instead of an array of Structs but the problem is, an array of UObjects is always an array of pointers, and when it gets saved, the pointers getting saved and not the actual data, so when it's loaded the data is useless.
Maybe there is a Struct-specific interface one can implement for a ListViewEntry widget? Or maybe there is a way to dereference the pointers of the array of Uobjects before saving them?
TL;DR
I have the following stuct:
c++
USTRUCT()
class FHighScoreEntry
{
GENERATED_BODY()
public:
//Player name
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString PlayerName;
//Player Score
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 PlayerScore;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FDateTime CurrentDateTime;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TEnumAsByte<EGameType> GameType;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 AccuracyTrialMaxTries;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 TimeTrialMaxTime;
}
In the following array;
c++
TArray<FHighScoreEntry> HighScores;
I want to show the array of high scores in a UMG ListView. The ListView requires its entries to implement the User List Object interface, which has this function:
As you can see, the event only accepts UObjects. Hence my problem.
This was asked 8 months ago, so may no longer be useful to you. But this post is the only thing I could find when searching for this issue on the Internet, so I am posting my solution for the next person researching this.
At a high level, create a UObject wrapper for the struct.
In my USaveGame class I have an array of structs because as you mentioned, an array of UObject pointers does not actually save any data. I created an UObject derived class that simply contains the same struct as the sole UPROPERTY.
UCLASS(Blueprintable, BlueprintType)
class PORTALTEST_API UHighScoreObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Score")
FHighScore HighScore;
};
In my Game Instance class, I have an array of pointers to this UObject
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Score")
TArray<UHighScoreObject*> HighScoreArray;
I use this array of UObject pointers for the List View of the widget.
HighScoreWidgetBlueprint
In the Save function of my Game Instance class I clear the struct of arrays and fill it with with the data contained in the array of UObject pointers. (I am only keeping the top ten high scores, so this seemed more efficient than keeping track of changes in both arrays.)
bool UMyGameInstance::SaveHighScore()
{
// Call SaveGameToSlot to serialize and save our SaveHighScoreObject with
//name HighScoreSaveSlot.sav
// Retrieve save values
SaveHighScoreObject->HighScoreArray.Empty();
for (auto HighScore : HighScoreArray)
{
SaveHighScoreObject->HighScoreArray.Add(HighScore->HighScore);
}
// Save game to file
const bool IsSaved = UGameplayStatics::SaveGameToSlot(SaveHighScoreObject,
UNIQUE_HIGHSCORE_SLOT, 0);
return IsSaved;
}
And in the Load function of my game instance I read in the array of structs and populate the array of UObjects.
bool UMyGameInstance::LoadHighScore()
{
// Try to load a saved game file with "HighScoreSaveSlot.sav if it exists
USaveGame* LoadedHighScore =
UGameplayStatics::LoadGameFromSlot(UNIQUE_HIGHSCORE_SLOT, 0);
SaveHighScoreObject = Cast<UHighScoreSaveGame>(LoadedHighScore);
//If the file does not exist, create a new one
if (!SaveHighScoreObject)
{
// Instantiate a new SaveGame object
SaveHighScoreObject = Cast<UHighScoreSaveGame>
(UGameplayStatics::CreateSaveGameObject(UHighScoreSaveGame::StaticClass()));
// Call SaveGameToSlot to serialize and save our game object with name
// "HighScoreSaveSlot.sav"
const bool IsSaved =
UGameplayStatics::SaveGameToSlot(SaveHighScoreObject, UNIQUE_HIGHSCORE_SLOT, 0);
return IsSaved;
}
else
{
for (auto HighScore : SaveHighScoreObject->HighScoreArray)
{
UHighScoreObject* HighScoreObj = NewObject<UHighScoreObject>
((UObject*)GetTransientPackage(), UHighScoreObject::StaticClass());
HighScoreObj->HighScore = HighScore;
HighScoreArray.Add(HighScoreObj);
}
return true;
}
}
ListView is made to represent unique objects, so its items need to be UObject, that’s the way the list view class is made.
That’s because adding/removing/looking up the widget for an item needs to be very fast. An object pointer is just a memory address, so it’s fast to find an item, and you can be sure they’re unique (your list won’t accidentally show two widget for the same object). Structs on the other hand, are any arbitrary data, which can be very long (depends on what they contain). So unless you make a hashing algorithm, it’s very expensive to look up if a struct is already in the list.
So for your needs, you can use objects instead of structs to show high scores. For example, objects for each player, since the players are probably already objects. The widget can then cast to the player class when on item object set, and take the high score variable of the player to show it.
If you want to use structs though, you can create a custom widget to show the high scores. To make a vertical list, just make a VerticalBox in your parent widget and a number of widgets for each item in your list, using the create widget from class node (or NewObject in cpp). Then, add your widgets as children of vertical box using the add child to vertical box function.

How to add ALL elements from one class to an array of another class

class Airplane{
public:
string airplaneName;
string captainName;
string copilotName;
int passangerNumber;
bool captain;
bool copilot;
};
class Fleet{
public:
string fleetName;
Airplane airplaneFleet;
};
So I have to add all elements from Airplane (actually a couple of airplanes) to one fleet, how do I do that. I've tried different codes but I'not even close, if you have some solution please explain, thanks!
Based on the question, you can either have an array of some defined size, or a vector to which you can add elements at runtime.
Airplane airplanesInFleet[10]; // Fixed - 10 airplans
std::vector<Airplane> airplanesInFleet; // Dynamic - use 'push_back' to add airplane

Stack array of structures

I'm trying to figure our how implement an array of structures into stacks in this machine problem that i have. Here is the problem:
Make a program that will allow the user to perform the following activities stated below through array approach. Car Park Station offers 10 park lanes and each lanes can accommodate 5 cars.
a. Entry. It must be able to register new car and assign an available parking lane. Registration requires plate number, brand name, car color, owner and telephone number.
b. Release. It must be able to release car from an identified lane
c. Search. It must be able to identify the car location based on plate number.
d. Vacancy. It must be able to display available parking space.
From what i understand, i have to make a 2 dimensional array of structures containing various data types and i have to make a lifo code out of it. But my problem is, i know how to simulate an array approach lifo code with just a single data type but not with multiple data types. The part where i have to implement the 2 dimensional array of structure into a stack is where i got me stuck and confused. I've searched online to look for problems similar to mine but i couldn't find any. I tried to make a code shown below:
struct Car
{
string brand, color, owner;
int plate, phone;
};
class Stack
{
private:
Car * pointer = new Car[10][5];
int top;
public:
Stack() // Constructor
{...}
void Push(int plate, string brand, string color, string color, string owner, int number)
{...}
Pop()
{...}
}
Try to analyze your problem further before choosing an actual implementation solution (like 2-dim array).
In your task you have the following abstract entities:
CarParkStation with attributes: NumberOfParkLanes, which should be able to do something like: FindFreeLane, FindCar(plateNum), RegisterACar(car), ReleaseACar(car)
Lane with attributes: NumberOfPlaces, and with actions like: IsFull(), and maybe also: FindACar(plateNum), AddACar(car), RemoveACar(car)
Car with attributes: PlateNumber, Brand, Color, Owner, which should be able to do: GetPlateNumber(), and maybe also provide access to other parameters
Below is a very general example of possible CarParkStation class declaration:
class CarParkStation
{
public:
CarParkStation() = delete;
explicit CarParkStation(int numParkLanes);
~CarParkStation() = default;
std::shared_ptr<const Lane> FindFreeLane();
std::shared_ptr<const Car> FindCar(const PlateNumber& pNumber);
std::pair<std::shared_ptr<const Lane>, int position> FindWhereMyCarIsParked(const PlateNumber& pNumber);
bool RegisterACar(const Car& car);
bool ReleaseACar(const Car& car);
private:
std::vector<std::shared_ptr<const Lane> > lanes_;
std::set<std::shared_ptr<Car>, CustomCompareFunction > cars_;
};
Don't forget to write the tests along with your implementation. This will help you to verify your requirements and overall design. For example:
TEST_F(CarParkStationShould, returnCorrectFreeLane)
{
ASSERT_EQ(expectedFreeLane, carParkStation->FindFreeLane());
}
In general, focus on what should your application do first, and then think about how to implement it.

C++ Accessing private vector values

I'm doing a restaurant management program. Right now I'm trying to output private vector data and am getting stuck.
So I have a Menu.h
private:
vector<Category> categories;
vector<Menu_Item> menu_items;
vector<Recipe> recipes;
vector<Ingredient> ingredients;
vector<Order> orders;
vector<Order_Item> order_items;
And Menu.cpp
Menu.read()
Menu.show()
The read function reads from a file like this
1010 Appetizers
1901 Entrees
1576 Desserts
1320 Drinks
And stores those values into the appropriate vector, for example this one would be vector categories.
I also have a .h file for all the different types of things like, Menu_Item.h, Recipe.h, etc. And I store values into the vector like such:
menu_items.push_back(Menu_Item(meniID, catID, rID....
However in Menu_Item.h the values are
private:
int menu_item_id;
int cat_id;
int recipe_id;
string menu_item_name;
double price;
The show() function queries the user what he/she wants to see. Let's say the user wants to see a specific menu item like Onion rings. What I can't do is
if(menu_items[0].menu_item_name == "Onion Rings")
because it says that menu_item_name value is private within Menu_Item.h. How can I access the private data?
You have to make menu_items public or make a public getter function like the following.
public:
vector<Menu_Item> get_menu_items(){ return menu_items;}
Then say if you had a Menu object of this type called Menu you can do this:
if(Menu.get_menu_items()[0].menu_item_name == "Onion Rings")
The other possible option is that you make a friend class if another specific class needs access, though usually this won't be the best design decision.
In response to the comment you could do this:
for(size_t n=0, n<menu_items.size()-1, ++n){
if(Menu.get_menu_items()[n].menu_item_name == "Onion rings")
cout << "something";
}
Two options:
Declare your fields in Menu_item.h as public, not private.
Keep your fields as private, but create public getters (and setters) to access the fields.

C++ Fantasy Football Draft Program - Adding Players to Teams

I am working on making a C++ program that will simulate a fantasy football draft.. I have used a linked list to create a list of team names, for each person participating in the draft. Now, I would like to know which way I should go about adding the players a team drafts to their respective team. I have the football players in a read in file and can figure out how to let them choose which, but cannot figure out how to store them on their respective team.
Any help appreciated
Thanks in advance
Well, you ought to have a Team class; the Team class ought to have a container to hold player names (another linked list, let's say). The list you have now should hold Teams rather than Strings.
Eventually the list of player names will probably be upgraded to a list of Player objects -- yet another class you'll want to define.
I know this is vague, but does it help?
It seems like you just need to understand the basic C++ containers a bit better.
One way might be to simply remove the player from a list or array of all players in the league, and add it to the fantasy player's list or array of players.
class Player; // ...
class FantasyPlayer
{
public:
std::vector< Player > picks; // array of my picks
};
std::vector< Player > all_players; // all available picks
std::vector< FantastyPlayer > fantasy_players; // all pickers
int iPicked = ...; // index of picked player in all_players
int iPicker = ...; // index of fantasy player currently picking
// add picked player to this fantasy player's pick list
fantasy_players[iPicker].picks.push_back(all_players[iPicked]);
// remove picked player from available players list
all_players.erase(iPicked);
Another, maybe easier, way to handle it might be to reference the "pickers" directly from the players themselves.
class FantasyPlayer; // ...
class Player
{
public:
Player() : owner(0) { /* empty */ }
FantastyPlayer* owner; // pointer to fantasy player who picked me
};
std::vector< Player > all_players; // all available picks
std::vector< FantastyPlayer > fantasy_players; // all pickers
int iPicked = ...; // index of picked player in all_players
int iPicker = ...; // index of fantasy player currently picking
// create link between a player and its picker
all_players[iPicked].owner = &(fantasy_players[iPicker]);
This code is all intentionally brief and incomplete, but maybe it'll get you started in the right direction. Good luck!