FolkeLogo

Rest A-Shored

Genre: Single Player, Survival, Explorer


Platform & Control: Voice controlled - Microphone required


Engine: Unreal Engine 4


Development Time: 4 Weeks


Team Size: 3 Designers, 3 3D Artist, 3 2D Artis, 3 Programmers


Describtion of the game: Rest A-Shored is a voice recognition simulation tech demo. In this game you literally talk to the characters helping them to survive and possibly escape the island.

Voice Recognition

Rest A-Shored is a voice recognition simulation tech demo. 


Play the game by commanding the characters in the game, telling them what to do.


Help the stranded people getting of the island by collecting resources and repair the stranded boat.

My responsibility as a programmer:

Components 

The goal of the project was to create everything modular. By making components, we could create systems that made the components cooperate with one and other.

Jump to Components


Game Systems

 By having components such as “Collectible” and “Craftable” we could make systems making them work for every object we wanted. We could tag the objects and the designers could easily do whatever they wanted to make it work.

Jump to Game Systems


Crafting 

I made a crafting system, making the player be able to combine various resources to create items. As an example; The player could pick up a stick and a stone, and tell the character “Craft axe!” and boom, you created an axe.

Jump to Crafting


Inventory 

I created an inventory system, so that if the player picked up certain objects, instead of having it equipped, it went into an inventory. The player can craft items from the resources by having the required resources in the inventory.

Jump to Inventory

 Game Systems

Creating components to easily tag objects for being used in various systems. As mention earlier, the goal of all the programming for the game was to make everything modular so that the designers could go “crazy” when creating content.


The designers could “tag” an object with a component so that object could be used in any system, such as making a stick “harvestable” and everything that was “craftable” required recipes that had “harvastable” objects as ingredients.


Every time we created a new component, we either had to implement a system that could use the component or add in the existing systems functionality for the new component. By doing like this, the designing of the game became modular and the designers could “go nuts”.

          		
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TTEdibleComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHaveBeenEaten);

UCLASS(ClassGroup = (Edible), meta = (BlueprintSpawnableComponent))
class GP2_TEAM3_API UTTEdibleComponent : public UActorComponent
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable, Category = "Eater")
		FORCEINLINE float GetFoodValue()const { return FoodValue; }
		void GetBeingEaten();

	UPROPERTY(EditAnywhere, Category = "Edible")
	    float FoodValue = 0;
	UPROPERTY(BlueprintAssignable, Category = "Edible")
	    FOnHaveBeenEaten BeenEaten;
};
       
	
          		
#include "TTEdibleComponent.h"
void UTTEdibleComponent::GetBeingEaten()
{
	BeenEaten.Broadcast();
}
        
	

Components

As mention in previous section (Components), every component needs a system to operate with one and other.


Say you have just created an axe, that have the component “equipable”, then you need a system for the characters that we called “equiper”, that can equip any equipable component. Just add the equipable to any object you want the character to be able to equip and you can use whatever you want. The axe has a “equipable” and can therefore be equiped by any character.


Later there are objects that require the character to have certain “equiped” items, such as fishing pools and trees. By checking what the character has equiped in its “equiper”, the harvesting begins if the equiped item match the required item for the harvesting.

          		
#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "../Interaction/TTInteractableComponent.h"
#include "TTEquiperComponent.generated.h"

class UTTEquipableComponent;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class GP2_TEAM3_API UTTEquiperComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	UTTEquiperComponent();

protected:

	UPROPERTY(EditDefaultsOnly)
	class USkeletalMeshSocket* equipmentSocket;

	UPROPERTY(BlueprintReadOnly)
	UTTEquipableComponent* currentEquipment;

public:	
	UFUNCTION(BlueprintCallable)
	bool Equip(UTTEquipableComponent* equipment);

	UFUNCTION(BlueprintCallable)
	TEnumAsByte<EInteractionAnimation> UseEqupment(UTTInteractableComponent* interactable);

	UFUNCTION(BlueprintCallable)
	float GetEquipmentRange();

	UFUNCTION(BlueprintCallable)
	void DropEquipment();
};
       
	
          		
