The InventoryManager Component

Please read the Inventory Guide section to learn more about inventory used in kheljs framework. The InventoryManager component is responsible for the following aspects of the game:

  • Loading player's inventory from a persistent store.
  • Providing a default inventory for the player if player's inventory was not found in the persistent store.
  • Loading the game level inventory for the level from a persistent store.
  • Providing a default inventory for the level if the level inventory was not found in the persistent store.
  • Save inventory status to persistent store transparently when inventory content changes.

The default InventoryManager component loads inventory for the player as well as for the game level from the following files

  • inventory-item-types.ts - declares a set of inventory item types.
  • player-inventory-items.ts - declares the initial inventory of the player at the given game level.
  • player-inventory-capacity.ts - Indicates the max number of the items the player inventory hold.
  • level-inventory-items.ts - declares the iintial inventory for the game level itself.
  • inventory-items-decorator-config.ts -Indicates how the inventory items are highlighted or decorated.

Declaring inventory types

The list of all inventory item types used in player's inventory or in a level inventory are described in the file inventory-item-types.ts as follows. This file provides the location of the asset used to display a given inventory item type, its scaling, initial rotation, and a set of attributes. The attributes object contains properties of the item type which do not change during the game e.g. mass, weight, maxrounds etc.

Every Item type also has one or more categories specified which helps the game to identify and categorize the inventory items for various purposes. For example, player will be able to weild an item only it is marked with a category "weapon" and will be able to fire with that item only if it is marked with category "gun" etc.

Note that this file simply describes what inventory items are possible at a given game level but does not actually create these items for the level. To create ineventory items for a given level you have to specify them in the file level-invetory-items.ts as described below. Similarly to create inventory items for the player itself, you have to specify them in the file player-inventory-items.ts. The following shows the content of a sample inventory-item-types.ts file.

import { AssetPack } from "@Kheljs/core"
import { InventoryItemType } from "@Kheljs/core";
import { manifest as guns } from "@idutta2007/guns"
import { manifest as gunSounds } from "@idutta2007/gun-sounds"
const gunsPack = new AssetPack( guns );
const soundPack = new AssetPack( gunSounds );
const rifleSoundAssets = {
far_distance: soundPack.getAssetInfoByName( "rifle_far_distance" ),
indoor_large_room: soundPack.getAssetInfoByName( "rifle_indoor_large_room" ),
indoor_med_room: soundPack.getAssetInfoByName( "rifle_indoor_med_room" ),
indoor_small_room: soundPack.getAssetInfoByName( "rifle_indoor_small_room" ),
raw_outdoor_close: soundPack.getAssetInfoByName( "rifle_raw_outdoor_close" ),
raw_outdoor_far: soundPack.getAssetInfoByName( "rifle_raw_outdoor_far" ),
reload_close: soundPack.getAssetInfoByName( "rifle_reload_close" ),
}
const pistolSoundAssets = {
far_distance: soundPack.getAssetInfoByName( "pistol_far_distance" ),
indoor_large_room: soundPack.getAssetInfoByName( "pistol_indoor_large_room" ),
indoor_med_room: soundPack.getAssetInfoByName( "pistol_indoor_med_room" ),
indoor_small_room: soundPack.getAssetInfoByName( "pistol_indoor_small_room" ),
raw_outdoor_close: soundPack.getAssetInfoByName( "pistol_raw_outdoor_close" ),
raw_outdoor_far: soundPack.getAssetInfoByName( "pistol_raw_outdoor_far" ),
}
// List all inventory types for this level
export const inventoryItemTypes: InventoryItemType[] = [
{
name: "AssaultRifle_1",
categories : [ "weapon", "gun", "rifle" ],
description : "This is AssaultRifle of type 1",
meshAssetInfo: gunsPack.getAssetInfoByName( "AssaultRifle_1" ),
pictureAssetInfo: gunsPack.getAssetInfoByName( "pic_AssaultRifle_1" ),
transform: {
scaling: new Vector3(0.5, 0.5, 0.5),
rotation: new Vector3(Math.PI/2, 0, 0)
},
attributes: {
maxRounds: 250,
soundAssets: rifleSoundAssets
}
},
...
{
name: "Pistol_2",
categories : [ "weapon", "gun", "pistol" ],
description : "This is a Pistol of type 2",
meshAssetInfo: gunsPack.getAssetInfoByName( "Pistol_2" ),
pictureAssetInfo: gunsPack.getAssetInfoByName( "pic_Pistol_2" ),
transform: {
scaling: new Vector3(0.6, 0.6, 0.6),
rotation: new Vector3(Math.PI/2, 0, 0)
},
attributes: {
maxRounds: 85,
soundAssets: pistolSoundAssets
}
},
];

Declaring initial inventory for the game level

The initial inventory for a given game level is specified in the file level-inventory-items.ts. This file describes which items are placed in what locations in the game. The content of this file is pretty straightforward. Notice that this file imports the inventory-item-types.ts file and uses the item types from there to specify an item's asset.

