Disclaimer: I do not claim this is the best (or even a good way) to design and implement an inventory system. There is a slight (great) chance that I throughout the authoring of this post decide that ‘this is stupid’ and just scrap the system all-together and start over. If so, you’ll get your money(time) back in the form of virtual cupcakes.
In this post I will try to explain the inventory system for my current lowpoly game project. A short explanation of the gameplay I’m ultimately going for is somewhat of an adventure/mystery game. This is because I want to keep the project on a difficulty level I can handle, therefor I don’t want to have a combat system and as few advanced models (characters) as possible (This is the first project where I make the models mostly myself).
Right now you can walk around, open a pneumatic house, pick up rocks and look out across the ocean. Epic gameplay!
Here is a demo of the current working version.
(Because of limitations in Chrome, you have to open it in Firefox)
You move around with WASD and look around with the mouse. The pointer is locked in the middle of the screen and invisible.
If you ‘look’ at something you get a small text describing what it is you are looking at (eg. “Tree”). This is done with a code similar to this (I removed some other code not needed for the inventory system):
[code lang=”js”]
function Update () {
var ray = Camera.main.ViewportPointToRay (Vector3(0.5f,0.5f,0.5f));
var hit : RaycastHit;
if (Physics.Raycast (ray, hit, 2)){
Debug.DrawLine (ray.origin, hit.point);
rayHitCollider = hit.transform.GetComponent(Collider);
switch (hit.transform.tag) {
case "Untagged":
information_text.GetComponent(UI.Text).text = "";
action_text.GetComponent(UI.Text).text = "";
action = "none";
break;
case "Item":
information_text.GetComponent(UI.Text).text = hit.transform.name;
if (hit.transform.GetComponent(Collider).GetComponent(Item)) {
rayHitCollider = hit.transform.GetComponent(Collider);
if (rayHitCollider.GetComponent(Item).ableToPickUp) {
action_text.GetComponent(UI.Text).text = "Pick up (E)";
action = "pickUpItem";
} else {
action_text.GetComponent(UI.Text).text = "";
}
}
break;
default:
information_text.GetComponent(UI.Text).text = hit.transform.name;
action_text.GetComponent(UI.Text).text = "";
action = "none";
break;
}
} else {
information_text.GetComponent(UI.Text).text = "";
action_text.GetComponent(UI.Text).text = "";
action = "none";
}
if (Input.GetKeyDown ("e")) {
doAction();
}
if (Input.GetKeyDown("f")) {
doItemAction("throw");
}
}
[/code]
The scripts shoots a raycast towards where the player is looking, locked to the center of the screen. If the hit of the raycast has a tag which is not “Untagged”, the text underneath the cursor changes to the name of the object and if the object type (decided by tag) has an option (eg. door->open) there is an actiontext below the cursor as well and a variable called “action” is set. If the object is “Untagged” or the raycast doesn’t hit anything the text is nulled.
If you aim your mouse at something you can interact with and press “E” a function called “doAction()” is called. It looks like this:
[code lang=”js”]
function doAction() {
switch (action) {
case "openDoor":
if (rayHitCollider.GetComponent(Door).doorOpen) {
rayHitCollider.GetComponent(Door).closeDoor();
} else {
rayHitCollider.GetComponent(Door).openDoor();
}
break;
case "pickUpItem":
transform.GetComponent(CharacterInventory).addItem(rayHitCollider.gameObject);
rayHitCollider.gameObject.SetActive(false);
rayHitCollider.gameObject.tag = "Untagged";
rayHitCollider.gameObject.transform.parent = equipItemObject.transform;
rayHitCollider.gameObject.transform.localPosition = Vector3(0,0,0);
rayHitCollider.gameObject.transform.localRotation = Quaternion(0f,0f,0f,0f);
break;
default:
break;
}
}
[/code]
I’m going to focus on the inventory-action. If you are able to pick up the item, determined in the first script (a bool in the “Item” script attached to all items), the “pickUpItem”-switch case is called and a few things happen.
- A function in the inventory script is called.
- The item is set to disabled.
- The item is “Untagged”.
- The items parent is set to an object called “equipItemObject”, which is basically just the position for the item in the players hand.
- The position and rotation of the item is set to “forward”.
So now the item is no longer on the ground but instead resides disabled as a child to a game object on the player. This is how my inventory looks in the Unity editor:
It’s an empty gameObject with 8 ‘slots’. When the game starts they an array with 8 empty objects (named “Empty” and with the empty thumbnail) is created and iterated through, changing the 1-8 to empty objects.
The function called in the inventory script on the other hand looks like this:
[code lang=”js”]
function addItem(item : UnityEngine.GameObject) {
var i=0;
for (var child: UnityEngine.Transform in inventoryUI.transform) {
if (child.name == "Empty") {
inventoryList[i] = item;
break;
}
i++;
}
i=0;
for (var child: UnityEngine.Transform in inventoryUI.transform) {
if (i < inventoryList.Count) {
var tempItem : UnityEngine.GameObject = inventoryList[i];
child.name = tempItem.GetComponent(Item).itemNameInInventory;
child.GetComponent(UI.Image).sprite = tempItem.GetComponent(Item).itemImageInInventory;
}
i++;
}
}
[/code]
It takes the item picked up from the ground as a parameter and tries to place it in an empty slot. Then it ‘resets’ all the items and images according to the new array.
A rock. In my inventory. Ready for throwing.
There we have it for the first part of the explaining of my inventory system. I’ll try to get the next one, where I’ll go over actions you can take with the item in hand and how to place it back on the ground, later this week.
Thanks for reading and comment with any questions or if you have any tips on how I could improve, both this code and in general.
Have a good one!
Edit: I noted a bug in the code that removes the item from the inventory when thrown. If you try the demo and throw the rock away, then pick it up, the “Action-text” will be nulled. It’s fixed now, but I won’t upload a new version of the demo just yet.