#include "TTEquiperComponent.h"
#include "Components/Interaction/TTInteractableComponent.h"
#include "Array.h"
#include "Components/Interaction/TTInteractorComponent.h"
#include "TTEquipableComponent.h"

UTTEquiperComponent::UTTEquiperComponent()
{
	PrimaryComponentTick.bCanEverTick = false;
}

bool UTTEquiperComponent::Equip(UTTEquipableComponent* equipment) //bool
{
	if(equipment->CurrentOwner != nullptr)
		return false;

	if (currentEquipment != equipment) {
		DropEquipment();
	}
	currentEquipment = equipment;
	if(currentEquipment != nullptr)
		currentEquipment->Equip(this);
	return true;
}

TEnumAsByte<EInteractionAnimation> UTTEquiperComponent::UseEqupment(UTTInteractableComponent* interactable)
{
	interactable->Use(this, currentEquipment);
	return interactable->UsageAnimation;
}

float UTTEquiperComponent::GetEquipmentRange()
{
	return currentEquipment != nullptr ? currentEquipment->Range : 5;
}

void UTTEquiperComponent::DropEquipment()
{
	if(currentEquipment != nullptr)
		currentEquipment->Drop(this);

	currentEquipment = nullptr;
}
        
	
          		
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TTHarvester.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHarvesterComplete);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHarvesterFail);

UCLASS(ClassGroup = (Edible), meta = (BlueprintSpawnableComponent))
class GP2_TEAM3_API UTTHarvester : public UActorComponent
{
	GENERATED_BODY()
protected:
	virtual void BeginPlay() override;
public:
	void GetHarvestedComplete();

	UFUNCTION(BlueprintCallable, Category = "Harvestabke")
	void ResetHarvest();

	UFUNCTION(BlueprintCallable, Category = "Harvestabke")
		AActor* Harvest(AActor* HarvestTarget, UTTEquiperComponent* CurrentToolEquiped);

	UPROPERTY(BlueprintAssignable, Category = "Harvestable")
		FOnHarvesterComplete OnHarvesterComplete;

	UPROPERTY(BlueprintAssignable, Category = "Harvestable")
		FOnHarvesterFail OnHarvestFailed;
		class UTTHarvestable* TargetHarvest;
	
	float CurrentHarvestTime = 0;
	float HarvestTime = 0;
};
        
	
          		
#include "TTHarvester.h"
#include "TTHarvestable.h"
#include "Engine/World.h"
#include "Components/ActorComponent.h"
#include "Components/Equipment/TTEquiperComponent.h"
void UTTHarvester::BeginPlay()
{
	Super::BeginPlay();
	CurrentHarvestTime = 0;	
}
void UTTHarvester::GetHarvestedComplete()
{
	OnHarvesterComplete.Broadcast();
}

void UTTHarvester::ResetHarvest()
{
	CurrentHarvestTime = 0;
}

AActor* UTTHarvester::Harvest(AActor* HarvestTarget, UTTEquiperComponent* CurrentToolEquiped)
{
	return nullptr;
}
        
	

Crafting

The crafting system is made for the designer to combine various “collectibles” into items the character can equip.


The designers can through blueprints create any kind of recipe. The final item in this case needs to be “equipable”, and the ingredients need to be “harvestable”. The designer chooses how many ingredients is needed the amount needed.





Once the player fulfills the requiredment for the recipe, the item can be made. For example; Crafting an axe require a rock and a stick. If the player has both of those and say “Craft Axe!” then the character will create an axe, consuming the required ingredients.

          		
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TTHarvestable.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHaveBeenHarvest);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnResourceDepleted);

