#Inventory System Discussion
1 messages · Page 1 of 1 (latest)
That is a very good Idea!
Also, you said the Player component represents the player. So would I pass it the players GameObject or give the player a script called Player?
The GameObject would not be very useful.
You'd need to find the player's Radar component somehow
I could create a script called Player, and get references to the radar and all that stuff,
so that in the Use() method I can just do cs player.radar.scanMultiplier *= upgradeMultiplier;
Yeah, something like that
A Player component will probably have actual methods and stuff in it too
but you will also create components that are literally just bags of references
especially for prefabs
it's a lot nicer than having to dig around with GetComponent
By bags of references you mean assigning in inspector?
Right
For example, your hotbar can be a bunch of instances of a “Hotbar Slot” prefab
It could start out like this
public class HotbarSlot : MonoBehaviour {
public Image itemIconDisplay;
public TMP_Text itemNameDisplay;
}
this would, you could do...
hotbar[3].itemIconDisplay.sprite = itemSpec.icon;
hotbar[3].itemNameDisplay.text = itemSpec.itemName;
You could then make it nicer by making the references private and adding some methods
public class HotbarSlot : MonoBehaviour {
[SerializeField] Image itemIconDisplay;
[SerializeField] TMP_Text itemNameDisplay;
public void Display(ItemSpec itemSpec) {
itemIconDisplay.sprite = itemSpec.icon;
itemNameDisplay.text = itemSpec.itemName;
}
}
and thus
hotbar[3].Display(itemSpec);
I have a prefab for displaying a single input hint icon
It used to look like this
and all of the logic had to go wherever it was used
Then I moved the logic into the class, so it looked more like this
For the UpgradeKindEnum would that be in a script or.. where would that be stored?
Inventory System Discussion
The actual declaration of the enum type can go anywhere
(in any script file, that is)
The only rule with declaring stuff is that you can only have one ScriptableObject or MonoBehaviour.
You can stuff a bunch of other classes, structs, and enums into a script file
So should I just put it into the UpgradeItemSpec class?
the radar doesnt have an upgrades thing yet.
also, would the upgrades on the radar be another enum?
They'd be the same enum!
Oh!
also, you might have to do a bit more than just |= to combine the enums
the idea with [Flags] is that each enum value is 1, 2, 4, 8, 16, ...
creating a bitmask
so a value of 3 is a combination of the enums with values 1 and 2
This makes sense for upgrades that add new features
you either have the flash or you don't
If it's something where you progressively upgrade it over time, then an enum doesn't make sense
e.g. if you can upgrade the flash further after you first unlock it
in that case you'd just have an int variable that tracks the flash level
Tbh, I feel like it would be easier to just have an int variable for everything, so even if it only does or doesnt have the flash, I could just say that if (flashEnabled == 0) hasFlash = false; else if (flashEnabled > 0) hasFlash = true;
Also, I tried creating the scriptable object for this script, and I got a null reference exception
Is this script not supposed to be a ScriptableObject?
Oh I see, its because its an abstract class
How can I assign the itemName?
I can't create an instance of the class at all because its abstract.
You need to create other classes that derive from it
like these: #💻┃unity-talk message
How do I use the classes that derive from it? Currently they are sitting in my assets and don't do all that much. Would I need to create a list like you said earlier?
If items don't stack and you don't need custom data for each instance (e.g. a durability value), you can just just List<ItemSpec> as an inventory
I've never used a List<> before, I normally use arrays. Do I set the length of it to the amount of hotbar slots I have somehow?
you can serialize a List<T> just like you can serialize a T[]
So like this in start: items = new List<ItemSpec>(5);?
If you want to be able to put some items in the player's inventory when the game starts, just do this:
[SerializeField] List<ItemSpec> items;
and then set it to have 5 slots in the inspector
(and maybe assign some items)
Would I need two of these lists? One for the left hand and another for the right hand, even though the right hand only holds one item.
the right hand wouldn't be a list
just an ItemSpec
and then you'd have a function that goes like...
public void Swap(int hotbarSlot) {
items[hotbarSlot], rightHand = rightHand, items[hotbarslot];
}
maybe a bit too clever :p
public void Swap(int hotbarSlot) {
ItemSpec temp = rightHand;
rightHand = items[hotbarSlot];
items[hotbarSlot] = temp;
}
less clever
Yeah, I don't quite know how this first one works, I mean I know it practically does the same thing, but I've never seen that type of thing before.
actually, I don't think this works
oh right, the syntax is wrong
it needs parentheses around the left half
too clever :p
and the right too
(contents[a], contents[b]) = (contents[b], contents[a]);
copied from somewhere in my project
It's creating a tuple on the right side and then assigning to a tuple on the left side
How could I determine which hotbar slot is currently selected?
you'd store the index (an integer)
is the index for lists the same as arrays, if there are 4 ItemSpec in the list it would be index's 0-3
correct?
For empty slots would I just leave them blank?
Also, I just set up controls for switching between slots and swapping hands
Right, since there is no item in that slot
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
This is what I did for input
Currently I am getting an Argument Out Of Range Exception when using the swapHands key.
Oh I know why, I made the list up to 4 but then changed the name so it reset the settings i had in inspector.
It works now
Now I just gotta set up the actual items.
Would this be an effective method to increase the players speed for a few seconds? cs public IEnumerator IncreasePlayerSpeed(int effectLength, int speedAmount) { movement.speed *= speedAmount; yield return new WaitForSeconds(effectLength); }
this would permanently increase your speed
you're getting into an "effects" system, which is another place that can get really complicated depending on your requirements
I usually prefer to calculate the value as needed, based on a list of active effects
if you do movement.speed /= speedAmount at the end, it should work out fine
you could accrue rounding errors with floating point math, though
so you wind up with, say, a speed of 0.99996 after several powerup cycles
An alternative would be to have a List<Powerup> where Powerup looks like...
public class Powerup {
public float endTime;
public float speedMultiplier = 1f;
public float damageMultiplier = 1f;
}
(with more fields as needed)
Once per frame, you would throw out all expired powerups, then compute things with them
powerups.RemoveAll(powerup => powerup.endTime <= Time.time);
movement.speed = movement.baseSpeed;
foreach (var powerup in powerups) {
movement.speed *= powerup.speedMultiplier;
}
e.g.
Uh, yeah, how do I set up the actual items? I have a place to store them, and I have data about them, but how do I create them?
the physical things you'll find in the world?
Yeah, like, for a consumable, do I instantiate an object with ConsumableItemSpec?
ConsumableItemSpec is not a component, so it can't be attached to a game object
You'll want to create an ItemPickup component (a MonoBehaviour, specifically). It'll hold a reference to an ItemSpec.
you can start by just making it a cube or something
As in, an ItemSpec thats in the inventory list?
Well it’s not in your inventory yet, right?
It’s on the floor
For this, where would you pass in the ItemSpec?
the Display methods takes one
I see that, but from which class would this method be called?
whoever wants to update the hotbar -- probably something inside the player class
like when you pick up a new item, or when you swap items
you could totally just call Display on every single hotbar slot ever time you do anything to your inventory
If the slot is empty wouldn't the method throw an error because there is no ItemSpec assigned?
It should clear itself if you give it a null reference.
The slot selection is working now. https://streamable.com/icwgpy
But I'm not sure how to assign items to the slots. How do I create the items with the data?
Also, all of those errors are null reference exceptions
Since there is nothing assigned by default.
have you not created any item spec assets yet?
Is this one?
I'm talking about assets: instances of ConsumableItemSpec (or UpgradeItemSpec, or some other kind of item) in your Project folder
you need to add CreateAssetMenu to this class so that you can create assets out of it
With this method, could I still make the radar gun itself its own item that you can find in the world. It would go in the player's right hand slot.
So that's where things get more complicated
If you want the radar gun to be exactly the same sort of "item" as an upgrade or a consumable, you now need to be able to turn an ItemSpec into a thing that can actually do stuff in the world
I suppose you could just make a new kind of item whose Use method does whatever radar does
But to be able to apply upgrades to the item, you'd need to create a new class to store information about those upgrades
remember when I was talking about having an ItemData class?
this would be a situation where you need that
Do I need to rework the whole inventory system to account for the radar object?
Currently the inventory UI doesn't work, but the backend does, items do get swapped between hands when pressing f. https://streamable.com/sglqzk
I can start reworking inventory things tomorrow
its bed time :)
An alternative would be to just "fake it"
you'd add a new kind of item spec -- maybe "key item spec"
like Key Items in a pokemon game
It would do absolutely nothing other than have a name and icon
The actual radar behavior would still be attached to the player
it would just check if you have an item that matches the radar item spec asset
Could I still make objects appear in front of the player? Like, if they have an upgrade in their left hand, it will show in front of them.
You could reuse the item pickup prefab
or you could make something that literally just displays a model
conceptually, this is very similar to a hotbar slot
just with a model (or a different image) instead of the item's icon
What if I added model displaying to the HotbarSlot script. So that the Display method would instantiate a prefab from the ItemSpec in the slot selected. Then when you switch slots, it deleted the instance and replaces it with the prefab from the ItemSpec in the new selected slot.
Yeah, that'd work.
Something like this. ```cs
public class HotbarSlot : MonoBehaviour {
[SerializeField] Image itemIconDisplay;
[SerializeField] Sprite defaultIcon;
ItemModel instance;
public void Display(ItemSpec itemSpec) {
Destroy(instance);
if (itemSpec != null) {
itemIconDisplay.sprite = itemSpec.icon;
instance = Instantiate(itemSpec.displayModel);
}
else {
itemIconDisplay.sprite = defaultIcon;
}
}
}```
Currently the UI side of things is giving me problems, I created a RefreshSlots() method to refresh the hotbar slots sprites. Here is a video of the issue: https://streamable.com/4wyhw2
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
Is it because the display function is null when the ItemSpec is null?
I fixed it by creating a type of ItemSpec called DefaultItemSpec which acts as an empty item, but none of its variables are null. This solves the problem of having constant errors in the console, as well as the problem with GUI not working properly. https://streamable.com/0nbvik
I am no longer struggling with getting the GUI to function properly, however, I am struggling with getting the models to appear correctly. I am trying to create prefabs of objects via the HotbarSlot script, but for some reason objects arent deleting correctly and arent being generated at all. Here are my scripts:
HotbarSlot: https://hastebin.com/share/odikadetaw.csharp
Inventory: https://hastebin.com/share/uzifejuzom.csharp
ItemSpec: https://hastebin.com/share/ugakarawow.csharp
instead of doing this...
if (leftHand.transform.childCount > 0) Destroy(leftHand.transform.GetChild(0).transform);
i would just store direct references to the spawned items
I would make a Hand component whose sole job is to show and hide items
HotbarSlot should not need to know how to deal with the prefabs
It can tell the Hand that it needs to show an item
You need to separate your concerns.
(although, really, I'd not have HotbarSlot care about hands at all)
Thank you, that fixes that, now objects are generating correctly at the players hand positions.
I am currently testing it and have encountered an issue with the RefreshSlots() method. For some reason, the objects in the players left hand were updating late, while the right hand was working perfectly. Currently my solution is to put the RefreshSlots() method in FixedUpdate() so it is constantly updated, but not enough to slow down the game a whole lot.
Hi fen, I have successfully made objects appear in front of the player, I have also made it to where I can decide what items are allowed in the right hand slot. https://streamable.com/9r011l
oops, sent that message in the totally wrong server lol
nice (:
What I really like about this is the radars screen doesnt reset at all when the gun gets deleted and created in the other hand. Since the screen is a render texture it works perfectly.
And to get the objects to move around the player smoothy I created Hand objects that have the same RotateAroundPlayer script that the radar gun had. So the objects just get parented to the hands and move smoothly.
Is there a way I can check if the object in the players main hand is the radar, and only then allow the player to use upgrades?
So if the main hand is empty, the radar doesnt get upgraded. But if the RadarGun is in the players main hand and the player uses an upgrade in their offhand it does get upgraded.
Hi fen, I really need help with this. I can't seem to figure out how I can make the player able to drop items. I want the player to press G, and then the item in the currently selected slot will spawn the Pickup version of the object at the players feet. My problem is if the player picks up an item, I don't know how to store the physical item that was picked up.
Here is my inventory script https://hastebin.com/share/ahibizinem.csharp
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
You don't need to store the original in-world item you picked up -- you can just create a brand-new object
Do I store the item data in the ItemPickup class that the in-world item has?
So, when the player picks the item up I set the item in the players currently selected slot to the item stored on the item picked up.
You should be able to construct an ItemPickup from nothing but the ItemSpec
and when you find an item in the world, you get the ItemSpec from the ItemPickup and put that in your inventory
That's exactly what I did :)
But, I added a little check that says if the ItemSpec doesn't have an item to spawn in the world, don't drop it, since if you drop it you can't pick it back up.
When I get home I'm going to rework the text so it displays on the UI instead of in world space.
I'm also going to figure out how I can make upgrades only get applied if the radar is equipped in the right hand.
You could make UpgradeItemSpec abstract
and then create more specific specs for each kind of upgrade
(assuming you have more than one kind of thing you can upgrade)
either way, the Use method can check the item in your right hand
and just do nothing if it's incompatible
one mildly annoying thing...
this means you need an ItemSpec reference (which will be to the radar's ItemSpec asset)
so that you can check if, say...
player.rightHand.itemSpec == radarItemSpec
you'd have to assign this to each instance of UpgradeItemSpec