Hello all. I encountered a strange problem and wanted to ask some opinions on what direction to take.
I am making a C++ based Inventory system for my 3rd Person RPG by following tutorials below. So far everything works just fine. But I noticed after picking up objects, around 30 seconds after I pick them up they simply disappear from the menu. Whether the menu is open or close does not matter. They just disappear.
I checked the UI system first, seemed to be fine. Made a small function to print currently stored inventory items to be printed (with AddOnScreenDebugMessage) with a key. Strange thing is within this 30 seconds it works perfectly. But after that 30 seconds when items disappear when I hit the key to print items whole thing simply crashes.
It almost seems like I seem to lose access to inventory (which is an TArray of PickUpBase class I made. Inventory is stored/written into a custom C++ GameInstance I made.) . I also tried packaging the project to try in game conditions, and it is still the same.
I am lost at this point. I am sharing screenshots to show the problem and graph of how UI shows items. I am also sharing the necessary code.
Using 4.18.3
If anymore info is needed please let me know.
Code of PickUpBase, Character class, GameInstance class:
What you are describing sounds like the inventory object is getting garbage collected. But looking at your code nothing jumped out at me. Usually this is because someone forgot to flag the reference with UPROPERTY() but both your TArray and the local definition in the Character look right. I’d suggest override Destroyed() in your inventory class and setting a break point there. Then looking to see why it’s being destroyed. That will help narrow it down.
Also, why are you storing the inventory in the game instance? Seems like it’s better suited in the Character.
Edit: I just looked at the your AddItemToInventory() function. You are destroying the item right after pickup. So while your inventory system has a reference to the actor, the actor has been flagged for destruction. So it’s getting cleaned up at GC.
Thank you very much. So what should I be doing in this case ? Is there a function I can use instead of Destroy() or do I have to change the whole thing ? Or should I somehow stop garbage collection from collecting the reference ?
Also I stored inventory in GameInstance because in many places it is mentioned that only properties and values stored in GameInstance are transferred between levels.
Ah, you’re trying to create persistent inventory. Well here is the thing. While GameInstance does exist between level loads, the actors that are you adding to your inventory do not. They exist in the current world and just storing a pointer to them in a TArray doesn’t change that. Then when you call PickedUpItem->Destory() it quite literally destroys them in the current world. In fact at that point you now have a dangling reference in your TArray which is a potential crash waiting to happen. When they are destroyed, it doesn’t happen right away. They are flagged as pending delete and are hidden/no longer updated. However they aren’t really removed until the next garbage collection. That’s why you don’t see it reflected in your menu until after GC.
So there are a couple of ways to do what you’re looking to do. One, you can add a step when transitioning from world A to world B that recreates your inventory in B. You need to dig in to the whole loadmap loop but it’s not terribly scary. This is the most flexible because you’re essentially making sure the inventory is carried over.
You could store just the class of the inventory item. This has a bunch of limitations but certainly workable. You add the class, delete the actor and respawn the actor when used.
You could utilize the persistent level and stream in sublevels instead of changing maps. This is probably the best bet if you’re doing a single player only game.
You could implement a checkpoint like system where you save the player’s state (including inventory) when you start the level load, then restore it on load complete. I believe there are a few packs in the marketplace for this type of system.
I think you got me wrong. GameInstance thingy is OK. I meant what should I do instead of Destroy() to have the items picked up stay there. For example I have seen some tutorials on inventorie using a DataTable, basically they enter all he properties an item can take including an ID number and make a list of all items in the game. Then they were just calling that ID number to create/ drop/ pick up items real time (kinda like The Elder Scrolls game style I suppose ?) But that seemed strange to me so I choose this way.
For example is there a function I can use instead of Destroy() in UE4 for these type of situations or something ? Or maybe I can implement a function called DisablePickedUpItem() that sets CanTick, PhysicalCollision or all other things to false ?
Also sorry I am new to this inventory thing. If I don’t sound sensible please go easy on me
Thanks.
That’s sort of my point. You have to decide how you want to manage the inventory. Your current method of holding pointers to APickupBase actors that were placed/created in the current world won’t work. Let’s say in world A you have placed an APickupBase AB. You can hide AB in the world A by toggling it’s visibility and turning off collision. But you still have the problem that when you transition from world A to world B the actors in world A go away which means AB goes way. So your inventory would become invalid.
The solution you are talking about (re: a DataTable) is similar to my second solution above. Here you are simply storing references/index/tag that can be used to look up what type of inventory you’ve stored. You can use fields in the DataTable to manage all of the different properties. This is a perfectly fine solution. Really it all comes down to what you are trying to do and what the limitations of your game are.
Thank you very much [USER=“1384187”]Joe Wilcox WisE[/USER] . I will take your advice I guess. I will try to dig a bit deeper and give a bit more thought on this to come up with something that makes sense.
If you have a source on this type of thing please let me know so I can study them too.
Also if I can finish this project before I die I’ll mention you in special thanks
OK I finally understood how it should be done and why.
Normally you might try to reference the class as stated above by using **FClassFinder **and pointing to general pathway where your blueprint items supposed to be. But as you can see the link below it warns against doing that and advises using a Game Data structure: https://docs.unrealengine.com/en-us/Resources/SampleGames/ARPG/BalancingBlueprintandC-
So that was why tutorials were using Data Tables. I hope this thread helps other people.