UCLASS(ClassGroup = (Edible), meta = (BlueprintSpawnableComponent))
class GP2_TEAM3_API UTTHarvestable : public UActorComponent
{
	GENERATED_BODY()
protected:
	virtual void BeginPlay() override;
public:

	UFUNCTION(BlueprintCallable, Category = "Harvestabke")
	AActor* Harvest();

	UPROPERTY(EditAnywhere, BlueprintReadOnly ,Category = "Harvestable")
	int32 StartAmount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Harvestable")
	int32 CurrentAmount = 0;

	UPROPERTY(BlueprintAssignable, Category = "Harvestable")
	FOnHaveBeenHarvest OnBeenHarvested;
	UPROPERTY(BlueprintAssignable, Category = "Harvestable")
	FOnResourceDepleted OnResourceDepleted;

	UPROPERTY(EditAnywhere, Category = "Harvestable")
	float HarvestDuration = 1;

	UPROPERTY(EditAnywhere, Category = "Harvestable")
	TSubclassOf<AActor> Resource;

	UFUNCTION(BlueprintCallable ,Category = Harvestable)
	bool IsAvailableForHarvest();

	UFUNCTION(BlueprintCallable, Category = Harvestable)
	void UpdateProgression(float deltaTime);

private:

	float progression;
};
       
	
          		
#include "TTHarvestable.h"
#include "Engine/World.h"
#include "GameFramework/Actor.h"

void UTTHarvestable::BeginPlay()
{
	Super::BeginPlay();
	CurrentAmount = StartAmount;
}

AActor* UTTHarvestable::Harvest()
{
	if(!IsAvailableForHarvest() || CurrentAmount <= 0) return nullptr;
	progression = 0;
	CurrentAmount--;
	OnBeenHarvested.Broadcast();
	if (CurrentAmount == 0)
	{
		OnResourceDepleted.Broadcast();
	}
	AActor* resource = GetWorld()->SpawnActor(Resource);
	return resource;
}

bool UTTHarvestable::IsAvailableForHarvest()
{
	return progression >= HarvestDuration && CurrentAmount > 0;
}

void UTTHarvestable::UpdateProgression(float deltaTime)
{
	progression += deltaTime;
}
        
	
          		
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Map.h"
#include "TTCrafterComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDoneCrafting);
USTRUCT(BlueprintType)
struct FIngredientPair
{
	GENERATED_BODY()
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
	FName DispayName;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
	TSubclassOf<AActor> Ingredient;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
	int Amount;
};

USTRUCT(BlueprintType)
struct FRecipe
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
		TArray<FName> Name;

	bool IsthisMyName(FName name)
	{
		if(Name.Contains(name)) return true;
		return false;
	}

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
	TArray<FIngredientPair> Ingridients;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Crafter")
	TSubclassOf<AActor> CraftIntoThisObject;

	UPROPERTY()
		bool DoesThisCombine = false;
};

UCLASS(ClassGroup = (Crafter), meta = (BlueprintSpawnableComponent))
class GP2_TEAM3_API UTTCrafterComponent : public UActorComponent
{
	GENERATED_BODY()
protected:
	//virtual void BeginPlay() override;
public:

	virtual void BeginPlay() override;

	void AddNameToCommandSystem();

	UFUNCTION(BlueprintCallable, Category = "Crafter")
	TSubclassOf<AActor> CraftByInventory(class UTTInventoryComponent* inventory);
	UFUNCTION(BlueprintCallable, Category = "Crafter")
	TSubclassOf<AActor> CraftByName(class UTTInventoryComponent* inventory, FName RecipeName, bool consumeItems);
	UFUNCTION(BlueprintCallable, Category = "Crafter")
	TArray<FIngredientPair> WhatAmIMissing(UTTInventoryComponent* inventory, FName RecipeName);
	UPROPERTY(BlueprintAssignable, Category = "Crafter")
	FOnDoneCrafting OnDoneCrafting;

	UPROPERTY(EditAnywhere, Category = "Crafter")
	TArray<FRecipe> Recipes;