import { inventoryItemTypes } from "./inventory-item-types";
// default list of inventory items
export const defaultLevelInventoryItems: InventoryItemConfig [] = [
{
inventoryItemType: inventoryItemTypes.find( x => x.name == "AssaultRifle_1" ),
transform: {
position: new Vector3( 7.5, 0, 137 ),
},
state: {
rounds: 20,
damage: 0.0
}
},
{
inventoryItemType: inventoryItemTypes.find( x => x.name == "AssaultRifle_2" ),
transform: {
position: new Vector3( -15, 0, 136)
},
state: {
rounds: 20,
}
},
....
]

The state object contains properties of the inventory item which changes over time. These properties will be saved to persistent store when the level state is saved.

Loading the game level inventory

The default level inventory can be loaded by creating an Inventory object and providing the configuation data for the inventory from configuration files. The InventoryManager class generated by kheljs already does this as follows:

export class InventoryManager implements IInventoryManager{
...
loadLevelInventory(){
// Get the level inventory config from state or use the default
let levelInventoryConfig = store.getCurrentLevelState().getLevelInventoryConfig();
if ( !levelInventoryConfig ){
levelInventoryConfig = {
name: "level-inventory",
itemConfigs: defaultLevelInventoryItems,
itemDecoratorConfigs: itemDecoratorConfigs
}
store.getCurrentLevelState().setLevelInventoryConfig( levelInventoryConfig)
}
// Create the inventory
this.levelInventory = new Inventory(levelInventoryConfig, this.level.scene);
DebugHelper.storeOnWindow( "levelInventory", this.levelInventory )
}
...
}

Declaring initial inventory for the player

The initial inventory items for the player can be specified in the file player-inventory-items.ts file. The format of this file is same as the file level-inventory-items.ts. By default, the player inventory is empty but you can add one or more inventory items if you want to start with a non-empty inventory for the player. However, there is a limit on how many items you can add to player's inventory. This limit is specified in the file name player-inventory-capacity.ts. The content of this file is pretty straightforward. For each item type or item category, a max limit is specified. During game play, the player cant acquire an item if the maximum capacity for that type or category of item is reached.

Loading Player Inventory

Player inventory is loaded in the same way as level inventory is loaded by default InventoryManager class generated by kheljs. The snippet of code to load the player inventory is shown below.

export class InventoryManager1 implements IInventoryManager{
playerInventory: Inventory;
levelInventory: Inventory;
...
loadPlayerInventory(){
let playerInventoryConfig = store.getCurrentLevelState().getPlayerInventoryConfig();
if ( !playerInventoryConfig ){
playerInventoryConfig = {
name: "player-inventory",
itemConfigs: defaultPlayerInventoryItems,
itemDecoratorConfigs: itemDecoratorConfigs,
itemCapacities: itemCapacities
}
store.getCurrentLevelState().setPlayerInventoryConfig( playerInventoryConfig)
}
// Create player inventory
this.playerInventory = new Inventory(playerInventoryConfig, this.level.scene);
DebugHelper.storeOnWindow( "playerInventory", this.playerInventory )
}
...
}

Decorating inventory items in the game

When inventory items are displayed on a game level, they need to be decorated or highlighted to catch attention of the user. An inventory item can be highlighted by associating itself with a decorator object. Kheljs provides a set of simple decorators and you can write your own decorator simply by implementing an interface. The decorators for inventory items at a given game level are specified in the file inventory-item-decorators.ts. This file specifies a decorator object for each inventory item type. Some decorators may allow customization while others may not depending on the particular implementation.

The default application generated by kheljs uses some of these basic decorators to highlight inventory items in the game. A sample of the decorator configuration file is shown below:

export const itemDecoratorConfigs: ItemDecoratorConfig [] =[
{
itemTypeName: "AssaultRifle_1",
highlighter: new GlowHighlighter({
// How much highlighter is offset from the item
translation: new Vector3( -1.55, 0, 0.1)
}),
},
{
itemTypeName: "AssaultRifle_2",
highlighter: new CylindricalHighlighter( {
useFireTexture: true,
glowIntensity: 3,
alpha: 0.2,
diameterTop: 1,
diameterBottom: 0,
height: 1.5,
scaling: new Vector3(0.8, 0.8, 0.8),
translation: new Vector3(0.5, 0, 0 )
}),
},
{
itemTypeName: "Pistol_1",
highlighter: new SphericalHighlighter( {glowIntensity: 0.9 }),
},
{
itemTypeName: "Pistol_2",
highlighter: new SphericalHighlighter({
useFireTexture: true,
glowIntensity: 0.2,
alpha: 0.4,
}),
}
]

Displaying Player Inventory

kheljs provides a very a basic UI to display the inventory of the player. You can easily write your own UI to display player's inventory or use third party package to do so. The following example shows how to create the inventory panel and display it.

const ui = new AdvancedDynamicTexture( "UI", scene );
const inventoryPanel = new InventoryPanel(this.playerInventory)

When running the default application generated by kheljs press the key "g" on your keyboard to see the default UI of the game. The inventory panel is displayed as part of this UI in one of the tabs.