	int32 NumberOfIngredient(TArray<class UTTStoreableComponent*> listOfIngerdients, TSubclassOf<AActor> Ingredient);
};
        
	
          		
#include "TTCrafterComponent.h"
#include "Engine/World.h"
#include "Map.h"
#include "CommandSystem/TTGameMode.h"
#include "CommandSystem/TTCommandSystem.h"
#include "../Equipment/TTStoreableComponent.h"
#include "../Interaction/TTInventoryComponent.h"
#include "SubclassOf.h"

void UTTCrafterComponent::BeginPlay()
{
	Super::BeginPlay();
	AddNameToCommandSystem();
}
void UTTCrafterComponent::AddNameToCommandSystem()
{
	ATTGameMode* correctGameMode = Cast<ATTGameMode>(GetWorld()->GetAuthGameMode());

	if (correctGameMode)
	{
		for (int i = 0; i < Recipes.Num(); i++)
		{
			for (int k = 0; k < Recipes[i].Name.Num(); k++)
			{
				correctGameMode->AddExtraWord(Recipes[i].Name[k].ToString());
			}
		}
	}
	else
		UE_LOG(LogTemp, Warning, TEXT("Using Wrong GameMode!"));
}

TSubclassOf<AActor> UTTCrafterComponent::CraftByInventory(UTTInventoryComponent* inventory)
{
	for (FRecipe recipe : Recipes)
	{
		if(recipe.Ingridients.Num() != inventory->GetInventorySize()) 
		continue;
		TArray<FIngredientPair> stuffINeed = WhatAmIMissing(inventory, recipe.Name[0]);
		if(stuffINeed.Num() == 0)
			return recipe.CraftIntoThisObject;
	}
	return nullptr;
}

TSubclassOf<AActor> UTTCrafterComponent::CraftByName(UTTInventoryComponent* inventory, FName RecipeName, bool consumeItems)
{
	FRecipe theRecipe;
	TArray<UTTStoreableComponent*> craftingMaterials = inventory->GetInventoryArray();
	TArray<UTTStoreableComponent*> materialToRemove;
	bool hasFoundStuff = false;;
	for (FRecipe recipe : Recipes)
	{
		if (recipe.Name.Contains(RecipeName))
		{
			theRecipe = recipe;
			hasFoundStuff = true;
			break;
		}
	}
	if(!hasFoundStuff)
		return nullptr;
	TMap<UClass*, int> materialCompletion;
	for (FIngredientPair ingredient : theRecipe.Ingridients)
	{
		materialCompletion.Add(ingredient.Ingredient->GetDefaultObject()->GetClass(), ingredient.Amount);
	}
	for (UTTStoreableComponent* craftingMaterial : craftingMaterials)
	{
		if(craftingMaterial == nullptr || !materialCompletion.Contains(craftingMaterial->GetOwner()->GetClass()) || materialCompletion[craftingMaterial->GetOwner()->GetClass()] <= 0) continue;

		materialCompletion[craftingMaterial->GetOwner()->GetClass()]--;
		materialToRemove.Add(craftingMaterial);
	}
	for (TPair<UClass*, int> ingidientPair : materialCompletion)
	{
		if(ingidientPair.Value > 0) return nullptr;
	}
	
	if(!consumeItems) return theRecipe.CraftIntoThisObject;

	for (UTTStoreableComponent* usedMaterial : materialToRemove)
	{
		inventory->RemoveItemFromInventory(usedMaterial);
	}

	return theRecipe.CraftIntoThisObject;
}

TArray<FIngredientPair&g; UTTCrafterComponent::WhatAmIMissing(UTTInventoryComponent* inventory, FName RecipeName) 
{
	TArray<FIngredientPair> missingIngredients;
	FRecipe theRecipe;
	TArray<UTTStoreableComponent*> craftingMaterials = inventory->GetInventoryArray();
	bool hasFoundStuff = false;;

	for (FRecipe recipe : Recipes)
	{
		if (recipe.Name.Contains(RecipeName))
		{
			theRecipe = recipe;
			hasFoundStuff = true;
			break;
		}
	}
	if (!hasFoundStuff)
		return missingIngredients;
	TMap<UClass*, FIngredientPair> materialCompletion;

	for (FIngredientPair ingredient : theRecipe.Ingridients)
	{
		materialCompletion.Add(ingredient.Ingredient->GetDefaultObject()->GetClass(), ingredient);
	}
	for (UTTStoreableComponent* craftingMaterial : craftingMaterials)
	{
		if (craftingMaterial == nullptr || !materialCompletion.Contains(craftingMaterial->GetOwner()->GetClass()) || materialCompletion[craftingMaterial->GetOwner()->GetClass()].Amount <= 0) continue;
		materialCompletion[craftingMaterial->GetOwner()->GetClass()].Amount--;
	}
	for (TPair<UClass*, FIngredientPair>> ingidientPair : materialCompletion)
	{
		if (ingidientPair.Value.Amount > 0)
		{
			TSubclassOf<AActor> storable = ingidientPair.Key;
			FIngredientPair pair;
			pair.Ingredient = storable;
			pair.Amount = ingidientPair.Value.Amount;
			pair.DispayName = ingidientPair.Value.DispayName;
			missingIngredients.Add(pair);
		}
	}
	return missingIngredients;
}

int32 UTTCrafterComponent::NumberOfIngredient(TArray<UTTStoreableComponent*> listOfIngerdients, TSubclassOf<AActor> Ingredient)
{
	int stuff = 0;
	for (int i = 0; i < listOfIngerdients.Num(); i++)
	{
		if (listOfIngerdients[i]->GetOwner()->IsA(Ingredient->GetDefaultObject()->GetClass()))
		{
			stuff++;
		}
	}
	return stuff;
}
        
	

Inventory

Each character in the game can carry different amount of items at once.


The designer choose how many items every character can carry at once, the item being carried needs to be taged by “StorableComponent”. Most items in the world can be carried except tools such as axe and fishing pole.


The inventory system is something I have been wanting to do for some time and when we decided to have collectible objects I finally had the opportunity to try it.

          		
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class GP2_TEAM3_API UTTStoreableComponent : public UActorComponent
{
	GENERATED_BODY()
public:	
	UTTStoreableComponent();

protected:
	virtual void BeginPlay() override;
public:	
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	class UTTInteractableComponent* GetInteractable();

private:

	class UTTInteractableComponent* interactable;
};
        
	
          		
#include "TTStoreableComponent.h"
#include "../Interaction/TTInteractableComponent.h"

UTTStoreableComponent::UTTStoreableComponent()
{
	PrimaryComponentTick.bCanEverTick = false;
}
void UTTStoreableComponent::BeginPlay()
{
	Super::BeginPlay();
}
void UTTStoreableComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
class UTTInteractableComponent* UTTStoreableComponent::GetInteractable()
{
	if (interactable == nullptr) {
		 UActorComponent* tempComp =  GetOwner()->GetComponentByClass(UTTInteractableComponent::StaticClass());
		 interactable = (tempComp != nullptr ?  CastChecked<UTTInteractableComponent>(tempComp) : nullptr);
	}
	return interactable;
}

        
	
          		
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "TTInventoryComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FInventoryEvent, const UTTStoreableComponent*, storeable);
class UTTStoreableComponent;

UCLASS( ClassGroup=(Interactable), meta=(BlueprintSpawnableComponent) )
class GP2_TEAM3_API UTTInventoryComponent : public UActorComponent
{
	GENERATED_BODY()
protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 size;

	UPROPERTY(EditAnywhere)
	TArray<UTTStoreableComponent*> inventory;
	class UTTInteractorComponent* interactor;

public:	

	UFUNCTION(BlueprintCallable, Category = Inventory)
	bool AddToInventory(UTTStoreableComponent* item);
	
	UFUNCTION(BlueprintCallable, Category = Inventory)
	TArray<UTTStoreableComponent*> GetInventoryArray();

	UFUNCTION(BlueprintCallable, Category = Inventory)
	FORCEINLINE int32 GetInventorySize() const {return inventory.Num(); }

	UFUNCTION(BlueprintCallable, Category = Inventor)
	UTTStoreableComponent* GetItem(int32 index);
	
	UFUNCTION(BlueprintCallable, Category = Inventory)
	UTTStoreableComponent* TakeItemFromInventorybyIndex(int32 index);

	UFUNCTION(BlueprintCallable, Category = Inventory)
	UTTStoreableComponent* GetItemByName(const FName name);
	
	UFUNCTION(BlueprintCallable, Category = Inventory)
	UTTStoreableComponent* DropItemByName(FName name, FVector dropPosition);

	UFUNCTION(BlueprintCallable, Category = Inventory)
	bool RemoveItemFromInventory(class UTTStoreableComponent* item);

	UPROPERTY(BlueprintAssignable)
	FInventoryEvent OnAddedItem;

	UPROPERTY(BlueprintAssignable)
	FInventoryEvent OnRemovedItem;
};
        
	
          		
bool UTTInventoryComponent::AddToInventory(class UTTStoreableComponent* item)
{
	if(inventory.Num() >= size) return false;

	if (!interactor)
		interactor = CastChecked<UTTInteractorComponent>(GetOwner()->GetComponentByClass(UTTInteractorComponent::StaticClass()));
	if (interactor)
		item->GetInteractable()->OnPickup.Broadcast(interactor, this);
	inventory.Add(item);
	OnAddedItem.Broadcast(item);
	item->GetOwner()->SetActorHiddenInGame(true);
	return true;
}

TArray<UTTStoreableComponent*> UTTInventoryComponent::GetInventoryArray()
{
	for (int32 i = inventory.Num() - 1; i >= 0; i--)
	{
		if(inventory[i] == nullptr)
			inventory.RemoveAt(i);
	}

	return inventory;
}

UTTStoreableComponent* UTTInventoryComponent::GetItem(int32 index)
{
	if(inventory.Num() > 0)
	{
		if(index <=inventory.Num())
		return inventory[index];
	}
	return nullptr;
}

UTTStoreableComponent* UTTInventoryComponent::TakeItemFromInventorybyIndex(int32 index)
{
	return ( inventory.Num() < index ? inventory[index] : nullptr);
}

UTTStoreableComponent* UTTInventoryComponent::GetItemByName(FName name)
{
	for (UTTStoreableComponent* storable : inventory)
	{
		if(storable->GetInteractable()->HasNametag(name))
			return storable;
	}
	return nullptr;
}

UTTStoreableComponent* UTTInventoryComponent::DropItemByName(const FName name, FVector dropPosition)
{
   UTTStoreableComponent* item = GetItemByName(name); 
   if(item == nullptr)
	   return nullptr;
   item->GetOwner()->SetActorHiddenInGame(false);
   item->GetOwner()->SetActorLocation(dropPosition);
   if(!interactor)
	   interactor = CastChecked<UTTInteractorComponent>(GetOwner()->GetComponentByClass(UTTInteractorComponent::StaticClass()));
   if(interactor)
	   item->GetInteractable()->OnDrop.Broadcast(interactor);
   RemoveItemFromInventory(item);

   return item;
}

bool UTTInventoryComponent::RemoveItemFromInventory(class UTTStoreableComponent* item)
{
	int32 size = inventory.Num() - 1;
	for (int i = size; i >= 0; i--)
	{
		if (inventory[i] == item)
		{
			inventory.RemoveAt(i);
			OnRemovedItem.Broadcast(item);
			return true;
		}
	}	
	return false;
}